diff options
Diffstat (limited to 'svtools/source/contnr')
23 files changed, 30922 insertions, 0 deletions
diff --git a/svtools/source/contnr/contentenumeration.cxx b/svtools/source/contnr/contentenumeration.cxx new file mode 100644 index 000000000000..e3ba48180e9c --- /dev/null +++ b/svtools/source/contnr/contentenumeration.cxx @@ -0,0 +1,464 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" +#include "contentenumeration.hxx" +#include <svl/urlfilter.hxx> +#include <svtools/inettbc.hxx> +#include <svtools/imagemgr.hxx> + +/** === begin UNO includes === **/ +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +/** === end UNO includes === **/ +#include <comphelper/processfactory.hxx> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> + +#include <memory> + +//........................................................................ +namespace svt +{ +//........................................................................ + +#define ROW_TITLE 1 +#define ROW_SIZE 2 +#define ROW_DATE_MOD 3 +#define ROW_DATE_CREATE 4 +#define ROW_IS_FOLDER 5 +#define ROW_TARGET_URL 6 +#define ROW_IS_HIDDEN 7 +#define ROW_IS_VOLUME 8 +#define ROW_IS_REMOTE 9 +#define ROW_IS_REMOVEABLE 10 +#define ROW_IS_FLOPPY 11 +#define ROW_IS_COMPACTDISC 12 + +#define CONVERT_DATETIME( aUnoDT, aToolsDT ) \ + aToolsDT = ::DateTime( Date( aUnoDT.Day, aUnoDT.Month, aUnoDT.Year ), \ + Time( aUnoDT.Hours, aUnoDT.Minutes, aUnoDT.Seconds, aUnoDT.HundredthSeconds ) ); + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::Any; + using ::com::sun::star::util::DateTime; + using ::com::sun::star::sdbc::XResultSet; + using ::com::sun::star::sdbc::XRow; + using ::com::sun::star::ucb::XDynamicResultSet; + using ::com::sun::star::ucb::CommandAbortedException; + using ::com::sun::star::ucb::XContentAccess; + using ::com::sun::star::ucb::XCommandEnvironment; + using ::com::sun::star::beans::XPropertySet; + using ::rtl::OUString; + using ::ucbhelper::ResultSetInclude; + using ::ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS; + + //==================================================================== + //= FileViewContentEnumerator + //==================================================================== + //-------------------------------------------------------------------- + FileViewContentEnumerator::FileViewContentEnumerator( + const Reference< XCommandEnvironment >& _rxCommandEnv, + ContentData& _rContentToFill, ::osl::Mutex& _rContentMutex, + const IContentTitleTranslation* _pTranslator ) + :m_rContent ( _rContentToFill ) + ,m_rContentMutex ( _rContentMutex ) + ,m_refCount ( 0 ) + ,m_xCommandEnv ( _rxCommandEnv ) + ,m_pFilter ( NULL ) + ,m_pTranslator ( _pTranslator ) + ,m_bCancelled ( false ) + ,m_rBlackList ( ::com::sun::star::uno::Sequence< ::rtl::OUString >() ) + { + } + + //-------------------------------------------------------------------- + FileViewContentEnumerator::~FileViewContentEnumerator() + { + } + + //-------------------------------------------------------------------- + void FileViewContentEnumerator::cancel() + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_bCancelled = true; + m_pResultHandler = NULL; + m_pTranslator = NULL; + m_pFilter = NULL; + m_aFolder.aContent = ::ucbhelper::Content(); + m_aFolder.sURL = String(); + } + + //-------------------------------------------------------------------- + EnumerationResult FileViewContentEnumerator::enumerateFolderContentSync( + const FolderDescriptor& _rFolder, + const IUrlFilter* _pFilter, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList ) + { + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_aFolder = _rFolder; + m_pFilter = _pFilter; + m_pResultHandler = NULL; + m_rBlackList = rBlackList; + } + return enumerateFolderContent(); + } + + //-------------------------------------------------------------------- + void FileViewContentEnumerator::enumerateFolderContent( + const FolderDescriptor& _rFolder, const IUrlFilter* _pFilter, IEnumerationResultHandler* _pResultHandler ) + { + // ensure that we don't get deleted while herein + acquire(); + // the matching "release" will be called in onTerminated + // Note that onTerminated is only called if run was left normally. + // If somebody terminates the thread from the outside, then onTerminated + // will never be called. However, our terminate method is not accessible + // to our clients, so the only class which could misbehave is this class + // here itself ... + + ::osl::MutexGuard aGuard( m_aMutex ); + m_aFolder = _rFolder; + m_pFilter = _pFilter; + m_pResultHandler = _pResultHandler; + + OSL_ENSURE( m_aFolder.aContent.get().is() || m_aFolder.sURL.Len(), + "FileViewContentEnumerator::enumerateFolderContent: invalid folder descriptor!" ); + + // start the thread + create(); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL FileViewContentEnumerator::acquire() + { + return osl_incrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL FileViewContentEnumerator::release() + { + if ( 0 == osl_decrementInterlockedCount( &m_refCount ) ) + { + delete this; + return 0; + } + return m_refCount; + } + + //-------------------------------------------------------------------- + EnumerationResult FileViewContentEnumerator::enumerateFolderContent() + { + EnumerationResult eResult = ERROR; + try + { + + Reference< XResultSet > xResultSet; + Sequence< OUString > aProps(12); + + aProps[0] = OUString::createFromAscii( "Title" ); + aProps[1] = OUString::createFromAscii( "Size" ); + aProps[2] = OUString::createFromAscii( "DateModified" ); + aProps[3] = OUString::createFromAscii( "DateCreated" ); + aProps[4] = OUString::createFromAscii( "IsFolder" ); + aProps[5] = OUString::createFromAscii( "TargetURL" ); + aProps[6] = OUString::createFromAscii( "IsHidden" ); + aProps[7] = OUString::createFromAscii( "IsVolume" ); + aProps[8] = OUString::createFromAscii( "IsRemote" ); + aProps[9] = OUString::createFromAscii( "IsRemoveable" ); + aProps[10] = OUString::createFromAscii( "IsFloppy" ); + aProps[11] = OUString::createFromAscii( "IsCompactDisc" ); + + Reference< XCommandEnvironment > xEnvironment; + try + { + FolderDescriptor aFolder; + { + ::osl::MutexGuard aGuard( m_aMutex ); + aFolder = m_aFolder; + xEnvironment = m_xCommandEnv; + } + if ( !aFolder.aContent.get().is() ) + { + aFolder.aContent = ::ucbhelper::Content( aFolder.sURL, xEnvironment ); + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_aFolder.aContent = aFolder.aContent; + } + } + + Reference< XDynamicResultSet > xDynResultSet; + ResultSetInclude eInclude = INCLUDE_FOLDERS_AND_DOCUMENTS; + xDynResultSet = aFolder.aContent.createDynamicCursor( aProps, eInclude ); + + if ( xDynResultSet.is() ) + xResultSet = xDynResultSet->getStaticResultSet(); + } + catch( CommandAbortedException& ) + { + DBG_ERRORFILE( "createCursor: CommandAbortedException" ); + } + catch( Exception& ) + { + } + + bool bCancelled = false; + if ( xResultSet.is() ) + { + Reference< XRow > xRow( xResultSet, UNO_QUERY ); + Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY ); + + try + { + SortingData_Impl* pData; + DateTime aDT; + + while ( !bCancelled && xResultSet->next() ) + { + sal_Bool bIsHidden = xRow->getBoolean( ROW_IS_HIDDEN ); + // don't show hidden files + if ( !bIsHidden || xRow->wasNull() ) + { + pData = NULL; + + aDT = xRow->getTimestamp( ROW_DATE_MOD ); + sal_Bool bContainsDate = !xRow->wasNull(); + if ( !bContainsDate ) + { + aDT = xRow->getTimestamp( ROW_DATE_CREATE ); + bContainsDate = !xRow->wasNull(); + } + + OUString aContentURL = xContentAccess->queryContentIdentifierString(); + OUString aTargetURL = xRow->getString( ROW_TARGET_URL ); + sal_Bool bHasTargetURL = !xRow->wasNull() && aTargetURL.getLength() > 0; + + OUString sRealURL = bHasTargetURL ? aTargetURL : aContentURL; + + // check for restrictions + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_pFilter && !m_pFilter->isUrlAllowed( sRealURL ) ) + continue; + + if ( /* m_rBlackList.hasElements() && */ URLOnBlackList ( sRealURL ) ) + continue; + } + + pData = new SortingData_Impl; + pData->maTargetURL = sRealURL; + + pData->mbIsFolder = xRow->getBoolean( ROW_IS_FOLDER ) && !xRow->wasNull(); + pData->mbIsVolume = xRow->getBoolean( ROW_IS_VOLUME ) && !xRow->wasNull(); + pData->mbIsRemote = xRow->getBoolean( ROW_IS_REMOTE ) && !xRow->wasNull(); + pData->mbIsRemoveable = xRow->getBoolean( ROW_IS_REMOVEABLE ) && !xRow->wasNull(); + pData->mbIsFloppy = xRow->getBoolean( ROW_IS_FLOPPY ) && !xRow->wasNull(); + pData->mbIsCompactDisc = xRow->getBoolean( ROW_IS_COMPACTDISC ) && !xRow->wasNull(); + pData->SetNewTitle( xRow->getString( ROW_TITLE ) ); + pData->maSize = xRow->getLong( ROW_SIZE ); + + if ( bHasTargetURL && + INetURLObject( aContentURL ).GetProtocol() == INET_PROT_VND_SUN_STAR_HIER ) + { + ::ucbhelper::Content aCnt( aTargetURL, xEnvironment ); + try + { + aCnt.getPropertyValue( OUString::createFromAscii( "Size" ) ) >>= pData->maSize; + aCnt.getPropertyValue( OUString::createFromAscii( "DateModified" ) ) >>= aDT; + } + catch (...) {} + } + + if ( bContainsDate ) + { + CONVERT_DATETIME( aDT, pData->maModDate ); + } + + if ( pData->mbIsFolder ) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + ::svtools::VolumeInfo aVolInfo( pData->mbIsVolume, pData->mbIsRemote, + pData->mbIsRemoveable, pData->mbIsFloppy, + pData->mbIsCompactDisc ); + pData->maType = SvFileInformationManager::GetFolderDescription( aVolInfo ); + } + else + pData->maType = SvFileInformationManager::GetFileDescription( + INetURLObject( pData->maTargetURL ) ); + + // replace names on demand + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( m_pTranslator ) + { + OUString sNewTitle; + sal_Bool bTranslated = sal_False; + + if ( pData->mbIsFolder ) + bTranslated = m_pTranslator->GetTranslation( pData->GetTitle(), sNewTitle ); + else + bTranslated = implGetDocTitle( pData->maTargetURL, sNewTitle ); + + if ( bTranslated ) + pData->ChangeTitle( sNewTitle ); + } + } + + { + ::osl::MutexGuard aGuard( m_rContentMutex ); + m_rContent.push_back( pData ); + } + } + + { + ::osl::MutexGuard aGuard( m_aMutex ); + bCancelled = m_bCancelled; + } + } + eResult = SUCCESS; + } + catch( CommandAbortedException& ) + { + DBG_ERRORFILE( "FileViewContentEnumerator::enumerateFolderContent: caught an CommandAbortedException while enumerating!" ); + } + catch( Exception& ) + { + DBG_ERRORFILE( "FileViewContentEnumerator::enumerateFolderContent: caught an exception other than CommandAbortedException while enumerating!" ); + } + } + } + catch( CommandAbortedException& ) + { + DBG_ERRORFILE( "FileViewContentEnumerator::enumerateFolderContent: caught an CommandAbortedException!" ); + } + catch( Exception& ) + { + DBG_ERRORFILE( "FileViewContentEnumerator::enumerateFolderContent: caught an exception other than CommandAbortedException!" ); + } + + IEnumerationResultHandler* pHandler = NULL; + { + ::osl::MutexGuard aGuard( m_aMutex ); + pHandler = m_pResultHandler; + if ( m_bCancelled ) + return ERROR; + } + + { + ::osl::MutexGuard aGuard( m_rContentMutex ); + if ( eResult != SUCCESS ) + // clear any "intermediate" and unfinished result + m_rContent.clear(); + } + + if ( pHandler ) + pHandler->enumerationDone( eResult ); + return eResult; + } + + //-------------------------------------------------------------------- + + sal_Bool FileViewContentEnumerator::URLOnBlackList ( const ::rtl::OUString& sRealURL ) + { + ::rtl::OUString entryName = sRealURL.copy( sRealURL.lastIndexOf( rtl::OUString::createFromAscii("/")) +1 ); + + for (int i = 0; i < m_rBlackList.getLength() ; i++) + { + if ( entryName.equals( m_rBlackList[i] ) ) + return true; + } + + return false; + } + + //-------------------------------------------------------------------- + sal_Bool FileViewContentEnumerator::implGetDocTitle( const OUString& _rTargetURL, OUString& _rRet ) const + { + sal_Bool bRet = sal_False; + + try + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( !m_xDocInfo.is() ) + { + m_xDocInfo = m_xDocInfo.query( + ::comphelper::getProcessServiceFactory()->createInstance( + String( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.document.StandaloneDocumentInfo") ) + ) + ); + } + + DBG_ASSERT( m_xDocInfo.is(), "FileViewContentEnumerator::implGetDocTitle: no DocumentProperties service!" ); + if ( !m_xDocInfo.is() ) + return sal_False; + + m_xDocInfo->loadFromURL( _rTargetURL ); + Reference< XPropertySet > xPropSet( m_xDocInfo, UNO_QUERY ); + + Any aAny = xPropSet->getPropertyValue( OUString::createFromAscii( "Title" ) ); + + OUString sTitle; + if ( ( aAny >>= sTitle ) && sTitle.getLength() > 0 ) + { + _rRet = sTitle; + bRet = sal_True; + } + } + catch ( const Exception& ) + { + } + + return bRet; + } + + //-------------------------------------------------------------------- + void SAL_CALL FileViewContentEnumerator::run() + { + enumerateFolderContent(); + } + + //-------------------------------------------------------------------- + void SAL_CALL FileViewContentEnumerator::onTerminated() + { + release(); + } + +//........................................................................ +} // namespace svt +//........................................................................ + diff --git a/svtools/source/contnr/contentenumeration.hxx b/svtools/source/contnr/contentenumeration.hxx new file mode 100644 index 000000000000..16db279ad547 --- /dev/null +++ b/svtools/source/contnr/contentenumeration.hxx @@ -0,0 +1,287 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX +#define SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX + +/** === begin UNO includes === **/ +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/document/XStandaloneDocumentInfo.hpp> +/** === end UNO includes === **/ +#include <osl/thread.hxx> +#include <rtl/ref.hxx> +#include <ucbhelper/content.hxx> +#include <rtl/ustring.hxx> +#include <tools/datetime.hxx> +#include <vcl/image.hxx> + +class IUrlFilter; +//........................................................................ +namespace svt +{ +//........................................................................ + + //==================================================================== + //= SortingData_Impl + //==================================================================== + struct SortingData_Impl + { + private: + ::rtl::OUString maFilename; // only filename in upper case - for compare purposes + ::rtl::OUString maTitle; // -> be carefull when changing maTitle to update maFilename only when new + ::rtl::OUString maLowerTitle; + + + public: + ::rtl::OUString maType; + ::rtl::OUString maTargetURL; + ::rtl::OUString maImageURL; + ::rtl::OUString maDisplayText; + DateTime maModDate; + Image maImage; + sal_Int64 maSize; + sal_Bool mbIsFolder; + sal_Bool mbIsVolume; + sal_Bool mbIsRemote; + sal_Bool mbIsRemoveable; + sal_Bool mbIsFloppy; + sal_Bool mbIsCompactDisc; + + inline SortingData_Impl(); + inline const ::rtl::OUString& GetTitle() const; + inline const ::rtl::OUString& GetLowerTitle() const; + inline const ::rtl::OUString& GetFileName() const; + inline void SetNewTitle( const ::rtl::OUString& rNewTitle ); // new maTitle is set -> maFilename is set to same! + inline void ChangeTitle( const ::rtl::OUString& rChangedTitle ); // maTitle is changed, maFilename is unchanged! + + private: + inline void SetTitles( const ::rtl::OUString& rNewTitle ); + }; + + inline SortingData_Impl::SortingData_Impl() : + maSize ( 0 ), + mbIsFolder ( sal_False ), + mbIsVolume ( sal_False ), + mbIsRemote ( sal_False ), + mbIsRemoveable ( sal_False ), + mbIsFloppy ( sal_False ), + mbIsCompactDisc ( sal_False ) + { + } + + inline const ::rtl::OUString& SortingData_Impl::GetTitle() const + { + return maTitle; + } + + inline const ::rtl::OUString& SortingData_Impl::GetLowerTitle() const + { + return maLowerTitle; + } + + inline const ::rtl::OUString& SortingData_Impl::GetFileName() const + { + return maFilename; + } + + inline void SortingData_Impl::SetNewTitle( const ::rtl::OUString& rNewTitle ) + { + SetTitles( rNewTitle ); + maFilename = rNewTitle.toAsciiUpperCase(); + } + + inline void SortingData_Impl::ChangeTitle( const ::rtl::OUString& rChangedTitle ) + { + SetTitles( rChangedTitle ); + } + + inline void SortingData_Impl::SetTitles( const ::rtl::OUString& rNewTitle ) + { + maTitle = rNewTitle; + maLowerTitle = rNewTitle.toAsciiLowerCase(); + } + + //==================================================================== + //= IContentTitleTranslation + //==================================================================== + class IContentTitleTranslation + { + public: + virtual sal_Bool GetTranslation( const ::rtl::OUString& _rOriginalName, ::rtl::OUString& _rTranslatedName ) const = 0; + }; + + //==================================================================== + //= EnumerationResult + //==================================================================== + enum EnumerationResult + { + SUCCESS, /// the enumration was successfull + ERROR, /// the enumration was unsuccessfull + RUNNING /// the enumeration is still running, and the maximum wait time has passed + }; + + //==================================================================== + //= FolderDescriptor + //==================================================================== + struct FolderDescriptor + { + /** a content object describing the folder. Can be <NULL/>, in this case <member>sURL</member> + is relevant. + */ + ::ucbhelper::Content aContent; + /** the URL of a folder. Will be ignored if <member>aContent</member> is not <NULL/>. + */ + String sURL; + + FolderDescriptor() { } + + FolderDescriptor( const ::ucbhelper::Content& _rContent ) + :aContent( _rContent ) + { + } + + FolderDescriptor( const String& _rURL ) + :sURL( _rURL ) + { + } + }; + + //==================================================================== + //= IEnumerationResultHandler + //==================================================================== + class IEnumerationResultHandler + { + public: + virtual void enumerationDone( EnumerationResult _eResult ) = 0; + }; + + //==================================================================== + //= FileViewContentEnumerator + //==================================================================== + class FileViewContentEnumerator + :public ::rtl::IReference + ,private ::osl::Thread + { + public: + typedef ::std::vector< SortingData_Impl* > ContentData; + + private: + ContentData& m_rContent; + ::osl::Mutex& m_rContentMutex; + + oslInterlockedCount m_refCount; + mutable ::osl::Mutex m_aMutex; + + FolderDescriptor m_aFolder; + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > + m_xCommandEnv; + const IUrlFilter* m_pFilter; + const IContentTitleTranslation* m_pTranslator; + IEnumerationResultHandler* m_pResultHandler; + bool m_bCancelled; + + mutable ::com::sun::star::uno::Reference< ::com::sun::star::document::XStandaloneDocumentInfo > + m_xDocInfo; + + ::com::sun::star::uno::Sequence< ::rtl::OUString > m_rBlackList; + + sal_Bool URLOnBlackList ( const ::rtl::OUString& sRealURL ); + + public: + /** constructs an enumerator instance + + @param _rContentToFill + the structure which is to be filled with the found content + @param _rContentMutex + the mutex which protects the access to <arg>_rContentToFill</arg> + @param _pTranslator + an instance which should be used to translate content titles. May be <NULL/> + */ + FileViewContentEnumerator( + const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >& _rxCommandEnv, + ContentData& _rContentToFill, + ::osl::Mutex& _rContentMutex, + const IContentTitleTranslation* _pTranslator + ); + + /** enumerates the content of a given folder + + @param _rFolder + the folder whose content is to be enumerated + @param _pFilter + a filter to apply to the found contents + @param _pResultHandler + an instance which should handle the results of the enumeration + */ + void enumerateFolderContent( + const FolderDescriptor& _rFolder, + const IUrlFilter* _pFilter, + IEnumerationResultHandler* _pResultHandler + ); + + /** enumerates the content of a given folder synchronously + */ + EnumerationResult enumerateFolderContentSync( + const FolderDescriptor& _rFolder, + const IUrlFilter* _pFilter, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList = ::com::sun::star::uno::Sequence< ::rtl::OUString >() + ); + + /** cancels the running operation. + + Note that "cancel" may mean that the operation is running, but its result + is simply disregarded later on. + */ + void cancel(); + + // IReference overridables + virtual oslInterlockedCount SAL_CALL acquire(); + virtual oslInterlockedCount SAL_CALL release(); + + using Thread::operator new; + using Thread::operator delete; + + protected: + ~FileViewContentEnumerator(); + + private: + EnumerationResult enumerateFolderContent(); + + // Thread overridables + virtual void SAL_CALL run(); + virtual void SAL_CALL onTerminated(); + + private: + sal_Bool implGetDocTitle( const ::rtl::OUString& _rTargetURL, ::rtl::OUString& _rRet ) const; + }; + +//........................................................................ +} // namespace svt +//........................................................................ + +#endif // SVTOOLS_SOURCE_CONTNR_CONTENTENUMERATION_HXX + diff --git a/svtools/source/contnr/fileview.cxx b/svtools/source/contnr/fileview.cxx new file mode 100644 index 000000000000..4ea086ad7580 --- /dev/null +++ b/svtools/source/contnr/fileview.cxx @@ -0,0 +1,2808 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <svtools/fileview.hxx> +#include <svtools/svtdata.hxx> +#include <svtools/imagemgr.hxx> +#include <svtools/headbar.hxx> +#include <svtools/svtabbx.hxx> +#include <svtools/svtools.hrc> +#include "fileview.hrc" +#include "contentenumeration.hxx" +#include <svtools/AccessibleBrowseBoxObjType.hxx> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/ucb/XProgressHandler.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/XDynamicResultSet.hpp> +#include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <vcl/waitobj.hxx> +#include <com/sun/star/io/XPersist.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/ucb/XCommandInfo.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +#include <algorithm> +#include <memory> +#include <tools/urlobj.hxx> +#include <tools/datetime.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/localfilehelper.hxx> +#include <ucbhelper/content.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <vcl/msgbox.hxx> +#ifndef INCLUDED_RTL_MATH_H +#include <rtl/math.hxx> +#endif +#include <tools/config.hxx> +#include <osl/mutex.hxx> +#include <osl/conditn.hxx> +#include <vos/timer.hxx> +#include <vcl/svapp.hxx> +#include <vcl/sound.hxx> +#include <unotools/ucbhelper.hxx> +#include <unotools/intlwrapper.hxx> +#include <unotools/syslocale.hxx> +#include <svl/urlfilter.hxx> + +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::task; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::beans; +using namespace ::comphelper; +using ::svt::SortingData_Impl; +using ::svt::FolderDescriptor; +using ::vos::TTimeValue; +using ::rtl::OUString; + +#define ALL_FILES_FILTER "*.*" + +#define COLUMN_TITLE 1 +#define COLUMN_TYPE 2 +#define COLUMN_SIZE 3 +#define COLUMN_DATE 4 + +DECLARE_LIST( StringList_Impl, OUString* ) + +#define ROW_HEIGHT 17 // the height of a row has to be a little higher than the bitmap +#define QUICK_SEARCH_TIMEOUT 1500 // time in mSec before the quicksearch string will be reseted + +namespace +{ + //==================================================================== + //= ReleaseSolarMutex + //==================================================================== + struct ReleaseSolarMutex + { + private: + sal_uLong m_nCount; + + public: + inline ReleaseSolarMutex() + { + m_nCount = Application::ReleaseSolarMutex(); + } + inline ~ReleaseSolarMutex() + { + Application::AcquireSolarMutex( m_nCount ); + } + }; + + //==================================================================== + //= ITimeoutHandler + //==================================================================== + class CallbackTimer; + class ITimeoutHandler + { + public: + virtual void onTimeout( CallbackTimer* _pInstigator ) = 0; + }; + + //==================================================================== + //= CallbackTimer + //==================================================================== + class CallbackTimer : public ::vos::OTimer + { + protected: + ITimeoutHandler* m_pTimeoutHandler; + + public: + CallbackTimer( ITimeoutHandler* _pHandler ) : m_pTimeoutHandler( _pHandler ) { } + + protected: + virtual void SAL_CALL onShot(); + }; + + //-------------------------------------------------------------------- + void SAL_CALL CallbackTimer::onShot() + { + OSL_ENSURE( m_pTimeoutHandler, "CallbackTimer::onShot: nobody interested in?" ); + ITimeoutHandler* pHandler( m_pTimeoutHandler ); + if ( pHandler ) + pHandler->onTimeout( this ); + } + +} + +// ----------------------------------------------------------------------- + +static sal_Bool isHighContrast( const Window* _pView ) +{ + return _pView->GetSettings().GetStyleSettings().GetHighContrastMode(); +} + +// ----------------------------------------------------------------------- + +void FilterMatch::createWildCardFilterList(const String& _rFilterList,::std::vector< WildCard >& _rFilters) +{ + if( _rFilterList.Len() ) + {// filter is given + xub_StrLen nCount = _rFilterList.GetTokenCount(); + _rFilters.reserve( nCount ); + xub_StrLen nIndex = 0; + OUString sToken; + do + { + sToken = _rFilterList.GetToken( 0, ';', nIndex ); + if ( sToken.getLength() ) + { + _rFilters.push_back( WildCard( sToken.toAsciiUpperCase() ) ); + } + } + while ( nIndex != STRING_NOTFOUND ); + } + else + // no filter is given -> match all + _rFilters.push_back( WildCard( String::CreateFromAscii( "*" ) ) ); +} +// class ViewTabListBox_Impl --------------------------------------------- + +class ViewTabListBox_Impl : public SvHeaderTabListBox +{ +private: + Reference< XCommandEnvironment > mxCmdEnv; + + ::osl::Mutex maMutex; + HeaderBar* mpHeaderBar; + SvtFileView_Impl* mpParent; + Timer maResetQuickSearch; + OUString maQuickSearchText; + String msAccessibleDescText; + String msFolder; + String msFile; + sal_uInt32 mnSearchIndex; + sal_Bool mbResizeDisabled : 1; + sal_Bool mbAutoResize : 1; + sal_Bool mbEnableDelete : 1; + sal_Bool mbEnableRename : 1; + + void DeleteEntries(); + void DoQuickSearch( const xub_Unicode& rChar ); + sal_Bool Kill( const OUString& rURL ); + +protected: + virtual sal_Bool DoubleClickHdl(); + virtual ::rtl::OUString GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const; + +public: + ViewTabListBox_Impl( Window* pParentWin, SvtFileView_Impl* pParent, sal_Int16 nFlags ); + ~ViewTabListBox_Impl(); + + virtual void Resize(); + virtual void KeyInput( const KeyEvent& rKEvt ); + virtual sal_Bool EditedEntry( SvLBoxEntry* pEntry, const XubString& rNewText ); + + void ClearAll(); + HeaderBar* GetHeaderBar() const { return mpHeaderBar; } + + void EnableAutoResize() { mbAutoResize = sal_True; } + void EnableDelete( sal_Bool bEnable ) { mbEnableDelete = bEnable; } + void EnableRename( sal_Bool bEnable ) { mbEnableRename = bEnable; } + sal_Bool IsDeleteOrContextMenuEnabled() { return mbEnableDelete || IsContextMenuHandlingEnabled(); } + + Reference< XCommandEnvironment > GetCommandEnvironment() const { return mxCmdEnv; } + + DECL_LINK( ResetQuickSearch_Impl, Timer * ); + + virtual PopupMenu* CreateContextMenu( void ); + virtual void ExcecuteContextMenuAction( sal_uInt16 nSelectedPopentry ); +}; + +// class HashedEntry -------------------------------------------------- + +class HashedEntry +{ // just a special String which can be compared on equality much faster +protected: + OUString maName; + sal_Int32 mnHashCode; +public: + inline HashedEntry( const OUString& rName ); + inline HashedEntry( const INetURLObject& rURL ); + inline HashedEntry( const HashedEntry& rCopy ); + virtual ~HashedEntry(); + + inline sal_Bool operator ==( const HashedEntry& rRef ) const; + inline sal_Bool operator !=( const HashedEntry& rRef ) const; + + inline const OUString& GetName() const; +}; + +inline HashedEntry::HashedEntry( const OUString& rName ): maName( rName ), mnHashCode( rName.hashCode() ) +{ +} + +inline HashedEntry::HashedEntry( const INetURLObject& rURL ): + maName( rURL.GetMainURL( INetURLObject::NO_DECODE ) ), + mnHashCode( maName.hashCode() ) +{ +} + +inline HashedEntry::HashedEntry( const HashedEntry& r ): maName( r.maName ), mnHashCode( r.mnHashCode ) +{ +} + +HashedEntry::~HashedEntry() +{ +} + +inline sal_Bool HashedEntry::operator ==( const HashedEntry& rRef ) const +{ + return mnHashCode == rRef.mnHashCode && maName.reverseCompareTo( rRef.maName ) == 0; +} + +inline sal_Bool HashedEntry::operator !=( const HashedEntry& rRef ) const +{ + return mnHashCode != rRef.mnHashCode || maName.reverseCompareTo( rRef.maName ) != 0; +} + +inline const OUString& HashedEntry::GetName() const +{ + return maName; +} + +// class HashedEntryList ---------------------------------------------- + +class HashedEntryList : protected List +{// provides a list of _unique_ Entries +protected: + inline HashedEntry* First(); + inline HashedEntry* Next(); + inline void Append( HashedEntry* pNewEntry ); +public: + virtual ~HashedEntryList(); + + const HashedEntry* Find( const OUString& rNameToSearchFor ); + const HashedEntry* Find( const HashedEntry& rToSearchFor ); + // not const, because First()/Next() is used + using List::Insert; + const HashedEntry& Insert( HashedEntry* pInsertOrDelete ); + // don't care about pInsertOrDelete after this any more and handle it as invalid! + // returns the Entry, which is effectively inserted + + void Clear(); +}; + +inline HashedEntry* HashedEntryList::First() +{ + return ( HashedEntry* ) List::First(); +} + +inline HashedEntry* HashedEntryList::Next() +{ + return ( HashedEntry* ) List::Next(); +} + +inline void HashedEntryList::Append( HashedEntry* pNew ) +{ + List::Insert( pNew, LIST_APPEND ); +} + +HashedEntryList::~HashedEntryList() +{ + Clear(); +} + +const HashedEntry* HashedEntryList::Find( const OUString& rRefName ) +{ // simple linear search, which should be fast enough for this purpose + HashedEntry aRef( rRefName ); + HashedEntry* pIter = First(); + while( pIter && *pIter != aRef ) + pIter = Next(); + + return pIter; +} + +const HashedEntry* HashedEntryList::Find( const HashedEntry& rRef ) +{ // simple linear search, which should be fast enough for this purpose + HashedEntry* pIter = First(); + while( pIter && *pIter != rRef ) + pIter = Next(); + + return pIter; +} + +const HashedEntry& HashedEntryList::Insert( HashedEntry* pNew ) +{ // inserts (appends) only, if entry doesn't already exists + // if it already exists, pNew is deleted, because the caller must not worry about pNew any more + + DBG_ASSERT( pNew, "HashedEntryList::Insert(): NULL-pointer can't be inserted" ); + + const HashedEntry* pSearch = Find( *pNew ); + if( pSearch ) + { + delete pNew; + return *pSearch; + } + + Append( pNew ); + + return *pNew; +} + +void HashedEntryList::Clear() +{ + HashedEntry* p = First(); + while( p ) + { + delete p; + p = Next(); + } +} + +// class NameTranslationEntry ----------------------------------------- + +class NameTranslationEntry : public HashedEntry +{// a fast compareble String and another String, which is used to get a substitution for a given String +protected: + OUString maTranslatedName; +public: + inline NameTranslationEntry( const OUString& rOriginalName, const OUString& rTranslatedName ); + inline NameTranslationEntry( const ByteString& rOriginalName, const ByteString& rTranslatedName ); + + inline const OUString& GetTranslation() const; +}; + +inline NameTranslationEntry::NameTranslationEntry( const OUString& rOrg, const OUString& rTrans ): + HashedEntry( rOrg ), + maTranslatedName( rTrans ) +{ +} + +inline NameTranslationEntry::NameTranslationEntry( const ByteString& rOrg, const ByteString& rTrans ): + HashedEntry( OUString( rOrg.GetBuffer(), rOrg.Len(), RTL_TEXTENCODING_ASCII_US ) ), + maTranslatedName( OUString( rTrans.GetBuffer(), rTrans.Len(), RTL_TEXTENCODING_UTF8 ) ) +{ +} + +inline const OUString& NameTranslationEntry::GetTranslation() const +{ + return maTranslatedName; +} + +// class NameTranslationList ----------------------------------------- + +class NameTranslationList : protected HashedEntryList +{ // contains a list of substitutes of strings for a given folder (as URL) + // explanation of the circumstances see in remarks for Init(); +protected: + INetURLObject maTransFile; // URL of file with translation entries + HashedEntry maHashedURL; // for future purposes when dealing with a set of cached + // NameTranslationLists +private: + const String maTransFileName; + void Init(); // reads the translation file and fills the (internal) list + +public: + NameTranslationList( const INetURLObject& rBaseURL ); + // rBaseURL: path to folder for which the translation of the entries + // should be done + + using List::operator==; + inline sal_Bool operator ==( const HashedEntry& rRef ) const; + using List::operator!=; + inline sal_Bool operator !=( const HashedEntry& rRef ) const; + + const OUString* Translate( const OUString& rName ) const; + // returns NULL, if rName can't be found + + inline void Update(); // clears list and init + + inline const String& GetTransTableFileName() const; + // returns the name for the file, which contains the translation strings +}; + +inline const String& NameTranslationList::GetTransTableFileName() const +{ + return maTransFileName; +} + +void NameTranslationList::Init() +{ +// Tries to read the file ".nametranslation.table" in the base folder. Complete path/name is in maTransFile. +// Further on, the found entries in the section "TRANSLATIONNAMES" are used to replace names in the +// base folder by translated ones. The translation must be given in UTF8 +// See examples of such a files in the samples-folder of an Office installation + + try + { + ::ucbhelper::Content aTestContent( maTransFile.GetMainURL( INetURLObject::NO_DECODE ), Reference< XCommandEnvironment >() ); + + if( aTestContent.isDocument() ) + {// ... also tests the existence of maTransFile by throwing an Exception + const sal_Char* pSection = "TRANSLATIONNAMES"; + String aFsysName( maTransFile.getFSysPath( INetURLObject::FSYS_DETECT ) ); + Config aConfig( aFsysName ); + + aConfig.SetGroup( ByteString( pSection ) ); + + sal_uInt16 nKeyCnt = aConfig.GetKeyCount(); + + for( sal_uInt16 nCnt = 0 ; nCnt < nKeyCnt ; ++nCnt ) + Insert( new NameTranslationEntry( aConfig.GetKeyName( nCnt ), aConfig.ReadKey( nCnt ) ) ); + } + } + catch( Exception const & ) {} +} + +NameTranslationList::NameTranslationList( const INetURLObject& rBaseURL ): + maTransFile( rBaseURL ), + maHashedURL( rBaseURL ), + maTransFileName( String::CreateFromAscii( ".nametranslation.table" ) ) +{ + maTransFile.insertName( maTransFileName ); + Init(); +} + +inline sal_Bool NameTranslationList::operator ==( const HashedEntry& rRef ) const +{ + return maHashedURL == rRef; +} + +inline sal_Bool NameTranslationList::operator !=( const HashedEntry& rRef ) const +{ + return maHashedURL != rRef; +} + +const OUString* NameTranslationList::Translate( const OUString& rName ) const +{ + const NameTranslationEntry* pSearch = static_cast< const NameTranslationEntry* >( + ( const_cast< NameTranslationList* >( this ) )->Find( rName ) ); + + return pSearch? &pSearch->GetTranslation() : NULL; +} + +inline void NameTranslationList::Update() +{ + Clear(); + Init(); +} + +// class NameTranslator_Impl ------------------------------------------ + +// enables the user to get string substitutions (translations for the content) for a given folder +// see more explanations above in the description for NameTranslationList +class NameTranslator_Impl : public ::svt::IContentTitleTranslation +{ +private: + NameTranslationList* mpActFolder; +public: + NameTranslator_Impl( void ); + NameTranslator_Impl( const INetURLObject& rActualFolder ); + virtual ~NameTranslator_Impl(); + + // IContentTitleTranslation + virtual sal_Bool GetTranslation( const OUString& rOriginalName, OUString& rTranslatedName ) const; + + void UpdateTranslationTable(); // reads the translation file again + + void SetActualFolder( const INetURLObject& rActualFolder ); + const String* GetTransTableFileName() const; + // returns the name for the file, which contains the translation strings +}; + +//==================================================================== +//= SvtFileView_Impl +//==================================================================== + +class SvtFileView_Impl :public ::svt::IEnumerationResultHandler + ,public ITimeoutHandler +{ +protected: + SvtFileView* mpAntiImpl; + Link m_aSelectHandler; + + ::rtl::Reference< ::svt::FileViewContentEnumerator > + m_pContentEnumerator; + Link m_aCurrentAsyncActionHandler; + ::osl::Condition m_aAsyncActionFinished; + ::rtl::Reference< ::vos::OTimer > m_pCancelAsyncTimer; + ::svt::EnumerationResult m_eAsyncActionResult; + bool m_bRunningAsyncAction; + bool m_bAsyncActionCancelled; + + +public: + + ::std::vector< SortingData_Impl* > maContent; + ::osl::Mutex maMutex; + + ViewTabListBox_Impl* mpView; + NameTranslator_Impl* mpNameTrans; + const IUrlFilter* mpUrlFilter; + sal_uInt16 mnSortColumn; + sal_Bool mbAscending : 1; + sal_Bool mbOnlyFolder : 1; + sal_Bool mbReplaceNames : 1; // translate folder names or display doc-title instead of file name + sal_Int16 mnSuspendSelectCallback : 1; + sal_Bool mbIsFirstResort : 1; + + IntlWrapper aIntlWrapper; + + String maViewURL; + String maAllFilter; + String maCurrentFilter; + Image maFolderImage; + Link maOpenDoneLink; + Reference< XCommandEnvironment > mxCmdEnv; + + SvtFileView_Impl( SvtFileView* pAntiImpl, Reference < XCommandEnvironment > xEnv, + sal_Int16 nFlags, + sal_Bool bOnlyFolder ); + virtual ~SvtFileView_Impl(); + + void Clear(); + + FileViewResult GetFolderContent_Impl( + const String& rFolder, + const FileViewAsyncAction* pAsyncDescriptor, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList = ::com::sun::star::uno::Sequence< ::rtl::OUString >() ); + + FileViewResult GetFolderContent_Impl( + const FolderDescriptor& _rFolder, + const FileViewAsyncAction* pAsyncDescriptor, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList = ::com::sun::star::uno::Sequence< ::rtl::OUString >()); + void FilterFolderContent_Impl( const OUString &rFilter ); + void CancelRunningAsyncAction(); + + void OpenFolder_Impl(); + // #83004# ------- + void ReplaceTabWithString( OUString& aValue ); + void CreateDisplayText_Impl(); + void CreateVector_Impl( const Sequence < OUString > &rList ); + void SortFolderContent_Impl(); + + void EntryRemoved( const OUString& rURL ); + void EntryRenamed( OUString& rURL, + const OUString& rName ); + String FolderInserted( const OUString& rURL, + const OUString& rTitle ); + + sal_uLong GetEntryPos( const OUString& rURL ); + + inline void EnableContextMenu( sal_Bool bEnable ); + inline void EnableDelete( sal_Bool bEnable ); + + void Resort_Impl( sal_Int16 nColumn, sal_Bool bAscending ); + sal_Bool SearchNextEntry( sal_uInt32 &nIndex, + const OUString& rTitle, + sal_Bool bWrapAround ); + + inline sal_Bool EnableNameReplacing( sal_Bool bEnable = sal_True ); // returns false, if action wasn't possible + void SetActualFolder( const INetURLObject& rActualFolder ); + + sal_Bool GetDocTitle( const OUString& rTargetURL, OUString& rDocTitle ) const; + + void SetSelectHandler( const Link& _rHdl ); + + void InitSelection(); + void ResetCursor(); + + inline void EndEditing( bool _bCancel ); + +protected: + DECL_LINK( SelectionMultiplexer, void* ); + +protected: + // IEnumerationResultHandler overridables + virtual void enumerationDone( ::svt::EnumerationResult _eResult ); + void implEnumerationSuccess(); + + // ITimeoutHandler + virtual void onTimeout( CallbackTimer* _pInstigator ); +}; + +inline void SvtFileView_Impl::EnableContextMenu( sal_Bool bEnable ) +{ + mpView->EnableContextMenuHandling( bEnable ); + if( bEnable ) + mbReplaceNames = sal_False; +} + +inline void SvtFileView_Impl::EnableDelete( sal_Bool bEnable ) +{ + mpView->EnableDelete( bEnable ); + if( bEnable ) + mbReplaceNames = sal_False; +} + +inline sal_Bool SvtFileView_Impl::EnableNameReplacing( sal_Bool bEnable ) +{ + mpView->EnableRename( bEnable ); + + sal_Bool bRet; + if( mpView->IsDeleteOrContextMenuEnabled() ) + { + DBG_ASSERT( !mbReplaceNames, "SvtFileView_Impl::EnableNameReplacing(): state should be not possible!" ); + bRet = !bEnable; // only for enabling this is an unsuccessful result + } + else + { + mbReplaceNames = bEnable; + bRet = sal_True; + } + + return bRet; +} + +inline void SvtFileView_Impl::EndEditing( bool _bCancel ) +{ + if ( mpView->IsEditingActive() ) + mpView->EndEditing( _bCancel != false ); +} + +// functions ------------------------------------------------------------- + +OUString CreateExactSizeText_Impl( sal_Int64 nSize ) +{ + double fSize( ( double ) nSize ); + int nDec; + + long nMega = 1024 * 1024; + long nGiga = nMega * 1024; + + String aUnitStr = ' '; + + if ( nSize < 10000 ) + { + aUnitStr += String( SvtResId( STR_SVT_BYTES ) ); + nDec = 0; + } + else if ( nSize < nMega ) + { + fSize /= 1024; + aUnitStr += String( SvtResId( STR_SVT_KB ) ); + nDec = 1; + } + else if ( nSize < nGiga ) + { + fSize /= nMega; + aUnitStr += String( SvtResId( STR_SVT_MB ) ); + nDec = 2; + } + else + { + fSize /= nGiga; + aUnitStr += String( SvtResId( STR_SVT_GB ) ); + nDec = 3; + } + + OUString aSizeStr( ::rtl::math::doubleToUString( fSize, + rtl_math_StringFormat_F, nDec, + SvtSysLocale().GetLocaleData().getNumDecimalSep().GetChar(0))); + aSizeStr += aUnitStr; + + return aSizeStr; +} + +// ----------------------------------------------------------------------- +// class ViewTabListBox_Impl --------------------------------------------- +// ----------------------------------------------------------------------- + +ViewTabListBox_Impl::ViewTabListBox_Impl( Window* pParentWin, + SvtFileView_Impl* pParent, + sal_Int16 nFlags ) : + + SvHeaderTabListBox( pParentWin, WB_TABSTOP ), + + mpHeaderBar ( NULL ), + mpParent ( pParent ), + msAccessibleDescText( SvtResId( STR_SVT_ACC_DESC_FILEVIEW ) ), + msFolder ( SvtResId( STR_SVT_ACC_DESC_FOLDER ) ), + msFile ( SvtResId( STR_SVT_ACC_DESC_FILE ) ), + mnSearchIndex ( 0 ), + mbResizeDisabled ( sal_False ), + mbAutoResize ( sal_False ), + mbEnableDelete ( sal_True ), + mbEnableRename ( sal_True ) + +{ + Size aBoxSize = pParentWin->GetSizePixel(); + mpHeaderBar = new HeaderBar( pParentWin, WB_BUTTONSTYLE | WB_BOTTOMBORDER ); + mpHeaderBar->SetPosSizePixel( Point( 0, 0 ), mpHeaderBar->CalcWindowSizePixel() ); + + HeaderBarItemBits nBits = ( HIB_LEFT | HIB_VCENTER | HIB_CLICKABLE ); + if ( ( nFlags & FILEVIEW_SHOW_ALL ) == FILEVIEW_SHOW_ALL ) + { + mpHeaderBar->InsertItem( COLUMN_TITLE, String( SvtResId( STR_SVT_FILEVIEW_COLUMN_TITLE ) ), 180, nBits | HIB_UPARROW ); + mpHeaderBar->InsertItem( COLUMN_TYPE, String( SvtResId( STR_SVT_FILEVIEW_COLUMN_TYPE ) ), 140, nBits ); + mpHeaderBar->InsertItem( COLUMN_SIZE, String( SvtResId( STR_SVT_FILEVIEW_COLUMN_SIZE ) ), 80, nBits ); + mpHeaderBar->InsertItem( COLUMN_DATE, String( SvtResId( STR_SVT_FILEVIEW_COLUMN_DATE ) ), 500, nBits ); + } + else + mpHeaderBar->InsertItem( COLUMN_TITLE, String( SvtResId( STR_SVT_FILEVIEW_COLUMN_TITLE ) ), 600, nBits ); + + Size aHeadSize = mpHeaderBar->GetSizePixel(); + SetPosSizePixel( Point( 0, aHeadSize.Height() ), + Size( aBoxSize.Width(), aBoxSize.Height() - aHeadSize.Height() ) ); + InitHeaderBar( mpHeaderBar ); + SetHighlightRange(); + SetEntryHeight( ROW_HEIGHT ); + + Show(); + mpHeaderBar->Show(); + + maResetQuickSearch.SetTimeout( QUICK_SEARCH_TIMEOUT ); + maResetQuickSearch.SetTimeoutHdl( LINK( this, ViewTabListBox_Impl, ResetQuickSearch_Impl ) ); + + Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory(); + Reference< XInteractionHandler > xInteractionHandler = Reference< XInteractionHandler > ( + xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uui.InteractionHandler") ) ), UNO_QUERY ); + + mxCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() ); + + EnableContextMenuHandling(); +} + +// ----------------------------------------------------------------------- + +ViewTabListBox_Impl::~ViewTabListBox_Impl() +{ + maResetQuickSearch.Stop(); + + delete mpHeaderBar; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( ViewTabListBox_Impl, ResetQuickSearch_Impl, Timer*, EMPTYARG ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + maQuickSearchText = OUString(); + mnSearchIndex = 0; + + return 0; +} + +// ----------------------------------------------------------------------- + +void ViewTabListBox_Impl::Resize() +{ + SvTabListBox::Resize(); + Size aBoxSize = Control::GetParent()->GetOutputSizePixel(); + + if ( mbResizeDisabled || !aBoxSize.Width() ) + return; + + Size aBarSize = mpHeaderBar->GetSizePixel(); + aBarSize.Width() = mbAutoResize ? aBoxSize.Width() : GetSizePixel().Width(); + mpHeaderBar->SetSizePixel( aBarSize ); + + if ( mbAutoResize ) + { + mbResizeDisabled = sal_True; + Point aPos = GetPosPixel(); + SetPosSizePixel( Point( 0, aBarSize.Height() ), + Size( aBoxSize.Width(), aBoxSize.Height() - aBarSize.Height() ) ); + mbResizeDisabled = sal_False; + } +} + +// ----------------------------------------------------------------------- + +void ViewTabListBox_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + bool bHandled = false; + + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + if ( 0 == rKeyCode.GetModifier() ) + { + if ( rKeyCode.GetCode() == KEY_RETURN ) + { + ResetQuickSearch_Impl( NULL ); + GetDoubleClickHdl().Call( this ); + bHandled = true; + } + else if ( ( rKeyCode.GetCode() == KEY_DELETE ) && + mbEnableDelete ) + { + ResetQuickSearch_Impl( NULL ); + DeleteEntries(); + bHandled = true; + } + else if ( ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_NUM ) || + ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_ALPHA ) ) + { + DoQuickSearch( rKEvt.GetCharCode() ); + bHandled = true; + } + } + + if ( !bHandled ) + { + ResetQuickSearch_Impl( NULL ); + SvHeaderTabListBox::KeyInput( rKEvt ); + } +} + +// ----------------------------------------------------------------------- + +PopupMenu* ViewTabListBox_Impl::CreateContextMenu( void ) +{ + bool bEnableDelete = mbEnableDelete; + bool bEnableRename = mbEnableRename; + + if ( bEnableDelete || bEnableRename ) + { + sal_Int32 nSelectedEntries = GetSelectionCount(); + bEnableDelete &= nSelectedEntries > 0; + bEnableRename &= nSelectedEntries == 1; + } + + if ( bEnableDelete || bEnableRename ) + { + SvLBoxEntry* pEntry = FirstSelected(); + while ( pEntry ) + { + ::ucbhelper::Content aCnt; + try + { + OUString aURL( static_cast< SvtContentEntry * >( + pEntry->GetUserData() )->maURL ); + aCnt = ::ucbhelper::Content( aURL, mxCmdEnv ); + } + catch( Exception const & ) + { + bEnableDelete = bEnableRename = false; + } + + if ( bEnableDelete ) + { + try + { + Reference< XCommandInfo > aCommands = aCnt.getCommands(); + if ( aCommands.is() ) + bEnableDelete + = aCommands->hasCommandByName( + OUString::createFromAscii( "delete" ) ); + else + bEnableDelete = false; + } + catch( Exception const & ) + { + bEnableDelete = false; + } + } + + if ( bEnableRename ) + { + try + { + Reference< XPropertySetInfo > aProps = aCnt.getProperties(); + if ( aProps.is() ) + { + Property aProp + = aProps->getPropertyByName( + OUString::createFromAscii( "Title" ) ); + bEnableRename + = !( aProp.Attributes & PropertyAttribute::READONLY ); + } + else + bEnableRename = false; + } + catch( Exception const & ) + { + bEnableRename = false; + } + } + + pEntry = ( bEnableDelete || bEnableRename ) + ? NextSelected( pEntry ) + : 0; + } + } + + if ( bEnableDelete || bEnableRename ) + { + PopupMenu * pRet + = new PopupMenu( SvtResId( RID_FILEVIEW_CONTEXTMENU ) ); + pRet->EnableItem( MID_FILEVIEW_DELETE, bEnableDelete ); + pRet->EnableItem( MID_FILEVIEW_RENAME, bEnableRename ); + pRet->RemoveDisabledEntries( sal_True, sal_True ); + return pRet; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +void ViewTabListBox_Impl::ExcecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry ) +{ + switch ( nSelectedPopupEntry ) + { + case MID_FILEVIEW_DELETE : + DeleteEntries(); + break; + + case MID_FILEVIEW_RENAME : + EditEntry( FirstSelected() ); + break; + } +} + +// ----------------------------------------------------------------------- + +void ViewTabListBox_Impl::ClearAll() +{ + for ( sal_uInt16 i = 0; i < GetEntryCount(); ++i ) + delete (SvtContentEntry*)GetEntry(i)->GetUserData(); + Clear(); +} + +// ----------------------------------------------------------------------- +void ViewTabListBox_Impl::DeleteEntries() +{ + svtools::QueryDeleteResult_Impl eResult = svtools::QUERYDELETE_YES; + SvLBoxEntry* pEntry = FirstSelected(); + String aURL; + + ByteString sDialogPosition; + while ( pEntry && ( eResult != svtools::QUERYDELETE_CANCEL ) ) + { + SvLBoxEntry *pCurEntry = pEntry; + pEntry = NextSelected( pEntry ); + + if ( pCurEntry->GetUserData() ) + aURL = ( (SvtContentEntry*)pCurEntry->GetUserData() )->maURL; + + if ( !aURL.Len() ) + continue; + + bool canDelete = true; + try + { + ::ucbhelper::Content aCnt( aURL, mxCmdEnv ); + Reference< XCommandInfo > aCommands = aCnt.getCommands(); + if ( aCommands.is() ) + canDelete + = aCommands->hasCommandByName( + OUString::createFromAscii( "delete" ) ); + else + canDelete = false; + } + catch( Exception const & ) + { + canDelete = false; + } + + if (!canDelete) + continue; // process next entry + + if ( eResult != svtools::QUERYDELETE_ALL ) + { + INetURLObject aObj( aURL ); + svtools::QueryDeleteDlg_Impl aDlg( NULL, aObj.GetName( INetURLObject::DECODE_WITH_CHARSET ) ); + if ( sDialogPosition.Len() ) + aDlg.SetWindowState( sDialogPosition ); + + if ( GetSelectionCount() > 1 ) + aDlg.EnableAllButton(); + + if ( aDlg.Execute() == RET_OK ) + eResult = aDlg.GetResult(); + else + eResult = svtools::QUERYDELETE_CANCEL; + + sDialogPosition = aDlg.GetWindowState( ); + } + + if ( ( eResult == svtools::QUERYDELETE_ALL ) || + ( eResult == svtools::QUERYDELETE_YES ) ) + { + if ( Kill( aURL ) ) + { + delete (SvtContentEntry*)pCurEntry->GetUserData(); + GetModel()->Remove( pCurEntry ); + mpParent->EntryRemoved( aURL ); + } + } + } +} + +// ----------------------------------------------------------------------- +sal_Bool ViewTabListBox_Impl::EditedEntry( SvLBoxEntry* pEntry, + const XubString& rNewText ) +{ + sal_Bool bRet = sal_False; + + OUString aURL; + SvtContentEntry* pData = (SvtContentEntry*)pEntry->GetUserData(); + + if ( pData ) + aURL = OUString( pData->maURL ); + + if ( ! aURL.getLength() ) + return bRet; + + try + { + OUString aPropName = OUString::createFromAscii( "Title" ); + bool canRename = true; + ::ucbhelper::Content aContent( aURL, mxCmdEnv ); + + try + { + Reference< XPropertySetInfo > aProps = aContent.getProperties(); + if ( aProps.is() ) + { + Property aProp = aProps->getPropertyByName( aPropName ); + canRename = !( aProp.Attributes & PropertyAttribute::READONLY ); + } + else + { + canRename = false; + } + } + catch ( Exception const & ) + { + canRename = false; + } + + if ( canRename ) + { + Any aValue; + aValue <<= OUString( rNewText ); + aContent.setPropertyValue( aPropName, aValue ); + mpParent->EntryRenamed( aURL, rNewText ); + + pData->maURL = aURL; + pEntry->SetUserData( pData ); + + bRet = sal_True; + } + } + catch( Exception const & ) + { + } + + return bRet; +} + +// ----------------------------------------------------------------------- +void ViewTabListBox_Impl::DoQuickSearch( const xub_Unicode& rChar ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + maResetQuickSearch.Stop(); + + OUString aLastText = maQuickSearchText; + sal_uInt32 aLastPos = mnSearchIndex; + sal_Bool bFound = sal_False; + + maQuickSearchText += OUString( String( rChar ) ).toAsciiLowerCase(); + + bFound = mpParent->SearchNextEntry( mnSearchIndex, maQuickSearchText, sal_False ); + + if ( !bFound && ( aLastText.getLength() == 1 ) && + ( aLastText == OUString( String( rChar ) ) ) ) + { + mnSearchIndex = aLastPos + 1; + maQuickSearchText = aLastText; + bFound = mpParent->SearchNextEntry( mnSearchIndex, maQuickSearchText, sal_True ); + } + + if ( bFound ) + { + SvLBoxEntry* pEntry = GetEntry( mnSearchIndex ); + if ( pEntry ) + { + SelectAll( sal_False ); + Select( pEntry ); + SetCurEntry( pEntry ); + MakeVisible( pEntry ); + } + else + bFound = sal_False; + } + + if ( !bFound ) + Sound::Beep(); + + maResetQuickSearch.Start(); +} + +// ----------------------------------------------------------------------- +sal_Bool ViewTabListBox_Impl::DoubleClickHdl() +{ + SvHeaderTabListBox::DoubleClickHdl(); + return sal_False; + // this means "do no additional handling". Especially this means that the SvImpLBox does not + // recognize that the entry at the double click position change after the handler call (which is + // the case if in the handler, our content was replaced) + // If it _would_ recognize this change, it would take this as a reason to select the entry, again + // - which is not what in the case of content replace + // (I really doubt that this behaviour of the SvImpLBox does make any sense at all, but + // who knows ...) + // 07.12.2001 - 95727 - fs@openoffice.org +} + +::rtl::OUString ViewTabListBox_Impl::GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const +{ + ::rtl::OUString sRet = SvHeaderTabListBox::GetAccessibleObjectDescription( _eType, _nPos ); + if ( ::svt::BBTYPE_TABLECELL == _eType ) + { + sal_Int32 nRow = -1; + const sal_uInt16 nColumnCount = GetColumnCount(); + if (nColumnCount > 0) + nRow = _nPos / nColumnCount; + SvLBoxEntry* pEntry = GetEntry( nRow ); + if ( pEntry ) + { + SvtContentEntry* pData = (SvtContentEntry*)pEntry->GetUserData(); + if ( pData ) + { + static const String sVar1( RTL_CONSTASCII_USTRINGPARAM( "%1" ) ); + static const String sVar2( RTL_CONSTASCII_USTRINGPARAM( "%2" ) ); + String aText( msAccessibleDescText ); + aText.SearchAndReplace( sVar1, pData->mbIsFolder ? msFolder : msFile ); + aText.SearchAndReplace( sVar2, pData->maURL ); + sRet += ::rtl::OUString( aText ); + } + } + } + + return sRet; +} + +// ----------------------------------------------------------------------- +sal_Bool ViewTabListBox_Impl::Kill( const OUString& rContent ) +{ + sal_Bool bRet = sal_True; + + try + { + ::ucbhelper::Content aCnt( rContent, mxCmdEnv ); + aCnt.executeCommand( OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) ); + } + catch( ::com::sun::star::ucb::CommandAbortedException const & ) + { + DBG_WARNING( "CommandAbortedException" ); + bRet = sal_False; + } + catch( Exception const & ) + { + DBG_WARNING( "Any other exception" ); + bRet = sal_False; + } + + return bRet; +} + + + + +// ----------------------------------------------------------------------- +// class SvtFileView ----------------------------------------------------- +// ----------------------------------------------------------------------- + +SvtFileView::SvtFileView( Window* pParent, const ResId& rResId, + sal_Bool bOnlyFolder, sal_Bool bMultiSelection ) : + + Control( pParent, rResId ) +{ + sal_Int8 nFlags = FILEVIEW_SHOW_ALL; + if ( bOnlyFolder ) + nFlags |= FILEVIEW_ONLYFOLDER; + if ( bMultiSelection ) + nFlags |= FILEVIEW_MULTISELECTION; + + Reference< XInteractionHandler > xInteractionHandler = Reference< XInteractionHandler > ( + ::comphelper::getProcessServiceFactory()->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uui.InteractionHandler") ) ), UNO_QUERY ); + Reference < XCommandEnvironment > xCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() ); + + mpImp = new SvtFileView_Impl( this, xCmdEnv, nFlags, bOnlyFolder ); + mpImp->mpView->ForbidEmptyText(); + + long pTabs[] = { 5, 20, 180, 320, 400, 600 }; + mpImp->mpView->SetTabs( &pTabs[0], MAP_PIXEL ); + mpImp->mpView->SetTabJustify( 2, AdjustRight ); // column "Size" + + if ( bMultiSelection ) + mpImp->mpView->SetSelectionMode( MULTIPLE_SELECTION ); + + HeaderBar* pHeaderBar = mpImp->mpView->GetHeaderBar(); + pHeaderBar->SetSelectHdl( LINK( this, SvtFileView, HeaderSelect_Impl ) ); + pHeaderBar->SetEndDragHdl( LINK( this, SvtFileView, HeaderEndDrag_Impl ) ); +} + +SvtFileView::SvtFileView( Window* pParent, const ResId& rResId, sal_Int8 nFlags ) : + + Control( pParent, rResId ) +{ + Reference< XInteractionHandler > xInteractionHandler = Reference< XInteractionHandler > ( + ::comphelper::getProcessServiceFactory()->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.uui.InteractionHandler") ) ), UNO_QUERY ); + Reference < XCommandEnvironment > xCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() ); + mpImp = new SvtFileView_Impl( this, xCmdEnv, nFlags, + ( nFlags & FILEVIEW_ONLYFOLDER ) == FILEVIEW_ONLYFOLDER ); + + if ( ( nFlags & FILEVIEW_SHOW_ALL ) == FILEVIEW_SHOW_ALL ) + { + long pTabs[] = { 5, 20, 180, 320, 400, 600 }; + mpImp->mpView->SetTabs( &pTabs[0], MAP_PIXEL ); + mpImp->mpView->SetTabJustify( 2, AdjustRight ); // column "Size" + } + else + { + // show only title + long pTabs[] = { 2, 20, 600 }; + mpImp->mpView->SetTabs( &pTabs[0], MAP_PIXEL ); + } + + if ( ( nFlags & FILEVIEW_MULTISELECTION ) == FILEVIEW_MULTISELECTION ) + mpImp->mpView->SetSelectionMode( MULTIPLE_SELECTION ); + + HeaderBar *pHeaderBar = mpImp->mpView->GetHeaderBar(); + pHeaderBar->SetSelectHdl( LINK( this, SvtFileView, HeaderSelect_Impl ) ); + pHeaderBar->SetEndDragHdl( LINK( this, SvtFileView, HeaderEndDrag_Impl ) ); +} + +// ----------------------------------------------------------------------- + +SvtFileView::~SvtFileView() +{ + // use temp pointer to prevent access of deleted member (GetFocus()) + SvtFileView_Impl* pTemp = mpImp; + mpImp = NULL; + delete pTemp; +} + +// ----------------------------------------------------------------------- + +void SvtFileView::OpenFolder( const Sequence< OUString >& aContents ) +{ + mpImp->mpView->ClearAll(); + const OUString* pFileProperties = aContents.getConstArray(); + sal_uInt32 i, nCount = aContents.getLength(); + for ( i = 0; i < nCount; ++i ) + { + String aRow( pFileProperties[i] ); + // extract columns + // the columns are: title, type, size, date, target url, is folder, image url + String aTitle, aType, aSize, aDate, aURL, aImageURL; + xub_StrLen nIdx = 0; + aTitle = aRow.GetToken( 0, '\t', nIdx ); + aType = aRow.GetToken( 0, '\t', nIdx ); + aSize = aRow.GetToken( 0, '\t', nIdx ); + aDate = aRow.GetToken( 0, '\t', nIdx ); + aURL = aRow.GetToken( 0, '\t', nIdx ); + sal_Unicode cFolder = aRow.GetToken( 0, '\t', nIdx ).GetChar(0); + sal_Bool bIsFolder = ( '1' == cFolder ); + if ( nIdx != STRING_NOTFOUND ) + aImageURL = aRow.GetToken( 0, '\t', nIdx ); + + if ( mpImp->mbOnlyFolder && !bIsFolder ) + continue; + + // build new row + String aNewRow = aTitle; + aNewRow += '\t'; + aNewRow += aType; + aNewRow += '\t'; + aNewRow += aSize; + aNewRow += '\t'; + aNewRow += aDate; + // detect image + sal_Bool bDoInsert = sal_True; + INetURLObject aObj( aImageURL.Len() > 0 ? aImageURL : aURL ); + Image aImage = SvFileInformationManager::GetImage( aObj, sal_False, isHighContrast( this ) ); + + if ( bDoInsert ) + { + // insert entry and set user data + SvLBoxEntry* pEntry = mpImp->mpView->InsertEntry( aNewRow, aImage, aImage, NULL ); + SvtContentEntry* pUserData = new SvtContentEntry( aURL, bIsFolder ); + pEntry->SetUserData( pUserData ); + } + } + + mpImp->InitSelection(); + mpImp->ResetCursor(); +} + +// ----------------------------------------------------------------------- + +String SvtFileView::GetURL( SvLBoxEntry* pEntry ) const +{ + String aURL; + if ( pEntry && pEntry->GetUserData() ) + aURL = ( (SvtContentEntry*)pEntry->GetUserData() )->maURL; + return aURL; +} + +// ----------------------------------------------------------------------- + +String SvtFileView::GetCurrentURL() const +{ + String aURL; + SvLBoxEntry* pEntry = mpImp->mpView->FirstSelected(); + if ( pEntry && pEntry->GetUserData() ) + aURL = ( (SvtContentEntry*)pEntry->GetUserData() )->maURL; + return aURL; +} +// ----------------------------------------------------------------------------- + +sal_Bool SvtFileView::CreateNewFolder( const String& rNewFolder ) +{ + sal_Bool bRet = sal_False; + INetURLObject aObj( mpImp->maViewURL ); + aObj.insertName( rNewFolder, false, INetURLObject::LAST_SEGMENT, true, INetURLObject::ENCODE_ALL ); + String sURL = aObj.GetMainURL( INetURLObject::NO_DECODE ); + if ( ::utl::UCBContentHelper::MakeFolder( sURL, sal_True ) ) + { + String sTitle = aObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET ); + String sEntry = mpImp->FolderInserted( sURL, sTitle ); + SvLBoxEntry* pEntry = mpImp->mpView->InsertEntry( sEntry, mpImp->maFolderImage, mpImp->maFolderImage ); + SvtContentEntry* pUserData = new SvtContentEntry( sURL, sal_True ); + pEntry->SetUserData( pUserData ); + mpImp->mpView->MakeVisible( pEntry ); + bRet = sal_True; + } + return bRet; +} + +// ----------------------------------------------------------------------- + +FileViewResult SvtFileView::PreviousLevel( const FileViewAsyncAction* pAsyncDescriptor ) +{ + FileViewResult eResult = eFailure; + + String sParentURL; + if ( GetParentURL( sParentURL ) ) + eResult = Initialize( sParentURL, mpImp->maCurrentFilter, pAsyncDescriptor, mpBlackList ); + + return eResult; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvtFileView::GetParentURL( String& rParentURL ) const +{ + sal_Bool bRet = sal_False; + try + { + ::ucbhelper::Content aCnt( mpImp->maViewURL, mpImp->mxCmdEnv ); + Reference< XContent > xContent( aCnt.get() ); + Reference< com::sun::star::container::XChild > xChild( xContent, UNO_QUERY ); + if ( xChild.is() ) + { + Reference< XContent > xParent( xChild->getParent(), UNO_QUERY ); + if ( xParent.is() ) + { + rParentURL = String( xParent->getIdentifier()->getContentIdentifier() ); + bRet = ( rParentURL.Len() > 0 && rParentURL != mpImp->maViewURL ); + } + } + } + catch( Exception const & ) + { + // perhaps an unkown url protocol (e.g. "private:newdoc") + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +const rtl::OString& SvtFileView::GetHelpId( ) const +{ + return mpImp->mpView->GetHelpId( ); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::SetHelpId( const rtl::OString& rHelpId ) +{ + mpImp->mpView->SetHelpId( rHelpId ); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::SetSizePixel( const Size& rNewSize ) +{ + Control::SetSizePixel( rNewSize ); + mpImp->mpView->SetSizePixel( rNewSize ); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::SetPosSizePixel( const Point& rNewPos, const Size& rNewSize ) +{ + SetPosPixel( rNewPos ); + SetSizePixel( rNewSize ); +} + +// ----------------------------------------------------------------------------- +sal_Bool SvtFileView::Initialize( const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContent>& _xContent, const String& rFilter ) +{ + WaitObject aWaitCursor( this ); + + mpImp->Clear(); + ::ucbhelper::Content aContent(_xContent, mpImp->mxCmdEnv ); + FileViewResult eResult = mpImp->GetFolderContent_Impl( FolderDescriptor( aContent ), NULL ); + OSL_ENSURE( eResult != eStillRunning, "SvtFileView::Initialize: this was expected to be synchronous!" ); + if ( eResult != eSuccess ) + return sal_False; + + mpImp->FilterFolderContent_Impl( rFilter ); + + mpImp->SortFolderContent_Impl(); // possibly not necessary!!!!!!!!!! + mpImp->CreateDisplayText_Impl(); + mpImp->OpenFolder_Impl(); + + mpImp->maOpenDoneLink.Call( this ); + return sal_True; +} + +// ----------------------------------------------------------------------- +FileViewResult SvtFileView::Initialize( + const String& rURL, + const String& rFilter, + const FileViewAsyncAction* pAsyncDescriptor, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList ) +{ + WaitObject aWaitCursor( this ); + mpBlackList = rBlackList; + + String sPushURL( mpImp->maViewURL ); + + mpImp->maViewURL = rURL; + FileViewResult eResult = ExecuteFilter( rFilter, pAsyncDescriptor ); + switch ( eResult ) + { + case eFailure: + case eTimeout: + mpImp->maViewURL = sPushURL; + return eResult; + + case eStillRunning: + OSL_ENSURE( pAsyncDescriptor, "SvtFileView::Initialize: we told it to read synchronously!" ); + case eSuccess: + return eResult; + } + + OSL_ENSURE( sal_False, "SvtFileView::Initialize: unreachable!" ); + return eFailure; +} + +// ----------------------------------------------------------------------- +FileViewResult SvtFileView::Initialize( + const String& rURL, + const String& rFilter, + const FileViewAsyncAction* pAsyncDescriptor ) +{ + return Initialize( rURL, rFilter, pAsyncDescriptor, ::com::sun::star::uno::Sequence< ::rtl::OUString >()); +} + +// ----------------------------------------------------------------------- + +// ----------------------------------------------------------------------- +sal_Bool SvtFileView::Initialize( const Sequence< OUString >& aContents ) +{ + WaitObject aWaitCursor( this ); + + mpImp->maViewURL = String(); + mpImp->maCurrentFilter = mpImp->maAllFilter; + + mpImp->Clear(); + mpImp->CreateVector_Impl( aContents ); + mpImp->SortFolderContent_Impl(); + + mpImp->OpenFolder_Impl(); + + mpImp->maOpenDoneLink.Call( this ); + + return sal_True; +} + +// ----------------------------------------------------------------------- + +FileViewResult SvtFileView::ExecuteFilter( const String& rFilter, const FileViewAsyncAction* pAsyncDescriptor ) +{ + mpImp->maCurrentFilter = rFilter; + mpImp->maCurrentFilter.ToLowerAscii(); + + mpImp->Clear(); + FileViewResult eResult = mpImp->GetFolderContent_Impl( mpImp->maViewURL, pAsyncDescriptor, mpBlackList ); + OSL_ENSURE( ( eResult != eStillRunning ) || pAsyncDescriptor, "SvtFileView::ExecuteFilter: we told it to read synchronously!" ); + return eResult; +} + +// ----------------------------------------------------------------------- + +void SvtFileView::CancelRunningAsyncAction() +{ + mpImp->CancelRunningAsyncAction(); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::SetNoSelection() +{ + mpImp->mpView->SelectAll( sal_False ); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::GetFocus() +{ + Control::GetFocus(); + if ( mpImp && mpImp->mpView ) + mpImp->mpView->GrabFocus(); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::ResetCursor() +{ + mpImp->ResetCursor(); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::SetSelectHdl( const Link& rHdl ) +{ + mpImp->SetSelectHandler( rHdl ); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::SetDoubleClickHdl( const Link& rHdl ) +{ + mpImp->mpView->SetDoubleClickHdl( rHdl ); +} + +// ----------------------------------------------------------------------- + +sal_uLong SvtFileView::GetSelectionCount() const +{ + return mpImp->mpView->GetSelectionCount(); +} + +// ----------------------------------------------------------------------- + +SvLBoxEntry* SvtFileView::FirstSelected() const +{ + return mpImp->mpView->FirstSelected(); +} + +// ----------------------------------------------------------------------- + +SvLBoxEntry* SvtFileView::NextSelected( SvLBoxEntry* pEntry ) const +{ + return mpImp->mpView->NextSelected( pEntry ); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::EnableAutoResize() +{ + mpImp->mpView->EnableAutoResize(); +} + +// ----------------------------------------------------------------------- + +void SvtFileView::SetFocus() +{ + mpImp->mpView->GrabFocus(); +} + +// ----------------------------------------------------------------------- +const String& SvtFileView::GetViewURL() const +{ + return mpImp->maViewURL; +} + +// ----------------------------------------------------------------------- +void SvtFileView::SetOpenDoneHdl( const Link& rHdl ) +{ + mpImp->maOpenDoneLink = rHdl; +} + +// ----------------------------------------------------------------------- +void SvtFileView::EnableContextMenu( sal_Bool bEnable ) +{ + mpImp->EnableContextMenu( bEnable ); +} + +// ----------------------------------------------------------------------- +void SvtFileView::EnableDelete( sal_Bool bEnable ) +{ + mpImp->EnableDelete( bEnable ); +} + +void SvtFileView::EnableNameReplacing( sal_Bool bEnable ) +{ + mpImp->EnableNameReplacing( bEnable ); +} + +// ----------------------------------------------------------------------- +void SvtFileView::EndInplaceEditing( bool _bCancel ) +{ + return mpImp->EndEditing( _bCancel ); +} + +// ----------------------------------------------------------------------- +IMPL_LINK( SvtFileView, HeaderSelect_Impl, HeaderBar*, pBar ) +{ + DBG_ASSERT( pBar, "no headerbar" ); + sal_uInt16 nItemID = pBar->GetCurItemId(); + + HeaderBarItemBits nBits; + + // clear the arrow of the recently used column + if ( nItemID != mpImp->mnSortColumn ) + { + if ( !nItemID ) + { + // first call -> remove arrow from title column, + // because another column is the sort column + nItemID = mpImp->mnSortColumn; + mpImp->mnSortColumn = COLUMN_TITLE; + } + nBits = pBar->GetItemBits( mpImp->mnSortColumn ); + nBits &= ~( HIB_UPARROW | HIB_DOWNARROW ); + pBar->SetItemBits( mpImp->mnSortColumn, nBits ); + } + + nBits = pBar->GetItemBits( nItemID ); + + sal_Bool bUp = ( ( nBits & HIB_UPARROW ) == HIB_UPARROW ); + + if ( bUp ) + { + nBits &= ~HIB_UPARROW; + nBits |= HIB_DOWNARROW; + } + else + { + nBits &= ~HIB_DOWNARROW; + nBits |= HIB_UPARROW; + } + + pBar->SetItemBits( nItemID, nBits ); + mpImp->Resort_Impl( nItemID, !bUp ); + return 1; +} + +// ----------------------------------------------------------------------- +IMPL_LINK( SvtFileView, HeaderEndDrag_Impl, HeaderBar*, pBar ) +{ + if ( !pBar->IsItemMode() ) + { + Size aSize; + sal_uInt16 nTabs = pBar->GetItemCount(); + long nTmpSize = 0; + + for ( sal_uInt16 i = 1; i <= nTabs; ++i ) + { + long nWidth = pBar->GetItemSize(i); + aSize.Width() = nWidth + nTmpSize; + nTmpSize += nWidth; + mpImp->mpView->SetTab( i, aSize.Width(), MAP_PIXEL ); + } + } + + return 0; +} + +// ----------------------------------------------------------------------- +String SvtFileView::GetConfigString() const +{ + String sRet; + HeaderBar* pBar = mpImp->mpView->GetHeaderBar(); + DBG_ASSERT( pBar, "invalid headerbar" ); + + // sort order + sRet += String::CreateFromInt32( mpImp->mnSortColumn ); + sRet += ';'; + HeaderBarItemBits nBits = pBar->GetItemBits( mpImp->mnSortColumn ); + sal_Bool bUp = ( ( nBits & HIB_UPARROW ) == HIB_UPARROW ); + sRet += bUp ? '1' : '0'; + sRet += ';'; + + sal_uInt16 nCount = pBar->GetItemCount(); + for ( sal_uInt16 i = 0; i < nCount; ++i ) + { + sal_uInt16 nId = pBar->GetItemId(i); + sRet += String::CreateFromInt32( nId ); + sRet += ';'; + sRet += String::CreateFromInt32( pBar->GetItemSize( nId ) ); + sRet += ';'; + } + + sRet.EraseTrailingChars( ';' ); + return sRet; +} + +// ----------------------------------------------------------------------- +void SvtFileView::SetConfigString( const String& rCfgStr ) +{ + HeaderBar* pBar = mpImp->mpView->GetHeaderBar(); + DBG_ASSERT( pBar, "invalid headerbar" ); + + sal_uInt16 nIdx = 0; + mpImp->mnSortColumn = (sal_uInt16)rCfgStr.GetToken( 0, ';', nIdx ).ToInt32(); + sal_Bool bUp = (sal_Bool)(sal_uInt16)rCfgStr.GetToken( 0, ';', nIdx ).ToInt32(); + HeaderBarItemBits nBits = pBar->GetItemBits( mpImp->mnSortColumn ); + + if ( bUp ) + { + nBits &= ~HIB_UPARROW; + nBits |= HIB_DOWNARROW; + } + else + { + nBits &= ~HIB_DOWNARROW; + nBits |= HIB_UPARROW; + } + pBar->SetItemBits( mpImp->mnSortColumn, nBits ); + + while ( nIdx != STRING_NOTFOUND ) + { + sal_uInt16 nItemId = (sal_uInt16)rCfgStr.GetToken( 0, ';', nIdx ).ToInt32(); + pBar->SetItemSize( nItemId, rCfgStr.GetToken( 0, ';', nIdx ).ToInt32() ); + } + + HeaderSelect_Impl( pBar ); + HeaderEndDrag_Impl( pBar ); +} + +// ----------------------------------------------------------------------- +void SvtFileView::SetUrlFilter( const IUrlFilter* _pFilter ) +{ + mpImp->mpUrlFilter = _pFilter; +} + +// ----------------------------------------------------------------------- +const IUrlFilter* SvtFileView::GetUrlFilter( ) const +{ + return mpImp->mpUrlFilter; +} + +// ----------------------------------------------------------------------- +void SvtFileView::StateChanged( StateChangedType nStateChange ) +{ + if ( nStateChange == STATE_CHANGE_ENABLE ) + Invalidate(); + Control::StateChanged( nStateChange ); +} + +// ----------------------------------------------------------------------- +// class NameTranslator_Impl +// ----------------------------------------------------------------------- + +NameTranslator_Impl::NameTranslator_Impl( void ) : + mpActFolder( NULL ) +{ +} + +NameTranslator_Impl::NameTranslator_Impl( const INetURLObject& rActualFolder ) +{ + mpActFolder = new NameTranslationList( rActualFolder ); +} + +NameTranslator_Impl::~NameTranslator_Impl() +{ + if( mpActFolder ) + delete mpActFolder; +} + +void NameTranslator_Impl::UpdateTranslationTable() +{ + if( mpActFolder ) + mpActFolder->Update(); +} + +void NameTranslator_Impl::SetActualFolder( const INetURLObject& rActualFolder ) +{ + HashedEntry aActFolder( rActualFolder ); + + if( mpActFolder ) + { + if( *mpActFolder != aActFolder ) + { + delete mpActFolder; + mpActFolder = new NameTranslationList( rActualFolder ); + } + } + else + mpActFolder = new NameTranslationList( rActualFolder ); +} + +sal_Bool NameTranslator_Impl::GetTranslation( const OUString& rOrg, OUString& rTrans ) const +{ + sal_Bool bRet = sal_False; + + if( mpActFolder ) + { + const OUString* pTrans = mpActFolder->Translate( rOrg ); + if( pTrans ) + { + rTrans = *pTrans; + bRet = sal_True; + } + } + + return bRet; +} + +const String* NameTranslator_Impl::GetTransTableFileName() const +{ + return mpActFolder? &mpActFolder->GetTransTableFileName() : NULL; +} + +// ----------------------------------------------------------------------- +// class SvtFileView_Impl +// ----------------------------------------------------------------------- + +SvtFileView_Impl::SvtFileView_Impl( SvtFileView* pAntiImpl, Reference < XCommandEnvironment > xEnv, sal_Int16 nFlags, sal_Bool bOnlyFolder ) + + :mpAntiImpl ( pAntiImpl ) + ,m_eAsyncActionResult ( ::svt::ERROR ) + ,m_bRunningAsyncAction ( false ) + ,m_bAsyncActionCancelled ( false ) + ,mpNameTrans ( NULL ) + ,mpUrlFilter ( NULL ) + ,mnSortColumn ( COLUMN_TITLE ) + ,mbAscending ( sal_True ) + ,mbOnlyFolder ( bOnlyFolder ) + ,mbReplaceNames ( sal_False ) + ,mnSuspendSelectCallback ( 0 ) + ,mbIsFirstResort ( sal_True ) + ,aIntlWrapper ( ::comphelper::getProcessServiceFactory(), Application::GetSettings().GetLocale() ) + ,maFolderImage ( SvtResId( IMG_SVT_FOLDER ) ) + ,mxCmdEnv ( xEnv ) + +{ + maAllFilter = String::CreateFromAscii( "*.*" ); + mpView = new ViewTabListBox_Impl( mpAntiImpl, this, nFlags ); + mpView->EnableCellFocus(); +} + +// ----------------------------------------------------------------------- +SvtFileView_Impl::~SvtFileView_Impl() +{ + Clear(); + + // use temp pointer to prevent access of deleted member (GetFocus()) + ViewTabListBox_Impl* pTemp = mpView; + mpView = NULL; + delete pTemp; +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::Clear() +{ + ::osl::MutexGuard aGuard( maMutex ); + + std::vector< SortingData_Impl* >::iterator aIt; + + for ( aIt = maContent.begin(); aIt != maContent.end(); aIt++ ) + delete (*aIt); + + maContent.clear(); + + if( mpNameTrans ) + DELETEZ( mpNameTrans ); +} + +// ----------------------------------------------------------------------- +FileViewResult SvtFileView_Impl::GetFolderContent_Impl( + const String& rFolder, + const FileViewAsyncAction* pAsyncDescriptor, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList ) +{ + ::osl::ClearableMutexGuard aGuard( maMutex ); + INetURLObject aFolderObj( rFolder ); + DBG_ASSERT( aFolderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" ); + + // prepare name translation + SetActualFolder( aFolderObj ); + + FolderDescriptor aFolder( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ) ); + + aGuard.clear(); + return GetFolderContent_Impl( aFolder, pAsyncDescriptor, rBlackList ); +} + +// ----------------------------------------------------------------------- +FileViewResult SvtFileView_Impl::GetFolderContent_Impl( + const FolderDescriptor& _rFolder, + const FileViewAsyncAction* pAsyncDescriptor, + const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rBlackList ) +{ + DBG_TESTSOLARMUTEX(); + ::osl::ClearableMutexGuard aGuard( maMutex ); + + OSL_ENSURE( !m_pContentEnumerator.is(), "SvtFileView_Impl::GetFolderContent_Impl: still running another enumeration!" ); + m_pContentEnumerator = new ::svt::FileViewContentEnumerator( + mpView->GetCommandEnvironment(), maContent, maMutex, mbReplaceNames ? mpNameTrans : NULL ); + // TODO: should we cache and re-use this thread? + + if ( !pAsyncDescriptor ) + { + ::svt::EnumerationResult eResult = m_pContentEnumerator->enumerateFolderContentSync( _rFolder, mpUrlFilter, rBlackList ); + if ( ::svt::SUCCESS == eResult ) + { + implEnumerationSuccess(); + m_pContentEnumerator = NULL; + return eSuccess; + } + m_pContentEnumerator = NULL; + return eFailure; + } + + m_bRunningAsyncAction = true; + m_bAsyncActionCancelled = false; + m_eAsyncActionResult = ::svt::ERROR; + m_aAsyncActionFinished.reset(); + + // don't (yet) set m_aCurrentAsyncActionHandler to pTimeout->aFinishHandler. + // By definition, this handler *only* get's called when the result cannot be obtained + // during the minimum wait time, so it is only set below, when needed. + m_aCurrentAsyncActionHandler = Link(); + + // minimum time to wait + ::std::auto_ptr< TimeValue > pTimeout( new TimeValue ); + sal_Int32 nMinTimeout = pAsyncDescriptor->nMinTimeout; + OSL_ENSURE( nMinTimeout > 0, "SvtFileView_Impl::GetFolderContent_Impl: invalid minimum timeout!" ); + if ( nMinTimeout <= 0 ) + nMinTimeout = sal_Int32( 1000L ); + pTimeout->Seconds = nMinTimeout / 1000L; + pTimeout->Nanosec = ( nMinTimeout % 1000L ) * 1000000L; + + m_pContentEnumerator->enumerateFolderContent( _rFolder, mpUrlFilter, this ); + + // wait until the enumeration is finished + // for this, release our own mutex (which is used by the enumerator thread) + aGuard.clear(); + + ::osl::Condition::Result eResult = ::osl::Condition::result_ok; + { + // also release the SolarMutex. Not all code which is needed during the enumeration + // is Solar-Thread-Safe, in particular there is some code which needs to access + // string resources (and our resource system relies on the SolarMutex :() + ReleaseSolarMutex aSolarRelease; + + // now wait. Note that if we didn't get an pAsyncDescriptor, then this is an infinite wait. + eResult = m_aAsyncActionFinished.wait( pTimeout.get() ); + } + + ::osl::MutexGuard aGuard2( maMutex ); + if ( ::osl::Condition::result_timeout == eResult ) + { + // maximum time to wait + OSL_ENSURE( !m_pCancelAsyncTimer.get(), "SvtFileView_Impl::GetFolderContent_Impl: there's still a previous timer!" ); + m_pCancelAsyncTimer = new CallbackTimer( this ); + sal_Int32 nMaxTimeout = pAsyncDescriptor->nMaxTimeout; + OSL_ENSURE( nMaxTimeout > nMinTimeout, + "SvtFileView_Impl::GetFolderContent_Impl: invalid maximum timeout!" ); + if ( nMaxTimeout <= nMinTimeout ) + nMaxTimeout = nMinTimeout + 5000; + m_pCancelAsyncTimer->setRemainingTime( TTimeValue( nMaxTimeout - nMinTimeout ) ); + // we already waited for nMinTimeout milliseconds, so take this into account + m_pCancelAsyncTimer->start(); + + m_aCurrentAsyncActionHandler = pAsyncDescriptor->aFinishHandler; + DBG_ASSERT( m_aCurrentAsyncActionHandler.IsSet(), "SvtFileView_Impl::GetFolderContent_Impl: nobody interested when it's finished?" ); + mpView->ClearAll(); + return eStillRunning; + } + + m_bRunningAsyncAction = false; + switch ( m_eAsyncActionResult ) + { + case ::svt::SUCCESS: + return eSuccess; + + case ::svt::ERROR: + return eFailure; + + case ::svt::RUNNING: + return eStillRunning; + } + + DBG_ERRORFILE( "SvtFileView_Impl::GetFolderContent_Impl: unreachable!" ); + return eFailure; +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::FilterFolderContent_Impl( const OUString &rFilter ) +{ + sal_Bool bHideTransFile = mbReplaceNames && mpNameTrans; + + String sHideEntry; + if( bHideTransFile ) + { + const String* pTransTableFileName = mpNameTrans->GetTransTableFileName(); + if( pTransTableFileName ) + { + sHideEntry = *pTransTableFileName; + sHideEntry.ToUpperAscii(); + } + else + bHideTransFile = sal_False; + } + + if ( !bHideTransFile && + ( !rFilter.getLength() || ( rFilter.compareToAscii( ALL_FILES_FILTER ) == COMPARE_EQUAL ) ) ) + // when replacing names, there is always something to filter (no view of ".nametranslation.table") + return; + + ::osl::MutexGuard aGuard( maMutex ); + + if ( maContent.empty() ) + return; + + // count (estimate) the number of filter tokens + sal_Int32 nTokens=0; + const sal_Unicode* pStart = rFilter.getStr(); + const sal_Unicode* pEnd = pStart + rFilter.getLength(); + while ( pStart != pEnd ) + if ( *pStart++ == ';' ) + ++nTokens; + + // collect the filter tokens + ::std::vector< WildCard > aFilters; + FilterMatch::createWildCardFilterList(rFilter,aFilters); + + + // do the filtering + ::std::vector< SortingData_Impl* >::iterator aContentLoop = maContent.begin(); + String sCompareString; + do + { + if ( (*aContentLoop)->mbIsFolder ) + ++aContentLoop; + else + { + // normalize the content title (we always match case-insensitive) + // 91872 - 11.09.2001 - frank.schoenheit@sun.com + sCompareString = (*aContentLoop)->GetFileName(); // filter works on file name, not on title! + sal_Bool bDelete; + + if( bHideTransFile && sCompareString == sHideEntry ) + bDelete = sal_True; + else + { + // search for the first filter which matches + ::std::vector< WildCard >::const_iterator pMatchingFilter = + ::std::find_if( + aFilters.begin(), + aFilters.end(), + FilterMatch( sCompareString ) + ); + + bDelete = aFilters.end() == pMatchingFilter; + } + + if( bDelete ) + { + // none of the filters did match + delete (*aContentLoop); + + if ( maContent.begin() == aContentLoop ) + { + maContent.erase( aContentLoop ); + aContentLoop = maContent.begin(); + } + else + { + std::vector< SortingData_Impl* >::iterator aDelete = aContentLoop; + --aContentLoop; // move the iterator to a position which is not invalidated by the erase + maContent.erase( aDelete ); + ++aContentLoop; // this is now the next one .... + } + } + else + ++aContentLoop; + } + } + while ( aContentLoop != maContent.end() ); +} + +// ----------------------------------------------------------------------- +IMPL_LINK( SvtFileView_Impl, SelectionMultiplexer, void*, _pSource ) +{ + return mnSuspendSelectCallback ? 0L : m_aSelectHandler.Call( _pSource ); +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::SetSelectHandler( const Link& _rHdl ) +{ + m_aSelectHandler = _rHdl; + + Link aMasterHandler; + if ( m_aSelectHandler.IsSet() ) + aMasterHandler = LINK( this, SvtFileView_Impl, SelectionMultiplexer ); + + mpView->SetSelectHdl( aMasterHandler ); +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::InitSelection() +{ + mpView->SelectAll( sal_False ); + SvLBoxEntry* pFirst = mpView->First(); + if ( pFirst ) + mpView->SetCursor( pFirst, sal_True ); +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::OpenFolder_Impl() +{ + ::osl::MutexGuard aGuard( maMutex ); + + mpView->SetUpdateMode( sal_False ); + mpView->ClearAll(); + + std::vector< SortingData_Impl* >::iterator aIt; + + for ( aIt = maContent.begin(); aIt != maContent.end(); aIt++ ) + { + if ( mbOnlyFolder && ! (*aIt)->mbIsFolder ) + continue; + + // insert entry and set user data + SvLBoxEntry* pEntry = mpView->InsertEntry( (*aIt)->maDisplayText, + (*aIt)->maImage, + (*aIt)->maImage ); + + SvtContentEntry* pUserData = new SvtContentEntry( (*aIt)->maTargetURL, + (*aIt)->mbIsFolder ); + pEntry->SetUserData( pUserData ); + } + + InitSelection(); + + ++mnSuspendSelectCallback; + mpView->SetUpdateMode( sal_True ); + --mnSuspendSelectCallback; + + ResetCursor(); +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::ResetCursor() +{ + // deselect + SvLBoxEntry* pEntry = mpView->FirstSelected(); + if ( pEntry ) + mpView->Select( pEntry, sal_False ); + // set cursor to the first entry + mpView->SetCursor( mpView->First(), sal_True ); + mpView->Update(); +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::CancelRunningAsyncAction() +{ + DBG_TESTSOLARMUTEX(); + ::osl::MutexGuard aGuard( maMutex ); + if ( !m_pContentEnumerator.is() ) + return; + + m_bAsyncActionCancelled = true; + m_pContentEnumerator->cancel(); + m_bRunningAsyncAction = false; + + m_pContentEnumerator = NULL; + if ( m_pCancelAsyncTimer.is() && m_pCancelAsyncTimer->isTicking() ) + m_pCancelAsyncTimer->stop(); + m_pCancelAsyncTimer = NULL; +} + +//----------------------------------------------------------------------- +void SvtFileView_Impl::onTimeout( CallbackTimer* ) +{ + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard( maMutex ); + if ( !m_bRunningAsyncAction ) + // there might have been a race condition while we waited for the mutex + return; + + CancelRunningAsyncAction(); + + if ( m_aCurrentAsyncActionHandler.IsSet() ) + { + Application::PostUserEvent( m_aCurrentAsyncActionHandler, reinterpret_cast< void* >( eTimeout ) ); + m_aCurrentAsyncActionHandler = Link(); + } +} + +//----------------------------------------------------------------------- +void SvtFileView_Impl::enumerationDone( ::svt::EnumerationResult _eResult ) +{ + ::vos::OGuard aSolarGuard( Application::GetSolarMutex() ); + ::osl::MutexGuard aGuard( maMutex ); + + m_pContentEnumerator = NULL; + if ( m_pCancelAsyncTimer.is() && m_pCancelAsyncTimer->isTicking() ) + m_pCancelAsyncTimer->stop(); + m_pCancelAsyncTimer = NULL; + + if ( m_bAsyncActionCancelled ) + // this is to prevent race conditions + return; + + m_eAsyncActionResult = _eResult; + m_bRunningAsyncAction = false; + + m_aAsyncActionFinished.set(); + + if ( svt::SUCCESS == _eResult ) + implEnumerationSuccess(); + + if ( m_aCurrentAsyncActionHandler.IsSet() ) + { + Application::PostUserEvent( m_aCurrentAsyncActionHandler, reinterpret_cast< void* >( m_eAsyncActionResult ) ); + m_aCurrentAsyncActionHandler = Link(); + } +} + +//----------------------------------------------------------------------- +void SvtFileView_Impl::implEnumerationSuccess() +{ + FilterFolderContent_Impl( maCurrentFilter ); + SortFolderContent_Impl(); + CreateDisplayText_Impl(); + OpenFolder_Impl(); + maOpenDoneLink.Call( mpAntiImpl ); +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::ReplaceTabWithString( OUString& aValue ) +{ + OUString aTab = OUString::createFromAscii( "\t" ); + OUString aTabString = OUString::createFromAscii( "%09" ); + sal_Int32 iPos; + + while ( ( iPos = aValue.indexOf( aTab ) ) >= 0 ) + aValue = aValue.replaceAt( iPos, 1, aTabString ); +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::CreateDisplayText_Impl() +{ + ::osl::MutexGuard aGuard( maMutex ); + + OUString aValue; + OUString aTab = OUString::createFromAscii( "\t" ); + OUString aDateSep = OUString::createFromAscii( ", " ); + + std::vector< SortingData_Impl* >::iterator aIt; + + for ( aIt = maContent.begin(); aIt != maContent.end(); aIt++ ) + { + // title, type, size, date + aValue = (*aIt)->GetTitle(); + // #83004# -------------------- + ReplaceTabWithString( aValue ); + aValue += aTab; + aValue += (*aIt)->maType; + aValue += aTab; + // folders don't have a size + if ( ! (*aIt)->mbIsFolder ) + aValue += CreateExactSizeText_Impl( (*aIt)->maSize ); + aValue += aTab; + // set the date, but volumes have no date + if ( ! (*aIt)->mbIsFolder || ! (*aIt)->mbIsVolume ) + { + SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData(); + aValue += rLocaleData.getDate( (*aIt)->maModDate ); + aValue += aDateSep; + aValue += rLocaleData.getTime( (*aIt)->maModDate ); + } + (*aIt)->maDisplayText = aValue; + + // detect image + if ( (*aIt)->mbIsFolder ) + { + ::svtools::VolumeInfo aVolInfo( (*aIt)->mbIsVolume, (*aIt)->mbIsRemote, + (*aIt)->mbIsRemoveable, (*aIt)->mbIsFloppy, + (*aIt)->mbIsCompactDisc ); + (*aIt)->maImage = SvFileInformationManager::GetFolderImage( aVolInfo, sal_False, isHighContrast( mpView ) ); + } + else + (*aIt)->maImage = SvFileInformationManager::GetFileImage( INetURLObject( (*aIt)->maTargetURL ), sal_False, isHighContrast( mpView )); + } +} + +// ----------------------------------------------------------------------- +// this function converts the sequence of strings into a vector of SortingData +// the string should have the form : +// title \t type \t size \t date \t target url \t is folder \t image url + +void SvtFileView_Impl::CreateVector_Impl( const Sequence < OUString > &rList ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + OUString aTab = OUString::createFromAscii( "\t" ); + + sal_uInt32 nCount = (sal_uInt32) rList.getLength(); + + for( sal_uInt32 i = 0; i < nCount; i++ ) + { + SortingData_Impl* pEntry = new SortingData_Impl; + OUString aValue = rList[i]; + OUString aDisplayText; + sal_Int32 nIndex = 0; + + // get the title + pEntry->SetNewTitle( aValue.getToken( 0, '\t', nIndex ) ); + aDisplayText = pEntry->GetTitle(); + // #83004# -------------------- + ReplaceTabWithString( aDisplayText ); + aDisplayText += aTab; + + // get the type + if ( nIndex >= 0 ) + { + pEntry->maType = aValue.getToken( 0, '\t', nIndex ); + aDisplayText += pEntry->maType; + } + aDisplayText += aTab; + + // get the size + if ( nIndex >= 0 ) + { + OUString aSize = aValue.getToken( 0, '\t', nIndex ); + aDisplayText += aSize; + + if ( aSize.getLength() ) + pEntry->maSize = aSize.toInt64(); + } + aDisplayText += aTab; + + // get the date + if ( nIndex >= 0 ) + { + OUString aDate = aValue.getToken( 0, '\t', nIndex ); + aDisplayText += aDate; + + if ( aDate.getLength() ) + { + DBG_ERRORFILE( "Don't know, how to convert date" ); + ;// convert date string to date + } + } + // get the target url + if ( nIndex >= 0 ) + { + pEntry->maTargetURL = aValue.getToken( 0, '\t', nIndex ); + } + // get the size + if ( nIndex >= 0 ) + { + OUString aBool = aValue.getToken( 0, '\t', nIndex ); + if ( aBool.getLength() ) + pEntry->mbIsFolder = aBool.toBoolean(); + } + // get the image url + if ( nIndex >= 0 ) + { + pEntry->maImageURL = aValue.getToken( 0, '\t', nIndex ); + } + + // set the display text + pEntry->maDisplayText = aDisplayText; + + // detect the image + INetURLObject aObj( pEntry->maImageURL.getLength() ? pEntry->maImageURL : pEntry->maTargetURL ); + pEntry->maImage = SvFileInformationManager::GetImage( aObj, sal_False, isHighContrast( mpView ) ); + + maContent.push_back( pEntry ); + } +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::Resort_Impl( sal_Int16 nColumn, sal_Bool bAscending ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + if ( ( nColumn == mnSortColumn ) && + ( bAscending == mbAscending ) ) + return; + + // reset the quick search index + mpView->ResetQuickSearch_Impl( NULL ); + + String aEntryURL; + SvLBoxEntry* pEntry = mpView->GetCurEntry(); + if ( pEntry && pEntry->GetUserData() ) + aEntryURL = ( (SvtContentEntry*)pEntry->GetUserData() )->maURL; + + mnSortColumn = nColumn; + mbAscending = bAscending; + + SortFolderContent_Impl(); + OpenFolder_Impl(); + + if ( !mbIsFirstResort ) + { + sal_uLong nPos = GetEntryPos( aEntryURL ); + if ( nPos < mpView->GetEntryCount() ) + { + pEntry = mpView->GetEntry( nPos ); + + ++mnSuspendSelectCallback; // #i15668# - 2004-04-25 - fs@openoffice.org + mpView->SetCurEntry( pEntry ); + --mnSuspendSelectCallback; + } + } + else + mbIsFirstResort = sal_False; +} + +// ----------------------------------------------------------------------- +static sal_Bool gbAscending = sal_True; +static sal_Int16 gnColumn = COLUMN_TITLE; +static const CollatorWrapper* pCollatorWrapper = NULL; + +/* this functions returns true, if aOne is less then aTwo +*/ +sal_Bool CompareSortingData_Impl( SortingData_Impl* const aOne, SortingData_Impl* const aTwo ) +{ + DBG_ASSERT( pCollatorWrapper, "*CompareSortingData_Impl(): Can't work this way!" ); + + sal_Int32 nComp; + sal_Bool bRet = sal_False; + sal_Bool bEqual = sal_False; + + if ( aOne->mbIsFolder != aTwo->mbIsFolder ) + { + if ( aOne->mbIsFolder ) + bRet = sal_True; + else + bRet = sal_False; + + // !!! pb: #100376# folder always on top + if ( !gbAscending ) + bRet = !bRet; + } + else + { + switch ( gnColumn ) + { + case COLUMN_TITLE: + // compare case insensitiv first + nComp = pCollatorWrapper->compareString( aOne->GetLowerTitle(), aTwo->GetLowerTitle() ); + + if ( nComp == 0 ) + nComp = pCollatorWrapper->compareString( aOne->GetTitle(), aTwo->GetTitle() ); + + if ( nComp < 0 ) + bRet = sal_True; + else if ( nComp > 0 ) + bRet = sal_False; + else + bEqual = sal_True; + break; + case COLUMN_TYPE: + nComp = pCollatorWrapper->compareString( aOne->maType, aTwo->maType ); + if ( nComp < 0 ) + bRet = sal_True; + else if ( nComp > 0 ) + bRet = sal_False; + else + bEqual = sal_True; + break; + case COLUMN_SIZE: + if ( aOne->maSize < aTwo->maSize ) + bRet = sal_True; + else if ( aOne->maSize > aTwo->maSize ) + bRet = sal_False; + else + bEqual = sal_True; + break; + case COLUMN_DATE: + if ( aOne->maModDate < aTwo->maModDate ) + bRet = sal_True; + else if ( aOne->maModDate > aTwo->maModDate ) + bRet = sal_False; + else + bEqual = sal_True; + break; + default: + DBG_WARNING( "CompareSortingData_Impl: Compare unknown type!" ); + bRet = sal_False; + } + } + + // when the two elements are equal, we must not return sal_True (which would + // happen if we just return ! ( a < b ) when not sorting ascending ) + if ( bEqual ) + return sal_False; + + return gbAscending ? bRet : !bRet; +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::SortFolderContent_Impl() +{ + ::osl::MutexGuard aGuard( maMutex ); + + sal_uInt32 nSize = maContent.size(); + + if ( nSize > 1 ) + { + gbAscending = mbAscending; + gnColumn = mnSortColumn; + pCollatorWrapper = aIntlWrapper.getCaseCollator(); + + std::stable_sort( maContent.begin(), maContent.end(), CompareSortingData_Impl ); + + pCollatorWrapper = NULL; + } +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::EntryRemoved( const OUString& rURL ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + std::vector< SortingData_Impl* >::iterator aIt; + + for ( aIt = maContent.begin(); aIt != maContent.end(); aIt++ ) + { + if ( (*aIt)->maTargetURL == rURL ) + { + maContent.erase( aIt ); + break; + } + } +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::EntryRenamed( OUString& rURL, + const OUString& rTitle ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + std::vector< SortingData_Impl* >::iterator aIt; + + for ( aIt = maContent.begin(); aIt != maContent.end(); aIt++ ) + { + if ( (*aIt)->maTargetURL == rURL ) + { + (*aIt)->SetNewTitle( rTitle ); + OUString aDisplayText = (*aIt)->maDisplayText; + sal_Int32 nIndex = aDisplayText.indexOf( '\t' ); + + if ( nIndex > 0 ) + (*aIt)->maDisplayText = aDisplayText.replaceAt( 0, nIndex, rTitle ); + + INetURLObject aURLObj( rURL ); + aURLObj.SetName( rTitle, INetURLObject::ENCODE_ALL ); + + rURL = aURLObj.GetMainURL( INetURLObject::NO_DECODE ); + + (*aIt)->maTargetURL = rURL; + break; + } + } +} + +// ----------------------------------------------------------------------- +String SvtFileView_Impl::FolderInserted( const OUString& rURL, const OUString& rTitle ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + SortingData_Impl* pData = new SortingData_Impl; + + pData->SetNewTitle( rTitle ); + pData->maSize = 0; + pData->mbIsFolder = sal_True; + pData->maTargetURL = rURL; + + INetURLObject aURLObj( rURL ); + + ::svtools::VolumeInfo aVolInfo; + pData->maType = SvFileInformationManager::GetFolderDescription( aVolInfo ); + pData->maImage = SvFileInformationManager::GetFolderImage( aVolInfo, sal_False, isHighContrast( mpView ) ); + + OUString aValue; + OUString aTab = OUString::createFromAscii( "\t" ); + OUString aDateSep = OUString::createFromAscii( ", " ); + + // title, type, size, date + aValue = pData->GetTitle(); + // #83004# -------------------- + ReplaceTabWithString( aValue ); + aValue += aTab; + aValue += pData->maType; + aValue += aTab; + // folders don't have a size + aValue += aTab; + // set the date + SvtSysLocale aSysLocale; + const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData(); + aValue += rLocaleData.getDate( pData->maModDate ); + aValue += aDateSep; + aValue += rLocaleData.getTime( pData->maModDate ); + + pData->maDisplayText = aValue; + maContent.push_back( pData ); + + return String( aValue ); +} + +// ----------------------------------------------------------------------- +sal_uLong SvtFileView_Impl::GetEntryPos( const OUString& rURL ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + std::vector< SortingData_Impl* >::iterator aIt; + sal_uLong nPos = 0; + + for ( aIt = maContent.begin(); aIt != maContent.end(); aIt++ ) + { + if ( (*aIt)->maTargetURL == rURL ) + return nPos; + nPos += 1; + } + + return nPos; +} + +// ----------------------------------------------------------------------- +sal_Bool SvtFileView_Impl::SearchNextEntry( sal_uInt32& nIndex, const OUString& rTitle, sal_Bool bWrapAround ) +{ + ::osl::MutexGuard aGuard( maMutex ); + + sal_uInt32 nEnd = maContent.size(); + sal_uInt32 nStart = nIndex; + while ( nIndex < nEnd ) + { + SortingData_Impl* pData = maContent[ nIndex ]; + if ( rTitle.compareTo( pData->GetLowerTitle(), rTitle.getLength() ) == 0 ) + return sal_True; + nIndex += 1; + } + + if ( bWrapAround ) + { + nIndex = 0; + while ( nIndex < nEnd && nIndex <= nStart ) + { + SortingData_Impl* pData = maContent[ nIndex ]; + if ( rTitle.compareTo( pData->GetLowerTitle(), rTitle.getLength() ) == 0 ) + return sal_True; + nIndex += 1; + } + } + + return sal_False; +} + +// ----------------------------------------------------------------------- +void SvtFileView_Impl::SetActualFolder( const INetURLObject& rActualFolder ) +{ + if( mbReplaceNames ) + { + if( mpNameTrans ) + mpNameTrans->SetActualFolder( rActualFolder ); + else + mpNameTrans = new NameTranslator_Impl( rActualFolder ); + } +} + +namespace svtools { + +// ----------------------------------------------------------------------- +// QueryDeleteDlg_Impl +// ----------------------------------------------------------------------- + +QueryDeleteDlg_Impl::QueryDeleteDlg_Impl +( + Window* pParent, + const String& rName // Eintragsname +) : + + ModalDialog( pParent, SvtResId( DLG_SVT_QUERYDELETE ) ), + + _aEntryLabel ( this, SvtResId( TXT_ENTRY ) ), + _aEntry ( this, SvtResId( TXT_ENTRYNAME ) ), + _aQueryMsg ( this, SvtResId( TXT_QUERYMSG ) ), + _aYesButton ( this, SvtResId( BTN_YES ) ), + _aAllButton ( this, SvtResId( BTN_ALL ) ), + _aNoButton ( this, SvtResId( BTN_NO ) ), + _aCancelButton( this, SvtResId( BTN_CANCEL ) ) + +{ + FreeResource(); + + // Handler + Link aLink( STATIC_LINK( this, QueryDeleteDlg_Impl, ClickLink ) ); + _aYesButton.SetClickHdl( aLink ); + _aAllButton.SetClickHdl( aLink ); + _aNoButton.SetClickHdl( aLink ); + + // Anzeige der spezifizierten Texte + + WinBits nTmpStyle = _aEntry.GetStyle(); + nTmpStyle |= WB_PATHELLIPSIS; + _aEntry.SetStyle( nTmpStyle ); + _aEntry.SetText( rName ); +} + +// ----------------------------------------------------------------------- + +IMPL_STATIC_LINK( QueryDeleteDlg_Impl, ClickLink, PushButton*, pBtn ) +{ + if ( pBtn == &pThis->_aYesButton ) + pThis->_eResult = QUERYDELETE_YES; + else if ( pBtn == &pThis->_aNoButton ) + pThis->_eResult = QUERYDELETE_NO; + else if ( pBtn == &pThis->_aAllButton ) + pThis->_eResult = QUERYDELETE_ALL; + else if ( pBtn == &pThis->_aCancelButton ) + pThis->_eResult = QUERYDELETE_CANCEL; + + pThis->EndDialog( RET_OK ); + + return 0; +} + +} + diff --git a/svtools/source/contnr/fileview.hrc b/svtools/source/contnr/fileview.hrc new file mode 100644 index 000000000000..bbf340148fc9 --- /dev/null +++ b/svtools/source/contnr/fileview.hrc @@ -0,0 +1,40 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#define MID_FILEVIEW_DELETE 1 +#define MID_FILEVIEW_RENAME 2 + +// DLG_SFX_QUERYDELETE ******************************************************** + +#define TXT_ENTRY 1 +#define TXT_ENTRYNAME 2 +#define TXT_QUERYMSG 3 +#define BTN_YES 4 +#define BTN_NO 5 +#define BTN_ALL 6 +#define BTN_CANCEL 7 + diff --git a/svtools/source/contnr/fileview.src b/svtools/source/contnr/fileview.src new file mode 100644 index 000000000000..bcb282f44615 --- /dev/null +++ b/svtools/source/contnr/fileview.src @@ -0,0 +1,200 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + // includes ------------------------------------------------------------------ + +#include <svtools/svtools.hrc> +#include "fileview.hrc" +#include <svtools/helpid.hrc> + +// strings -------------------------------------------------------------------- + +String STR_SVT_FILEVIEW_COLUMN_TITLE +{ + Text [ en-US ] = "Title"; +}; + +String STR_SVT_FILEVIEW_COLUMN_SIZE +{ + Text [ en-US ] = "Size"; +}; + +String STR_SVT_FILEVIEW_COLUMN_DATE +{ + Text [ en-US ] = "Date modified"; +}; + +String STR_SVT_FILEVIEW_COLUMN_TYPE +{ + Text [ en-US ] = "Type"; +}; + +String STR_SVT_FILEVIEW_ERR_MAKEFOLDER +{ + Text [ en-US ] = "Could not create the folder %1."; +}; + +String STR_SVT_BYTES +{ + Text [ en-US ] = "Bytes" ; +}; + +String STR_SVT_KB +{ + Text [ en-US ] = "KB" ; +}; + +String STR_SVT_MB +{ + Text [ en-US ] = "MB" ; +}; + + +String STR_SVT_GB +{ + Text [ en-US ] = "GB" ; +}; + +// Images --------------------------------------------------------------------- + +Image IMG_SVT_FOLDER +{ + ImageBitmap = Bitmap { File = "folder.bmp" ; }; + MaskColor = Color { Red = 0xFFFF ; Green = 0x0000 ; Blue = 0xFFFF ; }; +}; + +// Menus ----------------------------------------------------------------- + +Menu RID_FILEVIEW_CONTEXTMENU +{ + ItemList = + { + MenuItem + { + Identifier = MID_FILEVIEW_DELETE ; + HelpId = HID_FILEVIEW_MENU_DELETE ; + Text [ en-US ] = "~Delete"; + }; + MenuItem + { + Identifier = MID_FILEVIEW_RENAME ; + HelpId = HID_FILEVIEW_MENU_RENAME ; + Text [ en-US ] = "~Rename"; + }; + }; +}; + +ModalDialog DLG_SVT_QUERYDELETE +{ + HelpID = "svtools:ModalDialog:DLG_SVT_QUERYDELETE"; + SVLook = TRUE ; + OutputSize = TRUE ; + Moveable = TRUE ; + Size = MAP_APPFONT ( 221 , 67 ) ; + Text [ en-US ] = "Confirm Delete" ; + + FixedText TXT_ENTRY + { + NoLabel = TRUE; + Pos = MAP_APPFONT ( 6 , 6 ) ; + Size = MAP_APPFONT ( 40 , 10 ) ; + Text [ en-US ] = "Entry:" ; + }; + + FixedText TXT_ENTRYNAME + { + Pos = MAP_APPFONT ( 52 , 6 ) ; + Size = MAP_APPFONT ( 163 , 10 ) ; + NoLabel = TRUE ; + }; + + FixedText TXT_QUERYMSG + { + NoLabel = TRUE; + WordBreak = TRUE; + Pos = MAP_APPFONT ( 6 , 19 ) ; + Size = MAP_APPFONT ( 209 , 22 ) ; + Text [ en-US ] = "Are you sure you want to delete the selected data?" ; + }; + + PushButton BTN_YES + { + HelpID = "svtools:PushButton:DLG_SVT_QUERYDELETE:BTN_YES"; + Pos = MAP_APPFONT ( 6 , 47 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + DefButton = TRUE ; + Text [ en-US ] = "~Delete" ; + }; + + PushButton BTN_ALL + { + HelpID = "svtools:PushButton:DLG_SVT_QUERYDELETE:BTN_ALL"; + Pos = MAP_APPFONT ( 59 , 47 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Disable = TRUE ; + Text [ en-US ] = "Delete ~All" ; + }; + + PushButton BTN_NO + { + HelpID = "svtools:PushButton:DLG_SVT_QUERYDELETE:BTN_NO"; + Pos = MAP_APPFONT ( 112 , 47 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + Text [ en-US ] = "Do ~Not Delete" ; + }; + + CancelButton BTN_CANCEL + { + Pos = MAP_APPFONT ( 165 , 47 ) ; + Size = MAP_APPFONT ( 50 , 14 ) ; + TabStop = TRUE ; + }; +}; + + + + + + + + + + + + + + + + + + + + + diff --git a/svtools/source/contnr/imivctl.hxx b/svtools/source/contnr/imivctl.hxx new file mode 100644 index 000000000000..a54d578593cd --- /dev/null +++ b/svtools/source/contnr/imivctl.hxx @@ -0,0 +1,637 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _IMPICNVW_HXX +#define _IMPICNVW_HXX + +#ifndef _VIRDEV_HXX +#include <vcl/virdev.hxx> +#endif +#ifndef _SCRBAR_HXX +#include <vcl/scrbar.hxx> +#endif +#include <vcl/timer.hxx> +#include <vcl/seleng.hxx> +#include <tools/debug.hxx> +#include "svtaccessiblefactory.hxx" + +#include <limits.h> + +#include <svtools/ivctrl.hxx> +#include <svl/svarray.hxx> + +class IcnCursor_Impl; +class SvtIconChoiceCtrl; +class SvxIconChoiceCtrlEntry; +class IcnViewEdit_Impl; +class IcnGridMap_Impl; + +/////////////////////////////////////////////////////////////////////////////// +// +// some defines +// +#define PAINTFLAG_HOR_CENTERED 0x0001 +#define PAINTFLAG_VER_CENTERED 0x0002 + +#define F_VER_SBARSIZE_WITH_HBAR 0x0001 +#define F_HOR_SBARSIZE_WITH_VBAR 0x0002 +#define F_PAINTED 0x0004 // sal_True nach erstem Paint +#define F_ADD_MODE 0x0008 +#define F_SELECTING_RECT 0x0020 +#define F_DOWN_CTRL 0x0080 +#define F_DOWN_DESELECT 0x0100 +#define F_START_EDITTIMER_IN_MOUSEUP 0x0400 +#define F_MOVED_ENTRIES 0x0800 +#define F_ENTRYLISTPOS_VALID 0x1000 +#define F_CLEARING_SELECTION 0x2000 +#define F_ARRANGING 0x4000 + +// alle Angaben in Pixel +// Abstaende von Fensterraendern +#define LROFFS_WINBORDER 4 +#define TBOFFS_WINBORDER 4 +// fuer das Bounding-Rectangle +#define LROFFS_BOUND 2 +#define TBOFFS_BOUND 2 +// Abstand Fokusrechteck - Icon +#define LROFFS_ICON 2 +#define TBOFFS_ICON 2 +// Abstaende Icon - Text +#define HOR_DIST_BMP_STRING 3 +#define VER_DIST_BMP_STRING 3 +// Breitenoffset Highlight-Rect bei Text +#define LROFFS_TEXT 2 + +#define DEFAULT_MAX_VIRT_WIDTH 200 +#define DEFAULT_MAX_VIRT_HEIGHT 200 + +#define VIEWMODE_MASK (WB_ICON | WB_SMALLICON | WB_DETAILS) + +/////////////////////////////////////////////////////////////////////////////// +// +// +// +enum IcnViewFieldType +{ + IcnViewFieldTypeDontknow = 0, + IcnViewFieldTypeImage = 1, + IcnViewFieldTypeText = 2 +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Data about the focus of entries +// +struct LocalFocus +{ + sal_Bool bOn; + Rectangle aRect; + Color aPenColor; + + LocalFocus() { bOn = sal_False; } +}; + +/////////////////////////////////////////////////////////////////////////////// +// +// Entry-List +// +class EntryList_Impl : public List +{ +private: + + using List::Replace; + + SvxIconChoiceCtrl_Impl* _pOwner; + + void Removed_Impl( SvxIconChoiceCtrlEntry* pEntry ); + +public: + EntryList_Impl( + SvxIconChoiceCtrl_Impl*, + sal_uInt16 _nInitSize = 1024, + sal_uInt16 _nReSize = 1024 ); + EntryList_Impl( + SvxIconChoiceCtrl_Impl*, + sal_uInt16 _nBlockSize, + sal_uInt16 _nInitSize, + sal_uInt16 _nReSize ); + ~EntryList_Impl(); + + void Clear(); + void Insert( SvxIconChoiceCtrlEntry* pEntry, sal_uLong nPos ); + SvxIconChoiceCtrlEntry* Remove( sal_uLong nPos ); + void Remove( SvxIconChoiceCtrlEntry* pEntry ); +}; + + +/////////////////////////////////////////////////////////////////////////////// +// +// Implementation-class of IconChoiceCtrl +// +class SvxIconChoiceCtrl_Impl +{ + friend class IcnCursor_Impl; + friend class EntryList_Impl; + friend class IcnGridMap_Impl; + + sal_Bool bChooseWithCursor; + EntryList_Impl aEntries; + ScrollBar aVerSBar; + ScrollBar aHorSBar; + ScrollBarBox aScrBarBox; + Rectangle aCurSelectionRect; + SvPtrarr aSelectedRectList; + Timer aEditTimer; // fuer Inplace-Editieren + Timer aAutoArrangeTimer; + Timer aDocRectChangedTimer; + Timer aVisRectChangedTimer; + Timer aCallSelectHdlTimer; + Size aVirtOutputSize; + Size aImageSize; + Size aDefaultTextSize; + Size aOutputSize; // Pixel + Point aDDLastEntryPos; + Point aDDLastRectPos; + Point aDDPaintOffs; + Point aDDStartPos; + SvtIconChoiceCtrl* pView; + IcnCursor_Impl* pImpCursor; + IcnGridMap_Impl* pGridMap; + long nMaxVirtWidth; // max. Breite aVirtOutputSize bei ALIGN_TOP + long nMaxVirtHeight; // max. Hoehe aVirtOutputSize bei ALIGN_LEFT + List* pZOrderList; + SvPtrarr* pColumns; + IcnViewEdit_Impl* pEdit; + WinBits nWinBits; + long nMaxBoundHeight; // Hoehe des hoechsten BoundRects + sal_uInt16 nFlags; + sal_uInt16 nCurTextDrawFlags; + sal_uLong nUserEventAdjustScrBars; + sal_uLong nUserEventShowCursor; + SvxIconChoiceCtrlEntry* pCurHighlightFrame; + sal_Bool bHighlightFramePressed; + SvxIconChoiceCtrlEntry* pHead; // Eintrag oben links + SvxIconChoiceCtrlEntry* pCursor; + SvxIconChoiceCtrlEntry* pPrevDropTarget; + SvxIconChoiceCtrlEntry* pHdlEntry; + SvxIconChoiceCtrlEntry* pDDRefEntry; + VirtualDevice* pDDDev; + VirtualDevice* pDDBufDev; + VirtualDevice* pDDTempDev; + VirtualDevice* pEntryPaintDev; + SvxIconChoiceCtrlEntry* pAnchor; // fuer Selektion + LocalFocus aFocus; // Data for focusrect + ::svt::AccessibleFactoryAccess aAccFactory; + + List* pDraggedSelection; + SvxIconChoiceCtrlEntry* pCurEditedEntry; + SvxIconChoiceCtrlTextMode eTextMode; + SelectionMode eSelectionMode; + sal_uLong nSelectionCount; + SvxIconChoiceCtrlPositionMode ePositionMode; + sal_Bool bBoundRectsDirty; + sal_Bool bUpdateMode; + sal_Bool bEntryEditingEnabled; + sal_Bool bInDragDrop; + + void ShowCursor( sal_Bool bShow ); + + void ImpArrange( sal_Bool bKeepPredecessors = sal_False ); + void AdjustVirtSize( const Rectangle& ); + void ResetVirtSize(); + void CheckScrollBars(); + + DECL_LINK( ScrollUpDownHdl, ScrollBar * ); + DECL_LINK( ScrollLeftRightHdl, ScrollBar * ); + DECL_LINK( EditTimeoutHdl, Timer* ); + DECL_LINK( UserEventHdl, void* ); + DECL_LINK( EndScrollHdl, void* ); + DECL_LINK( AutoArrangeHdl, void* ); + DECL_LINK( DocRectChangedHdl, void* ); + DECL_LINK( VisRectChangedHdl, void* ); + DECL_LINK( CallSelectHdlHdl, void* ); + + void AdjustScrollBars( sal_Bool bVirtSizeGrowedOnly = sal_False); + void PositionScrollBars( long nRealWidth, long nRealHeight ); + long GetScrollBarPageSize( long nVisibleRange ) const { return ((nVisibleRange*75)/100); } + long GetScrollBarLineSize() const { return nMaxBoundHeight / 2; } + sal_Bool HandleScrollCommand( const CommandEvent& rCmd ); + void ToDocPos( Point& rPosPixel ) { rPosPixel -= pView->GetMapMode().GetOrigin(); } + void InitScrollBarBox(); + SvxIconChoiceCtrlEntry* FindNewCursor(); + void ToggleSelection( SvxIconChoiceCtrlEntry* ); + void DeselectAllBut( SvxIconChoiceCtrlEntry*, sal_Bool bPaintSync=sal_False ); + void Center( SvxIconChoiceCtrlEntry* pEntry ) const; + void StopEditTimer() { aEditTimer.Stop(); } + void StartEditTimer() { aEditTimer.Start(); } + void ImpHideDDIcon(); + void CallSelectHandler( SvxIconChoiceCtrlEntry* ); + void SelectRect( + SvxIconChoiceCtrlEntry* pEntry1, + SvxIconChoiceCtrlEntry* pEntry2, + sal_Bool bAdd = sal_True, + SvPtrarr* pOtherRects = 0 ); + + void SelectRange( + SvxIconChoiceCtrlEntry* pStart, + SvxIconChoiceCtrlEntry* pEnd, + sal_Bool bAdd = sal_True ); + + void AddSelectedRect( const Rectangle& ); + void AddSelectedRect( + SvxIconChoiceCtrlEntry* pEntry1, + SvxIconChoiceCtrlEntry* pEntry2 ); + + void ClearSelectedRectList(); + void ClearColumnList(); + Rectangle CalcMaxTextRect( const SvxIconChoiceCtrlEntry* pEntry ) const; + + void ClipAtVirtOutRect( Rectangle& rRect ) const; + void AdjustAtGrid( const SvPtrarr& rRow, SvxIconChoiceCtrlEntry* pStart=0 ); + Point AdjustAtGrid( + const Rectangle& rCenterRect, // "Schwerpunkt" des Objekts (typ. Bmp-Rect) + const Rectangle& rBoundRect ) const; + sal_uLong GetPredecessorGrid( const Point& rDocPos) const; + + void InitPredecessors(); + void ClearPredecessors(); + + sal_Bool CheckVerScrollBar(); + sal_Bool CheckHorScrollBar(); + void CancelUserEvents(); + void EntrySelected( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bSelect, + sal_Bool bSyncPaint ); + void SaveSelection( List** ); + void RepaintEntries( sal_uInt16 nEntryFlagsMask ); + void SetListPositions(); + void SetDefaultTextSize(); + sal_Bool IsAutoArrange() const { + return (sal_Bool)(ePositionMode == IcnViewPositionModeAutoArrange); } + sal_Bool IsAutoAdjust() const { + return (sal_Bool)(ePositionMode == IcnViewPositionModeAutoAdjust); } + void DocRectChanged() { aDocRectChangedTimer.Start(); } + void VisRectChanged() { aVisRectChangedTimer.Start(); } + void SetOrigin( const Point&, sal_Bool bDoNotUpdateWallpaper = sal_False ); + + DECL_LINK( TextEditEndedHdl, IcnViewEdit_Impl* ); + + void ShowFocus ( Rectangle& rRect ); + void HideFocus (); + void DrawFocusRect ( OutputDevice* pOut ); + + sal_Bool IsMnemonicChar( sal_Unicode cChar, sal_uLong& rPos ) const; + +public: + + long nGridDX, + nGridDY; + long nHorSBarHeight, + nVerSBarWidth; + + SvxIconChoiceCtrl_Impl( SvtIconChoiceCtrl* pView, WinBits nWinStyle ); + ~SvxIconChoiceCtrl_Impl(); + + sal_Bool SetChoiceWithCursor ( sal_Bool bDo = sal_True ) { sal_Bool bOld=bChooseWithCursor; bChooseWithCursor = bDo; return bOld; } + void Clear( sal_Bool bInCtor = sal_False ); + void SetStyle( WinBits nWinStyle ); + WinBits GetStyle() const { return nWinBits; } + void InsertEntry( SvxIconChoiceCtrlEntry*, sal_uLong nPos, const Point* pPos=0 ); + void CreateAutoMnemonics( MnemonicGenerator* _pGenerator = NULL ); + void RemoveEntry( SvxIconChoiceCtrlEntry* pEntry ); + void FontModified(); + void SelectAll( sal_Bool bSelect = sal_True, sal_Bool bPaint = sal_True ); + void SelectEntry( + SvxIconChoiceCtrlEntry*, + sal_Bool bSelect, + sal_Bool bCallHdl = sal_True, + sal_Bool bAddToSelection = sal_False, + sal_Bool bSyncPaint = sal_False ); + void Paint( const Rectangle& rRect ); + sal_Bool MouseButtonDown( const MouseEvent& ); + sal_Bool MouseButtonUp( const MouseEvent& ); + sal_Bool MouseMove( const MouseEvent&); + sal_Bool RequestHelp( const HelpEvent& rHEvt ); + void SetCursor_Impl( + SvxIconChoiceCtrlEntry* pOldCursor, + SvxIconChoiceCtrlEntry* pNewCursor, + sal_Bool bMod1, + sal_Bool bShift, + sal_Bool bPaintSync = sal_False); + sal_Bool KeyInput( const KeyEvent& ); + void Resize(); + void GetFocus(); + void LoseFocus(); + void SetUpdateMode( sal_Bool bUpdate ); + sal_Bool GetUpdateMode() const { return bUpdateMode; } + void PaintEntry( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bIsBackgroundPainted=sal_False ); + void PaintEntry( + SvxIconChoiceCtrlEntry*, + const Point&, + OutputDevice* pOut = 0, + sal_Bool bIsBackgroundPainted = sal_False); + void PaintEntryVirtOutDev( SvxIconChoiceCtrlEntry* ); + + void SetEntryPos( + SvxIconChoiceCtrlEntry* pEntry, + const Point& rPos, + sal_Bool bAdjustRow = sal_False, + sal_Bool bCheckScrollBars = sal_False, + sal_Bool bKeepGridMap = sal_False ); + + void InvalidateEntry( SvxIconChoiceCtrlEntry* ); + IcnViewFieldType GetItem( SvxIconChoiceCtrlEntry*, const Point& rAbsPos ); + + void SetNoSelection(); + + SvxIconChoiceCtrlEntry* GetCurEntry() const { return pCursor; } + void SetCursor( + SvxIconChoiceCtrlEntry*, + // sal_True == bei Single-Selection die Sel. mitfuehren + sal_Bool bSyncSingleSelection = sal_True, + sal_Bool bShowFocusAsync = sal_False ); + + SvxIconChoiceCtrlEntry* GetEntry( const Point& rDocPos, sal_Bool bHit = sal_False ); + SvxIconChoiceCtrlEntry* GetNextEntry( const Point& rDocPos, SvxIconChoiceCtrlEntry* pCurEntry ); + SvxIconChoiceCtrlEntry* GetPrevEntry( const Point& rDocPos, SvxIconChoiceCtrlEntry* pCurEntry ); + + Point GetEntryPos( SvxIconChoiceCtrlEntry* ); + void MakeEntryVisible( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bBound = sal_True ); + + void Arrange(sal_Bool bKeepPredecessors = sal_False, long nSetMaxVirtWidth =0, long nSetMaxVirtHeight =0 ); + + Rectangle CalcFocusRect( SvxIconChoiceCtrlEntry* ); + Rectangle CalcBmpRect( SvxIconChoiceCtrlEntry*, const Point* pPos = 0 ); + Rectangle CalcTextRect( + SvxIconChoiceCtrlEntry*, + const Point* pPos = 0, + sal_Bool bForInplaceEdit = sal_False, + const String* pStr = 0 ); + + long CalcBoundingWidth( SvxIconChoiceCtrlEntry* ) const; + long CalcBoundingHeight( SvxIconChoiceCtrlEntry* ) const; + Size CalcBoundingSize( SvxIconChoiceCtrlEntry* ) const; + void FindBoundingRect( SvxIconChoiceCtrlEntry* pEntry ); + void SetBoundingRect_Impl( + SvxIconChoiceCtrlEntry* pEntry, + const Point& rPos, + const Size& rBoundingSize ); + // berechnet alle BoundRects neu + void RecalcAllBoundingRects(); + // berechnet alle ungueltigen BoundRects neu + void RecalcAllBoundingRectsSmart(); + const Rectangle& GetEntryBoundRect( SvxIconChoiceCtrlEntry* ); + void InvalidateBoundingRect( SvxIconChoiceCtrlEntry* ); + void InvalidateBoundingRect( Rectangle& rRect ) { rRect.Right() = LONG_MAX; bBoundRectsDirty = sal_True; } + sal_Bool IsBoundingRectValid( const Rectangle& rRect ) const { return (sal_Bool)( rRect.Right() != LONG_MAX ); } + + void PaintEmphasis( + const Rectangle& rRect1, + const Rectangle& rRect2, + sal_Bool bSelected, + sal_Bool bDropTarget, + sal_Bool bCursored, + OutputDevice* pOut, + sal_Bool bIsBackgroundPainted = sal_False); + + void PaintItem( + const Rectangle& rRect, + IcnViewFieldType eItem, + SvxIconChoiceCtrlEntry* pEntry, + sal_uInt16 nPaintFlags, + OutputDevice* pOut, + const String* pStr = 0, + ::vcl::ControlLayoutData* _pLayoutData = NULL ); + + // berechnet alle BoundingRects neu, wenn bMustRecalcBoundingRects == sal_True + void CheckBoundingRects() { if (bBoundRectsDirty) RecalcAllBoundingRectsSmart(); } + // berechnet alle invalidierten BoundingRects neu + void UpdateBoundingRects(); + void ShowTargetEmphasis( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bShow ); + void PrepareCommandEvent( const CommandEvent& ); + void Command( const CommandEvent& rCEvt ); + void ToTop( SvxIconChoiceCtrlEntry* ); + + sal_uLong GetSelectionCount() const; + void SetGrid( const Size& ); + Size GetMinGrid() const; + sal_uLong GetGridCount( + const Size& rSize, + sal_Bool bCheckScrBars, + sal_Bool bSmartScrBar ) const; + void Scroll( long nDeltaX, long nDeltaY, sal_Bool bScrollBar = sal_False ); + const Size& GetItemSize( SvxIconChoiceCtrlEntry*, IcnViewFieldType ) const; + + void HideDDIcon(); + void ShowDDIcon( SvxIconChoiceCtrlEntry* pRefEntry, const Point& rPos ); + void HideShowDDIcon( + SvxIconChoiceCtrlEntry* pRefEntry, + const Point& rPos ); + + sal_Bool IsOver( + SvPtrarr* pSelectedRectList, + const Rectangle& rEntryBoundRect ) const; + + void SelectRect( + const Rectangle&, + sal_Bool bAdd = sal_True, + SvPtrarr* pOtherRects = 0 ); + + void CalcScrollOffsets( + const Point& rRefPosPixel, + long& rX, + long& rY, + sal_Bool bDragDrop = sal_False, + sal_uInt16 nBorderWidth = 10 ); + + sal_Bool IsTextHit( SvxIconChoiceCtrlEntry* pEntry, const Point& rDocPos ); + void MakeVisible( + const Rectangle& rDocPos, + sal_Bool bInScrollBarEvent=sal_False, + sal_Bool bCallRectChangedHdl = sal_True ); + + void AdjustEntryAtGrid( SvxIconChoiceCtrlEntry* pStart = 0 ); + void SetEntryTextMode( SvxIconChoiceCtrlTextMode, SvxIconChoiceCtrlEntry* pEntry = 0 ); + SvxIconChoiceCtrlTextMode GetTextMode( const SvxIconChoiceCtrlEntry* pEntry = 0 ) const; + void ShowEntryFocusRect( const SvxIconChoiceCtrlEntry* pEntry ); + void EnableEntryEditing( sal_Bool bEnable ) { bEntryEditingEnabled = bEnable; } + sal_Bool IsEntryEditingEnabled() const { return bEntryEditingEnabled; } + sal_Bool IsEntryEditing() const { return (sal_Bool)(pCurEditedEntry!=0); } + void EditEntry( SvxIconChoiceCtrlEntry* pEntry ); + void StopEntryEditing( sal_Bool bCancel ); + void LockEntryPos( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bLock ); + sal_uLong GetEntryCount() const { return aEntries.Count(); } + SvxIconChoiceCtrlEntry* GetEntry( sal_uLong nPos ) const { return (SvxIconChoiceCtrlEntry*)aEntries.GetObject(nPos); } + SvxIconChoiceCtrlEntry* GetFirstSelectedEntry( sal_uLong& ) const; + SvxIconChoiceCtrlEntry* GetNextSelectedEntry( sal_uLong& ) const; + SvxIconChoiceCtrlEntry* GetHdlEntry() const { return pHdlEntry; } + void SetHdlEntry( SvxIconChoiceCtrlEntry* pEntry ) { pHdlEntry = pEntry; } + + SvxIconChoiceCtrlTextMode GetEntryTextModeSmart( const SvxIconChoiceCtrlEntry* pEntry ) const; + void SetSelectionMode( SelectionMode eMode ) { eSelectionMode=eMode; } + SelectionMode GetSelectionMode() const { return eSelectionMode; } + sal_Bool AreEntriesMoved() const { return (sal_Bool)((nFlags & F_MOVED_ENTRIES)!=0); } + void SetEntriesMoved( sal_Bool bMoved ) + { + if( bMoved ) nFlags |= F_MOVED_ENTRIES; + else nFlags &= ~(F_MOVED_ENTRIES); + } + sal_uLong GetEntryListPos( SvxIconChoiceCtrlEntry* ) const; + void SetEntryListPos( SvxIconChoiceCtrlEntry* pEntry, sal_uLong nNewPos ); + void SetEntryImageSize( const Size& rSize ) { aImageSize = rSize; } + void SetEntryFlags( SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nFlags ); + SvxIconChoiceCtrlEntry* GoLeftRight( SvxIconChoiceCtrlEntry*, sal_Bool bRight ); + SvxIconChoiceCtrlEntry* GoUpDown( SvxIconChoiceCtrlEntry*, sal_Bool bDown ); + void InitSettings(); + Rectangle GetOutputRect() const; + + sal_Bool ArePredecessorsSet() const { return (sal_Bool)(pHead != 0); } + SvxIconChoiceCtrlEntry* GetPredecessorHead() const { return pHead; } + void SetEntryPredecessor(SvxIconChoiceCtrlEntry* pEntry,SvxIconChoiceCtrlEntry* pPredecessor); + sal_Bool GetEntryPredecessor(SvxIconChoiceCtrlEntry* pEntry,SvxIconChoiceCtrlEntry** ppPredecessor); + // liefert gueltige Ergebnisse nur im AutoArrange-Modus! + SvxIconChoiceCtrlEntry* FindEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry, const Point& ); + + void SetPositionMode( SvxIconChoiceCtrlPositionMode ); + SvxIconChoiceCtrlPositionMode GetPositionMode() const { return ePositionMode;} + + void Flush(); + void SetColumn( sal_uInt16 nIndex, const SvxIconChoiceCtrlColumnInfo& ); + const SvxIconChoiceCtrlColumnInfo* GetColumn( sal_uInt16 nIndex ) const; + const SvxIconChoiceCtrlColumnInfo* GetItemColumn( sal_uInt16 nSubItem, long& rLeft ) const; + + Rectangle GetDocumentRect() const { return Rectangle( Point(), aVirtOutputSize ); } + Rectangle GetVisibleRect() const { return GetOutputRect(); } + + void SetEntryHighlightFrame( SvxIconChoiceCtrlEntry* pEntry,sal_Bool bKeepHighlightFlags=sal_False ); + void HideEntryHighlightFrame(); + void DrawHighlightFrame( OutputDevice* pOut, + const Rectangle& rBmpRect, sal_Bool bHide ); + void StopSelectTimer() { aCallSelectHdlTimer.Stop(); } + void Tracking( const TrackingEvent& rTEvt ); + Point GetPopupMenuPosPixel() const; + + sal_Bool HandleShortCutKey( const KeyEvent& rKeyEvent ); + + void CallEventListeners( sal_uLong nEvent, void* pData = NULL ); + + inline ::svt::IAccessibleFactory& + GetAccessibleFactory() { return aAccFactory.getFactory(); } +}; + +// ---------------------------------------------------------------------------------------------- + +class IcnCursor_Impl +{ + SvxIconChoiceCtrl_Impl* pView; + SvPtrarr* pColumns; + SvPtrarr* pRows; + long nCols; + long nRows; + short nDeltaWidth; + short nDeltaHeight; + SvxIconChoiceCtrlEntry* pCurEntry; + void SetDeltas(); + void ImplCreate(); + void Create() { if( !pColumns ) ImplCreate(); } + + sal_uInt16 GetSortListPos( SvPtrarr* pList, long nValue, int bVertical); + SvxIconChoiceCtrlEntry* SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom,sal_uInt16 nPref, + sal_Bool bDown, sal_Bool bSimple ); + + SvxIconChoiceCtrlEntry* SearchRow(sal_uInt16 nRow,sal_uInt16 nRight,sal_uInt16 nLeft,sal_uInt16 nPref, + sal_Bool bRight, sal_Bool bSimple ); + +public: + IcnCursor_Impl( SvxIconChoiceCtrl_Impl* pOwner ); + ~IcnCursor_Impl(); + void Clear(); + + // fuer Cursortravelling usw. + SvxIconChoiceCtrlEntry* GoLeftRight( SvxIconChoiceCtrlEntry*, sal_Bool bRight ); + SvxIconChoiceCtrlEntry* GoUpDown( SvxIconChoiceCtrlEntry*, sal_Bool bDown ); + SvxIconChoiceCtrlEntry* GoPageUpDown( SvxIconChoiceCtrlEntry*, sal_Bool bDown ); + + // Erzeugt fuer jede Zeile (Hoehe=nGridDY) eine nach BoundRect.Left() + // sortierte Liste der Eintraege, die in ihr stehen. Eine Liste kann + // leer sein. Die Listen gehen in das Eigentum des Rufenden ueber und + // muessen mit DestroyGridAdjustData geloescht werden + void CreateGridAjustData( SvPtrarr& pLists, SvxIconChoiceCtrlEntry* pRow=0); + static void DestroyGridAdjustData( SvPtrarr& rLists ); +}; + +// ---------------------------------------------------------------------------------------------- + +typedef sal_uLong GridId; + +#define GRID_NOT_FOUND ((GridId)ULONG_MAX) + +class IcnGridMap_Impl +{ + Rectangle _aLastOccupiedGrid; + SvxIconChoiceCtrl_Impl* _pView; + sal_Bool* _pGridMap; + sal_uInt16 _nGridCols, _nGridRows; + + void Expand(); + void Create_Impl(); + void Create() { if(!_pGridMap) Create_Impl(); } + + void GetMinMapSize( sal_uInt16& rDX, sal_uInt16& rDY ) const; + +public: + IcnGridMap_Impl(SvxIconChoiceCtrl_Impl* pView); + ~IcnGridMap_Impl(); + + void Clear(); + + GridId GetGrid( const Point& rDocPos, sal_Bool* pbClipped = 0 ); + GridId GetGrid( sal_uInt16 nGridX, sal_uInt16 nGridY ); + GridId GetUnoccupiedGrid( sal_Bool bOccupyFound=sal_True ); + + void OccupyGrids( const Rectangle&, sal_Bool bOccupy = sal_True ); + void OccupyGrids( const SvxIconChoiceCtrlEntry*, sal_Bool bOccupy = sal_True ); + void OccupyGrid( GridId nId, sal_Bool bOccupy = sal_True ) + { + DBG_ASSERT(!_pGridMap || nId<(sal_uLong)(_nGridCols*_nGridRows),"OccupyGrid: Bad GridId"); + if(_pGridMap && nId < (sal_uLong)(_nGridCols *_nGridRows) ) + _pGridMap[ nId ] = bOccupy; + } + + Rectangle GetGridRect( GridId ); + void GetGridCoord( GridId, sal_uInt16& rGridX, sal_uInt16& rGridY ); + static sal_uLong GetGridCount( const Size& rSizePixel, sal_uInt16 nGridWidth, sal_uInt16 nGridHeight ); + + void OutputSizeChanged(); +}; + + + + + +#endif + + diff --git a/svtools/source/contnr/imivctl1.cxx b/svtools/source/contnr/imivctl1.cxx new file mode 100644 index 000000000000..3963ce48c255 --- /dev/null +++ b/svtools/source/contnr/imivctl1.cxx @@ -0,0 +1,4681 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <limits.h> +#include <tools/debug.hxx> +#include <vcl/wall.hxx> +#include <vcl/help.hxx> +#include <vcl/decoview.hxx> +#include <vcl/svapp.hxx> +#include <tools/poly.hxx> +#include <vcl/lineinfo.hxx> +#include <vcl/i18nhelp.hxx> +#include <vcl/mnemonic.hxx> +#include <vcl/controllayout.hxx> + +#include <svtools/ivctrl.hxx> +#include "imivctl.hxx" +#include <svtools/svmedit.hxx> + +#include <algorithm> +#include <memory> + +#define DD_SCROLL_PIXEL 24 +#define IMPICNVIEW_ACC_RETURN 1 +#define IMPICNVIEW_ACC_ESCAPE 2 + +#define DRAWTEXT_FLAGS_ICON \ + ( TEXT_DRAW_CENTER | TEXT_DRAW_TOP | TEXT_DRAW_ENDELLIPSIS | \ + TEXT_DRAW_CLIP | TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK | TEXT_DRAW_MNEMONIC ) + +#define DRAWTEXT_FLAGS_SMALLICON (TEXT_DRAW_LEFT|TEXT_DRAW_ENDELLIPSIS|TEXT_DRAW_CLIP) + +#define EVENTID_SHOW_CURSOR ((void*)1) +#define EVENTID_ADJUST_SCROLLBARS ((void*)2) + +struct SvxIconChoiceCtrlEntry_Impl +{ + SvxIconChoiceCtrlEntry* _pEntry; + Point _aPos; + SvxIconChoiceCtrlEntry_Impl( SvxIconChoiceCtrlEntry* pEntry, const Rectangle& rBoundRect ) + : _pEntry( pEntry), _aPos( rBoundRect.TopLeft()) {} +}; + +static sal_Bool bEndScrollInvalidate = sal_True; + +// ---------------------------------------------------------------------------------------------- + +class IcnViewEdit_Impl : public MultiLineEdit +{ + Link aCallBackHdl; + Accelerator aAccReturn; + Accelerator aAccEscape; + Timer aTimer; + sal_Bool bCanceled; + sal_Bool bAlreadyInCallback; + sal_Bool bGrabFocus; + + void CallCallBackHdl_Impl(); + DECL_LINK( Timeout_Impl, Timer * ); + DECL_LINK( ReturnHdl_Impl, Accelerator * ); + DECL_LINK( EscapeHdl_Impl, Accelerator * ); + +public: + + IcnViewEdit_Impl( + SvtIconChoiceCtrl* pParent, + const Point& rPos, + const Size& rSize, + const XubString& rData, + const Link& rNotifyEditEnd ); + + ~IcnViewEdit_Impl(); + virtual void KeyInput( const KeyEvent& rKEvt ); + virtual long PreNotify( NotifyEvent& rNEvt ); + sal_Bool EditingCanceled() const { return bCanceled; } + void StopEditing( sal_Bool bCancel = sal_False ); + sal_Bool IsGrabFocus() const { return bGrabFocus; } +}; + +// ---------------------------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------------------------- + +SvxIconChoiceCtrl_Impl::SvxIconChoiceCtrl_Impl( SvtIconChoiceCtrl* pCurView, + WinBits nWinStyle ) : + aEntries( this ), + aVerSBar( pCurView, WB_DRAG | WB_VSCROLL ), + aHorSBar( pCurView, WB_DRAG | WB_HSCROLL ), + aScrBarBox( pCurView ), + aImageSize( 32, 32 ), + pColumns( 0 ) +{ + bChooseWithCursor=sal_False; + pEntryPaintDev = 0; + pCurEditedEntry = 0; + pCurHighlightFrame = 0; + pEdit = 0; + pAnchor = 0; + pDraggedSelection = 0; + pPrevDropTarget = 0; + pHdlEntry = 0; + pHead = NULL; + pCursor = NULL; + bUpdateMode = sal_True; + bEntryEditingEnabled = sal_False; + bInDragDrop = sal_False; + bHighlightFramePressed = sal_False; + eSelectionMode = MULTIPLE_SELECTION; + pView = pCurView; + pZOrderList = new List; //SvPtrarr; + ePositionMode = IcnViewPositionModeFree; + SetStyle( nWinStyle ); + nFlags = 0; + nUserEventAdjustScrBars = 0; + nUserEventShowCursor = 0; + nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH; + nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT; + pDDRefEntry = 0; + pDDDev = 0; + pDDBufDev = 0; + pDDTempDev = 0; + eTextMode = IcnShowTextShort; + pImpCursor = new IcnCursor_Impl( this ); + pGridMap = new IcnGridMap_Impl( this ); + + aVerSBar.SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollUpDownHdl ) ); + aHorSBar.SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl ) ); + Link aEndScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, EndScrollHdl ) ); + aVerSBar.SetEndScrollHdl( aEndScrollHdl ); + aHorSBar.SetEndScrollHdl( aEndScrollHdl ); + + nHorSBarHeight = aHorSBar.GetSizePixel().Height(); + nVerSBarWidth = aVerSBar.GetSizePixel().Width(); + + aEditTimer.SetTimeout( 800 ); + aEditTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,EditTimeoutHdl)); + aAutoArrangeTimer.SetTimeout( 100 ); + aAutoArrangeTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,AutoArrangeHdl)); + aCallSelectHdlTimer.SetTimeout( 500 ); + aCallSelectHdlTimer.SetTimeoutHdl( LINK(this,SvxIconChoiceCtrl_Impl,CallSelectHdlHdl)); + + aDocRectChangedTimer.SetTimeout( 50 ); + aDocRectChangedTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,DocRectChangedHdl)); + aVisRectChangedTimer.SetTimeout( 50 ); + aVisRectChangedTimer.SetTimeoutHdl(LINK(this,SvxIconChoiceCtrl_Impl,VisRectChangedHdl)); + + Clear( sal_True ); + + SetGrid( Size(100, 70) ); +} + +SvxIconChoiceCtrl_Impl::~SvxIconChoiceCtrl_Impl() +{ + pCurEditedEntry = 0; + DELETEZ(pEdit); + Clear(); + StopEditTimer(); + CancelUserEvents(); + delete pZOrderList; + delete pImpCursor; + delete pGridMap; + delete pDDDev; + delete pDDBufDev; + delete pDDTempDev; + delete pDraggedSelection; + delete pEntryPaintDev; + ClearSelectedRectList(); + ClearColumnList(); +} + +void SvxIconChoiceCtrl_Impl::Clear( sal_Bool bInCtor ) +{ + StopEntryEditing( sal_True ); + nSelectionCount = 0; + DELETEZ(pDraggedSelection); + bInDragDrop = sal_False; + pCurHighlightFrame = 0; + StopEditTimer(); + CancelUserEvents(); + ShowCursor( sal_False ); + bBoundRectsDirty = sal_False; + nMaxBoundHeight = 0; + + nFlags &= ~(F_PAINTED | F_MOVED_ENTRIES); + pCursor = 0; + if( !bInCtor ) + { + pImpCursor->Clear(); + pGridMap->Clear(); + aVirtOutputSize.Width() = 0; + aVirtOutputSize.Height() = 0; + Size aSize( pView->GetOutputSizePixel() ); + nMaxVirtWidth = aSize.Width() - nVerSBarWidth; + if( nMaxVirtWidth <= 0 ) + nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH; + nMaxVirtHeight = aSize.Height() - nHorSBarHeight; + if( nMaxVirtHeight <= 0 ) + nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT; + pZOrderList->Clear(); //Remove(0,pZOrderList->Count()); + SetOrigin( Point() ); + if( bUpdateMode ) + pView->Invalidate(INVALIDATE_NOCHILDREN); + } + AdjustScrollBars(); + sal_uLong nCount = aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + delete pCur; + } + aEntries.Clear(); + DocRectChanged(); + VisRectChanged(); +} + +void SvxIconChoiceCtrl_Impl::SetStyle( WinBits nWinStyle ) +{ + nWinBits = nWinStyle; + nCurTextDrawFlags = DRAWTEXT_FLAGS_ICON; + if( nWinBits & (WB_SMALLICON | WB_DETAILS) ) + nCurTextDrawFlags = DRAWTEXT_FLAGS_SMALLICON; + if( nWinBits & WB_NOSELECTION ) + eSelectionMode = NO_SELECTION; + if( !(nWinStyle & (WB_ALIGN_TOP | WB_ALIGN_LEFT))) + nWinBits |= WB_ALIGN_LEFT; + if( (nWinStyle & WB_DETAILS)) + { + if( !pColumns ) + SetColumn( 0, SvxIconChoiceCtrlColumnInfo( 0, 100, IcnViewAlignLeft )); + } +} + +IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollUpDownHdl, ScrollBar*, pScrollBar ) +{ + StopEntryEditing( sal_True ); + // Pfeil hoch: delta=-1; Pfeil runter: delta=+1 + Scroll( 0, pScrollBar->GetDelta(), sal_True ); + bEndScrollInvalidate = sal_True; + return 0; +} + +IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl, ScrollBar*, pScrollBar ) +{ + StopEntryEditing( sal_True ); + // Pfeil links: delta=-1; Pfeil rechts: delta=+1 + Scroll( pScrollBar->GetDelta(), 0, sal_True ); + bEndScrollInvalidate = sal_True; + return 0; +} + +IMPL_LINK( SvxIconChoiceCtrl_Impl, EndScrollHdl, void*, EMPTYARG ) +{ + if( pView->HasBackground() && !pView->GetBackground().IsScrollable() && + bEndScrollInvalidate ) + { + pView->Invalidate(INVALIDATE_NOCHILDREN); + } + return 0; +} + +void SvxIconChoiceCtrl_Impl::FontModified() +{ + StopEditTimer(); + DELETEZ(pDDDev); + DELETEZ(pDDBufDev); + DELETEZ(pDDTempDev); + DELETEZ(pEntryPaintDev); + SetDefaultTextSize(); + ShowCursor( sal_False ); + ShowCursor( sal_True ); +} + +void SvxIconChoiceCtrl_Impl::InsertEntry( SvxIconChoiceCtrlEntry* pEntry, sal_uLong nPos, + const Point* pPos ) +{ + StopEditTimer(); + aEntries.Insert( pEntry, nPos ); + if( (nFlags & F_ENTRYLISTPOS_VALID) && nPos >= aEntries.Count() - 1 ) + pEntry->nPos = aEntries.Count() - 1; + else + nFlags &= ~F_ENTRYLISTPOS_VALID; + + pZOrderList->Insert( (void*)pEntry, LIST_APPEND ); //pZOrderList->Count() ); + pImpCursor->Clear(); +// pGridMap->Clear(); + if( pPos ) + { + Size aSize( CalcBoundingSize( pEntry ) ); + SetBoundingRect_Impl( pEntry, *pPos, aSize ); + SetEntryPos( pEntry, *pPos, sal_False, sal_True, sal_True /*keep grid map*/ ); + pEntry->nFlags |= ICNVIEW_FLAG_POS_MOVED; + SetEntriesMoved( sal_True ); + } + else + { + // wenn der UpdateMode sal_True ist, wollen wir nicht pauschal alle + // BoundRects auf 'zu ueberpruefen' setzen, sondern nur das des + // neuen Eintrags. Deshalb kein InvalidateBoundingRect aufrufen! + pEntry->aRect.Right() = LONG_MAX; + if( bUpdateMode ) + { + FindBoundingRect( pEntry ); + Rectangle aOutputArea( GetOutputRect() ); + pGridMap->OccupyGrids( pEntry ); + if( !aOutputArea.IsOver( pEntry->aRect ) ) + return; // ist nicht sichtbar + pView->Invalidate( pEntry->aRect ); + } + else + InvalidateBoundingRect( pEntry->aRect ); + } +} + +void SvxIconChoiceCtrl_Impl::CreateAutoMnemonics( MnemonicGenerator* _pGenerator ) +{ + ::std::auto_ptr< MnemonicGenerator > pAutoDeleteOwnGenerator; + if ( !_pGenerator ) + { + _pGenerator = new MnemonicGenerator; + pAutoDeleteOwnGenerator.reset( _pGenerator ); + } + + sal_uLong nEntryCount = GetEntryCount(); + sal_uLong i; + + // insert texts in generator + for( i = 0; i < nEntryCount; ++i ) + { + DBG_ASSERT( GetEntry( i ), "-SvxIconChoiceCtrl_Impl::CreateAutoMnemonics(): more expected than provided!" ); + + _pGenerator->RegisterMnemonic( GetEntry( i )->GetText() ); + } + + // exchange texts with generated mnemonics + for( i = 0; i < nEntryCount; ++i ) + { + SvxIconChoiceCtrlEntry* pEntry = GetEntry( i ); + String aTxt = pEntry->GetText(); + + if( _pGenerator->CreateMnemonic( aTxt ) ) + pEntry->SetText( aTxt ); + } +} + +Rectangle SvxIconChoiceCtrl_Impl::GetOutputRect() const +{ + Point aOrigin( pView->GetMapMode().GetOrigin() ); + aOrigin *= -1; + return Rectangle( aOrigin, aOutputSize ); +} + +void SvxIconChoiceCtrl_Impl::SetListPositions() +{ + if( nFlags & F_ENTRYLISTPOS_VALID ) + return; + + sal_uLong nCount = aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + pEntry->nPos = nCur; + } + nFlags |= F_ENTRYLISTPOS_VALID; +} + +void SvxIconChoiceCtrl_Impl::RemoveEntry( SvxIconChoiceCtrlEntry* pEntry ) +{ + sal_Bool bSyncSingleSelection; + // bei Single-Selection wird die Selektion beim Umsetzen des Cursors + // mitgefuehrt. Das soll aber nur erfolgen, wenn ueberhaupt ein + // Eintrag selektiert ist. + if( GetSelectionCount() ) + bSyncSingleSelection = sal_True; + else + bSyncSingleSelection = sal_False; + + if( pEntry == pCurHighlightFrame ) + pCurHighlightFrame = 0; + + if( bInDragDrop ) + { + DELETEZ(pDraggedSelection); + bInDragDrop = sal_False; + } + + if( pEntry->IsSelected() ) + CallSelectHandler( 0 ); + + if( aEntries.Count() == 1 && aEntries.GetObject(0) == pEntry ) + { + Clear(); + return; + } + + StopEditTimer(); + if( pEntry == pAnchor ) + pAnchor = 0; + if( pEntry->IsSelected() ) + nSelectionCount--; + sal_Bool bEntryBoundValid = IsBoundingRectValid( pEntry->aRect ); + if( bEntryBoundValid ) + pView->Invalidate( pEntry->aRect ); + + sal_Bool bSetNewCursor = sal_False; + SvxIconChoiceCtrlEntry* pNewCursor = NULL; + + if( pEntry == pCursor ) + { + bSetNewCursor = sal_True; + pNewCursor = FindNewCursor(); + ShowCursor( sal_False ); + pCursor = 0; + } + + sal_Bool bCurEntryPosValid = (nFlags & F_ENTRYLISTPOS_VALID) ? sal_True : sal_False; + if( bCurEntryPosValid && aEntries.GetObject(aEntries.Count()-1) != pEntry ) + nFlags &= ~F_ENTRYLISTPOS_VALID; + sal_uLong nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos ); + if( bCurEntryPosValid ) + { + DBG_ASSERT(aEntries.GetObject(pEntry->nPos)==pEntry,"RemoveEntry: Wrong nPos in entry"); + aEntries.Remove( pEntry->nPos ); + } + else + aEntries.Remove( pEntry ); + pImpCursor->Clear(); + pGridMap->Clear(); + delete pEntry; + if( IsAutoArrange() && aEntries.Count() ) + aAutoArrangeTimer.Start(); + if( bSetNewCursor ) + { + // Fokusrechteck asynchron einblenden, um das Loeschen einer + // Multiselektion zu beschleunigen. + SetCursor( pNewCursor, bSyncSingleSelection, sal_True ); + } +} + +void SvxIconChoiceCtrl_Impl::SelectEntry( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bSelect, + sal_Bool bCallHdl, sal_Bool bAdd, sal_Bool bSyncPaint ) +{ + if( eSelectionMode == NO_SELECTION ) + return; + + if( !bAdd ) + { + if ( 0 == ( nFlags & F_CLEARING_SELECTION ) ) + { + nFlags |= F_CLEARING_SELECTION; + DeselectAllBut( pEntry, sal_True ); + nFlags &= ~F_CLEARING_SELECTION; + } + } + if( pEntry->IsSelected() != bSelect ) + { + pHdlEntry = pEntry; + sal_uInt16 nEntryFlags = pEntry->GetFlags(); + if( bSelect ) + { + nEntryFlags |= ICNVIEW_FLAG_SELECTED; + pEntry->AssignFlags( nEntryFlags ); + nSelectionCount++; + if( bCallHdl ) + CallSelectHandler( pEntry ); + } + else + { + nEntryFlags &= ~( ICNVIEW_FLAG_SELECTED); + pEntry->AssignFlags( nEntryFlags ); + nSelectionCount--; + if( bCallHdl ) + CallSelectHandler( 0 ); + } + EntrySelected( pEntry, bSelect, bSyncPaint ); + } +} + +void SvxIconChoiceCtrl_Impl::EntrySelected( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bSelect, + sal_Bool bSyncPaint ) +{ + // bei SingleSelection dafuer sorgen, dass der Cursor immer + // auf dem (einzigen) selektierten Eintrag steht. Aber nur, + // wenn es bereits einen Cursor gibt + if( bSelect && pCursor && + eSelectionMode == SINGLE_SELECTION && + pEntry != pCursor ) + { + SetCursor( pEntry ); + //DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?") + } + + // beim Aufziehen nicht, da sonst die Schleife in SelectRect + // nicht richtig funktioniert! + if( !(nFlags & F_SELECTING_RECT) ) + ToTop( pEntry ); + if( bUpdateMode ) + { + if( pEntry == pCursor ) + ShowCursor( sal_False ); + if( pView->IsTracking() && (bSelect || !pView->HasBackground()) ) // beim Tracken immer synchron + PaintEntry( pEntry ); + else if( bSyncPaint ) // synchron & mit virtuellem OutDev! + PaintEntryVirtOutDev( pEntry ); + else + { + pView->Invalidate( CalcFocusRect( pEntry ) ); + } + if( pEntry == pCursor ) + ShowCursor( sal_True ); + } // if( bUpdateMode ) + + // --> OD 2009-05-27 #i101012# + // emit vcl event LISTBOX_SELECT only in case that the given entry is selected. + if ( bSelect ) + { + CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry ); + } + // <-- +} + +void SvxIconChoiceCtrl_Impl::ResetVirtSize() +{ + StopEditTimer(); + aVirtOutputSize.Width() = 0; + aVirtOutputSize.Height() = 0; + sal_Bool bLockedEntryFound = sal_False; + const sal_uLong nCount = aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + pCur->ClearFlags( ICNVIEW_FLAG_POS_MOVED ); + if( pCur->IsPosLocked() ) + { + // VirtSize u.a. anpassen + if( !IsBoundingRectValid( pCur->aRect ) ) + FindBoundingRect( pCur ); + else + AdjustVirtSize( pCur->aRect ); + bLockedEntryFound = sal_True; + } + else + InvalidateBoundingRect( pCur->aRect ); + } + + if( !(nWinBits & (WB_NOVSCROLL | WB_NOHSCROLL)) ) + { + Size aRealOutputSize( pView->GetOutputSizePixel() ); + if( aVirtOutputSize.Width() < aRealOutputSize.Width() || + aVirtOutputSize.Height() < aRealOutputSize.Height() ) + { + sal_uLong nGridCount = IcnGridMap_Impl::GetGridCount( + aRealOutputSize, (sal_uInt16)nGridDX, (sal_uInt16)nGridDY ); + if( nGridCount < nCount ) + { + if( nWinBits & WB_ALIGN_TOP ) + nMaxVirtWidth = aRealOutputSize.Width() - nVerSBarWidth; + else // WB_ALIGN_LEFT + nMaxVirtHeight = aRealOutputSize.Height() - nHorSBarHeight; + } + } + } + + pImpCursor->Clear(); + pGridMap->Clear(); + VisRectChanged(); +} + +void SvxIconChoiceCtrl_Impl::AdjustVirtSize( const Rectangle& rRect ) +{ + long nHeightOffs = 0; + long nWidthOffs = 0; + + if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) ) + nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width(); + + if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) ) + nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height(); + + if( nWidthOffs || nHeightOffs ) + { + Range aRange; + aVirtOutputSize.Width() += nWidthOffs; + aRange.Max() = aVirtOutputSize.Width(); + aHorSBar.SetRange( aRange ); + + aVirtOutputSize.Height() += nHeightOffs; + aRange.Max() = aVirtOutputSize.Height(); + aVerSBar.SetRange( aRange ); + + pImpCursor->Clear(); + pGridMap->OutputSizeChanged(); + AdjustScrollBars(); + DocRectChanged(); + } +} + +void SvxIconChoiceCtrl_Impl::InitPredecessors() +{ + DBG_ASSERT(!pHead,"SvxIconChoiceCtrl_Impl::InitPredecessors() >> Already initialized"); + sal_uLong nCount = aEntries.Count(); + if( nCount ) + { + SvxIconChoiceCtrlEntry* pPrev = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 ); + for( sal_uLong nCur = 1; nCur <= nCount; nCur++ ) + { + pPrev->ClearFlags( ICNVIEW_FLAG_POS_LOCKED | ICNVIEW_FLAG_POS_MOVED | + ICNVIEW_FLAG_PRED_SET); + + SvxIconChoiceCtrlEntry* pNext; + if( nCur == nCount ) + pNext = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 ); + else + pNext = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + pPrev->pflink = pNext; + pNext->pblink = pPrev; + pPrev = pNext; + } + pHead = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 ); + } + else + pHead = 0; + nFlags &= ~F_MOVED_ENTRIES; +} + +void SvxIconChoiceCtrl_Impl::ClearPredecessors() +{ + if( pHead ) + { + sal_uLong nCount = aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + pCur->pflink = 0; + pCur->pblink = 0; + pCur->ClearFlags( ICNVIEW_FLAG_PRED_SET ); + } + pHead = 0; + } +} + +void SvxIconChoiceCtrl_Impl::Arrange( sal_Bool bKeepPredecessors, long nSetMaxVirtWidth, long nSetMaxVirtHeight ) +{ + if ( nSetMaxVirtWidth != 0 ) + nMaxVirtWidth = nSetMaxVirtWidth; + else + nMaxVirtWidth = aOutputSize.Width(); + + if ( nSetMaxVirtHeight != 0 ) + nMaxVirtHeight = nSetMaxVirtHeight; + else + nMaxVirtHeight = aOutputSize.Height(); + + ImpArrange( bKeepPredecessors ); +} + +void SvxIconChoiceCtrl_Impl::ImpArrange( sal_Bool bKeepPredecessors ) +{ + static Point aEmptyPoint; + + sal_Bool bOldUpdate = bUpdateMode; + Rectangle aCurOutputArea( GetOutputRect() ); + if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint ) + bUpdateMode = sal_False; + aAutoArrangeTimer.Stop(); + nFlags &= ~F_MOVED_ENTRIES; + nFlags |= F_ARRANGING; + StopEditTimer(); + ShowCursor( sal_False ); + ResetVirtSize(); + if( !bKeepPredecessors ) + ClearPredecessors(); + bBoundRectsDirty = sal_False; + SetOrigin( Point() ); + VisRectChanged(); + RecalcAllBoundingRectsSmart(); + // in der Detailsview muss das Invalidieren intelligenter erfolgen + //if( !(nWinBits & WB_DETAILS )) + pView->Invalidate( INVALIDATE_NOCHILDREN ); + nFlags &= ~F_ARRANGING; + if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint ) + { + MakeVisible( aCurOutputArea ); + SetUpdateMode( bOldUpdate ); + } + ShowCursor( sal_True ); +} + +void SvxIconChoiceCtrl_Impl::Paint( const Rectangle& rRect ) +{ + bEndScrollInvalidate = sal_False; + +#if defined(OV_DRAWGRID) + Color aOldColor ( pView->GetLineColor() ); + Color aColor( COL_BLACK ); + pView->SetLineColor( aColor ); + Point aOffs( pView->GetMapMode().GetOrigin()); + Size aXSize( pView->GetOutputSizePixel() ); + + { + Point aStart( LROFFS_WINBORDER, 0 ); + Point aEnd( LROFFS_WINBORDER, aXSize.Height()); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + { + Point aStart( 0, TBOFFS_WINBORDER ); + Point aEnd( aXSize.Width(), TBOFFS_WINBORDER ); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + + for( long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX ) + { + Point aStart( nDX+LROFFS_WINBORDER, 0 ); + Point aEnd( nDX+LROFFS_WINBORDER, aXSize.Height()); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + for( long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY ) + { + Point aStart( 0, nDY+TBOFFS_WINBORDER ); + Point aEnd( aXSize.Width(), nDY+TBOFFS_WINBORDER ); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + pView->SetLineColor( aOldColor ); +#endif + nFlags |= F_PAINTED; + + if( !aEntries.Count() ) + return; + if( !pCursor ) + { + // set cursor to item with focus-flag + sal_Bool bfound = sal_False; + for ( sal_uLong i = 0; i < pView->GetEntryCount() && !bfound; i++) + { + SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry ( i ); + if( pEntry->IsFocused() ) + { + pCursor = pEntry; + bfound=sal_True; + } + } + + if( !bfound ) + pCursor = (SvxIconChoiceCtrlEntry*)aEntries.First(); + } + + // Show Focus at Init-Time + if ( pView->HasFocus() ) + GetFocus(); + + sal_uLong nCount = pZOrderList->Count(); + if( !nCount ) + return; + + sal_Bool bResetClipRegion = sal_False; + if( !pView->IsClipRegion() ) + { + Rectangle aOutputArea( GetOutputRect() ); + bResetClipRegion = sal_True; + pView->SetClipRegion( aOutputArea ); + } + + const sal_uInt16 nListInitSize = aEntries.Count() > USHRT_MAX ? + USHRT_MAX : (sal_uInt16)aEntries.Count(); + List* pNewZOrderList = new List( nListInitSize ); + List* pPaintedEntries = new List( nListInitSize ); + + sal_uLong nPos = 0; + while( nCount ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nPos )); + const Rectangle& rBoundRect = GetEntryBoundRect( pEntry ); + if( rRect.IsOver( rBoundRect ) ) + { + PaintEntry( pEntry, rBoundRect.TopLeft(), pView, sal_True ); + // Eintraege, die neu gezeichnet werden, auf Top setzen + pPaintedEntries->Insert( pEntry, LIST_APPEND ); + } + else + pNewZOrderList->Insert( pEntry, LIST_APPEND ); + + nCount--; + nPos++; + } + delete pZOrderList; + pZOrderList = pNewZOrderList; + nCount = pPaintedEntries->Count(); + if( nCount ) + { + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + pZOrderList->Insert( pPaintedEntries->GetObject(nCur), LIST_APPEND); + } + delete pPaintedEntries; + + if( bResetClipRegion ) + pView->SetClipRegion(); +} + +void SvxIconChoiceCtrl_Impl::RepaintEntries( sal_uInt16 nEntryFlagsMask ) +{ + const sal_uLong nCount = pZOrderList->Count(); + if( !nCount ) + return; + + sal_Bool bResetClipRegion = sal_False; + Rectangle aOutRect( GetOutputRect() ); + if( !pView->IsClipRegion() ) + { + bResetClipRegion = sal_True; + pView->SetClipRegion( aOutRect ); + } + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nCur)); + if( pEntry->GetFlags() & nEntryFlagsMask ) + { + const Rectangle& rBoundRect = GetEntryBoundRect( pEntry ); + if( aOutRect.IsOver( rBoundRect ) ) + PaintEntry( pEntry, rBoundRect.TopLeft() ); + } + } + if( bResetClipRegion ) + pView->SetClipRegion(); +} + + +void SvxIconChoiceCtrl_Impl::InitScrollBarBox() +{ + aScrBarBox.SetSizePixel( Size(nVerSBarWidth-1, nHorSBarHeight-1) ); + Size aSize( pView->GetOutputSizePixel() ); + aScrBarBox.SetPosPixel( Point(aSize.Width()-nVerSBarWidth+1, aSize.Height()-nHorSBarHeight+1)); +} + +IcnViewFieldType SvxIconChoiceCtrl_Impl::GetItem( SvxIconChoiceCtrlEntry* pEntry, + const Point& rAbsPos ) +{ + Rectangle aRect( CalcTextRect( pEntry ) ); + if( aRect.IsInside( rAbsPos ) ) + return IcnViewFieldTypeText; + + aRect = CalcBmpRect( pEntry ); + if( aRect.IsInside( rAbsPos ) ) + return IcnViewFieldTypeImage; + + return IcnViewFieldTypeDontknow; +} + +sal_Bool SvxIconChoiceCtrl_Impl::MouseButtonDown( const MouseEvent& rMEvt) +{ + sal_Bool bHandled = sal_True; + bHighlightFramePressed = sal_False; + StopEditTimer(); + sal_Bool bGotFocus = (sal_Bool)(!pView->HasFocus() && !(nWinBits & WB_NOPOINTERFOCUS)); + if( !(nWinBits & WB_NOPOINTERFOCUS) ) + pView->GrabFocus(); + + Point aDocPos( rMEvt.GetPosPixel() ); + if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height()) + return sal_False; + ToDocPos( aDocPos ); + SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, sal_True ); + if( pEntry ) + MakeEntryVisible( pEntry, sal_False ); + + if( rMEvt.IsShift() && eSelectionMode != SINGLE_SELECTION ) + { + if( pEntry ) + SetCursor_Impl( pCursor, pEntry, rMEvt.IsMod1(), rMEvt.IsShift(), sal_True); + return sal_True; + } + + if( pAnchor && (rMEvt.IsShift() || rMEvt.IsMod1())) // Tastaturselektion? + { + DBG_ASSERT(eSelectionMode != SINGLE_SELECTION,"Invalid selection mode"); + if( rMEvt.IsMod1() ) + nFlags |= F_ADD_MODE; + + if( rMEvt.IsShift() ) + { + Rectangle aRect( GetEntryBoundRect( pAnchor )); + if( pEntry ) + aRect.Union( GetEntryBoundRect( pEntry ) ); + else + { + Rectangle aTempRect( aDocPos, Size(1,1)); + aRect.Union( aTempRect ); + } + aCurSelectionRect = aRect; + SelectRect( aRect, (nFlags & F_ADD_MODE)!=0, &aSelectedRectList ); + } + else if( rMEvt.IsMod1() ) + { + AddSelectedRect( aCurSelectionRect ); + pAnchor = 0; + aCurSelectionRect.SetPos( aDocPos ); + } + + if( !pEntry && !(nWinBits & WB_NODRAGSELECTION)) + pView->StartTracking( STARTTRACK_SCROLLREPEAT ); + return sal_True; + } + else + { + if( !pEntry ) + { + if( eSelectionMode == MULTIPLE_SELECTION ) + { + if( !rMEvt.IsMod1() ) // Ctrl + { + if( !bGotFocus ) + { + SetNoSelection(); + ClearSelectedRectList(); + } + } + else + nFlags |= F_ADD_MODE; + aCurSelectionRect.SetPos( aDocPos ); + pView->StartTracking( STARTTRACK_SCROLLREPEAT ); + } + else + bHandled = sal_False; + return bHandled; + } + } + sal_Bool bSelected = pEntry->IsSelected(); + sal_Bool bEditingEnabled = IsEntryEditingEnabled(); + + if( rMEvt.GetClicks() == 2 ) + { + DeselectAllBut( pEntry ); + SelectEntry( pEntry, sal_True, sal_True, sal_False, sal_True ); + pHdlEntry = pEntry; + pView->ClickIcon(); + } + else + { + // Inplace-Editing ? + if( rMEvt.IsMod2() ) // Alt? + { + if( bEntryEditingEnabled && pEntry && + pEntry->IsSelected()) + { + if( pView->EditingEntry( pEntry )) + EditEntry( pEntry ); + } + } + else if( eSelectionMode == SINGLE_SELECTION ) + { + DeselectAllBut( pEntry ); + SetCursor( pEntry ); + if( bEditingEnabled && bSelected && !rMEvt.GetModifier() && + rMEvt.IsLeft() && IsTextHit( pEntry, aDocPos ) ) + { + nFlags |= F_START_EDITTIMER_IN_MOUSEUP; + } + } + else if( eSelectionMode == NO_SELECTION ) + { + if( rMEvt.IsLeft() && (nWinBits & WB_HIGHLIGHTFRAME) ) + { + pCurHighlightFrame = 0; // Neues painten des Frames erzwingen + bHighlightFramePressed = sal_True; + SetEntryHighlightFrame( pEntry, sal_True ); + } + } + else + { + if( !rMEvt.GetModifier() && rMEvt.IsLeft() ) + { + if( !bSelected ) + { + DeselectAllBut( pEntry, sal_True /* Synchron painten */ ); + SetCursor( pEntry ); + SelectEntry( pEntry, sal_True, sal_True, sal_False, sal_True ); + } + else + { + // erst im Up deselektieren, falls Move per D&D! + nFlags |= F_DOWN_DESELECT; + if( bEditingEnabled && IsTextHit( pEntry, aDocPos ) && + rMEvt.IsLeft()) + { + nFlags |= F_START_EDITTIMER_IN_MOUSEUP; + } + } + } + else if( rMEvt.IsMod1() ) + nFlags |= F_DOWN_CTRL; + } + } + return bHandled; +} + +sal_Bool SvxIconChoiceCtrl_Impl::MouseButtonUp( const MouseEvent& rMEvt ) +{ + sal_Bool bHandled = sal_False; + if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) )) + { + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + bHandled = sal_True; + } + + Point aDocPos( rMEvt.GetPosPixel() ); + ToDocPos( aDocPos ); + SvxIconChoiceCtrlEntry* pDocEntry = GetEntry( aDocPos ); + if( pDocEntry ) + { + if( nFlags & F_DOWN_CTRL ) + { + // Ctrl & MultiSelection + ToggleSelection( pDocEntry ); + SetCursor( pDocEntry ); + bHandled = sal_True; + } + else if( nFlags & F_DOWN_DESELECT ) + { + DeselectAllBut( pDocEntry ); + SetCursor( pDocEntry ); + SelectEntry( pDocEntry, sal_True, sal_True, sal_False, sal_True ); + bHandled = sal_True; + } + } + + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + if( nFlags & F_START_EDITTIMER_IN_MOUSEUP ) + { + bHandled = sal_True; + StartEditTimer(); + nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP; + } + + if((nWinBits & WB_HIGHLIGHTFRAME) && bHighlightFramePressed && pCurHighlightFrame) + { + bHandled = sal_True; + SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame; + pCurHighlightFrame = 0; // Neues painten des Frames erzwingen + bHighlightFramePressed = sal_False; + SetEntryHighlightFrame( pEntry, sal_True ); +#if 0 + CallSelectHandler( pCurHighlightFrame ); +#else + pHdlEntry = pCurHighlightFrame; + pView->ClickIcon(); + + // set focus on Icon + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + SetCursor_Impl( pOldCursor, pHdlEntry, sal_False, sal_False, sal_True ); +#endif + pHdlEntry = 0; + } + return bHandled; +} + +sal_Bool SvxIconChoiceCtrl_Impl::MouseMove( const MouseEvent& rMEvt ) +{ + const Point aDocPos( pView->PixelToLogic(rMEvt.GetPosPixel()) ); + + if( pView->IsTracking() ) + return sal_False; + else if( nWinBits & WB_HIGHLIGHTFRAME ) + { + SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, sal_True ); + SetEntryHighlightFrame( pEntry ); + } + else + return sal_False; + return sal_True; +} + +void SvxIconChoiceCtrl_Impl::Tracking( const TrackingEvent& rTEvt ) +{ + if ( rTEvt.IsTrackingEnded() ) + { + // Das Rechteck darf nicht "justified" sein, da seine + // TopLeft-Position u.U. zur Berechnung eines Ankers + // benutzt wird. + AddSelectedRect( aCurSelectionRect ); + pView->HideTracking(); + nFlags &= ~(F_ADD_MODE); + if( rTEvt.IsTrackingCanceled() ) + SetNoSelection(); + } + else + { + Point aPosPixel = rTEvt.GetMouseEvent().GetPosPixel(); + Point aDocPos( aPosPixel ); + ToDocPos( aDocPos ); + + long nScrollDX, nScrollDY; + + CalcScrollOffsets( aPosPixel, nScrollDX, nScrollDY, sal_False ); + if( nScrollDX || nScrollDY ) + { + pView->HideTracking(); + pView->Scroll( nScrollDX, nScrollDY ); + } + Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos ); + if( aRect != aCurSelectionRect ) + { + pView->HideTracking(); + sal_Bool bAdd = (nFlags & F_ADD_MODE) ? sal_True : sal_False; + SelectRect( aRect, bAdd, &aSelectedRectList ); + } + pView->ShowTracking( aRect, SHOWTRACK_SMALL | SHOWTRACK_CLIP ); + } +} + +void SvxIconChoiceCtrl_Impl::SetCursor_Impl( SvxIconChoiceCtrlEntry* pOldCursor, + SvxIconChoiceCtrlEntry* pNewCursor, sal_Bool bMod1, sal_Bool bShift, sal_Bool bPaintSync ) +{ + if( pNewCursor ) + { + SvxIconChoiceCtrlEntry* pFilterEntry = 0; + sal_Bool bDeselectAll = sal_False; + if( eSelectionMode != SINGLE_SELECTION ) + { + if( !bMod1 && !bShift ) + bDeselectAll = sal_True; + else if( bShift && !bMod1 && !pAnchor ) + { + bDeselectAll = sal_True; + pFilterEntry = pOldCursor; + } + } + if( bDeselectAll ) + DeselectAllBut( pFilterEntry, bPaintSync ); + ShowCursor( sal_False ); + MakeEntryVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( bMod1 && !bShift ) + { + if( pAnchor ) + { + AddSelectedRect( pAnchor, pOldCursor ); + pAnchor = 0; + } + } + else if( bShift ) + { + if( !pAnchor ) + pAnchor = pOldCursor; + if ( nWinBits & WB_ALIGN_LEFT ) + SelectRange( pAnchor, pNewCursor, (nFlags & F_ADD_MODE)!=0 ); + else + SelectRect(pAnchor,pNewCursor,(nFlags & F_ADD_MODE)!=0,&aSelectedRectList); + } + else + { + SelectEntry( pCursor, sal_True, sal_True, sal_False, bPaintSync ); + aCurSelectionRect = GetEntryBoundRect( pCursor ); + } + } +} + +sal_Bool SvxIconChoiceCtrl_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + StopEditTimer(); + + sal_Bool bMod2 = rKEvt.GetKeyCode().IsMod2(); + sal_Unicode cChar = rKEvt.GetCharCode(); + sal_uLong nPos = (sal_uLong)-1; + if ( bMod2 && cChar && IsMnemonicChar( cChar, nPos ) ) + { + // shortcut is clicked + SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos ); + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + if ( pNewCursor != pOldCursor ) + SetCursor_Impl( pOldCursor, pNewCursor, sal_False, sal_False, sal_False ); + return sal_True; + } + + if ( bMod2 ) + // no actions with <ALT> + return sal_False; + + sal_Bool bKeyUsed = sal_True; + sal_Bool bMod1 = rKEvt.GetKeyCode().IsMod1(); + sal_Bool bShift = rKEvt.GetKeyCode().IsShift(); + + if( eSelectionMode == SINGLE_SELECTION || eSelectionMode == NO_SELECTION) + { + bShift = sal_False; + bMod1 = sal_False; + } + + if( bMod1 ) + nFlags |= F_ADD_MODE; + sal_Bool bDeselectAll = sal_False; + if( eSelectionMode != SINGLE_SELECTION ) + { + if( !bMod1 && !bShift ) + bDeselectAll = sal_True; + if( bShift && !bMod1 && !pAnchor ) + bDeselectAll = sal_True; + } + + SvxIconChoiceCtrlEntry* pNewCursor; + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + switch( nCode ) + { + case KEY_UP: + case KEY_PAGEUP: + if( pCursor ) + { + MakeEntryVisible( pCursor ); + if( nCode == KEY_UP ) + pNewCursor = pImpCursor->GoUpDown(pCursor,sal_False); + else + pNewCursor = pImpCursor->GoPageUpDown(pCursor,sal_False); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True ); + if( !pNewCursor ) + { + Rectangle aRect( GetEntryBoundRect( pCursor ) ); + if( aRect.Top()) + { + aRect.Bottom() -= aRect.Top(); + aRect.Top() = 0; + MakeVisible( aRect ); + } + } + + if ( bChooseWithCursor && pNewCursor != NULL ) + { + pHdlEntry = pNewCursor;//GetCurEntry(); + pCurHighlightFrame = pHdlEntry; + pView->ClickIcon(); + pCurHighlightFrame = NULL; + } + } + break; + + case KEY_DOWN: + case KEY_PAGEDOWN: + if( pCursor ) + { + if( nCode == KEY_DOWN ) + pNewCursor=pImpCursor->GoUpDown( pCursor,sal_True ); + else + pNewCursor=pImpCursor->GoPageUpDown( pCursor,sal_True ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True ); + + if ( bChooseWithCursor && pNewCursor != NULL) + { + pHdlEntry = pNewCursor;//GetCurEntry(); + pCurHighlightFrame = pHdlEntry; + pView->ClickIcon(); + pCurHighlightFrame = NULL; + } + } + break; + + case KEY_RIGHT: + if( pCursor ) + { + pNewCursor=pImpCursor->GoLeftRight(pCursor,sal_True ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True ); + } + break; + + case KEY_LEFT: + if( pCursor ) + { + MakeEntryVisible( pCursor ); + pNewCursor = pImpCursor->GoLeftRight(pCursor,sal_False ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True ); + if( !pNewCursor ) + { + Rectangle aRect( GetEntryBoundRect(pCursor)); + if( aRect.Left() ) + { + aRect.Right() -= aRect.Left(); + aRect.Left() = 0; + MakeVisible( aRect ); + } + } + } + break; + +// wird vom VCL-Tracking gesteuert +#if 0 + case KEY_ESCAPE: + if( pView->IsTracking() ) + { + HideSelectionRect(); + //SelectAll( sal_False ); + SetNoSelection(); + ClearSelectedRectList(); + nFlags &= ~F_TRACKING; + } + else + bKeyUsed = sal_False; + break; +#endif + + + case KEY_F2: + if( !bMod1 && !bShift ) + EditTimeoutHdl( 0 ); + else + bKeyUsed = sal_False; + break; + + case KEY_F8: + if( rKEvt.GetKeyCode().IsShift() ) + { + if( nFlags & F_ADD_MODE ) + nFlags &= (~F_ADD_MODE); + else + nFlags |= F_ADD_MODE; + } + else + bKeyUsed = sal_False; + break; + + case KEY_SPACE: + if( pCursor && eSelectionMode != SINGLE_SELECTION ) + { + if( !bMod1 ) + { + //SelectAll( sal_False ); + SetNoSelection(); + ClearSelectedRectList(); + + // click Icon with spacebar + SetEntryHighlightFrame( GetCurEntry(), sal_True ); + pView->ClickIcon(); + pHdlEntry = pCurHighlightFrame; + pCurHighlightFrame=0; + } + else + ToggleSelection( pCursor ); + } + break; + +#ifdef DBG_UTIL + case KEY_F10: + if( rKEvt.GetKeyCode().IsShift() ) + { + if( pCursor ) + pView->SetEntryTextMode( IcnShowTextFull, pCursor ); + } + if( rKEvt.GetKeyCode().IsMod1() ) + { + if( pCursor ) + pView->SetEntryTextMode( IcnShowTextShort, pCursor ); + } + break; +#endif + + case KEY_ADD: + case KEY_DIVIDE : + case KEY_A: + if( bMod1 && (eSelectionMode != SINGLE_SELECTION)) + SelectAll( sal_True ); + else + bKeyUsed = sal_False; + break; + + case KEY_SUBTRACT: + case KEY_COMMA : + if( bMod1 ) + SetNoSelection(); + else + bKeyUsed = sal_False; + break; + + case KEY_RETURN: + if( bMod1 ) + { + if( pCursor && bEntryEditingEnabled ) + /*pView->*/EditEntry( pCursor ); + } + else + bKeyUsed = sal_False; + break; + + case KEY_END: + if( pCursor ) + { + pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( aEntries.Count() - 1 ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True ); + } + break; + + case KEY_HOME: + if( pCursor ) + { + pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( 0 ); + SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, sal_True ); + } + break; + + default: + bKeyUsed = sal_False; + + } + return bKeyUsed; +} + +// Berechnet TopLeft der Scrollbars (nicht ihre Groessen!) +void SvxIconChoiceCtrl_Impl::PositionScrollBars( long nRealWidth, long nRealHeight ) +{ + // hor scrollbar + Point aPos( 0, nRealHeight ); + aPos.Y() -= nHorSBarHeight; + + if( aHorSBar.GetPosPixel() != aPos ) + aHorSBar.SetPosPixel( aPos ); + + // ver scrollbar + aPos.X() = nRealWidth; aPos.Y() = 0; + aPos.X() -= nVerSBarWidth; + aPos.X()++; + aPos.Y()--; + + if( aVerSBar.GetPosPixel() != aPos ) + aVerSBar.SetPosPixel( aPos ); +} + +void SvxIconChoiceCtrl_Impl::AdjustScrollBars( sal_Bool ) +{ + Rectangle aOldOutRect( GetOutputRect() ); + long nVirtHeight = aVirtOutputSize.Height(); + long nVirtWidth = aVirtOutputSize.Width(); + + Size aOSize( pView->Control::GetOutputSizePixel() ); + long nRealHeight = aOSize.Height(); + long nRealWidth = aOSize.Width(); + + PositionScrollBars( nRealWidth, nRealHeight ); + + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + + long nVisibleWidth; + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + long nVisibleHeight; + if( nRealHeight > nVirtHeight ) + nVisibleHeight = nVirtHeight + aOrigin.Y(); + else + nVisibleHeight = nRealHeight; + + sal_Bool bVerSBar = ( nWinBits & WB_VSCROLL ) != 0; + sal_Bool bHorSBar = ( nWinBits & WB_HSCROLL ) != 0; + sal_Bool bNoVerSBar = ( nWinBits & WB_NOVSCROLL ) != 0; + sal_Bool bNoHorSBar = ( nWinBits & WB_NOHSCROLL ) != 0; + + sal_uInt16 nResult = 0; + if( nVirtHeight ) + { + // activate ver scrollbar ? + if( !bNoVerSBar && (bVerSBar || ( nVirtHeight > nVisibleHeight)) ) + { + nResult = 0x0001; + nRealWidth -= nVerSBarWidth; + + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + nFlags |= F_HOR_SBARSIZE_WITH_VBAR; + } + // activate hor scrollbar ? + if( !bNoHorSBar && (bHorSBar || (nVirtWidth > nVisibleWidth)) ) + { + nResult |= 0x0002; + nRealHeight -= nHorSBarHeight; + + if( nRealHeight > nVirtHeight ) + nVisibleHeight = nVirtHeight + aOrigin.Y(); + else + nVisibleHeight = nRealHeight; + + // brauchen wir jetzt doch eine senkrechte Scrollbar ? + if( !(nResult & 0x0001) && // nur wenn nicht schon da + ( !bNoVerSBar && ((nVirtHeight > nVisibleHeight) || bVerSBar)) ) + { + nResult = 3; // beide sind an + nRealWidth -= nVerSBarWidth; + + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + } + } + + // size ver scrollbar + long nThumb = aVerSBar.GetThumbPos(); + Size aSize( nVerSBarWidth, nRealHeight ); + aSize.Height() += 2; + if( aSize != aVerSBar.GetSizePixel() ) + aVerSBar.SetSizePixel( aSize ); + aVerSBar.SetVisibleSize( nVisibleHeight ); + aVerSBar.SetPageSize( GetScrollBarPageSize( nVisibleHeight )); + + if( nResult & 0x0001 ) + { + aVerSBar.SetThumbPos( nThumb ); + aVerSBar.Show(); + } + else + { + aVerSBar.SetThumbPos( 0 ); + aVerSBar.Hide(); + } + + // size hor scrollbar + nThumb = aHorSBar.GetThumbPos(); + aSize.Width() = nRealWidth; + aSize.Height() = nHorSBarHeight; + aSize.Width()++; + if( nResult & 0x0001 ) // vertikale Scrollbar ? + { + aSize.Width()++; + nRealWidth++; + } + if( aSize != aHorSBar.GetSizePixel() ) + aHorSBar.SetSizePixel( aSize ); + aHorSBar.SetVisibleSize( nVisibleWidth ); + aHorSBar.SetPageSize( GetScrollBarPageSize(nVisibleWidth )); + if( nResult & 0x0002 ) + { + aHorSBar.SetThumbPos( nThumb ); + aHorSBar.Show(); + } + else + { + aHorSBar.SetThumbPos( 0 ); + aHorSBar.Hide(); + } + + aOutputSize.Width() = nRealWidth; + if( nResult & 0x0002 ) // hor scrollbar ? + nRealHeight++; // weil unterer Rand geclippt wird + aOutputSize.Height() = nRealHeight; + + Rectangle aNewOutRect( GetOutputRect() ); + if( aNewOutRect != aOldOutRect && pView->HasBackground() ) + { + Wallpaper aPaper( pView->GetBackground() ); + aPaper.SetRect( aNewOutRect ); + pView->SetBackground( aPaper ); + } + + if( (nResult & (0x0001|0x0002)) == (0x0001|0x0002) ) + aScrBarBox.Show(); + else + aScrBarBox.Hide(); +} + +void SvxIconChoiceCtrl_Impl::Resize() +{ + StopEditTimer(); + InitScrollBarBox(); + aOutputSize = pView->GetOutputSizePixel(); + pImpCursor->Clear(); + pGridMap->OutputSizeChanged(); + + const Size& rSize = pView->Control::GetOutputSizePixel(); + PositionScrollBars( rSize.Width(), rSize.Height() ); + // Die ScrollBars werden asynchron ein/ausgeblendet, damit abgeleitete + // Klassen im Resize ein Arrange durchfuehren koennen, ohne dass + // die ScrollBars aufblitzen + // Wenn schon ein Event unterwegs ist, dann braucht kein neues verschickt werden, + // zumindest, solange es nur einen EventTypen gibt + if ( ! nUserEventAdjustScrBars ) + nUserEventAdjustScrBars = + Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl), + EVENTID_ADJUST_SCROLLBARS); + + if( pView->HasBackground() && !pView->GetBackground().IsScrollable() ) + { + Rectangle aRect( GetOutputRect()); + Wallpaper aPaper( pView->GetBackground() ); + aPaper.SetRect( aRect ); + pView->SetBackground( aPaper ); + } + VisRectChanged(); +} + +sal_Bool SvxIconChoiceCtrl_Impl::CheckHorScrollBar() +{ + if( !pZOrderList || !aHorSBar.IsVisible() ) + return sal_False; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!( nWinBits & WB_HSCROLL) && !aOrigin.X() ) + { + long nWidth = aOutputSize.Width(); + const sal_uLong nCount = pZOrderList->Count(); + long nMostRight = 0; + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pZOrderList->GetObject(nCur); + long nRight = GetEntryBoundRect(pEntry).Right(); + if( nRight > nWidth ) + return sal_False; + if( nRight > nMostRight ) + nMostRight = nRight; + } + aHorSBar.Hide(); + aOutputSize.Height() += nHorSBarHeight; + aVirtOutputSize.Width() = nMostRight; + aHorSBar.SetThumbPos( 0 ); + Range aRange; + aRange.Max() = nMostRight - 1; + aHorSBar.SetRange( aRange ); + if( aVerSBar.IsVisible() ) + { + Size aSize( aVerSBar.GetSizePixel()); + aSize.Height() += nHorSBarHeight; + aVerSBar.SetSizePixel( aSize ); + } + return sal_True; + } + return sal_False; +} + +sal_Bool SvxIconChoiceCtrl_Impl::CheckVerScrollBar() +{ + if( !pZOrderList || !aVerSBar.IsVisible() ) + return sal_False; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!( nWinBits & WB_VSCROLL) && !aOrigin.Y() ) + { + long nDeepest = 0; + long nHeight = aOutputSize.Height(); + const sal_uLong nCount = pZOrderList->Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pZOrderList->GetObject(nCur); + long nBottom = GetEntryBoundRect(pEntry).Bottom(); + if( nBottom > nHeight ) + return sal_False; + if( nBottom > nDeepest ) + nDeepest = nBottom; + } + aVerSBar.Hide(); + aOutputSize.Width() += nVerSBarWidth; + aVirtOutputSize.Height() = nDeepest; + aVerSBar.SetThumbPos( 0 ); + Range aRange; + aRange.Max() = nDeepest - 1; + aVerSBar.SetRange( aRange ); + if( aHorSBar.IsVisible() ) + { + Size aSize( aHorSBar.GetSizePixel()); + aSize.Width() += nVerSBarWidth; + aHorSBar.SetSizePixel( aSize ); + } + return sal_True; + } + return sal_False; +} + + +// blendet Scrollbars aus, wenn sie nicht mehr benoetigt werden +void SvxIconChoiceCtrl_Impl::CheckScrollBars() +{ + CheckVerScrollBar(); + if( CheckHorScrollBar() ) + CheckVerScrollBar(); + if( aVerSBar.IsVisible() && aHorSBar.IsVisible() ) + aScrBarBox.Show(); + else + aScrBarBox.Hide(); +} + + +void SvxIconChoiceCtrl_Impl::GetFocus() +{ + RepaintEntries( ICNVIEW_FLAG_SELECTED ); + if( pCursor ) + { + pCursor->SetFlags( ICNVIEW_FLAG_FOCUSED ); + ShowCursor( sal_True ); + } +} + +void SvxIconChoiceCtrl_Impl::LoseFocus() +{ + StopEditTimer(); + if( pCursor ) + pCursor->ClearFlags( ICNVIEW_FLAG_FOCUSED ); + ShowCursor( sal_False ); + +// HideFocus (); +// pView->Invalidate ( aFocus.aRect ); + + RepaintEntries( ICNVIEW_FLAG_SELECTED ); +} + +void SvxIconChoiceCtrl_Impl::SetUpdateMode( sal_Bool bUpdate ) +{ + if( bUpdate != bUpdateMode ) + { + bUpdateMode = bUpdate; + if( bUpdate ) + { + AdjustScrollBars(); + pImpCursor->Clear(); + pGridMap->Clear(); + pView->Invalidate(INVALIDATE_NOCHILDREN); + } + } +} + +void SvxIconChoiceCtrl_Impl::PaintEntry( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bIsBackgroundPainted ) +{ + Point aPos( GetEntryPos( pEntry ) ); + PaintEntry( pEntry, aPos, 0, bIsBackgroundPainted ); +} + +// Prios der Emphasis: bDropTarget => bCursored => bSelected +void SvxIconChoiceCtrl_Impl::PaintEmphasis( + const Rectangle& rTextRect, const Rectangle& rImageRect, + sal_Bool bSelected, sal_Bool bDropTarget, sal_Bool bCursored, OutputDevice* pOut, + sal_Bool bIsBackgroundPainted ) +{ + static Color aTransparent( COL_TRANSPARENT ); + + if( !pOut ) + pOut = pView; + +#ifdef OV_CHECK_EMPH_RECTS + { + Color aXOld( pOut->GetFillColor() ); + pOut->SetFillColor( Color( COL_GREEN )); + pOut->DrawRect( rTextRect ); + pOut->DrawRect( rImageRect ); + pOut->SetFillColor( aXOld ); + } +#endif + + const StyleSettings& rSettings = pOut->GetSettings().GetStyleSettings(); + Color aOldFillColor( pOut->GetFillColor() ); + + sal_Bool bSolidTextRect = sal_False; + sal_Bool bSolidImageRect = sal_False; + + if( bDropTarget && ( eSelectionMode != NO_SELECTION ) ) + { + pOut->SetFillColor( rSettings.GetHighlightColor() ); + bSolidTextRect = sal_True; + bSolidImageRect = sal_True; + } + else + { + if ( !bSelected || bCursored ) + { + if( !pView->HasFontFillColor() ) + pOut->SetFillColor( pOut->GetBackground().GetColor() ); + else + { + const Color& rFillColor = pView->GetFont().GetFillColor(); + pOut->SetFillColor( rFillColor ); + if( rFillColor != aTransparent ) + bSolidTextRect = sal_True; + } + } + } + + // Textrechteck zeichnen + if( !bSolidTextRect ) + { + if( !bIsBackgroundPainted ) + pOut->Erase( rTextRect ); + } + else + { + Color aOldLineColor; + if( bCursored ) + { + aOldLineColor = pOut->GetLineColor(); + pOut->SetLineColor( Color( COL_GRAY ) ); + } + pOut->DrawRect( rTextRect ); + if( bCursored ) + pOut->SetLineColor( aOldLineColor ); + } + + // Bildrechteck zeichnen + if( !bSolidImageRect ) + { + if( !bIsBackgroundPainted ) + pOut->Erase( rImageRect ); + } +// die Emphasis des Images muss von der abgeleiteten Klasse gezeichnet werden +// (in der virtuellen Funktion DrawEntryImage) +// else +// pOut->DrawRect( rImageRect ); + + pOut->SetFillColor( aOldFillColor ); +} + + +void SvxIconChoiceCtrl_Impl::PaintItem( const Rectangle& rRect, + IcnViewFieldType eItem, SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nPaintFlags, + OutputDevice* pOut, const String* pStr, ::vcl::ControlLayoutData* _pLayoutData ) +{ + if( eItem == IcnViewFieldTypeText ) + { + String aText; + if( !pStr ) + aText = pView->GetEntryText( pEntry, sal_False ); + else + aText = *pStr; + + if ( _pLayoutData ) + { + pOut->DrawText( rRect, aText, nCurTextDrawFlags, + &_pLayoutData->m_aUnicodeBoundRects, &_pLayoutData->m_aDisplayText ); + } + else + { + Color aOldFontColor = pOut->GetTextColor(); + if ( pView->AutoFontColor() ) + { + Color aBkgColor( pOut->GetBackground().GetColor() ); + Color aFontColor; + sal_uInt16 nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3; + if ( nColor > 127 ) + aFontColor.SetColor ( COL_BLACK ); + else + aFontColor.SetColor( COL_WHITE ); + pOut->SetTextColor( aFontColor ); + } + + pOut->DrawText( rRect, aText, nCurTextDrawFlags ); + + if ( pView->AutoFontColor() ) + pOut->SetTextColor( aOldFontColor ); + + if( pEntry->IsFocused() ) + { + Rectangle aRect ( CalcFocusRect( (SvxIconChoiceCtrlEntry*)pEntry ) ); + /*pView->*/ShowFocus( aRect ); + DrawFocusRect( pOut ); + } + } + } + else + { + Point aPos( rRect.TopLeft() ); + if( nPaintFlags & PAINTFLAG_HOR_CENTERED ) + aPos.X() += (rRect.GetWidth() - aImageSize.Width() ) / 2; + if( nPaintFlags & PAINTFLAG_VER_CENTERED ) + aPos.Y() += (rRect.GetHeight() - aImageSize.Height() ) / 2; + pView->DrawEntryImage( pEntry, aPos, *pOut ); + } +} + +void SvxIconChoiceCtrl_Impl::PaintEntryVirtOutDev( SvxIconChoiceCtrlEntry* pEntry ) +{ +#ifdef OV_NO_VIRT_OUTDEV + PaintEntry( pEntry ); +#else + if( !pEntryPaintDev ) + { + pEntryPaintDev = new VirtualDevice( *pView ); + pEntryPaintDev->SetFont( pView->GetFont() ); + pEntryPaintDev->SetLineColor(); + //pEntryPaintDev->SetBackground( pView->GetBackground() ); + } + const Rectangle& rRect = GetEntryBoundRect( pEntry ); + Rectangle aOutRect( GetOutputRect() ); + if( !rRect.IsOver( aOutRect ) ) + return; + Wallpaper aPaper( pView->GetBackground() ); + Rectangle aRect( aPaper.GetRect() ); + + // Rechteck verschieben, so dass das Boundrect des Entries im + // VirtOut-Dev bei 0,0 liegt. + aRect.Move( -rRect.Left(), -rRect.Top() ); + aPaper.SetRect( aRect ); + pEntryPaintDev->SetBackground( aPaper ); + pEntryPaintDev->SetFont( pView->GetFont() ); + Rectangle aPix ( pEntryPaintDev->LogicToPixel(aRect) ); + + + Size aSize( rRect.GetSize() ); + pEntryPaintDev->SetOutputSizePixel( aSize ); + pEntryPaintDev->DrawOutDev( + Point(), aSize, rRect.TopLeft(), aSize, *pView ); + + PaintEntry( pEntry, Point(), pEntryPaintDev ); + + pView->DrawOutDev( + rRect.TopLeft(), + aSize, + Point(), + aSize, + *pEntryPaintDev ); +#endif +} + + +void SvxIconChoiceCtrl_Impl::PaintEntry( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, + OutputDevice* pOut, sal_Bool bIsBackgroundPainted ) +{ + if( !pOut ) + pOut = pView; + + sal_Bool bSelected = sal_False; + + if( eSelectionMode != NO_SELECTION ) + bSelected = pEntry->IsSelected(); + + sal_Bool bCursored = pEntry->IsCursored(); + sal_Bool bDropTarget = pEntry->IsDropTarget(); + sal_Bool bNoEmphasis = pEntry->IsBlockingEmphasis(); + + Font aTempFont( pOut->GetFont() ); + + // AutoFontColor + /* + if ( pView->AutoFontColor() ) + { + aTempFont.SetColor ( aFontColor ); + } + */ + + String aEntryText( pView->GetEntryText( pEntry, sal_False ) ); + Rectangle aTextRect( CalcTextRect(pEntry,&rPos,sal_False,&aEntryText)); + Rectangle aBmpRect( CalcBmpRect(pEntry, &rPos ) ); + + sal_Bool bShowSelection = + ( ( ( bSelected && !bCursored ) + || bDropTarget + ) + && !bNoEmphasis + && ( eSelectionMode != NO_SELECTION ) + ); + sal_Bool bActiveSelection = ( 0 != ( nWinBits & WB_NOHIDESELECTION ) ) || pView->HasFocus(); + + if ( bShowSelection ) + { + const StyleSettings& rSettings = pOut->GetSettings().GetStyleSettings(); + Font aNewFont( aTempFont ); + + // bei hart attributierter Font-Fuellcolor muessen wir diese + // hart auf die Highlight-Color setzen + if( pView->HasFontFillColor() ) + { + if( (nWinBits & WB_NOHIDESELECTION) || pView->HasFocus() ) + aNewFont.SetFillColor( rSettings.GetHighlightColor() ); + else + aNewFont.SetFillColor( rSettings.GetDeactiveColor() ); + } + + Color aWinCol = rSettings.GetWindowTextColor(); + if ( !bActiveSelection && rSettings.GetFaceColor().IsBright() == aWinCol.IsBright() ) + aNewFont.SetColor( rSettings.GetWindowTextColor() ); + else + aNewFont.SetColor( rSettings.GetHighlightTextColor() ); + + pOut->SetFont( aNewFont ); + + pOut->SetFillColor( pOut->GetBackground().GetColor() ); + pOut->DrawRect( CalcFocusRect( pEntry ) ); + pOut->SetFillColor( ); + } + + sal_Bool bResetClipRegion = sal_False; + if( !pView->IsClipRegion() && (aVerSBar.IsVisible() || aHorSBar.IsVisible()) ) + { + Rectangle aOutputArea( GetOutputRect() ); + if( aOutputArea.IsOver(aTextRect) || aOutputArea.IsOver(aBmpRect) ) + { + pView->SetClipRegion( aOutputArea ); + bResetClipRegion = sal_True; + } + } + +#ifdef OV_DRAWBOUNDRECT + { + Color aXOldColor = pOut->GetLineColor(); + pOut->SetLineColor( Color( COL_LIGHTRED ) ); + Rectangle aXRect( pEntry->aRect ); + aXRect.SetPos( rPos ); + pOut->DrawRect( aXRect ); + pOut->SetLineColor( aXOldColor ); + } +#endif + + sal_Bool bLargeIconMode = WB_ICON == ( nWinBits & (VIEWMODE_MASK) ); + sal_uInt16 nBmpPaintFlags = PAINTFLAG_VER_CENTERED; + if ( bLargeIconMode ) + nBmpPaintFlags |= PAINTFLAG_HOR_CENTERED; + sal_uInt16 nTextPaintFlags = bLargeIconMode ? PAINTFLAG_HOR_CENTERED : PAINTFLAG_VER_CENTERED; + + if( !bNoEmphasis ) + PaintEmphasis(aTextRect,aBmpRect,bSelected,bDropTarget,bCursored,pOut,bIsBackgroundPainted); + + if ( bShowSelection ) + pView->DrawSelectionBackground( CalcFocusRect( pEntry ), + bActiveSelection ? 1 : 2 /* highlight */, sal_False /* check */, sal_True /* border */, sal_False /* ext border only */ ); + + PaintItem( aBmpRect, IcnViewFieldTypeImage, pEntry, nBmpPaintFlags, pOut ); + + PaintItem( aTextRect, IcnViewFieldTypeText, pEntry, + nTextPaintFlags, pOut ); + + // Highlight-Frame zeichnen + if( pEntry == pCurHighlightFrame && !bNoEmphasis ) + DrawHighlightFrame( pOut, CalcFocusRect( pEntry ), sal_False ); + + pOut->SetFont( aTempFont ); + if( bResetClipRegion ) + pView->SetClipRegion(); +} + +void SvxIconChoiceCtrl_Impl::SetEntryPos( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, + sal_Bool bAdjustAtGrid, sal_Bool bCheckScrollBars, sal_Bool bKeepGridMap ) +{ + ShowCursor( sal_False ); + Rectangle aBoundRect( GetEntryBoundRect( pEntry )); + pView->Invalidate( aBoundRect ); + ToTop( pEntry ); + if( !IsAutoArrange() ) + { + sal_Bool bAdjustVirtSize = sal_False; + if( rPos != aBoundRect.TopLeft() ) + { + Point aGridOffs( + pEntry->aGridRect.TopLeft() - pEntry->aRect.TopLeft() ); + pImpCursor->Clear(); + if( !bKeepGridMap ) + pGridMap->Clear(); + aBoundRect.SetPos( rPos ); + pEntry->aRect = aBoundRect; + pEntry->aGridRect.SetPos( rPos + aGridOffs ); + bAdjustVirtSize = sal_True; + } + if( bAdjustAtGrid ) + { + if( bAdjustVirtSize ) + { + // Durch das Ausrichten des (ggf. gerade neu positionierten) Eintrags, + // kann er wieder komplett + // in den sichtbaren Bereich rutschen, so dass u.U. doch keine Scrollbar + // eingeblendet werden muss. Um deshalb ein 'Aufblitzen' der + // Scrollbar(s) zu vermeiden, wird zum Aufplustern der virtuellen + // Ausgabegroesse bereits das ausgerichtete Boundrect des + // Eintrags genommen. Die virtuelle Groesse muss angepasst werden, + // da AdjustEntryAtGrid von ihr abhaengt. + const Rectangle& rBoundRect = GetEntryBoundRect( pEntry ); + Rectangle aCenterRect( CalcBmpRect( pEntry, 0 )); + Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) ); + Rectangle aNewBoundRect( aNewPos, pEntry->aRect.GetSize()); + AdjustVirtSize( aNewBoundRect ); + bAdjustVirtSize = sal_False; + } + AdjustEntryAtGrid( pEntry ); + ToTop( pEntry ); + } + if( bAdjustVirtSize ) + AdjustVirtSize( pEntry->aRect ); + + if( bCheckScrollBars && bUpdateMode ) + CheckScrollBars(); + + pView->Invalidate( pEntry->aRect ); + pGridMap->OccupyGrids( pEntry ); + } + else + { + SvxIconChoiceCtrlEntry* pPrev = FindEntryPredecessor( pEntry, rPos ); + SetEntryPredecessor( pEntry, pPrev ); + aAutoArrangeTimer.Start(); + } + ShowCursor( sal_True ); +} + +void SvxIconChoiceCtrl_Impl::SetNoSelection() +{ + // rekursive Aufrufe ueber SelectEntry abblocken + if( !(nFlags & F_CLEARING_SELECTION )) + { + nFlags |= F_CLEARING_SELECTION; + DeselectAllBut( 0, sal_True ); + nFlags &= ~F_CLEARING_SELECTION; + } +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetEntry( const Point& rDocPos, sal_Bool bHit ) +{ + CheckBoundingRects(); + // Z-Order-Liste vom Ende her absuchen + sal_uLong nCount = pZOrderList->Count(); + while( nCount ) + { + nCount--; + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nCount)); + if( pEntry->aRect.IsInside( rDocPos ) ) + { + if( bHit ) + { + Rectangle aRect = CalcBmpRect( pEntry ); + aRect.Top() -= 3; + aRect.Bottom() += 3; + aRect.Left() -= 3; + aRect.Right() += 3; + if( aRect.IsInside( rDocPos ) ) + return pEntry; + aRect = CalcTextRect( pEntry ); + if( aRect.IsInside( rDocPos ) ) + return pEntry; + } + else + return pEntry; + } + } + return 0; +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetNextEntry( const Point& rDocPos, SvxIconChoiceCtrlEntry* pCurEntry ) +{ + CheckBoundingRects(); + SvxIconChoiceCtrlEntry* pTarget = 0; + const sal_uLong nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); + if( nStartPos != LIST_ENTRY_NOTFOUND ) + { + const sal_uLong nCount = pZOrderList->Count(); + for( sal_uLong nCur = nStartPos+1; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nCur)); + if( pEntry->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } + } + return pTarget; +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetPrevEntry( const Point& rDocPos, SvxIconChoiceCtrlEntry* pCurEntry ) +{ + CheckBoundingRects(); + SvxIconChoiceCtrlEntry* pTarget = 0; + sal_uLong nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); + if( nStartPos != LIST_ENTRY_NOTFOUND && nStartPos != 0 ) + { + nStartPos--; + do + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nStartPos)); + if( pEntry->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } while( nStartPos > 0 ); + } + return pTarget; +} + +Point SvxIconChoiceCtrl_Impl::GetEntryPos( SvxIconChoiceCtrlEntry* pEntry ) +{ + return pEntry->aRect.TopLeft(); +} + +void SvxIconChoiceCtrl_Impl::MakeEntryVisible( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bBound ) +{ + if ( bBound ) + { + const Rectangle& rRect = GetEntryBoundRect( pEntry ); + MakeVisible( rRect ); + } + else + { + Rectangle aRect = CalcBmpRect( pEntry ); + aRect.Union( CalcTextRect( pEntry ) ); + aRect.Top() += TBOFFS_BOUND; + aRect.Bottom() += TBOFFS_BOUND; + aRect.Left() += LROFFS_BOUND; + aRect.Right() += LROFFS_BOUND; + MakeVisible( aRect ); + } +} + +const Rectangle& SvxIconChoiceCtrl_Impl::GetEntryBoundRect( SvxIconChoiceCtrlEntry* pEntry ) +{ + if( !IsBoundingRectValid( pEntry->aRect )) + FindBoundingRect( pEntry ); + return pEntry->aRect; +} + +Rectangle SvxIconChoiceCtrl_Impl::CalcBmpRect( SvxIconChoiceCtrlEntry* pEntry, const Point* pPos ) +{ + Rectangle aBound = GetEntryBoundRect( pEntry ); + if( pPos ) + aBound.SetPos( *pPos ); + Point aPos( aBound.TopLeft() ); + + switch( nWinBits & (VIEWMODE_MASK) ) + { + case WB_ICON: + { + aPos.X() += ( aBound.GetWidth() - aImageSize.Width() ) / 2; + return Rectangle( aPos, aImageSize ); + } + + case WB_SMALLICON: + case WB_DETAILS: + aPos.Y() += ( aBound.GetHeight() - aImageSize.Height() ) / 2; + //todo: hor. Abstand zum BoundRect? + return Rectangle( aPos, aImageSize ); + + default: + DBG_ERROR("IconView: Viewmode not set"); + return aBound; + } +} + +Rectangle SvxIconChoiceCtrl_Impl::CalcTextRect( SvxIconChoiceCtrlEntry* pEntry, + const Point* pEntryPos, sal_Bool bEdit, const String* pStr ) +{ + String aEntryText; + if( !pStr ) + aEntryText = pView->GetEntryText( pEntry, bEdit ); + else + aEntryText = *pStr; + + const Rectangle aMaxTextRect( CalcMaxTextRect( pEntry ) ); + Rectangle aBound( GetEntryBoundRect( pEntry ) ); + if( pEntryPos ) + aBound.SetPos( *pEntryPos ); + + Rectangle aTextRect( aMaxTextRect ); + if( !bEdit ) + aTextRect = pView->GetTextRect( aTextRect, aEntryText, nCurTextDrawFlags ); + + Size aTextSize( aTextRect.GetSize() ); + + Point aPos( aBound.TopLeft() ); + long nBoundWidth = aBound.GetWidth(); + long nBoundHeight = aBound.GetHeight(); + + switch( nWinBits & (VIEWMODE_MASK) ) + { + case WB_ICON: + aPos.Y() += aImageSize.Height(); + aPos.Y() += VER_DIST_BMP_STRING; + // beim Editieren etwas mehr Platz + if( bEdit ) + { + // 20% rauf + long nMinWidth = (( (aImageSize.Width()*10) / 100 ) * 2 ) + + aImageSize.Width(); + if( nMinWidth > nBoundWidth ) + nMinWidth = nBoundWidth; + + if( aTextSize.Width() < nMinWidth ) + aTextSize.Width() = nMinWidth; + + // beim Editieren ist Ueberlappung nach unten erlaubt + Size aOptSize = aMaxTextRect.GetSize(); + if( aOptSize.Height() > aTextSize.Height() ) + aTextSize.Height() = aOptSize.Height(); + } + aPos.X() += (nBoundWidth - aTextSize.Width()) / 2; + break; + + case WB_SMALLICON: + case WB_DETAILS: + aPos.X() += aImageSize.Width(); + aPos.X() += HOR_DIST_BMP_STRING; + aPos.Y() += (nBoundHeight - aTextSize.Height()) / 2; + break; + } + return Rectangle( aPos, aTextSize ); +} + + +long SvxIconChoiceCtrl_Impl::CalcBoundingWidth( SvxIconChoiceCtrlEntry* pEntry ) const +{ + long nStringWidth = GetItemSize( pEntry, IcnViewFieldTypeText ).Width(); +// nStringWidth += 2*LROFFS_TEXT; + long nWidth = 0; + + switch( nWinBits & (VIEWMODE_MASK) ) + { + case WB_ICON: + nWidth = Max( nStringWidth, aImageSize.Width() ); + break; + + case WB_SMALLICON: + case WB_DETAILS: + nWidth = aImageSize.Width(); + nWidth += HOR_DIST_BMP_STRING; + nWidth += nStringWidth; + break; + } + return nWidth; +} + +long SvxIconChoiceCtrl_Impl::CalcBoundingHeight( SvxIconChoiceCtrlEntry* pEntry ) const +{ + long nStringHeight = GetItemSize( pEntry, IcnViewFieldTypeText).Height(); + long nHeight = 0; + + switch( nWinBits & (VIEWMODE_MASK) ) + { + case WB_ICON: + nHeight = aImageSize.Height(); + nHeight += VER_DIST_BMP_STRING; + nHeight += nStringHeight; + break; + + case WB_SMALLICON: + case WB_DETAILS: + nHeight = Max( aImageSize.Height(), nStringHeight ); + break; + } + if( nHeight > nMaxBoundHeight ) + { + ((SvxIconChoiceCtrl_Impl*)this)->nMaxBoundHeight = nHeight; + ((SvxIconChoiceCtrl_Impl*)this)->aHorSBar.SetLineSize( GetScrollBarLineSize() ); + ((SvxIconChoiceCtrl_Impl*)this)->aVerSBar.SetLineSize( GetScrollBarLineSize() ); + } + return nHeight; +} + +Size SvxIconChoiceCtrl_Impl::CalcBoundingSize( SvxIconChoiceCtrlEntry* pEntry ) const +{ + return Size( CalcBoundingWidth( pEntry ), + CalcBoundingHeight( pEntry ) ); +} + +void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRects() +{ + nMaxBoundHeight = 0; + pZOrderList->Clear(); + sal_uLong nCount = aEntries.Count(); + sal_uLong nCur; + SvxIconChoiceCtrlEntry* pEntry; + + if( !IsAutoArrange() || !pHead ) + { + for( nCur = 0; nCur < nCount; nCur++ ) + { + pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + FindBoundingRect( pEntry ); + pZOrderList->Insert( pEntry, LIST_APPEND ); + } + } + else + { + nCur = 0; + pEntry = pHead; + while( nCur != nCount ) + { + DBG_ASSERT(pEntry->pflink&&pEntry->pblink,"SvxIconChoiceCtrl_Impl::RecalcAllBoundingRect > Bad link(s)"); + FindBoundingRect( pEntry ); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + pEntry = pEntry->pflink; + nCur++; + } + } + bBoundRectsDirty = sal_False; + AdjustScrollBars(); +} + +void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRectsSmart() +{ + nMaxBoundHeight = 0; + pZOrderList->Clear(); + sal_uLong nCur; + SvxIconChoiceCtrlEntry* pEntry; + const sal_uLong nCount = aEntries.Count(); + + if( !IsAutoArrange() || !pHead ) + { + for( nCur = 0; nCur < nCount; nCur++ ) + { + pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + if( IsBoundingRectValid( pEntry->aRect )) + { + Size aBoundSize( pEntry->aRect.GetSize() ); + if( aBoundSize.Height() > nMaxBoundHeight ) + nMaxBoundHeight = aBoundSize.Height(); + } + else + FindBoundingRect( pEntry ); + pZOrderList->Insert( pEntry, LIST_APPEND ); + } + } + else + { + nCur = 0; + pEntry = pHead; + while( nCur != nCount ) + { + DBG_ASSERT(pEntry->pflink&&pEntry->pblink,"SvxIconChoiceCtrl_Impl::RecalcAllBoundingRect > Bad link(s)"); + if( IsBoundingRectValid( pEntry->aRect )) + { + Size aBoundSize( pEntry->aRect.GetSize() ); + if( aBoundSize.Height() > nMaxBoundHeight ) + nMaxBoundHeight = aBoundSize.Height(); + } + else + FindBoundingRect( pEntry ); + pZOrderList->Insert( pEntry, LIST_APPEND ); + pEntry = pEntry->pflink; + nCur++; + } + } + AdjustScrollBars(); +} + +void SvxIconChoiceCtrl_Impl::UpdateBoundingRects() +{ + const sal_uLong nCount = aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + GetEntryBoundRect( pEntry ); + } +} + +void SvxIconChoiceCtrl_Impl::FindBoundingRect( SvxIconChoiceCtrlEntry* pEntry ) +{ + DBG_ASSERT(!pEntry->IsPosLocked(),"Locked entry pos in FindBoundingRect"); + if( pEntry->IsPosLocked() && IsBoundingRectValid( pEntry->aRect) ) + { + AdjustVirtSize( pEntry->aRect ); + return; + } + Size aSize( CalcBoundingSize( pEntry ) ); + Point aPos(pGridMap->GetGridRect(pGridMap->GetUnoccupiedGrid(sal_True)).TopLeft()); + SetBoundingRect_Impl( pEntry, aPos, aSize ); +} + +void SvxIconChoiceCtrl_Impl::SetBoundingRect_Impl( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, + const Size& /*rBoundingSize*/ ) +{ + Rectangle aGridRect( rPos, Size(nGridDX, nGridDY) ); + pEntry->aGridRect = aGridRect; + Center( pEntry ); + AdjustVirtSize( pEntry->aRect ); + pGridMap->OccupyGrids( pEntry ); +} + + +void SvxIconChoiceCtrl_Impl::SetCursor( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bSyncSingleSelection, + sal_Bool bShowFocusAsync ) +{ + if( pEntry == pCursor ) + { + if( pCursor && eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection && + !pCursor->IsSelected() ) + SelectEntry( pCursor, sal_True, sal_True ); + return; + } + ShowCursor( sal_False ); + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + pCursor = pEntry; + if( pOldCursor ) + { + pOldCursor->ClearFlags( ICNVIEW_FLAG_FOCUSED ); + if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection ) + SelectEntry( pOldCursor, sal_False, sal_True ); // alten Cursor deselektieren + } + if( pCursor ) + { + ToTop( pCursor ); + pCursor->SetFlags( ICNVIEW_FLAG_FOCUSED ); + if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection ) + SelectEntry( pCursor, sal_True, sal_True ); + if( !bShowFocusAsync ) + ShowCursor( sal_True ); + else + { + if( !nUserEventShowCursor ) + nUserEventShowCursor = + Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl), + EVENTID_SHOW_CURSOR ); + } + } +} + + +void SvxIconChoiceCtrl_Impl::ShowCursor( sal_Bool bShow ) +{ + if( !pCursor || !bShow || !pView->HasFocus() ) + { + pView->HideFocus(); + return; + } + Rectangle aRect ( CalcFocusRect( pCursor ) ); + /*pView->*/ShowFocus( aRect ); +} + + +void SvxIconChoiceCtrl_Impl::HideDDIcon() +{ + pView->Update(); + ImpHideDDIcon(); + pDDBufDev = pDDDev; + pDDDev = 0; +} + +void SvxIconChoiceCtrl_Impl::ImpHideDDIcon() +{ + if( pDDDev ) + { + Size aSize( pDDDev->GetOutputSizePixel() ); + // pView restaurieren + pView->DrawOutDev( aDDLastRectPos, aSize, Point(), aSize, *pDDDev ); + } +} + + +void SvxIconChoiceCtrl_Impl::ShowDDIcon( SvxIconChoiceCtrlEntry* pRefEntry, const Point& rPosPix ) +{ + pView->Update(); + if( pRefEntry != pDDRefEntry ) + { + DELETEZ(pDDDev); + DELETEZ(pDDBufDev); + } + sal_Bool bSelected = pRefEntry->IsSelected(); + pRefEntry->ClearFlags( ICNVIEW_FLAG_SELECTED ); + if( !pDDDev ) + { + if( pDDBufDev ) + { + // nicht bei jedem Move ein Device anlegen, da dies besonders + // auf Remote-Clients zu langsam ist + pDDDev = pDDBufDev; + pDDBufDev = 0; + } + else + { + pDDDev = new VirtualDevice( *pView ); + pDDDev->SetFont( pView->GetFont() ); + } + } + else + { + ImpHideDDIcon(); + } + const Rectangle& rRect = GetEntryBoundRect( pRefEntry ); + pDDDev->SetOutputSizePixel( rRect.GetSize() ); + + Point aPos( rPosPix ); + ToDocPos( aPos ); + + Size aSize( pDDDev->GetOutputSizePixel() ); + pDDRefEntry = pRefEntry; + aDDLastEntryPos = aPos; + aDDLastRectPos = aPos; + + // Hintergrund sichern + pDDDev->DrawOutDev( Point(), aSize, aPos, aSize, *pView ); + // Icon in pView malen + pRefEntry->SetFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS ); + PaintEntry( pRefEntry, aPos ); + pRefEntry->ClearFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS ); + if( bSelected ) + pRefEntry->SetFlags( ICNVIEW_FLAG_SELECTED ); +} + +void SvxIconChoiceCtrl_Impl::HideShowDDIcon( SvxIconChoiceCtrlEntry* pRefEntry, const Point& rPosPix ) +{ +/* In Notfaellen folgenden flackernden Code aktivieren: + + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; +*/ + if( !pDDDev ) + { + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + if( pRefEntry != pDDRefEntry ) + { + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + Point aEmptyPoint; + + Point aCurEntryPos( rPosPix ); + ToDocPos( aCurEntryPos ); + + const Rectangle& rRect = GetEntryBoundRect( pRefEntry ); + Size aEntrySize( rRect.GetSize() ); + Rectangle aPrevEntryRect( aDDLastEntryPos, aEntrySize ); + Rectangle aCurEntryRect( aCurEntryPos, aEntrySize ); + + if( !aPrevEntryRect.IsOver( aCurEntryRect ) ) + { + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + // Ueberlappung des neuen und alten D&D-Pointers! + + Rectangle aFullRect( aPrevEntryRect.Union( aCurEntryRect ) ); + if( !pDDTempDev ) + { + pDDTempDev = new VirtualDevice( *pView ); + pDDTempDev->SetFont( pView->GetFont() ); + } + + Size aFullSize( aFullRect.GetSize() ); + Point aFullPos( aFullRect.TopLeft() ); + + pDDTempDev->SetOutputSizePixel( aFullSize ); + + // Hintergrund (mit dem alten D&D-Pointer!) sichern + pDDTempDev->DrawOutDev( aEmptyPoint, aFullSize, aFullPos, aFullSize, *pView ); + // den alten Buffer in den neuen Buffer pasten + aDDLastRectPos = aDDLastRectPos - aFullPos; + + pDDTempDev->DrawOutDev( + aDDLastRectPos, + pDDDev->GetOutputSizePixel(), + aEmptyPoint, + pDDDev->GetOutputSizePixel(), + *pDDDev ); + + // Swap + VirtualDevice* pTemp = pDDDev; + pDDDev = pDDTempDev; + pDDTempDev = pTemp; + + // in den restaurierten Hintergrund den neuen D&D-Pointer zeichnen + pDDTempDev->SetOutputSizePixel( pDDDev->GetOutputSizePixel() ); + pDDTempDev->DrawOutDev( + aEmptyPoint, aFullSize, aEmptyPoint, aFullSize, *pDDDev ); + Point aRelPos = aCurEntryPos - aFullPos; + pRefEntry->SetFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS ); + PaintEntry( pRefEntry, aRelPos, pDDTempDev ); + pRefEntry->ClearFlags( ICNVIEW_FLAG_BLOCK_EMPHASIS ); + + aDDLastRectPos = aFullPos; + aDDLastEntryPos = aCurEntryPos; + + pView->DrawOutDev( + aDDLastRectPos, + pDDDev->GetOutputSizePixel(), + aEmptyPoint, + pDDDev->GetOutputSizePixel(), + *pDDTempDev ); +} + +void SvxIconChoiceCtrl_Impl::InvalidateBoundingRect( SvxIconChoiceCtrlEntry* pEntry ) +{ + InvalidateBoundingRect( pEntry->aRect ); +} + + +sal_Bool SvxIconChoiceCtrl_Impl::HandleScrollCommand( const CommandEvent& rCmd ) +{ + Rectangle aDocRect( GetDocumentRect() ); + Rectangle aVisRect( GetVisibleRect() ); + if( aVisRect.IsInside( aDocRect )) + return sal_False; + Size aDocSize( aDocRect.GetSize() ); + Size aVisSize( aVisRect.GetSize() ); + sal_Bool bHor = aDocSize.Width() > aVisSize.Width(); + sal_Bool bVer = aDocSize.Height() > aVisSize.Height(); + + long nScrollDX = 0, nScrollDY = 0; + + switch( rCmd.GetCommand() ) + { + case COMMAND_STARTAUTOSCROLL: + { + pView->EndTracking(); + sal_uInt16 nScrollFlags = 0; + if( bHor ) + nScrollFlags |= AUTOSCROLL_HORZ; + if( bVer ) + nScrollFlags |= AUTOSCROLL_VERT; + if( nScrollFlags ) + { + pView->StartAutoScroll( nScrollFlags ); + return sal_True; + } + } + break; + + case COMMAND_WHEEL: + { + const CommandWheelData* pData = rCmd.GetWheelData(); + if( pData && (COMMAND_WHEEL_SCROLL == pData->GetMode()) && !pData->IsHorz() ) + { + sal_uLong nScrollLines = pData->GetScrollLines(); + if( nScrollLines == COMMAND_WHEEL_PAGESCROLL ) + { + nScrollDY = GetScrollBarPageSize( aVisSize.Width() ); + if( pData->GetDelta() < 0 ) + nScrollDY *= -1; + } + else + { + nScrollDY = pData->GetNotchDelta() * (long)nScrollLines; + nScrollDY *= GetScrollBarLineSize(); + } + } + } + break; + + case COMMAND_AUTOSCROLL: + { + const CommandScrollData* pData = rCmd.GetAutoScrollData(); + if( pData ) + { + nScrollDX = pData->GetDeltaX() * GetScrollBarLineSize(); + nScrollDY = pData->GetDeltaY() * GetScrollBarLineSize(); + } + } + break; + } + + if( nScrollDX || nScrollDY ) + { + aVisRect.Top() -= nScrollDY; + aVisRect.Bottom() -= nScrollDY; + aVisRect.Left() -= nScrollDX; + aVisRect.Right() -= nScrollDX; + MakeVisible( aVisRect ); + return sal_True; + } + return sal_False; +} + + +void SvxIconChoiceCtrl_Impl::Command( const CommandEvent& rCEvt ) +{ + // Rollmaus-Event? + if( (rCEvt.GetCommand() == COMMAND_WHEEL) || + (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) || + (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) ) + { +#if 1 + if( HandleScrollCommand( rCEvt ) ) + return; +#else + ScrollBar* pHor = aHorSBar.IsVisible() ? &aHorSBar : 0; + ScrollBar* pVer = aVerSBar.IsVisible() ? &aVerSBar : 0; + if( pView->HandleScrollCommand( rCEvt, pHor, pVer ) ) + return; +#endif + } +} + +void SvxIconChoiceCtrl_Impl::ToTop( SvxIconChoiceCtrlEntry* pEntry ) +{ + if( pZOrderList->GetObject( pZOrderList->Count() - 1 ) != pEntry ) + { + sal_uLong nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos ); + pZOrderList->Insert( pEntry, LIST_APPEND ); + } +} + +void SvxIconChoiceCtrl_Impl::ClipAtVirtOutRect( Rectangle& rRect ) const +{ + if( rRect.Bottom() >= aVirtOutputSize.Height() ) + rRect.Bottom() = aVirtOutputSize.Height() - 1; + if( rRect.Right() >= aVirtOutputSize.Width() ) + rRect.Right() = aVirtOutputSize.Width() - 1; + if( rRect.Top() < 0 ) + rRect.Top() = 0; + if( rRect.Left() < 0 ) + rRect.Left() = 0; +} + +// rRect: Bereich des Dokumentes (in Dokumentkoordinaten), der +// sichtbar gemacht werden soll. +// bScrBar == sal_True: Das Rect wurde aufgrund eines ScrollBar-Events berechnet + +void SvxIconChoiceCtrl_Impl::MakeVisible( const Rectangle& rRect, sal_Bool bScrBar, + sal_Bool bCallRectChangedHdl ) +{ + Rectangle aVirtRect( rRect ); + ClipAtVirtOutRect( aVirtRect ); + Point aOrigin( pView->GetMapMode().GetOrigin() ); + // in Dokumentkoordinate umwandeln + aOrigin *= -1; + Rectangle aOutputArea( GetOutputRect() ); + if( aOutputArea.IsInside( aVirtRect ) ) + return; // ist schon sichtbar + + long nDy; + if( aVirtRect.Top() < aOutputArea.Top() ) + { + // nach oben scrollen (nDy < 0) + nDy = aVirtRect.Top() - aOutputArea.Top(); + } + else if( aVirtRect.Bottom() > aOutputArea.Bottom() ) + { + // nach unten scrollen (nDy > 0) + nDy = aVirtRect.Bottom() - aOutputArea.Bottom(); + } + else + nDy = 0; + + long nDx; + if( aVirtRect.Left() < aOutputArea.Left() ) + { + // nach links scrollen (nDx < 0) + nDx = aVirtRect.Left() - aOutputArea.Left(); + } + else if( aVirtRect.Right() > aOutputArea.Right() ) + { + // nach rechts scrollen (nDx > 0) + nDx = aVirtRect.Right() - aOutputArea.Right(); + } + else + nDx = 0; + + aOrigin.X() += nDx; + aOrigin.Y() += nDy; + aOutputArea.SetPos( aOrigin ); + if( GetUpdateMode() ) + { + HideDDIcon(); + pView->Update(); + ShowCursor( sal_False ); + } + + // Origin fuer SV invertieren (damit wir in + // Dokumentkoordinaten scrollen/painten koennen) + aOrigin *= -1; + SetOrigin( aOrigin ); + + sal_Bool bScrollable = pView->GetBackground().IsScrollable(); + if( pView->HasBackground() && !bScrollable ) + { + Rectangle aRect( GetOutputRect()); + Wallpaper aPaper( pView->GetBackground() ); + aPaper.SetRect( aRect ); + pView->SetBackground( aPaper ); + } + + if( bScrollable && GetUpdateMode() ) + { + // in umgekehrte Richtung scrollen! + pView->Control::Scroll( -nDx, -nDy, aOutputArea, + SCROLL_NOCHILDREN | SCROLL_USECLIPREGION | SCROLL_CLIP ); + } + else + pView->Invalidate(INVALIDATE_NOCHILDREN); + + if( aHorSBar.IsVisible() || aVerSBar.IsVisible() ) + { + if( !bScrBar ) + { + aOrigin *= -1; + // Thumbs korrigieren + if(aHorSBar.IsVisible() && aHorSBar.GetThumbPos() != aOrigin.X()) + aHorSBar.SetThumbPos( aOrigin.X() ); + if(aVerSBar.IsVisible() && aVerSBar.GetThumbPos() != aOrigin.Y()) + aVerSBar.SetThumbPos( aOrigin.Y() ); + } + } + + if( GetUpdateMode() ) + ShowCursor( sal_True ); + + // pruefen, ob ScrollBars noch benoetigt werden + CheckScrollBars(); + if( bScrollable && GetUpdateMode() ) + pView->Update(); + + // kann der angeforderte Bereich nicht komplett sichtbar gemacht werden, + // wird auf jeden Fall der Vis-Rect-Changed-Handler gerufen. Eintreten kann der + // Fall z.B. wenn nur wenige Pixel des unteren Randes nicht sichtbar sind, + // eine ScrollBar aber eine groessere Line-Size eingestellt hat. + if( bCallRectChangedHdl || GetOutputRect() != rRect ) + VisRectChanged(); +} + + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindNewCursor() +{ + SvxIconChoiceCtrlEntry* pNewCursor; + if( pCursor ) + { + pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_False ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_True ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoUpDown( pCursor, sal_False ); + if( !pNewCursor ) + pNewCursor = pImpCursor->GoUpDown( pCursor, sal_True ); + } + } + } + else + pNewCursor = (SvxIconChoiceCtrlEntry*)aEntries.First(); + DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"FindNewCursor failed"); + return pNewCursor; +} + +sal_uLong SvxIconChoiceCtrl_Impl::GetSelectionCount() const +{ + if( (nWinBits & WB_HIGHLIGHTFRAME) && pCurHighlightFrame ) + return 1; + return nSelectionCount; +} + +void SvxIconChoiceCtrl_Impl::ToggleSelection( SvxIconChoiceCtrlEntry* pEntry ) +{ + sal_Bool bSel; + if( pEntry->IsSelected() ) + bSel = sal_False; + else + bSel = sal_True; + SelectEntry( pEntry, bSel, sal_True, sal_True ); +} + +void SvxIconChoiceCtrl_Impl::DeselectAllBut( SvxIconChoiceCtrlEntry* pThisEntryNot, + sal_Bool bPaintSync ) +{ + ClearSelectedRectList(); + // + // !!!!!!! Todo: Evtl. Z-Orderlist abarbeiten !!!!!!! + // + sal_uLong nCount = aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + if( pEntry != pThisEntryNot && pEntry->IsSelected() ) + SelectEntry( pEntry, sal_False, sal_True, sal_True, bPaintSync ); + } + pAnchor = 0; + nFlags &= (~F_ADD_MODE); +} + +Size SvxIconChoiceCtrl_Impl::GetMinGrid() const +{ + Size aMinSize( aImageSize ); + aMinSize.Width() += 2 * LROFFS_BOUND; + aMinSize.Height() += TBOFFS_BOUND; // PB: einmal Offset reicht (FileDlg) + String aStrDummy( RTL_CONSTASCII_USTRINGPARAM( "XXX" ) ); + Size aTextSize( pView->GetTextWidth( aStrDummy ), pView->GetTextHeight() ); + if( nWinBits & WB_ICON ) + { + aMinSize.Height() += VER_DIST_BMP_STRING; + aMinSize.Height() += aTextSize.Height(); + } + else + { + aMinSize.Width() += HOR_DIST_BMP_STRING; + aMinSize.Width() += aTextSize.Width(); + } + return aMinSize; +} + +void SvxIconChoiceCtrl_Impl::SetGrid( const Size& rSize ) +{ + Size aSize( rSize ); + Size aMinSize( GetMinGrid() ); + if( aSize.Width() < aMinSize.Width() ) + aSize.Width() = aMinSize.Width(); + if( aSize.Height() < aMinSize.Height() ) + aSize.Height() = aMinSize.Height(); + + nGridDX = aSize.Width(); + // HACK(Detail-Modus ist noch nicht vollstaendig implementiert!) + // dieses Workaround bringts mit einer Spalte zum Fliegen + if( nWinBits & WB_DETAILS ) + { + const SvxIconChoiceCtrlColumnInfo* pCol = GetColumn( 0 ); + if( pCol ) + ((SvxIconChoiceCtrlColumnInfo*)pCol)->SetWidth( nGridDX ); + } + nGridDY = aSize.Height(); + SetDefaultTextSize(); +} + +// berechnet die maximale Groesse, die das Textrechteck innerhalb des +// umschliessenden Rechtecks einnehmen kann. Im Modus WB_ICON und +// IcnShowTextFull wird Bottom auf LONG_MAX gesetzt + +Rectangle SvxIconChoiceCtrl_Impl::CalcMaxTextRect( const SvxIconChoiceCtrlEntry* pEntry ) const +{ + Rectangle aBoundRect; + // keine Endlosrekursion! deshalb das Bound-Rect hier nicht berechnen + if( IsBoundingRectValid( pEntry->aRect ) ) + aBoundRect = pEntry->aRect; + else + aBoundRect = pEntry->aGridRect; + + Rectangle aBmpRect( ((SvxIconChoiceCtrl_Impl*)this)->CalcBmpRect( + (SvxIconChoiceCtrlEntry*)pEntry ) ); + if( nWinBits & WB_ICON ) + { + aBoundRect.Top() = aBmpRect.Bottom(); + aBoundRect.Top() += VER_DIST_BMP_STRING; + if( aBoundRect.Top() > aBoundRect.Bottom()) + aBoundRect.Top() = aBoundRect.Bottom(); + aBoundRect.Left() += LROFFS_BOUND; + aBoundRect.Left()++; + aBoundRect.Right() -= LROFFS_BOUND; + aBoundRect.Right()--; + if( aBoundRect.Left() > aBoundRect.Right()) + aBoundRect.Left() = aBoundRect.Right(); + if( GetEntryTextModeSmart( pEntry ) == IcnShowTextFull ) + aBoundRect.Bottom() = LONG_MAX; + } + else + { + aBoundRect.Left() = aBmpRect.Right(); + aBoundRect.Left() += HOR_DIST_BMP_STRING; + aBoundRect.Right() -= LROFFS_BOUND; + if( aBoundRect.Left() > aBoundRect.Right() ) + aBoundRect.Left() = aBoundRect.Right(); + long nHeight = aBoundRect.GetSize().Height(); + nHeight = nHeight - aDefaultTextSize.Height(); + nHeight /= 2; + aBoundRect.Top() += nHeight; + aBoundRect.Bottom() -= nHeight; + } + return aBoundRect; +} + +void SvxIconChoiceCtrl_Impl::SetDefaultTextSize() +{ + long nDY = nGridDY; + nDY -= aImageSize.Height(); + nDY -= VER_DIST_BMP_STRING; + nDY -= 2*TBOFFS_BOUND; + if( nDY <= 0 ) + nDY = 2; + + long nDX = nGridDX; + nDX -= 2*LROFFS_BOUND; + nDX -= 2; + if( nDX <= 0 ) + nDX = 2; + + String aStrDummy( RTL_CONSTASCII_USTRINGPARAM( "X" ) ); + long nHeight = pView->GetTextHeight(); + if( nDY < nHeight ) + nDY = nHeight; + aDefaultTextSize = Size( nDX, nDY ); +} + + +void SvxIconChoiceCtrl_Impl::Center( SvxIconChoiceCtrlEntry* pEntry ) const +{ + pEntry->aRect = pEntry->aGridRect; + Size aSize( CalcBoundingSize( pEntry ) ); + if( nWinBits & WB_ICON ) + { + // horizontal zentrieren + long nBorder = pEntry->aGridRect.GetWidth() - aSize.Width(); + pEntry->aRect.Left() += nBorder / 2; + pEntry->aRect.Right() -= nBorder / 2; + } + // vertikal zentrieren + pEntry->aRect.Bottom() = pEntry->aRect.Top() + aSize.Height(); +} + + +// Die Deltas entsprechen Offsets, um die die View auf dem Doc verschoben wird +// links, hoch: Offsets < 0 +// rechts, runter: Offsets > 0 +void SvxIconChoiceCtrl_Impl::Scroll( long nDeltaX, long nDeltaY, sal_Bool bScrollBar ) +{ + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + // in Dokumentkoordinate umwandeln + aOrigin *= -1; + aOrigin.Y() += nDeltaY; + aOrigin.X() += nDeltaX; + Rectangle aRect( aOrigin, aOutputSize ); + MakeVisible( aRect, bScrollBar ); +} + + +const Size& SvxIconChoiceCtrl_Impl::GetItemSize( SvxIconChoiceCtrlEntry*, + IcnViewFieldType eItem ) const +{ + if( eItem == IcnViewFieldTypeText ) + return aDefaultTextSize; + return aImageSize; +} + +Rectangle SvxIconChoiceCtrl_Impl::CalcFocusRect( SvxIconChoiceCtrlEntry* pEntry ) +{ + Rectangle aBmpRect( CalcBmpRect( pEntry ) ); + Rectangle aTextRect( CalcTextRect( pEntry ) ); + Rectangle aBoundRect( GetEntryBoundRect( pEntry ) ); + Rectangle aFocusRect( aBoundRect.Left(), aBmpRect.Top() - 1, + aBoundRect.Right() - 4, aTextRect.Bottom() + 1 ); + // Das Fokusrechteck soll nicht den Text beruehren + if( aFocusRect.Left() - 1 >= pEntry->aRect.Left() ) + aFocusRect.Left()--; + if( aFocusRect.Right() + 1 <= pEntry->aRect.Right() ) + aFocusRect.Right()++; + + return aFocusRect; +} + +// Der 'Hot Spot' sind die inneren 50% der Rechteckflaeche +static Rectangle GetHotSpot( const Rectangle& rRect ) +{ + Rectangle aResult( rRect ); + aResult.Justify(); + Size aSize( rRect.GetSize() ); + long nDelta = aSize.Width() / 4; + aResult.Left() += nDelta; + aResult.Right() -= nDelta; + nDelta = aSize.Height() / 4; + aResult.Top() += nDelta; + aResult.Bottom() -= nDelta; + return aResult; +} + +void SvxIconChoiceCtrl_Impl::SelectRect( SvxIconChoiceCtrlEntry* pEntry1, SvxIconChoiceCtrlEntry* pEntry2, + sal_Bool bAdd, SvPtrarr* pOtherRects ) +{ + DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr"); + Rectangle aRect( GetEntryBoundRect( pEntry1 ) ); + aRect.Union( GetEntryBoundRect( pEntry2 ) ); + SelectRect( aRect, bAdd, pOtherRects ); +} + +void SvxIconChoiceCtrl_Impl::SelectRect( const Rectangle& rRect, sal_Bool bAdd, + SvPtrarr* pOtherRects ) +{ + aCurSelectionRect = rRect; + if( !pZOrderList || !pZOrderList->Count() ) + return; + + // Flag setzen, damit im Select kein ToTop gerufen wird + sal_Bool bAlreadySelectingRect = nFlags & F_SELECTING_RECT ? sal_True : sal_False; + nFlags |= F_SELECTING_RECT; + + CheckBoundingRects(); + pView->Update(); + const sal_uLong nCount = pZOrderList->Count(); + + Rectangle aRect( rRect ); + aRect.Justify(); + sal_Bool bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? sal_True : sal_False; + + sal_Bool bResetClipRegion = sal_False; + if( !pView->IsClipRegion() ) + { + bResetClipRegion = sal_True; + pView->SetClipRegion( GetOutputRect() ); + } + + for( sal_uLong nPos = 0; nPos < nCount; nPos++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pZOrderList->GetObject(nPos )); + + if( !IsBoundingRectValid( pEntry->aRect )) + FindBoundingRect( pEntry ); + Rectangle aBoundRect( GetHotSpot( pEntry->aRect ) ); + sal_Bool bSelected = pEntry->IsSelected(); + + sal_Bool bOverlaps; + if( bCalcOverlap ) + bOverlaps = IsOver( pOtherRects, aBoundRect ); + else + bOverlaps = sal_False; + sal_Bool bOver = aRect.IsOver( aBoundRect ); + + if( bOver && !bOverlaps ) + { + // Ist im neuen Selektionsrechteck und in keinem alten + // => selektieren + if( !bSelected ) + SelectEntry( pEntry, sal_True, sal_True, sal_True ); + } + else if( !bAdd ) + { + // ist ausserhalb des Selektionsrechtecks + // => Selektion entfernen + if( bSelected ) + SelectEntry( pEntry, sal_False, sal_True, sal_True ); + } + else if( bAdd && bOverlaps ) + { + // Der Eintrag befindet sich in einem alten (=>Aufspannen + // mehrerer Rechtecke mit Ctrl!) Selektionsrechteck + + // Hier ist noch ein Bug! Der Selektionsstatus eines Eintrags + // in einem vorherigen Rechteck, muss restauriert werden, wenn + // er vom aktuellen Selektionsrechteck beruehrt wurde, jetzt aber + // nicht mehr in ihm liegt. Ich gehe hier der Einfachheit halber + // pauschal davon aus, dass die Eintraege in den alten Rechtecken + // alle selektiert sind. Ebenso ist es falsch, die Schnittmenge + // nur zu deselektieren. + // Loesungsmoeglichkeit: Snapshot der Selektion vor dem Auf- + // spannen des Rechtecks merken + if( aBoundRect.IsOver( rRect)) + { + // Schnittmenge zwischen alten Rects & aktuellem Rect desel. + if( bSelected ) + SelectEntry( pEntry, sal_False, sal_True, sal_True ); + } + else + { + // Eintrag eines alten Rects selektieren + if( !bSelected ) + SelectEntry( pEntry, sal_True, sal_True, sal_True ); + } + } + else if( !bOver && bSelected ) + { + // Der Eintrag liegt voellig ausserhalb und wird deshalb desel. + SelectEntry( pEntry, sal_False, sal_True, sal_True ); + } + } + + if( !bAlreadySelectingRect ) + nFlags &= ~F_SELECTING_RECT; + + pView->Update(); + if( bResetClipRegion ) + pView->SetClipRegion(); +} + +void SvxIconChoiceCtrl_Impl::SelectRange( + SvxIconChoiceCtrlEntry* pStart, + SvxIconChoiceCtrlEntry* pEnd, + sal_Bool bAdd ) +{ + sal_uLong nFront = GetEntryListPos( pStart ); + sal_uLong nBack = GetEntryListPos( pEnd ); + sal_uLong nFirst = std::min( nFront, nBack ); + sal_uLong nLast = std::max( nFront, nBack ); + sal_uLong i; + SvxIconChoiceCtrlEntry* pEntry; + + if ( ! bAdd ) + { + // deselect everything before the first entry if not in + // adding mode + for ( i=0; i<nFirst; i++ ) + { + pEntry = GetEntry( i ); + if( pEntry->IsSelected() ) + SelectEntry( pEntry, sal_False, sal_True, sal_True, sal_True ); + } + } + + // select everything between nFirst and nLast + for ( i=nFirst; i<=nLast; i++ ) + { + pEntry = GetEntry( i ); + if( ! pEntry->IsSelected() ) + SelectEntry( pEntry, sal_True, sal_True, sal_True, sal_True ); + } + + if ( ! bAdd ) + { + // deselect everything behind the last entry if not in + // adding mode + sal_uLong nEnd = GetEntryCount(); + for ( ; i<nEnd; i++ ) + { + pEntry = GetEntry( i ); + if( pEntry->IsSelected() ) + SelectEntry( pEntry, sal_False, sal_True, sal_True, sal_True ); + } + } +} + +sal_Bool SvxIconChoiceCtrl_Impl::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const +{ + const sal_uInt16 nCount = pRectList->Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur ); + if( rBoundRect.IsOver( *pRect )) + return sal_True; + } + return sal_False; +} + +void SvxIconChoiceCtrl_Impl::AddSelectedRect( SvxIconChoiceCtrlEntry* pEntry1, + SvxIconChoiceCtrlEntry* pEntry2 ) +{ + DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr"); + Rectangle aRect( GetEntryBoundRect( pEntry1 ) ); + aRect.Union( GetEntryBoundRect( pEntry2 ) ); + AddSelectedRect( aRect ); +} + +void SvxIconChoiceCtrl_Impl::AddSelectedRect( const Rectangle& rRect ) +{ + Rectangle* pRect = new Rectangle( rRect ); + pRect->Justify(); + aSelectedRectList.Insert( (void*)pRect, aSelectedRectList.Count() ); +} + +void SvxIconChoiceCtrl_Impl::ClearSelectedRectList() +{ + const sal_uInt16 nCount = aSelectedRectList.Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + Rectangle* pRect = (Rectangle*)aSelectedRectList.GetObject( nCur ); + delete pRect; + } + aSelectedRectList.Remove( 0, aSelectedRectList.Count() ); +} + +void SvxIconChoiceCtrl_Impl::CalcScrollOffsets( const Point& rPosPixel, + long& rX, long& rY, sal_Bool isInDragDrop, sal_uInt16 nBorderWidth) +{ + // Scrolling der View, falls sich der Mauszeiger im Grenzbereich des + // Fensters befindet + long nPixelToScrollX = 0; + long nPixelToScrollY = 0; + Size aWndSize = aOutputSize; + + nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth )); + nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Width()-1), (long)nBorderWidth )); + + if ( rPosPixel.X() < nBorderWidth ) + { + if( isInDragDrop ) + nPixelToScrollX = -DD_SCROLL_PIXEL; + else + nPixelToScrollX = rPosPixel.X()- nBorderWidth; + } + else if ( rPosPixel.X() > aWndSize.Width() - nBorderWidth ) + { + if( isInDragDrop ) + nPixelToScrollX = DD_SCROLL_PIXEL; + else + nPixelToScrollX = rPosPixel.X() - (aWndSize.Width() - nBorderWidth); + } + if ( rPosPixel.Y() < nBorderWidth ) + { + if( isInDragDrop ) + nPixelToScrollY = -DD_SCROLL_PIXEL; + else + nPixelToScrollY = rPosPixel.Y() - nBorderWidth; + } + else if ( rPosPixel.Y() > aWndSize.Height() - nBorderWidth ) + { + if( isInDragDrop ) + nPixelToScrollY = DD_SCROLL_PIXEL; + else + nPixelToScrollY = rPosPixel.Y() - (aWndSize.Height() - nBorderWidth); + } + + rX = nPixelToScrollX; + rY = nPixelToScrollY; +} + +IMPL_LINK(SvxIconChoiceCtrl_Impl, AutoArrangeHdl, void*, EMPTYARG ) +{ + aAutoArrangeTimer.Stop(); + Arrange( IsAutoArrange() ); + return 0; +} + +IMPL_LINK(SvxIconChoiceCtrl_Impl, VisRectChangedHdl, void*, EMPTYARG ) +{ + aVisRectChangedTimer.Stop(); + pView->VisibleRectChanged(); + return 0; +} + +IMPL_LINK(SvxIconChoiceCtrl_Impl, DocRectChangedHdl, void*, EMPTYARG ) +{ + aDocRectChangedTimer.Stop(); + pView->DocumentRectChanged(); + return 0; +} + +void SvxIconChoiceCtrl_Impl::PrepareCommandEvent( const CommandEvent& rCEvt ) +{ + StopEditTimer(); + SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry( rCEvt.GetMousePosPixel() ); + if( (nFlags & F_DOWN_CTRL) && pEntry && !pEntry->IsSelected() ) + SelectEntry( pEntry, sal_True, sal_True ); + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); +} + +sal_Bool SvxIconChoiceCtrl_Impl::IsTextHit( SvxIconChoiceCtrlEntry* pEntry, const Point& rDocPos ) +{ + Rectangle aRect( CalcTextRect( pEntry )); + if( aRect.IsInside( rDocPos ) ) + return sal_True; + return sal_False; +} + +IMPL_LINK(SvxIconChoiceCtrl_Impl, EditTimeoutHdl, Timer*, EMPTYARG ) +{ + SvxIconChoiceCtrlEntry* pEntry = GetCurEntry(); + if( bEntryEditingEnabled && pEntry && + pEntry->IsSelected()) + { + if( pView->EditingEntry( pEntry )) + EditEntry( pEntry ); + } + return 0; +} + + +// +// Funktionen zum Ausrichten der Eintraege am Grid +// + +// pStart == 0: Alle Eintraege werden ausgerichtet +// sonst: Alle Eintraege der Zeile ab einschliesslich pStart werden ausgerichtet +void SvxIconChoiceCtrl_Impl::AdjustEntryAtGrid( SvxIconChoiceCtrlEntry* pStart ) +{ + SvPtrarr aLists; + pImpCursor->CreateGridAjustData( aLists, pStart ); + const sal_uInt16 nCount = aLists.Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + AdjustAtGrid( *(SvPtrarr*)aLists[ nCur ], pStart ); + IcnCursor_Impl::DestroyGridAdjustData( aLists ); + CheckScrollBars(); +} + +// Richtet eine Zeile aus, erweitert ggf. die Breite; Bricht die Zeile nicht um +void SvxIconChoiceCtrl_Impl::AdjustAtGrid( const SvPtrarr& rRow, SvxIconChoiceCtrlEntry* pStart ) +{ + if( !rRow.Count() ) + return; + + sal_Bool bGo; + if( !pStart ) + bGo = sal_True; + else + bGo = sal_False; + + long nCurRight = 0; + for( sal_uInt16 nCur = 0; nCur < rRow.Count(); nCur++ ) + { + SvxIconChoiceCtrlEntry* pCur = (SvxIconChoiceCtrlEntry*)rRow[ nCur ]; + if( !bGo && pCur == pStart ) + bGo = sal_True; + + //SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur); + // Massgebend (fuer unser Auge) ist die Bitmap, da sonst + // durch lange Texte der Eintrag stark springen kann + const Rectangle& rBoundRect = GetEntryBoundRect( pCur ); + Rectangle aCenterRect( CalcBmpRect( pCur, 0 )); + if( bGo && !pCur->IsPosLocked() ) + { + long nWidth = aCenterRect.GetSize().Width(); + Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) ); + while( aNewPos.X() < nCurRight ) + aNewPos.X() += nGridDX; + if( aNewPos != rBoundRect.TopLeft() ) + { + SetEntryPos( pCur, aNewPos ); + pCur->SetFlags( ICNVIEW_FLAG_POS_MOVED ); + nFlags |= F_MOVED_ENTRIES; + } + nCurRight = aNewPos.X() + nWidth; + } + else + { + nCurRight = rBoundRect.Right(); + } + } +} + +// Richtet Rect am Grid aus, garantiert jedoch nicht, dass die +// neue Pos. frei ist. Die Pos. kann fuer SetEntryPos verwendet werden. +// Das CenterRect beschreibt den Teil des BoundRects, der fuer +// die Berechnung des Ziel-Rechtecks verwendet wird. +Point SvxIconChoiceCtrl_Impl::AdjustAtGrid( const Rectangle& rCenterRect, + const Rectangle& rBoundRect ) const +{ + Point aPos( rCenterRect.TopLeft() ); + Size aSize( rCenterRect.GetSize() ); + + aPos.X() -= LROFFS_WINBORDER; + aPos.Y() -= TBOFFS_WINBORDER; + + // align (ref ist mitte des rects) + short nGridX = (short)((aPos.X()+(aSize.Width()/2)) / nGridDX); + short nGridY = (short)((aPos.Y()+(aSize.Height()/2)) / nGridDY); + aPos.X() = nGridX * nGridDX; + aPos.Y() = nGridY * nGridDY; + // hor. center + aPos.X() += (nGridDX - rBoundRect.GetSize().Width() ) / 2; + + aPos.X() += LROFFS_WINBORDER; + aPos.Y() += TBOFFS_WINBORDER; + + return aPos; +} + +void SvxIconChoiceCtrl_Impl::SetEntryTextMode( SvxIconChoiceCtrlTextMode eMode, SvxIconChoiceCtrlEntry* pEntry ) +{ + if( !pEntry ) + { + if( eTextMode != eMode ) + { + if( eTextMode == IcnShowTextDontKnow ) + eTextMode = IcnShowTextShort; + eTextMode = eMode; + Arrange( sal_True ); + } + } + else + { + if( pEntry->eTextMode != eMode ) + { + pEntry->eTextMode = eMode; + InvalidateEntry( pEntry ); + pView->Invalidate( GetEntryBoundRect( pEntry ) ); + AdjustVirtSize( pEntry->aRect ); + } + } +} + +SvxIconChoiceCtrlTextMode SvxIconChoiceCtrl_Impl::GetTextMode( const SvxIconChoiceCtrlEntry* pEntry ) const +{ + if( !pEntry ) + return eTextMode; + return pEntry->GetTextMode(); +} + +SvxIconChoiceCtrlTextMode SvxIconChoiceCtrl_Impl::GetEntryTextModeSmart( const SvxIconChoiceCtrlEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"GetEntryTextModeSmart: Entry not set"); + SvxIconChoiceCtrlTextMode eMode = pEntry->GetTextMode(); + if( eMode == IcnShowTextDontKnow ) + return eTextMode; + return eMode; +} + +void SvxIconChoiceCtrl_Impl::ShowEntryFocusRect( const SvxIconChoiceCtrlEntry* pEntry ) +{ + if( !pEntry ) + { + pView->HideFocus(); + } + else + { + Rectangle aRect ( CalcFocusRect( (SvxIconChoiceCtrlEntry*)pEntry ) ); + /*pView->*/ShowFocus( aRect ); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// +// +// Draw my own focusrect, because the focusrect of the outputdevice has got the inverted color +// of the background. But what will we see, if the the backgroundcolor is gray ? - We will see +// a gray focusrect on a gray background !!! +// +void SvxIconChoiceCtrl_Impl::ShowFocus ( Rectangle& rRect ) +{ + Color aBkgColor ( pView->GetBackground().GetColor() ); + Color aPenColor; + sal_uInt16 nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3; + if ( nColor > 128 ) + aPenColor.SetColor ( COL_BLACK ); + else + aPenColor.SetColor( COL_WHITE ); + + aFocus.bOn = sal_True; + aFocus.aPenColor = aPenColor; + aFocus.aRect = rRect; +} + +void SvxIconChoiceCtrl_Impl::HideFocus () +{ + aFocus.bOn = sal_False; +} + +void SvxIconChoiceCtrl_Impl::DrawFocusRect ( OutputDevice* pOut ) +{ + pOut->SetLineColor( aFocus.aPenColor ); + pOut->SetFillColor(); + Polygon aPolygon ( aFocus.aRect ); + + LineInfo aLineInfo ( LINE_DASH ); + + aLineInfo.SetDashLen ( 1 ); + + aLineInfo.SetDotLen ( 1L ); + aLineInfo.SetDistance ( 1L ); + aLineInfo.SetDotCount ( 1 ); + + pOut->DrawPolyLine ( aPolygon, aLineInfo ); +} + +sal_Bool SvxIconChoiceCtrl_Impl::IsMnemonicChar( sal_Unicode cChar, sal_uLong& rPos ) const +{ + sal_Bool bRet = sal_False; + const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper(); + sal_uLong nEntryCount = GetEntryCount(); + for ( sal_uLong i = 0; i < nEntryCount; ++i ) + { + if ( rI18nHelper.MatchMnemonic( GetEntry( i )->GetText(), cChar ) ) + { + bRet = sal_True; + rPos = i; + break; + } + } + + return bRet; +} + +// +//////////////////////////////////////////////////////////////////////////////////////////////// + +IMPL_LINK(SvxIconChoiceCtrl_Impl, UserEventHdl, void*, nId ) +{ + if( nId == EVENTID_ADJUST_SCROLLBARS ) + { + nUserEventAdjustScrBars = 0; + AdjustScrollBars(); + } + else if( nId == EVENTID_SHOW_CURSOR ) + { + nUserEventShowCursor = 0; + ShowCursor( sal_True ); + } + return 0; +} + +void SvxIconChoiceCtrl_Impl::CancelUserEvents() +{ + if( nUserEventAdjustScrBars ) + { + Application::RemoveUserEvent( nUserEventAdjustScrBars ); + nUserEventAdjustScrBars = 0; + } + if( nUserEventShowCursor ) + { + Application::RemoveUserEvent( nUserEventShowCursor ); + nUserEventShowCursor = 0; + } +} + +void SvxIconChoiceCtrl_Impl::InvalidateEntry( SvxIconChoiceCtrlEntry* pEntry ) +{ + if( pEntry == pCursor ) + ShowCursor( sal_False ); + pView->Invalidate( pEntry->aRect ); + Center( pEntry ); + pView->Invalidate( pEntry->aRect ); + if( pEntry == pCursor ) + ShowCursor( sal_True ); +} + +void SvxIconChoiceCtrl_Impl::EditEntry( SvxIconChoiceCtrlEntry* pEntry ) +{ + DBG_ASSERT(pEntry,"EditEntry: Entry not set"); + if( !pEntry ) + return; + + StopEntryEditing( sal_True ); + DELETEZ(pEdit); + SetNoSelection(); + + pCurEditedEntry = pEntry; + String aEntryText( pView->GetEntryText( pEntry, sal_True ) ); + Rectangle aRect( CalcTextRect( pEntry, 0, sal_True, &aEntryText ) ); + MakeVisible( aRect ); + Point aPos( aRect.TopLeft() ); + aPos = pView->GetPixelPos( aPos ); + aRect.SetPos( aPos ); + pView->HideFocus(); + pEdit = new IcnViewEdit_Impl( + pView, + aRect.TopLeft(), + aRect.GetSize(), + aEntryText, + LINK( this, SvxIconChoiceCtrl_Impl, TextEditEndedHdl ) ); +} + +IMPL_LINK( SvxIconChoiceCtrl_Impl, TextEditEndedHdl, IcnViewEdit_Impl*, EMPTYARG ) +{ + DBG_ASSERT(pEdit,"TextEditEnded: pEdit not set"); + if( !pEdit ) + { + pCurEditedEntry = 0; + return 0; + } + DBG_ASSERT(pCurEditedEntry,"TextEditEnded: pCurEditedEntry not set"); + + if( !pCurEditedEntry ) + { + pEdit->Hide(); + if( pEdit->IsGrabFocus() ) + pView->GrabFocus(); + return 0; + } + + String aText; + if ( !pEdit->EditingCanceled() ) + aText = pEdit->GetText(); + else + aText = pEdit->GetSavedValue(); + + if( pView->EditedEntry( pCurEditedEntry, aText, pEdit->EditingCanceled() ) ) + InvalidateEntry( pCurEditedEntry ); + if( !GetSelectionCount() ) + SelectEntry( pCurEditedEntry, sal_True ); + + pEdit->Hide(); + if( pEdit->IsGrabFocus() ) + pView->GrabFocus(); + // Das Edit kann nicht hier geloescht werden, weil es noch in einem + // Handler steht. Es wird im Dtor oder im naechsten EditEntry geloescht. + pCurEditedEntry = 0; + return 0; +} + +void SvxIconChoiceCtrl_Impl::StopEntryEditing( sal_Bool bCancel ) +{ + if( pEdit ) + pEdit->StopEditing( bCancel ); +} + +void SvxIconChoiceCtrl_Impl::LockEntryPos( SvxIconChoiceCtrlEntry* pEntry, sal_Bool bLock ) +{ + if( bLock ) + pEntry->SetFlags( ICNVIEW_FLAG_POS_LOCKED ); + else + pEntry->ClearFlags( ICNVIEW_FLAG_POS_LOCKED ); +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry( sal_uLong& rPos ) const +{ + if( !GetSelectionCount() ) + return 0; + + if( (nWinBits & WB_HIGHLIGHTFRAME) && (eSelectionMode == NO_SELECTION) ) + { + rPos = pView->GetEntryListPos( pCurHighlightFrame ); + return pCurHighlightFrame; + } + + sal_uLong nCount = aEntries.Count(); + if( !pHead ) + { + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + if( pEntry->IsSelected() ) + { + rPos = nCur; + return pEntry; + } + } + } + else + { + SvxIconChoiceCtrlEntry* pEntry = pHead; + while( nCount-- ) + { + if( pEntry->IsSelected() ) + { + rPos = GetEntryListPos( pEntry ); + return pEntry; + } + pEntry = pEntry->pflink; + if( nCount && pEntry == pHead ) + { + DBG_ERROR("SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry > Endlosschleife!"); + return 0; + } + } + } + return 0; +} + +// kein Round Robin! +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetNextSelectedEntry( sal_uLong& rStartPos ) const +{ + sal_uLong nCount = aEntries.Count(); + if( rStartPos > nCount || !GetSelectionCount() ) + return 0; + if( !pHead ) + { + for( sal_uLong nCur = rStartPos+1; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + if( pEntry->IsSelected() ) + { + rStartPos = nCur; + return pEntry; + } + } + } + else + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( rStartPos ); + pEntry = pEntry->pflink; + while( pEntry != pHead ) + { + if( pEntry->IsSelected() ) + { + rStartPos = GetEntryListPos( pEntry ); + return pEntry; + } + pEntry = pEntry->pflink; + } + } + + rStartPos = 0xffffffff; + return 0; +} + +void SvxIconChoiceCtrl_Impl::SelectAll( sal_Bool bSelect, sal_Bool bPaint ) +{ + bPaint = sal_True; + + sal_uLong nCount = aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount && (bSelect || GetSelectionCount() ); nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + SelectEntry( pEntry, bSelect, sal_True, sal_True, bPaint ); + } + nFlags &= (~F_ADD_MODE); + pAnchor = 0; +} + +void SvxIconChoiceCtrl_Impl::SaveSelection( List** ppList ) +{ + if( !*ppList ) + *ppList = new List; + sal_uLong nPos; + SvxIconChoiceCtrlEntry* pEntry = GetFirstSelectedEntry( nPos ); + while( pEntry && GetSelectionCount() != (*ppList)->Count() ) + { + (*ppList)->Insert( pEntry, LIST_APPEND ); + pEntry = GetNextSelectedEntry( nPos ); + } +} + +IcnViewEdit_Impl::IcnViewEdit_Impl( SvtIconChoiceCtrl* pParent, const Point& rPos, + const Size& rSize, const XubString& rData, const Link& rNotifyEditEnd ) : + MultiLineEdit( pParent, (pParent->GetStyle() & WB_ICON) ? WB_CENTER : WB_LEFT), + aCallBackHdl( rNotifyEditEnd ), + bCanceled( sal_False ), + bAlreadyInCallback( sal_False ), + bGrabFocus( sal_False ) +{ + Font aFont( pParent->GetPointFont() ); + aFont.SetTransparent( sal_False ); + SetControlFont( aFont ); + if( !pParent->HasFontFillColor() ) + { + Color aColor( pParent->GetBackground().GetColor() ); + SetControlBackground( aColor ); + } + else + SetControlBackground( aFont.GetFillColor() ); + SetControlForeground( aFont.GetColor() ); + SetPosPixel( rPos ); + SetSizePixel( CalcAdjustedSize(rSize) ); + SetText( rData ); + SaveValue(); + + aAccReturn.InsertItem( IMPICNVIEW_ACC_RETURN, KeyCode(KEY_RETURN) ); + aAccEscape.InsertItem( IMPICNVIEW_ACC_ESCAPE, KeyCode(KEY_ESCAPE) ); + + aAccReturn.SetActivateHdl( LINK( this, IcnViewEdit_Impl, ReturnHdl_Impl) ); + aAccEscape.SetActivateHdl( LINK( this, IcnViewEdit_Impl, EscapeHdl_Impl) ); + GetpApp()->InsertAccel( &aAccReturn);//, ACCEL_ALWAYS ); + GetpApp()->InsertAccel( &aAccEscape);//, ACCEL_ALWAYS ); + Show(); + GrabFocus(); +} + +IcnViewEdit_Impl::~IcnViewEdit_Impl() +{ + if( !bAlreadyInCallback ) + { + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + } +} + +void IcnViewEdit_Impl::CallCallBackHdl_Impl() +{ + aTimer.Stop(); + if ( !bAlreadyInCallback ) + { + bAlreadyInCallback = sal_True; + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + Hide(); + aCallBackHdl.Call( this ); + } +} + +IMPL_LINK( IcnViewEdit_Impl, Timeout_Impl, Timer*, EMPTYARG ) +{ + CallCallBackHdl_Impl(); + return 0; +} + +IMPL_LINK( IcnViewEdit_Impl, ReturnHdl_Impl, Accelerator*, EMPTYARG ) +{ + bCanceled = sal_False; + bGrabFocus = sal_True; + CallCallBackHdl_Impl(); + return 1; +} + +IMPL_LINK( IcnViewEdit_Impl, EscapeHdl_Impl, Accelerator*, EMPTYARG ) +{ + bCanceled = sal_True; + bGrabFocus = sal_True; + CallCallBackHdl_Impl(); + return 1; +} + +void IcnViewEdit_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + KeyCode aCode = rKEvt.GetKeyCode(); + sal_uInt16 nCode = aCode.GetCode(); + + switch ( nCode ) + { + case KEY_ESCAPE: + bCanceled = sal_True; + bGrabFocus = sal_True; + CallCallBackHdl_Impl(); + break; + + case KEY_RETURN: + bCanceled = sal_False; + bGrabFocus = sal_True; + CallCallBackHdl_Impl(); + break; + + default: + MultiLineEdit::KeyInput( rKEvt ); + } +} + +long IcnViewEdit_Impl::PreNotify( NotifyEvent& rNEvt ) +{ + if( rNEvt.GetType() == EVENT_LOSEFOCUS ) + { + if ( !bAlreadyInCallback && + ((!Application::GetFocusWindow()) || !IsChild(Application::GetFocusWindow()))) + { + bCanceled = sal_False; + aTimer.SetTimeout(10); + aTimer.SetTimeoutHdl(LINK(this,IcnViewEdit_Impl,Timeout_Impl)); + aTimer.Start(); + } + } + return 0; +} + +void IcnViewEdit_Impl::StopEditing( sal_Bool bCancel ) +{ + if ( !bAlreadyInCallback ) + { + bCanceled = bCancel; + CallCallBackHdl_Impl(); + } +} + +sal_uLong SvxIconChoiceCtrl_Impl::GetEntryListPos( SvxIconChoiceCtrlEntry* pEntry ) const +{ + if( !(nFlags & F_ENTRYLISTPOS_VALID )) + ((SvxIconChoiceCtrl_Impl*)this)->SetListPositions(); + return pEntry->nPos; +} + +void SvxIconChoiceCtrl_Impl::SetEntryListPos( SvxIconChoiceCtrlEntry* pListEntry, sal_uLong nNewPos ) +{ + sal_uLong nCurPos = GetEntryListPos( pListEntry ); + if( nCurPos == nNewPos ) + return; + aEntries.List::Remove( nCurPos ); + aEntries.List::Insert( (void*)pListEntry, nNewPos ); + // Eintragspositionen anpassen + sal_uLong nStart, nEnd; + if( nNewPos < nCurPos ) + { + nStart = nNewPos; + nEnd = nCurPos; + } + else + { + nStart = nCurPos; + nEnd = nNewPos; + } + for( ; nStart <= nEnd; nStart++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nStart ); + pEntry->nPos = nStart; + } +} + +void SvxIconChoiceCtrl_Impl::SetEntryFlags( SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nEntryFlags ) +{ + pEntry->nFlags = nEntryFlags; + if( nEntryFlags & ICNVIEW_FLAG_POS_MOVED ) + nFlags |= F_MOVED_ENTRIES; +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GoLeftRight( SvxIconChoiceCtrlEntry* pStart, sal_Bool bRight ) +{ + return pImpCursor->GoLeftRight( pStart, bRight ); +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GoUpDown( SvxIconChoiceCtrlEntry* pStart, sal_Bool bDown ) +{ + return pImpCursor->GoUpDown( pStart, bDown ); +} + +void SvxIconChoiceCtrl_Impl::InitSettings() +{ + const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings(); + + if( !pView->HasFont() ) + { + // Unit aus den Settings ist Point + Font aFont( rStyleSettings.GetFieldFont() ); + //const Font& rFont = pView->GetFont(); + //if( pView->HasFontTextColor() ) + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + //if( pView->HasFontFillColor() ) + //aFont.SetFillColor( rFont.GetFillColor() ); + pView->SetPointFont( aFont ); + SetDefaultTextSize(); + } + + //if( !pView->HasFontTextColor() ) + pView->SetTextColor( rStyleSettings.GetFieldTextColor() ); + //if( !pView->HasFontFillColor() ) + pView->SetTextFillColor(); + + //if( !pView->HasBackground() ) + pView->SetBackground( rStyleSettings.GetFieldColor()); + + long nScrBarSize = rStyleSettings.GetScrollBarSize(); + if( nScrBarSize != nHorSBarHeight || nScrBarSize != nVerSBarWidth ) + { + nHorSBarHeight = nScrBarSize; + Size aSize( aHorSBar.GetSizePixel() ); + aSize.Height() = nScrBarSize; + aHorSBar.Hide(); + aHorSBar.SetSizePixel( aSize ); + + nVerSBarWidth = nScrBarSize; + aSize = aVerSBar.GetSizePixel(); + aSize.Width() = nScrBarSize; + aVerSBar.Hide(); + aVerSBar.SetSizePixel( aSize ); + + Size aOSize( pView->Control::GetOutputSizePixel() ); + PositionScrollBars( aOSize.Width(), aOSize.Height() ); + AdjustScrollBars(); + } +} + +EntryList_Impl::EntryList_Impl( SvxIconChoiceCtrl_Impl* pOwner, sal_uInt16 _nInitSize , sal_uInt16 _nReSize ) : + List( _nInitSize, _nReSize ), + _pOwner( pOwner ) +{ + _pOwner->pHead = 0; +} + +EntryList_Impl::EntryList_Impl( SvxIconChoiceCtrl_Impl* pOwner, sal_uInt16 _nBlockSize, sal_uInt16 _nInitSize, sal_uInt16 _nReSize ) : + List( _nBlockSize, _nInitSize, _nReSize ), + _pOwner( pOwner ) +{ + _pOwner->pHead = 0; +} + +EntryList_Impl::~EntryList_Impl() +{ + _pOwner->pHead = 0; +} + +void EntryList_Impl::Clear() +{ + _pOwner->pHead = 0; + List::Clear(); +} + +void EntryList_Impl::Insert( SvxIconChoiceCtrlEntry* pEntry, sal_uLong nPos ) +{ + List::Insert( pEntry, nPos ); + if( _pOwner->pHead ) + pEntry->SetBacklink( _pOwner->pHead->pblink ); +} + +SvxIconChoiceCtrlEntry* EntryList_Impl::Remove( sal_uLong nPos ) +{ + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)List::Remove( nPos ); + DBG_ASSERT(pEntry,"EntryList_Impl::Remove > Entry not found"); + Removed_Impl( pEntry ); + return pEntry; +} + +void EntryList_Impl::Remove( SvxIconChoiceCtrlEntry* pEntry ) +{ + List::Remove( (void*)pEntry ); + Removed_Impl( pEntry ); +} + +void EntryList_Impl::Removed_Impl( SvxIconChoiceCtrlEntry* pEntry ) +{ + if( _pOwner->pHead ) + { + if( _pOwner->pHead == pEntry ) + { + if( _pOwner->pHead != pEntry->pflink ) + _pOwner->pHead = pEntry->pflink; + else + { + DBG_ASSERT(!Count(),"EntryList_Impl::Remove > Invalid predecessor" ); + _pOwner->pHead = 0; + } + } + pEntry->Unlink(); + } +} + +void SvxIconChoiceCtrl_Impl::SetPositionMode( SvxIconChoiceCtrlPositionMode eMode ) +{ + sal_uLong nCur; + + if( eMode == ePositionMode ) + return; + + SvxIconChoiceCtrlPositionMode eOldMode = ePositionMode; + ePositionMode = eMode; + sal_uLong nCount = aEntries.Count(); + + if( eOldMode == IcnViewPositionModeAutoArrange ) + { + // positionieren wir verschobene Eintraege 'hart' gibts noch Probleme + // mit ungewollten Ueberlappungen, da diese Eintrage im Arrange + // nicht beruecksichtigt werden. +#if 1 + if( aEntries.Count() ) + aAutoArrangeTimer.Start(); +#else + if( pHead ) + { + // verschobene Eintraege 'hart' auf ihre Position setzen + nCur = nCount; + SvxIconChoiceCtrlEntry* pEntry = pHead; + while( nCur ) + { + SvxIconChoiceCtrlEntry* pPred; + if( GetEntryPredecessor( pEntry, &pPred )) + SetEntryFlags( pEntry, ICNVIEW_FLAG_POS_MOVED ); + pEntry = pEntry->pflink; + nCur--; + } + ClearPredecessors(); + } +#endif + return; + } + + if( ePositionMode == IcnViewPositionModeAutoArrange ) + { + List aMovedEntries; + for( nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nCur ); + if( pEntry->GetFlags() & (ICNVIEW_FLAG_POS_LOCKED | ICNVIEW_FLAG_POS_MOVED)) + { + SvxIconChoiceCtrlEntry_Impl* pE = new SvxIconChoiceCtrlEntry_Impl( + pEntry, GetEntryBoundRect( pEntry )); + aMovedEntries.Insert( pE, LIST_APPEND ); + } + } + nCount = aMovedEntries.Count(); + for( nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry_Impl* pE = (SvxIconChoiceCtrlEntry_Impl*)aMovedEntries.GetObject(nCur); + SetEntryPos( pE->_pEntry, pE->_aPos ); + } + for( nCur = 0; nCur < nCount; nCur++ ) + delete (SvxIconChoiceCtrlEntry_Impl*)aMovedEntries.GetObject( nCur ); + if( aEntries.Count() ) + aAutoArrangeTimer.Start(); + } + else if( ePositionMode == IcnViewPositionModeAutoAdjust ) + { + AdjustEntryAtGrid( 0 ); + } +} + +void SvxIconChoiceCtrl_Impl::SetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry, + SvxIconChoiceCtrlEntry* pPredecessor ) +{ + if( !IsAutoArrange() ) + return; + + if( pEntry == pPredecessor ) + return; + + sal_uLong nPos1 = GetEntryListPos( pEntry ); + if( !pHead ) + { + if( pPredecessor ) + { + sal_uLong nPos2 = GetEntryListPos( pPredecessor ); + if( nPos1 == (nPos2 + 1) ) + return; // ist schon Vorgaenger + } + else if( !nPos1 ) + return; + } + + if( !pHead ) + InitPredecessors(); + + if( !pPredecessor && pHead == pEntry ) + return; // ist schon der Erste + + sal_Bool bSetHead = sal_False; + if( !pPredecessor ) + { + bSetHead = sal_True; + pPredecessor = pHead->pblink; + } + if( pEntry == pHead ) + { + pHead = pHead->pflink; + bSetHead = sal_False; + } + if( pEntry != pPredecessor ) + { + pEntry->Unlink(); + pEntry->SetBacklink( pPredecessor ); + } + if( bSetHead ) + pHead = pEntry; + pEntry->SetFlags( ICNVIEW_FLAG_PRED_SET ); + aAutoArrangeTimer.Start(); +} + +sal_Bool SvxIconChoiceCtrl_Impl::GetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry, + SvxIconChoiceCtrlEntry** ppPredecessor ) +{ + *ppPredecessor = 0; + if( !pHead ) + return sal_False; + DBG_ASSERT(pEntry->pblink,"GetEntryPredecessor: Backward link not set"); + DBG_ASSERT(pEntry->pflink,"GetEntryPredecessor: Forward link not set"); + + if( pEntry == pHead ) + { + SvxIconChoiceCtrlEntry* pFirst = (SvxIconChoiceCtrlEntry*)aEntries.GetObject(0); + if( pFirst != pEntry ) + return sal_True; + return sal_False; + } + *ppPredecessor = pEntry->pblink; + if( !(pEntry->nFlags & ICNVIEW_FLAG_PRED_SET) && + (GetEntryListPos( *ppPredecessor ) + 1) == GetEntryListPos( pEntry )) + return sal_False; + return sal_True; +} + +SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry, + const Point& rPosTopLeft ) +{ + Point aPos( rPosTopLeft ); //TopLeft + Rectangle aCenterRect( CalcBmpRect( pEntry, &aPos )); + Point aNewPos( aCenterRect.Center() ); + sal_uLong nGrid = GetPredecessorGrid( aNewPos ); + sal_uLong nCount = aEntries.Count(); + if( nGrid == ULONG_MAX ) + return 0; + if( nGrid >= nCount ) + nGrid = nCount - 1; + if( !pHead ) + return (SvxIconChoiceCtrlEntry*)aEntries.GetObject( nGrid ); + + SvxIconChoiceCtrlEntry* pCur = pHead; // Grid 0 + // todo: Liste von hinten aufrollen wenn nGrid > nCount/2 + for( sal_uLong nCur = 0; nCur < nGrid; nCur++ ) + pCur = pCur->pflink; + + return pCur; +} + +sal_uLong SvxIconChoiceCtrl_Impl::GetPredecessorGrid( const Point& rPos) const +{ + Point aPos( rPos ); + aPos.X() -= LROFFS_WINBORDER; + aPos.Y() -= TBOFFS_WINBORDER; + sal_uInt16 nMaxCol = (sal_uInt16)(aVirtOutputSize.Width() / nGridDX); + if( nMaxCol ) + nMaxCol--; + sal_uInt16 nGridX = (sal_uInt16)(aPos.X() / nGridDX); + if( nGridX > nMaxCol ) + nGridX = nMaxCol; + sal_uInt16 nGridY = (sal_uInt16)(aPos.Y() / nGridDY); + sal_uInt16 nGridsX = (sal_uInt16)(aOutputSize.Width() / nGridDX); + sal_uLong nGrid = (nGridY * nGridsX) + nGridX; + long nMiddle = (nGridX * nGridDX) + (nGridDX / 2); + if( rPos.X() < nMiddle ) + { + if( !nGrid ) + nGrid = ULONG_MAX; + else + nGrid--; + } + return nGrid; +} + +void SvxIconChoiceCtrl_Impl::Flush() +{ + if( aAutoArrangeTimer.IsActive() ) + { + AutoArrangeHdl( 0 ); + } +} + +sal_Bool SvxIconChoiceCtrl_Impl::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( !(rHEvt.GetMode() & HELPMODE_QUICK ) ) + return sal_False; + + Point aPos( pView->ScreenToOutputPixel(rHEvt.GetMousePosPixel() ) ); + aPos -= pView->GetMapMode().GetOrigin(); + SvxIconChoiceCtrlEntry* pEntry = GetEntry( aPos, sal_True ); + + if ( !pEntry ) + return sal_False; + + String sQuickHelpText = pEntry->GetQuickHelpText(); + String aEntryText( pView->GetEntryText( pEntry, sal_False ) ); + Rectangle aTextRect( CalcTextRect( pEntry, 0, sal_False, &aEntryText ) ); + if ( ( !aTextRect.IsInside( aPos ) || !aEntryText.Len() ) && !sQuickHelpText.Len() ) + return sal_False; + + Rectangle aOptTextRect( aTextRect ); + aOptTextRect.Bottom() = LONG_MAX; + sal_uInt16 nNewFlags = nCurTextDrawFlags; + nNewFlags &= ~( TEXT_DRAW_CLIP | TEXT_DRAW_ENDELLIPSIS ); + aOptTextRect = pView->GetTextRect( aOptTextRect, aEntryText, nNewFlags ); + if ( aOptTextRect != aTextRect || sQuickHelpText.Len() > 0 ) + { + //aTextRect.Right() = aTextRect.Left() + aRealSize.Width() + 4; + Point aPt( aOptTextRect.TopLeft() ); + aPt += pView->GetMapMode().GetOrigin(); + aPt = pView->OutputToScreenPixel( aPt ); + // Border der Tiphilfe abziehen + aPt.Y() -= 1; + aPt.X() -= 3; + aOptTextRect.SetPos( aPt ); + String sHelpText; + if ( sQuickHelpText.Len() > 0 ) + sHelpText = sQuickHelpText; + else + sHelpText = aEntryText; + Help::ShowQuickHelp( (Window*)pView, aOptTextRect, sHelpText, QUICKHELP_LEFT | QUICKHELP_VCENTER ); + } + + return sal_True; +} + +void SvxIconChoiceCtrl_Impl::ClearColumnList() +{ + if( !pColumns ) + return; + + const sal_uInt16 nCount = pColumns->Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlColumnInfo* pInfo = (SvxIconChoiceCtrlColumnInfo*) + pColumns->GetObject( nCur ); + delete pInfo; + } + DELETEZ(pColumns); +} + +void SvxIconChoiceCtrl_Impl::SetColumn( sal_uInt16 nIndex, const SvxIconChoiceCtrlColumnInfo& rInfo) +{ + if( !pColumns ) + pColumns = new SvPtrarr; + while( pColumns->Count() < nIndex + 1 ) + pColumns->Insert( (void*)0, pColumns->Count() ); + + SvxIconChoiceCtrlColumnInfo* pInfo = + (SvxIconChoiceCtrlColumnInfo*)pColumns->GetObject(nIndex); + if( !pInfo ) + { + pInfo = new SvxIconChoiceCtrlColumnInfo( rInfo ); + pColumns->Insert( (void*)pInfo, nIndex ); + } + else + { + delete pInfo; + pInfo = new SvxIconChoiceCtrlColumnInfo( rInfo ); + pColumns->Replace( pInfo, nIndex ); + } + + // HACK(Detail-Modus ist noch nicht vollstaendig implementiert!) + // dieses Workaround bringts mit einer Spalte zum Fliegen + if( !nIndex && (nWinBits & WB_DETAILS) ) + nGridDX = pInfo->GetWidth(); + + if( GetUpdateMode() ) + Arrange( IsAutoArrange() ); +} + +const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetColumn( sal_uInt16 nIndex ) const +{ + if( !pColumns || nIndex >= pColumns->Count() ) + return 0; + return (const SvxIconChoiceCtrlColumnInfo*)pColumns->GetObject( nIndex ); +} + +const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetItemColumn( sal_uInt16 nSubItem, + long& rLeft ) const +{ + rLeft = 0; + if( !pColumns ) + return 0; + const sal_uInt16 nCount = pColumns->Count(); + const SvxIconChoiceCtrlColumnInfo* pCol = 0; + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + pCol = (const SvxIconChoiceCtrlColumnInfo*)pColumns->GetObject( nCur ); + if( !pCol || pCol->GetSubItem() == nSubItem ) + return pCol; + rLeft += pCol->GetWidth(); + } + return pCol; +} + +void SvxIconChoiceCtrl_Impl::DrawHighlightFrame( + OutputDevice* pOut, const Rectangle& rBmpRect, sal_Bool bHide ) +{ + Rectangle aBmpRect( rBmpRect ); + long nBorder = 2; + if( aImageSize.Width() < 32 ) + nBorder = 1; + aBmpRect.Right() += nBorder; + aBmpRect.Left() -= nBorder; + aBmpRect.Bottom() += nBorder; + aBmpRect.Top() -= nBorder; + + if ( bHide ) + pView->Invalidate( aBmpRect ); + else + { + DecorationView aDecoView( pOut ); + sal_uInt16 nDecoFlags; + if ( bHighlightFramePressed ) + nDecoFlags = FRAME_HIGHLIGHT_TESTBACKGROUND | FRAME_HIGHLIGHT_IN; + else + nDecoFlags = FRAME_HIGHLIGHT_TESTBACKGROUND | FRAME_HIGHLIGHT_OUT; + aDecoView.DrawHighlightFrame( aBmpRect, nDecoFlags ); + } +} + +void SvxIconChoiceCtrl_Impl::SetEntryHighlightFrame( SvxIconChoiceCtrlEntry* pEntry, + sal_Bool bKeepHighlightFlags ) +{ + if( pEntry == pCurHighlightFrame ) + return; + + if( !bKeepHighlightFlags ) + bHighlightFramePressed = sal_False; + + HideEntryHighlightFrame(); + pCurHighlightFrame = pEntry; + if( pEntry ) + { + Rectangle aBmpRect( CalcFocusRect(pEntry) ); + DrawHighlightFrame( pView, aBmpRect, sal_False ); + } +} + +void SvxIconChoiceCtrl_Impl::HideEntryHighlightFrame() +{ + if( !pCurHighlightFrame ) + return; + + SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame; + pCurHighlightFrame = 0; + Rectangle aBmpRect( CalcFocusRect(pEntry) ); + DrawHighlightFrame( pView, aBmpRect, sal_True ); +} + +void SvxIconChoiceCtrl_Impl::CallSelectHandler( SvxIconChoiceCtrlEntry* ) +{ + // Bei aktiviertem Single-Click-Modus sollte der Selektionshandler + // synchron gerufen werden, weil die Selektion automatisch + // weggenommen wird, wenn der Mauszeiger nicht mehr das Objekt + // beruehrt. Es kann sonst zu fehlenden Select-Aufrufen kommen, + // wenn das Objekt aus einer Mausbewegung heraus selektiert wird, + // weil beim Ausloesen des Timers der Mauszeiger das Objekt u.U. + // schon verlassen hat. + // Fuer spezielle Faelle (=>SfxFileDialog!) koennen synchrone + // Aufrufe auch per WB_NOASYNCSELECTHDL erzwungen werden. + if( nWinBits & (WB_NOASYNCSELECTHDL | WB_HIGHLIGHTFRAME) ) + { + pHdlEntry = 0; + pView->ClickIcon(); + //pView->Select(); + } + else + aCallSelectHdlTimer.Start(); +} + +IMPL_LINK( SvxIconChoiceCtrl_Impl, CallSelectHdlHdl, void*, EMPTYARG ) +{ + pHdlEntry = 0; + pView->ClickIcon(); + //pView->Select(); + return 0; +} + +Point SvxIconChoiceCtrl_Impl::GetPopupMenuPosPixel() const +{ + Point aResult; + if( !GetSelectionCount() ) + return aResult; + + SvxIconChoiceCtrlEntry* pEntry = GetCurEntry(); + if( !pEntry || !pEntry->IsSelected() ) + { + sal_uLong nNext; + pEntry = GetFirstSelectedEntry( nNext ); + } + if( pEntry ) + { + Rectangle aRect( ((SvxIconChoiceCtrl_Impl*)this)->CalcBmpRect( pEntry ) ); + aResult = aRect.Center(); + aResult = pView->GetPixelPos( aResult ); + } + return aResult; +} + +void SvxIconChoiceCtrl_Impl::SetOrigin( const Point& rPos, sal_Bool bDoNotUpdateWallpaper ) +{ + MapMode aMapMode( pView->GetMapMode() ); + aMapMode.SetOrigin( rPos ); + pView->SetMapMode( aMapMode ); + if( !bDoNotUpdateWallpaper ) + { + sal_Bool bScrollable = pView->GetBackground().IsScrollable(); + if( pView->HasBackground() && !bScrollable ) + { + Rectangle aRect( GetOutputRect()); + Wallpaper aPaper( pView->GetBackground() ); + aPaper.SetRect( aRect ); + pView->SetBackground( aPaper ); + } + } +} + +sal_uLong SvxIconChoiceCtrl_Impl::GetGridCount( const Size& rSize, sal_Bool bCheckScrBars, + sal_Bool bSmartScrBar ) const +{ + Size aSize( rSize ); + if( bCheckScrBars && aHorSBar.IsVisible() ) + aSize.Height() -= nHorSBarHeight; + else if( bSmartScrBar && (nWinBits & WB_ALIGN_LEFT) ) + aSize.Height() -= nHorSBarHeight; + + if( bCheckScrBars && aVerSBar.IsVisible() ) + aSize.Width() -= nVerSBarWidth; + else if( bSmartScrBar && (nWinBits & WB_ALIGN_TOP) ) + aSize.Width() -= nVerSBarWidth; + + if( aSize.Width() < 0 ) + aSize.Width() = 0; + if( aSize.Height() < 0 ) + aSize.Height() = 0; + + return IcnGridMap_Impl::GetGridCount( aSize, (sal_uInt16)nGridDX, (sal_uInt16)nGridDY ); +} + +sal_Bool SvxIconChoiceCtrl_Impl::HandleShortCutKey( const KeyEvent& rKEvt ) +{ + StopEditTimer(); + + sal_Bool bRet = sal_False; + + DBG_ASSERT( rKEvt.GetKeyCode().IsMod2(), "*SvxIconChoiceCtrl_Impl::HandleShortCutKey(): no <ALT> pressed!?" ); + + sal_Unicode cChar = rKEvt.GetCharCode(); + sal_uLong nPos = (sal_uLong)-1; + + if( cChar && IsMnemonicChar( cChar, nPos ) ) + { + // shortcut is clicked + SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos ); + SvxIconChoiceCtrlEntry* pOldCursor = pCursor; + if( pNewCursor != pOldCursor ) + { + SetCursor_Impl( pOldCursor, pNewCursor, sal_False, sal_False, sal_False ); + + if( pNewCursor != NULL ) + { + pHdlEntry = pNewCursor; + pCurHighlightFrame = pHdlEntry; + pView->ClickIcon(); + pCurHighlightFrame = NULL; + } + } + bRet = sal_True; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +void SvxIconChoiceCtrl_Impl::CallEventListeners( sal_uLong nEvent, void* pData ) +{ + pView->CallImplEventListeners( nEvent, pData ); +} + + diff --git a/svtools/source/contnr/imivctl2.cxx b/svtools/source/contnr/imivctl2.cxx new file mode 100644 index 000000000000..539477c03599 --- /dev/null +++ b/svtools/source/contnr/imivctl2.cxx @@ -0,0 +1,848 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" +#include "imivctl.hxx" + +IcnCursor_Impl::IcnCursor_Impl( SvxIconChoiceCtrl_Impl* pOwner ) +{ + pView = pOwner; + pColumns = 0; + pRows = 0; + pCurEntry = 0; + nDeltaWidth = 0; + nDeltaHeight= 0; + nCols = 0; + nRows = 0; +} + +IcnCursor_Impl::~IcnCursor_Impl() +{ + delete[] pColumns; + delete[] pRows; +} + +sal_uInt16 IcnCursor_Impl::GetSortListPos( SvPtrarr* pList, long nValue, + int bVertical ) +{ + sal_uInt16 nCount = (sal_uInt16)pList->Count(); + if( !nCount ) + return 0; + + sal_uInt16 nCurPos = 0; + long nPrevValue = LONG_MIN; + while( nCount ) + { + const Rectangle& rRect= + pView->GetEntryBoundRect((SvxIconChoiceCtrlEntry*)(pList->GetObject(nCurPos))); + long nCurValue; + if( bVertical ) + nCurValue = rRect.Top(); + else + nCurValue = rRect.Left(); + if( nValue >= nPrevValue && nValue <= nCurValue ) + return (sal_uInt16)nCurPos; + nPrevValue = nCurValue; + nCount--; + nCurPos++; + } + return pList->Count(); +} + +void IcnCursor_Impl::ImplCreate() +{ + pView->CheckBoundingRects(); + DBG_ASSERT(pColumns==0&&pRows==0,"ImplCreate: Not cleared"); + + SetDeltas(); + + pColumns = new SvPtrarr[ nCols ]; + pRows = new SvPtrarr[ nRows ]; + + sal_uLong nCount = pView->aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nCur ); + // const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + Rectangle rRect( pView->CalcBmpRect( pEntry,0 ) ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / nDeltaHeight ); + short nX = (short)( ((rRect.Left()+rRect.Right())/2) / nDeltaWidth ); + + // Rundungsfehler abfangen + if( nY >= nRows ) + nY = sal::static_int_cast< short >(nRows - 1); + if( nX >= nCols ) + nX = sal::static_int_cast< short >(nCols - 1); + + sal_uInt16 nIns = GetSortListPos( &pColumns[nX], rRect.Top(), sal_True ); + pColumns[ nX ].Insert( pEntry, nIns ); + + nIns = GetSortListPos( &pRows[nY], rRect.Left(), sal_False ); + pRows[ nY ].Insert( pEntry, nIns ); + + pEntry->nX = nX; + pEntry->nY = nY; + } +} + + + + +void IcnCursor_Impl::Clear() +{ + if( pColumns ) + { + delete[] pColumns; + delete[] pRows; + pColumns = 0; + pRows = 0; + pCurEntry = 0; + nDeltaWidth = 0; + nDeltaHeight = 0; + } +} + +SvxIconChoiceCtrlEntry* IcnCursor_Impl::SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom, + sal_uInt16, sal_Bool bDown, sal_Bool bSimple ) +{ + DBG_ASSERT(pCurEntry,"SearchCol: No reference entry"); + SvPtrarr* pList = &(pColumns[ nCol ]); + const sal_uInt16 nCount = pList->Count(); + if( !nCount ) + return 0; + + const Rectangle& rRefRect = pView->GetEntryBoundRect(pCurEntry); + + if( bSimple ) + { + sal_uInt16 nListPos = pList->GetPos( pCurEntry ); + DBG_ASSERT(nListPos!=0xffff,"Entry not in Col-List"); + if( bDown ) + { + while( nListPos < nCount-1 ) + { + nListPos++; + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + if( rRect.Top() > rRefRect.Top() ) + return pEntry; + } + return 0; + } + else + { + while( nListPos ) + { + nListPos--; + if( nListPos < nCount ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + if( rRect.Top() < rRefRect.Top() ) + return pEntry; + } + } + return 0; + } + } + + if( nTop > nBottom ) + { + sal_uInt16 nTemp = nTop; + nTop = nBottom; + nBottom = nTemp; + } + long nMinDistance = LONG_MAX; + SvxIconChoiceCtrlEntry* pResult = 0; + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pList->GetObject( nCur )); + if( pEntry != pCurEntry ) + { + sal_uInt16 nY = pEntry->nY; + if( nY >= nTop && nY <= nBottom ) + { + const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + long nDistance = rRect.Top() - rRefRect.Top(); + if( nDistance < 0 ) + nDistance *= -1; + if( nDistance && nDistance < nMinDistance ) + { + nMinDistance = nDistance; + pResult = pEntry; + } + } + } + } + return pResult; +} + +SvxIconChoiceCtrlEntry* IcnCursor_Impl::SearchRow(sal_uInt16 nRow,sal_uInt16 nLeft,sal_uInt16 nRight, + sal_uInt16, sal_Bool bRight, sal_Bool bSimple ) +{ + DBG_ASSERT(pCurEntry,"SearchRow: No reference entry"); + SvPtrarr* pList = &(pRows[ nRow ]); + const sal_uInt16 nCount = pList->Count(); + if( !nCount ) + return 0; + + const Rectangle& rRefRect = pView->GetEntryBoundRect(pCurEntry); + + if( bSimple ) + { + sal_uInt16 nListPos = pList->GetPos( pCurEntry ); + DBG_ASSERT(nListPos!=0xffff,"Entry not in Row-List"); + if( bRight ) + { + while( nListPos < nCount-1 ) + { + nListPos++; + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + if( rRect.Left() > rRefRect.Left() ) + return pEntry; + } + return 0; + } + else + { + while( nListPos ) + { + nListPos--; + if( nListPos < nCount ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + if( rRect.Left() < rRefRect.Left() ) + return pEntry; + } + } + return 0; + } + + } + if( nRight < nLeft ) + { + sal_uInt16 nTemp = nRight; + nRight = nLeft; + nLeft = nTemp; + } + long nMinDistance = LONG_MAX; + SvxIconChoiceCtrlEntry* pResult = 0; + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)(pList->GetObject( nCur )); + if( pEntry != pCurEntry ) + { + sal_uInt16 nX = pEntry->nX; + if( nX >= nLeft && nX <= nRight ) + { + const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + long nDistance = rRect.Left() - rRefRect.Left(); + if( nDistance < 0 ) + nDistance *= -1; + if( nDistance && nDistance < nMinDistance ) + { + nMinDistance = nDistance; + pResult = pEntry; + } + } + } + } + return pResult; +} + + + +/* + Sucht ab dem uebergebenen Eintrag den naechsten rechts- bzw. + linksstehenden. Suchverfahren am Beispiel bRight = sal_True: + + c + b c + a b c + S 1 1 1 ====> Suchrichtung + a b c + b c + c + + S : Startposition + 1 : erstes Suchrechteck + a,b,c : 2., 3., 4. Suchrechteck +*/ + +SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoLeftRight( SvxIconChoiceCtrlEntry* pCtrlEntry, sal_Bool bRight ) +{ + SvxIconChoiceCtrlEntry* pResult; + pCurEntry = pCtrlEntry; + Create(); + sal_uInt16 nY = pCtrlEntry->nY; + sal_uInt16 nX = pCtrlEntry->nX; + DBG_ASSERT(nY< nRows,"GoLeftRight:Bad column"); + DBG_ASSERT(nX< nCols,"GoLeftRight:Bad row"); + // Nachbar auf gleicher Zeile ? + if( bRight ) + pResult = SearchRow( + nY, nX, sal::static_int_cast< sal_uInt16 >(nCols-1), nX, sal_True, sal_True ); + else + pResult = SearchRow( nY, nX ,0, nX, sal_False, sal_True ); + if( pResult ) + return pResult; + + long nCurCol = nX; + + long nColOffs, nLastCol; + if( bRight ) + { + nColOffs = 1; + nLastCol = nCols; + } + else + { + nColOffs = -1; + nLastCol = -1; // 0-1 + } + + sal_uInt16 nRowMin = nY; + sal_uInt16 nRowMax = nY; + do + { + SvxIconChoiceCtrlEntry* pEntry = SearchCol((sal_uInt16)nCurCol,nRowMin,nRowMax,nY,sal_True, sal_False); + if( pEntry ) + return pEntry; + if( nRowMin ) + nRowMin--; + if( nRowMax < (nRows-1)) + nRowMax++; + nCurCol += nColOffs; + } while( nCurCol != nLastCol ); + return 0; +} + +SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoPageUpDown( SvxIconChoiceCtrlEntry* pStart, sal_Bool bDown) +{ + if( pView->IsAutoArrange() && !(pView->nWinBits & WB_ALIGN_TOP) ) + { + const long nPos = (long)pView->GetEntryListPos( pStart ); + long nEntriesInView = (pView->aOutputSize.Height() / pView->nGridDY); + nEntriesInView *= + ((pView->aOutputSize.Width()+(pView->nGridDX/2)) / pView->nGridDX ); + long nNewPos = nPos; + if( bDown ) + { + nNewPos += nEntriesInView; + if( nNewPos >= (long)pView->aEntries.Count() ) + nNewPos = pView->aEntries.Count() - 1; + } + else + { + nNewPos -= nEntriesInView; + if( nNewPos < 0 ) + nNewPos = 0; + } + if( nPos != nNewPos ) + return (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( (sal_uLong)nNewPos ); + return 0; + } + long nOpt = pView->GetEntryBoundRect( pStart ).Top(); + if( bDown ) + { + nOpt += pView->aOutputSize.Height(); + nOpt -= pView->nGridDY; + } + else + { + nOpt -= pView->aOutputSize.Height(); + nOpt += pView->nGridDY; + } + if( nOpt < 0 ) + nOpt = 0; + + long nPrevErr = LONG_MAX; + + SvxIconChoiceCtrlEntry* pPrev = pStart; + SvxIconChoiceCtrlEntry* pNext = GoUpDown( pStart, bDown ); + while( pNext ) + { + long nCur = pView->GetEntryBoundRect( pNext ).Top(); + long nErr = nOpt - nCur; + if( nErr < 0 ) + nErr *= -1; + if( nErr > nPrevErr ) + return pPrev; + nPrevErr = nErr; + pPrev = pNext; + pNext = GoUpDown( pNext, bDown ); + } + if( pPrev != pStart ) + return pPrev; + return 0; +} + +SvxIconChoiceCtrlEntry* IcnCursor_Impl::GoUpDown( SvxIconChoiceCtrlEntry* pCtrlEntry, sal_Bool bDown) +{ + if( pView->IsAutoArrange() && !(pView->nWinBits & WB_ALIGN_TOP) ) + { + sal_uLong nPos = pView->GetEntryListPos( pCtrlEntry ); + if( bDown && nPos < (pView->aEntries.Count() - 1) ) + return (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nPos + 1 ); + else if( !bDown && nPos > 0 ) + return (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nPos - 1 ); + return 0; + } + + SvxIconChoiceCtrlEntry* pResult; + pCurEntry = pCtrlEntry; + Create(); + sal_uInt16 nY = pCtrlEntry->nY; + sal_uInt16 nX = pCtrlEntry->nX; + DBG_ASSERT(nY<nRows,"GoUpDown:Bad column"); + DBG_ASSERT(nX<nCols,"GoUpDown:Bad row"); + + // Nachbar in gleicher Spalte ? + if( bDown ) + pResult = SearchCol( + nX, nY, sal::static_int_cast< sal_uInt16 >(nRows-1), nY, sal_True, sal_True ); + else + pResult = SearchCol( nX, nY ,0, nY, sal_False, sal_True ); + if( pResult ) + return pResult; + + long nCurRow = nY; + + long nRowOffs, nLastRow; + if( bDown ) + { + nRowOffs = 1; + nLastRow = nRows; + } + else + { + nRowOffs = -1; + nLastRow = -1; // 0-1 + } + + sal_uInt16 nColMin = nX; + sal_uInt16 nColMax = nX; + do + { + SvxIconChoiceCtrlEntry* pEntry = SearchRow((sal_uInt16)nCurRow,nColMin,nColMax,nX,sal_True, sal_False); + if( pEntry ) + return pEntry; + if( nColMin ) + nColMin--; + if( nColMax < (nCols-1)) + nColMax++; + nCurRow += nRowOffs; + } while( nCurRow != nLastRow ); + return 0; +} + +void IcnCursor_Impl::SetDeltas() +{ + const Size& rSize = pView->aVirtOutputSize; + nCols = rSize.Width() / pView->nGridDX; + if( !nCols ) + nCols = 1; + nRows = rSize.Height() / pView->nGridDY; + if( (nRows * pView->nGridDY) < rSize.Height() ) + nRows++; + if( !nRows ) + nRows = 1; + + nDeltaWidth = (short)(rSize.Width() / nCols); + nDeltaHeight = (short)(rSize.Height() / nRows); + if( !nDeltaHeight ) + { + nDeltaHeight = 1; + DBG_WARNING("SetDeltas:Bad height"); + } + if( !nDeltaWidth ) + { + nDeltaWidth = 1; + DBG_WARNING("SetDeltas:Bad width"); + } +} + +void IcnCursor_Impl::CreateGridAjustData( SvPtrarr& rLists, SvxIconChoiceCtrlEntry* pRefEntry) +{ + if( !pRefEntry ) + { + sal_uInt16 nGridRows = (sal_uInt16)(pView->aVirtOutputSize.Height() / pView->nGridDY); + nGridRows++; // wg. Abrundung! + + if( !nGridRows ) + return; + for( sal_uInt16 nCurList = 0; nCurList < nGridRows; nCurList++ ) + { + SvPtrarr* pRow = new SvPtrarr; + rLists.Insert( (void*)pRow, nCurList ); + } + const sal_uLong nCount = pView->aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nCur ); + const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); + sal_uInt16 nIns = GetSortListPos((SvPtrarr*)rLists[nY],rRect.Left(),sal_False); + ((SvPtrarr*)rLists[ nY ])->Insert( pEntry, nIns ); + } + } + else + { + // Aufbau eines hor. "Schlauchs" auf der RefEntry-Zeile + // UEBERLEGEN: BoundingRect nehmen wg. Ueberlappungen??? + Rectangle rRefRect( pView->CalcBmpRect( pRefEntry ) ); + //const Rectangle& rRefRect = pView->GetEntryBoundRect( pRefEntry ); + short nRefRow = (short)( ((rRefRect.Top()+rRefRect.Bottom())/2) / pView->nGridDY ); + SvPtrarr* pRow = new SvPtrarr; + rLists.Insert( (void*)pRow, 0 ); + sal_uLong nCount = pView->aEntries.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvxIconChoiceCtrlEntry* pEntry = (SvxIconChoiceCtrlEntry*)pView->aEntries.GetObject( nCur ); + Rectangle rRect( pView->CalcBmpRect(pEntry) ); + //const Rectangle& rRect = pView->GetEntryBoundRect( pEntry ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); + if( nY == nRefRow ) + { + sal_uInt16 nIns = GetSortListPos( pRow, rRect.Left(), sal_False ); + pRow->Insert( pEntry, nIns ); + } + } + } +} + +//static +void IcnCursor_Impl::DestroyGridAdjustData( SvPtrarr& rLists ) +{ + const sal_uInt16 nCount = rLists.Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvPtrarr* pArr = (SvPtrarr*)rLists[ nCur ]; + delete pArr; + } + rLists.Remove( 0, rLists.Count() ); +} + +IcnGridMap_Impl::IcnGridMap_Impl(SvxIconChoiceCtrl_Impl* pView) +{ + _pView = pView; + _pGridMap = 0; + _nGridCols = 0; + _nGridRows = 0; +} + +IcnGridMap_Impl::~IcnGridMap_Impl() +{ + delete[] _pGridMap, _pGridMap=0; +} + +void IcnGridMap_Impl::Expand() +{ + if( !_pGridMap ) + Create_Impl(); + else + { + sal_uInt16 nNewGridRows = _nGridRows; + sal_uInt16 nNewGridCols = _nGridCols; + if( _pView->nWinBits & WB_ALIGN_TOP ) + nNewGridRows += 50; + else + nNewGridCols += 50; + + sal_Bool* pNewGridMap = new sal_Bool[nNewGridRows*nNewGridCols]; + memset( pNewGridMap, 0, nNewGridRows * nNewGridCols * sizeof(sal_Bool) ); + memcpy( pNewGridMap, _pGridMap, _nGridRows * _nGridCols * sizeof(sal_Bool) ); + delete[] _pGridMap; + _pGridMap = pNewGridMap; + _nGridRows = nNewGridRows; + _nGridCols = nNewGridCols; + } +} + +void IcnGridMap_Impl::Create_Impl() +{ + DBG_ASSERT(!_pGridMap,"Unnecessary call to IcnGridMap_Impl::Create_Impl()"); + if( _pGridMap ) + return; + GetMinMapSize( _nGridCols, _nGridRows ); + if( _pView->nWinBits & WB_ALIGN_TOP ) + _nGridRows += 50; // avoid resize of gridmap too often + else + _nGridCols += 50; + + _pGridMap = new sal_Bool[ _nGridRows * _nGridCols]; + memset( (void*)_pGridMap, 0, _nGridRows * _nGridCols ); + + const sal_uLong nCount = _pView->aEntries.Count(); + for( sal_uLong nCur=0; nCur < nCount; nCur++ ) + OccupyGrids( (SvxIconChoiceCtrlEntry*)_pView->aEntries.GetObject( nCur )); +} + +void IcnGridMap_Impl::GetMinMapSize( sal_uInt16& rDX, sal_uInt16& rDY ) const +{ + long nX, nY; + if( _pView->nWinBits & WB_ALIGN_TOP ) + { + // The view grows in vertical direction. Its max. width is _pView->nMaxVirtWidth + nX = _pView->nMaxVirtWidth; + if( !nX ) + nX = _pView->pView->GetOutputSizePixel().Width(); + if( !(_pView->nFlags & F_ARRANGING) ) + nX -= _pView->nVerSBarWidth; + + nY = _pView->aVirtOutputSize.Height(); + } + else + { + // The view grows in horizontal direction. Its max. height is _pView->nMaxVirtHeight + nY = _pView->nMaxVirtHeight; + if( !nY ) + nY = _pView->pView->GetOutputSizePixel().Height(); + if( !(_pView->nFlags & F_ARRANGING) ) + nY -= _pView->nHorSBarHeight; + nX = _pView->aVirtOutputSize.Width(); + } + + if( !nX ) + nX = DEFAULT_MAX_VIRT_WIDTH; + if( !nY ) + nY = DEFAULT_MAX_VIRT_HEIGHT; + + long nDX = nX / _pView->nGridDX; + long nDY = nY / _pView->nGridDY; + + if( !nDX ) + nDX++; + if( !nDY ) + nDY++; + + rDX = (sal_uInt16)nDX; + rDY = (sal_uInt16)nDY; +} + +GridId IcnGridMap_Impl::GetGrid( sal_uInt16 nGridX, sal_uInt16 nGridY ) +{ + Create(); + if( _pView->nWinBits & WB_ALIGN_TOP ) + return nGridX + ( nGridY * _nGridCols ); + else + return nGridY + ( nGridX * _nGridRows ); +} + +GridId IcnGridMap_Impl::GetGrid( const Point& rDocPos, sal_Bool* pbClipped ) +{ + Create(); + + long nX = rDocPos.X(); + long nY = rDocPos.Y(); + nX -= LROFFS_WINBORDER; + nY -= TBOFFS_WINBORDER; + nX /= _pView->nGridDX; + nY /= _pView->nGridDY; + sal_Bool bClipped = sal_False; + if( nX >= _nGridCols ) + { + nX = _nGridCols - 1; + bClipped = sal_True; + } + if( nY >= _nGridRows ) + { + nY = _nGridRows - 1; + bClipped = sal_True; + } + GridId nId = GetGrid( (sal_uInt16)nX, (sal_uInt16)nY ); + if( pbClipped ) + *pbClipped = bClipped; + DBG_ASSERT(nId <(sal_uLong)(_nGridCols*_nGridRows),"GetGrid failed"); + return nId; +} + +Rectangle IcnGridMap_Impl::GetGridRect( GridId nId ) +{ + Create(); + sal_uInt16 nGridX, nGridY; + GetGridCoord( nId, nGridX, nGridY ); + const long nLeft = nGridX * _pView->nGridDX+ LROFFS_WINBORDER; + const long nTop = nGridY * _pView->nGridDY + TBOFFS_WINBORDER; + return Rectangle( + nLeft, nTop, + nLeft + _pView->nGridDX, + nTop + _pView->nGridDY ); +} + +GridId IcnGridMap_Impl::GetUnoccupiedGrid( sal_Bool bOccupyFound ) +{ + Create(); + sal_uLong nStart = 0; + sal_Bool bExpanded = sal_False; + + while( 1 ) + { + const sal_uLong nCount = (sal_uInt16)(_nGridCols * _nGridRows); + for( sal_uLong nCur = nStart; nCur < nCount; nCur++ ) + { + if( !_pGridMap[ nCur ] ) + { + if( bOccupyFound ) + _pGridMap[ nCur ] = sal_True; + return (GridId)nCur; + } + } + DBG_ASSERT(!bExpanded,"ExpandGrid failed"); + if( bExpanded ) + return 0; // prevent never ending loop + bExpanded = sal_True; + Expand(); + nStart = nCount; + } +} + +// ein Eintrag belegt nur das unter seinem Zentrum liegende GridRect +// diese Variante ist bedeutend schneller als die Belegung ueber das +// Bounding-Rect, kann aber zu kleinen Ueberlappungen fuehren +#define OCCUPY_CENTER + +void IcnGridMap_Impl::OccupyGrids( const SvxIconChoiceCtrlEntry* pEntry, sal_Bool bOccupy ) +{ + if( !_pGridMap || !_pView->IsBoundingRectValid( pEntry->aRect )) + return; +#ifndef OCCUPY_CENTER + OccupyGrids( pEntry->aRect, bOccupy ); +#else + OccupyGrid( GetGrid( pEntry->aRect.Center()), bOccupy ); +#endif + +} + +void IcnGridMap_Impl::OccupyGrids( const Rectangle& rRect, sal_Bool bUsed ) +{ + if( !_pGridMap ) + return; + + if( bUsed ) + { + if( _aLastOccupiedGrid == rRect ) + return; + _aLastOccupiedGrid = rRect; + } + else + _aLastOccupiedGrid.SetEmpty(); + + sal_Bool bTopLeftClipped, bBottomRightClipped; + GridId nIdTL = GetGrid( rRect.TopLeft(), &bTopLeftClipped ); + GridId nIdBR = GetGrid( rRect.BottomRight(), &bBottomRightClipped ); + + if( bTopLeftClipped && bBottomRightClipped ) + return; + + sal_uInt16 nX1,nX2,nY1,nY2; + GetGridCoord( nIdTL, nX1, nY1 ); + GetGridCoord( nIdBR, nX2, nY2 ); + sal_uInt16 nTemp; + if( nX1 > nX2 ) + { + nTemp = nX1; + nX1 = nX2; + nX2 = nTemp; + } + if( nY1 > nY2 ) + { + nTemp = nY1; + nY1 = nY2; + nY2 = nTemp; + } + for( ; nX1 <= nX2; nX1++ ) + for( ; nY1 <= nY2; nY1++ ) + OccupyGrid( GetGrid( nX1, nY1 ) ); +} + +void IcnGridMap_Impl::Clear() +{ + if( _pGridMap ) + { + delete[] _pGridMap, _pGridMap=0; + _nGridRows = 0; + _nGridCols = 0; + _aLastOccupiedGrid.SetEmpty(); + } +} + +sal_uLong IcnGridMap_Impl::GetGridCount( const Size& rSizePixel, sal_uInt16 nDX, sal_uInt16 nDY) +{ + long ndx = (rSizePixel.Width() - LROFFS_WINBORDER) / nDX; + if( ndx < 0 ) ndx *= -1; + long ndy = (rSizePixel.Height() - TBOFFS_WINBORDER) / nDY; + if( ndy < 0 ) ndy *= -1; + return (sal_uLong)(ndx * ndy); +} + +void IcnGridMap_Impl::OutputSizeChanged() +{ + if( _pGridMap ) + { + sal_uInt16 nCols, nRows; + GetMinMapSize( nCols, nRows ); + if( _pView->nWinBits & WB_ALIGN_TOP ) + { + if( nCols != _nGridCols ) + Clear(); + else if( nRows >= _nGridRows ) + Expand(); + } + else + { + if( nRows != _nGridRows ) + Clear(); + else if( nCols >= _nGridCols ) + Expand(); + } + } +} + +// Independendly of the views alignment (TOP or LEFT) the gridmap +// should contain the data in a continues region, to make it possible +// to copy the whole block if the gridmap needs to be expanded. +void IcnGridMap_Impl::GetGridCoord( GridId nId, sal_uInt16& rGridX, sal_uInt16& rGridY ) +{ + Create(); + if( _pView->nWinBits & WB_ALIGN_TOP ) + { + rGridX = (sal_uInt16)(nId % _nGridCols); + rGridY = (sal_uInt16)(nId / _nGridCols); + } + else + { + rGridX = (sal_uInt16)(nId / _nGridRows); + rGridY = (sal_uInt16)(nId % _nGridRows); + } +} + + + diff --git a/svtools/source/contnr/ivctrl.cxx b/svtools/source/contnr/ivctrl.cxx new file mode 100644 index 000000000000..8a94d3ff086b --- /dev/null +++ b/svtools/source/contnr/ivctrl.cxx @@ -0,0 +1,639 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <svtools/ivctrl.hxx> +#include "imivctl.hxx" +#include <vcl/bitmapex.hxx> +#include <vcl/controllayout.hxx> +#include <vcl/mnemonic.hxx> +using namespace ::com::sun::star::accessibility; + +/***************************************************************************** +| +| class : SvxIconChoiceCtrlEntry +| +\*****************************************************************************/ + +SvxIconChoiceCtrlEntry::SvxIconChoiceCtrlEntry( const String& rText, const Image& rImage, sal_uInt16 _nFlags ) +{ + aText = rText; + aImage = rImage; + aImageHC = rImage; + pUserData = NULL; + + nFlags = _nFlags; + eTextMode = IcnShowTextShort; + pblink = 0; + pflink = 0; +} + +SvxIconChoiceCtrlEntry::SvxIconChoiceCtrlEntry( const String& rText, const Image& rImage, const Image& rImageHC, sal_uInt16 _nFlags ) +{ + aText = rText; + aImage = rImage; + aImageHC = rImageHC; + pUserData = NULL; + + nFlags = _nFlags; + eTextMode = IcnShowTextShort; + pblink = 0; + pflink = 0; +} + +SvxIconChoiceCtrlEntry::SvxIconChoiceCtrlEntry( sal_uInt16 _nFlags ) +{ + pUserData = NULL; + + nFlags = _nFlags; + eTextMode = IcnShowTextShort; + pblink = 0; + pflink = 0; +} + +void SvxIconChoiceCtrlEntry::SetMoved( sal_Bool bMoved ) +{ + if( bMoved ) + nFlags |= ICNVIEW_FLAG_POS_MOVED; + else + nFlags &= ~ICNVIEW_FLAG_POS_MOVED; +} + +void SvxIconChoiceCtrlEntry::LockPos( sal_Bool bLock ) +{ + if( bLock ) + nFlags |= ICNVIEW_FLAG_POS_LOCKED; + else + nFlags &= ~ICNVIEW_FLAG_POS_LOCKED; +} + +/*sal_Unicode SvxIconChoiceCtrlEntry::GetMnemonicChar() const +{ + sal_Unicode cChar = 0; + xub_StrLen nPos = aText.Search( '~' ); + if ( nPos != STRING_NOTFOUND && nPos < ( aText.Len() ) - 1 ) + cChar = aText.GetChar( nPos + 1 ); + return cChar; +}*/ + +String SvxIconChoiceCtrlEntry::GetDisplayText() const +{ + return MnemonicGenerator::EraseAllMnemonicChars( aText ); +} + +// ---------------------------------------------------------------------------- + +SvxIconChoiceCtrlColumnInfo::SvxIconChoiceCtrlColumnInfo( const SvxIconChoiceCtrlColumnInfo& rInfo ) + : aColText( rInfo.aColText ), aColImage( rInfo.aColImage ) +{ + nWidth = rInfo.nWidth; + eAlignment = rInfo.eAlignment; + nSubItem = rInfo.nSubItem; +} + +/***************************************************************************** +| +| class : SvtIconChoiceCtrl +| +\*****************************************************************************/ + +SvtIconChoiceCtrl::SvtIconChoiceCtrl( Window* pParent, WinBits nWinStyle ) : + + // WB_CLIPCHILDREN an, da ScrollBars auf dem Fenster liegen! + Control( pParent, nWinStyle | WB_CLIPCHILDREN ), + + _pCurKeyEvent ( NULL ), + _pImp ( new SvxIconChoiceCtrl_Impl( this, nWinStyle ) ), + _bAutoFontColor ( sal_False ) + +{ + SetLineColor(); + _pImp->SetGrid( Size( 100, 70 ) ); + _pImp->InitSettings(); + _pImp->SetPositionMode( IcnViewPositionModeAutoArrange ); +} + +SvtIconChoiceCtrl::SvtIconChoiceCtrl( Window* pParent, const ResId& rResId ) : + + Control( pParent, rResId ), + + _pCurKeyEvent ( NULL ), + _pImp ( new SvxIconChoiceCtrl_Impl( this, WB_BORDER ) ), + _bAutoFontColor ( sal_False ) + +{ + SetLineColor(); + _pImp->SetGrid( Size( 100, 70 ) ); + _pImp->InitSettings(); + _pImp->SetPositionMode( IcnViewPositionModeAutoArrange ); +} + +SvtIconChoiceCtrl::~SvtIconChoiceCtrl() +{ + _pImp->CallEventListeners( VCLEVENT_OBJECT_DYING ); + delete _pImp; +} + +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::InsertEntry( sal_uLong nPos, const Point* pPos, sal_uInt16 nFlags ) +{ + SvxIconChoiceCtrlEntry* pEntry = new SvxIconChoiceCtrlEntry( nFlags ); + _pImp->InsertEntry( pEntry, nPos, pPos ); + return pEntry; +} + +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::InsertEntry( const String& rText, const Image& rImage, sal_uLong nPos, const Point* pPos, sal_uInt16 nFlags ) +{ + SvxIconChoiceCtrlEntry* pEntry = new SvxIconChoiceCtrlEntry( rText, rImage, nFlags); + + _pImp->InsertEntry( pEntry, nPos, pPos ); + + return pEntry; +} + +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::InsertEntry( const String& rText, const Image& rImage, const Image& rImageHC, sal_uLong nPos, const Point* pPos, sal_uInt16 nFlags ) +{ + SvxIconChoiceCtrlEntry* pEntry = new SvxIconChoiceCtrlEntry( rText, rImage, rImageHC, nFlags); + + _pImp->InsertEntry( pEntry, nPos, pPos ); + + return pEntry; +} + +sal_Bool SvtIconChoiceCtrl::EditedEntry( SvxIconChoiceCtrlEntry*, const XubString&, sal_Bool ) +{ + return sal_True; +} +sal_Bool SvtIconChoiceCtrl::EditingEntry( SvxIconChoiceCtrlEntry* ) +{ + return sal_True; +} +void SvtIconChoiceCtrl::DrawEntryImage( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, OutputDevice& rDev ) +{ + rDev.DrawImage( rPos, GetSettings().GetStyleSettings().GetHighContrastMode() ? pEntry->GetImageHC() : pEntry->GetImage() ); +} +String SvtIconChoiceCtrl::GetEntryText( SvxIconChoiceCtrlEntry* pEntry, sal_Bool ) +{ + return pEntry->GetText(); +} +sal_Bool SvtIconChoiceCtrl::HasBackground() const +{ + return sal_False; +} +sal_Bool SvtIconChoiceCtrl::HasFont() const +{ + return sal_False; +} +sal_Bool SvtIconChoiceCtrl::HasFontTextColor() const +{ + return sal_True; +} +sal_Bool SvtIconChoiceCtrl::HasFontFillColor() const +{ + return sal_True; +} + +void SvtIconChoiceCtrl::Paint( const Rectangle& rRect ) +{ + _pImp->Paint( rRect ); +} + +void SvtIconChoiceCtrl::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if( !_pImp->MouseButtonDown( rMEvt ) ) + Control::MouseButtonDown( rMEvt ); +} + +void SvtIconChoiceCtrl::MouseButtonUp( const MouseEvent& rMEvt ) +{ + if( !_pImp->MouseButtonUp( rMEvt ) ) + Control::MouseButtonUp( rMEvt ); +} + +void SvtIconChoiceCtrl::MouseMove( const MouseEvent& rMEvt ) +{ + if( !_pImp->MouseMove( rMEvt ) ) + Control::MouseMove( rMEvt ); +} +void SvtIconChoiceCtrl::ArrangeIcons() +{ + if ( GetStyle() & WB_ALIGN_TOP ) + { + Size aFullSize; + Rectangle aEntryRect; + + for ( sal_uLong i = 0; i < GetEntryCount(); i++ ) + { + SvxIconChoiceCtrlEntry* pEntry = GetEntry ( i ); + aEntryRect = _pImp->GetEntryBoundRect ( pEntry ); + + aFullSize.setWidth ( aFullSize.getWidth()+aEntryRect.GetWidth() ); + } + + _pImp->Arrange ( sal_False, aFullSize.getWidth() ); + } + else if ( GetStyle() & WB_ALIGN_LEFT ) + { + Size aFullSize; + Rectangle aEntryRect; + + for ( sal_uLong i = 0; i < GetEntryCount(); i++ ) + { + SvxIconChoiceCtrlEntry* pEntry = GetEntry ( i ); + aEntryRect = _pImp->GetEntryBoundRect ( pEntry ); + + aFullSize.setHeight ( aFullSize.getHeight()+aEntryRect.GetHeight() ); + } + + _pImp->Arrange ( sal_False, 0, aFullSize.getHeight() ); + } + else + { + _pImp->Arrange(); + } + _pImp->Arrange( sal_False, 0, 1000 ); +} +void SvtIconChoiceCtrl::Resize() +{ + _pImp->Resize(); + Control::Resize(); +} + +Point SvtIconChoiceCtrl::GetLogicPos( const Point& rPosPixel ) const +{ + Point aPos( rPosPixel ); + aPos -= GetMapMode().GetOrigin(); + return aPos; +} + +Point SvtIconChoiceCtrl::GetPixelPos( const Point& rPosLogic ) const +{ + Point aPos( rPosLogic ); + aPos += GetMapMode().GetOrigin(); + return aPos; +} + +void SvtIconChoiceCtrl::DocumentRectChanged() +{ + _aDocRectChangedHdl.Call( this ); +} + +void SvtIconChoiceCtrl::VisibleRectChanged() +{ + _aVisRectChangedHdl.Call( this ); +} + +void SvtIconChoiceCtrl::GetFocus() +{ + _pImp->GetFocus(); + Control::GetFocus(); + sal_uLong nPos; + SvxIconChoiceCtrlEntry* pSelectedEntry = GetSelectedEntry ( nPos ); + if ( pSelectedEntry ) + _pImp->CallEventListeners( VCLEVENT_LISTBOX_SELECT, pSelectedEntry ); +} + +void SvtIconChoiceCtrl::LoseFocus() +{ + _pImp->LoseFocus(); + Control::LoseFocus(); +} + +void SvtIconChoiceCtrl::SetUpdateMode( sal_Bool bUpdate ) +{ + Control::SetUpdateMode( bUpdate ); + _pImp->SetUpdateMode( bUpdate ); +} +void SvtIconChoiceCtrl::SetFont( const Font& rFont ) +{ + if( rFont != GetFont() ) + { + Control::SetFont( rFont ); + _pImp->FontModified(); + } +} + +void SvtIconChoiceCtrl::SetPointFont( const Font& rFont ) +{ + if( rFont != GetPointFont() ) + { + Control::SetPointFont( rFont ); + _pImp->FontModified(); + } +} +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::GetEntry( const Point& rPixPos, sal_Bool bHit ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvtIconChoiceCtrl*)this)->_pImp->GetEntry( aPos, bHit ); +} + +void SvtIconChoiceCtrl::SetStyle( WinBits nWinStyle ) +{ + _pImp->SetStyle( nWinStyle ); +} + +WinBits SvtIconChoiceCtrl::GetStyle() const +{ + return _pImp->GetStyle(); +} +void SvtIconChoiceCtrl::Command( const CommandEvent& rCEvt ) +{ + _pImp->Command( rCEvt ); +} + +void SvtIconChoiceCtrl::SetEntryTextMode( SvxIconChoiceCtrlTextMode eMode, SvxIconChoiceCtrlEntry* pEntry ) +{ + _pImp->SetEntryTextMode( eMode, pEntry ); +} + +SvxIconChoiceCtrlTextMode SvtIconChoiceCtrl::GetEntryTextMode( const SvxIconChoiceCtrlEntry* pEntry ) const +{ + return _pImp->GetEntryTextModeSmart( pEntry ); +} + +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::GetNextEntry( const Point& rPixPos, SvxIconChoiceCtrlEntry* pCurEntry, sal_Bool ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvtIconChoiceCtrl*)this)->_pImp->GetNextEntry( aPos, pCurEntry ); +} + +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::GetPrevEntry( const Point& rPixPos, SvxIconChoiceCtrlEntry* pCurEntry, sal_Bool ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvtIconChoiceCtrl*)this)->_pImp->GetPrevEntry( aPos, pCurEntry ); +} +sal_uLong SvtIconChoiceCtrl::GetEntryCount() const +{ + return _pImp->GetEntryCount(); +} + +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::GetEntry( sal_uLong nPos ) const +{ + return _pImp->GetEntry( nPos ); +} + +void SvtIconChoiceCtrl::CreateAutoMnemonics( MnemonicGenerator& _rUsedMnemonics ) +{ + _pImp->CreateAutoMnemonics( &_rUsedMnemonics ); +} + +void SvtIconChoiceCtrl::CreateAutoMnemonics( void ) +{ + _pImp->CreateAutoMnemonics(); +} + +void SvtIconChoiceCtrl::RemoveEntry( SvxIconChoiceCtrlEntry* pEntry ) +{ + _pImp->RemoveEntry( pEntry ); +} + +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::GetSelectedEntry( sal_uLong& rPos ) const +{ + return _pImp->GetFirstSelectedEntry( rPos ); +} + +void SvtIconChoiceCtrl::ClickIcon() +{ + sal_uLong nPos; + GetSelectedEntry ( nPos ); + _aClickIconHdl.Call( this ); +} +sal_Bool SvtIconChoiceCtrl::IsEntryEditing() const +{ + return _pImp->IsEntryEditing(); +} + +sal_Bool SvtIconChoiceCtrl::SetChoiceWithCursor ( sal_Bool bDo ) +{ + return _pImp->SetChoiceWithCursor (bDo); +} + +void SvtIconChoiceCtrl::KeyInput( const KeyEvent& rKEvt ) +{ + sal_Bool bKeyUsed = DoKeyInput( rKEvt ); + if ( !bKeyUsed ) + { + _pCurKeyEvent = (KeyEvent*)&rKEvt; + Control::KeyInput( rKEvt ); + _pCurKeyEvent = NULL; + } +} +sal_Bool SvtIconChoiceCtrl::DoKeyInput( const KeyEvent& rKEvt ) +{ + // unter OS/2 bekommen wir auch beim Editieren Key-Up/Down + if( IsEntryEditing() ) + return sal_True; + _pCurKeyEvent = (KeyEvent*)&rKEvt; + sal_Bool bHandled = _pImp->KeyInput( rKEvt ); + _pCurKeyEvent = NULL; + return bHandled; +} +sal_uLong SvtIconChoiceCtrl::GetEntryListPos( SvxIconChoiceCtrlEntry* pEntry ) const +{ + return _pImp->GetEntryListPos( pEntry ); +} +SvxIconChoiceCtrlEntry* SvtIconChoiceCtrl::GetCursor( ) const +{ + return _pImp->GetCurEntry( ); +} +void SvtIconChoiceCtrl::SetCursor( SvxIconChoiceCtrlEntry* pEntry ) +{ + _pImp->SetCursor( pEntry ); +} +void SvtIconChoiceCtrl::InvalidateEntry( SvxIconChoiceCtrlEntry* pEntry ) +{ + _pImp->InvalidateEntry( pEntry ); +} +void SvtIconChoiceCtrl::Clear() +{ + _pImp->Clear(); +} +void SvtIconChoiceCtrl::StateChanged( StateChangedType nType ) +{ + Control::StateChanged( nType ); +} + + +void SvtIconChoiceCtrl::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( ((rDCEvt.GetType() == DATACHANGED_SETTINGS) || + (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) || + (rDCEvt.GetType() == DATACHANGED_FONTS) ) && + (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + _pImp->InitSettings(); + Invalidate(INVALIDATE_NOCHILDREN); + } + else + Control::DataChanged( rDCEvt ); +} + +void SvtIconChoiceCtrl::SetBackground( const Wallpaper& rPaper ) +{ + if( rPaper != GetBackground() ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + Wallpaper aEmpty; + if( rPaper == aEmpty ) + Control::SetBackground( rStyleSettings.GetFieldColor() ); + else + { + Wallpaper aBackground( rPaper ); + // HACK, da Hintergrund sonst transparent sein koennte + if( !aBackground.IsBitmap() ) + aBackground.SetStyle( WALLPAPER_TILE ); + + WallpaperStyle eStyle = aBackground.GetStyle(); + Color aBack( aBackground.GetColor()); + Color aTrans( COL_TRANSPARENT ); + if( aBack == aTrans && ( + (!aBackground.IsBitmap() || + aBackground.GetBitmap().IsTransparent() || + (eStyle != WALLPAPER_TILE && eStyle != WALLPAPER_SCALE)))) + { + aBackground.SetColor( rStyleSettings.GetFieldColor() ); + } + if( aBackground.IsScrollable() ) + { + Rectangle aRect; + aRect.SetSize( Size(32765, 32765) ); + aBackground.SetRect( aRect ); + } + else + { + Rectangle aRect( _pImp->GetOutputRect() ); + aBackground.SetRect( aRect ); + } + Control::SetBackground( aBackground ); + } + + // bei hart attributierter Textfarbe keine 'Automatik', die eine + // lesbare Textfarbe einstellt. + Font aFont( GetFont() ); + aFont.SetColor( rStyleSettings.GetFieldTextColor() ); + SetFont( aFont ); + + Invalidate(INVALIDATE_NOCHILDREN); + } +} + +void SvtIconChoiceCtrl::Flush() +{ + _pImp->Flush(); +} + +void SvtIconChoiceCtrl::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( !_pImp->RequestHelp( rHEvt ) ) + Control::RequestHelp( rHEvt ); +} + +void SvtIconChoiceCtrl::SetSelectionMode( SelectionMode eMode ) +{ + _pImp->SetSelectionMode( eMode ); +} + +sal_Bool SvtIconChoiceCtrl::HandleShortCutKey( const KeyEvent& r ) +{ + return _pImp->HandleShortCutKey( r ); +} + +Rectangle SvtIconChoiceCtrl::GetBoundingBox( SvxIconChoiceCtrlEntry* pEntry ) const +{ + return _pImp->GetEntryBoundRect( pEntry ); +} + +void SvtIconChoiceCtrl::FillLayoutData() const +{ + CreateLayoutData(); + + SvtIconChoiceCtrl* pNonConstMe = const_cast< SvtIconChoiceCtrl* >( this ); + + // loop through all entries + sal_uInt16 nCount = (sal_uInt16)GetEntryCount(); + sal_uInt16 nPos = 0; + while ( nPos < nCount ) + { + SvxIconChoiceCtrlEntry* pEntry = GetEntry( nPos ); + + Point aPos = _pImp->GetEntryBoundRect( pEntry ).TopLeft(); + String sEntryText = pEntry->GetDisplayText( ); + Rectangle aTextRect = _pImp->CalcTextRect( pEntry, &aPos, sal_False, &sEntryText ); + + sal_Bool bLargeIconMode = WB_ICON == ( _pImp->GetStyle() & ( VIEWMODE_MASK ) ); + sal_uInt16 nTextPaintFlags = bLargeIconMode ? PAINTFLAG_HOR_CENTERED : PAINTFLAG_VER_CENTERED; + + _pImp->PaintItem( aTextRect, IcnViewFieldTypeText, pEntry, nTextPaintFlags, pNonConstMe, &sEntryText, GetLayoutData() ); + + ++nPos; + } +} + +Rectangle SvtIconChoiceCtrl::GetEntryCharacterBounds( const sal_Int32 _nEntryPos, const sal_Int32 _nCharacterIndex ) const +{ + Rectangle aRect; + + Pair aEntryCharacterRange = GetLineStartEnd( _nEntryPos ); + if ( aEntryCharacterRange.A() + _nCharacterIndex < aEntryCharacterRange.B() ) + { + aRect = GetCharacterBounds( aEntryCharacterRange.A() + _nCharacterIndex ); + } + + return aRect; +} + +void SvtIconChoiceCtrl::SetNoSelection() +{ + _pImp->SetNoSelection(); +} + +void SvtIconChoiceCtrl::CallImplEventListeners(sal_uLong nEvent, void* pData) +{ + CallEventListeners(nEvent, pData); +} +::com::sun::star::uno::Reference< XAccessible > SvtIconChoiceCtrl::CreateAccessible() +{ + Window* pParent = GetAccessibleParentWindow(); + DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" ); + + ::com::sun::star::uno::Reference< XAccessible > xAccessible; + if ( pParent ) + { + ::com::sun::star::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible(); + if ( xAccParent.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xTemp(GetComponentInterface()); + xAccessible = _pImp->GetAccessibleFactory().createAccessibleIconChoiceCtrl( *this, xAccParent ); + } + } + return xAccessible; +} + diff --git a/svtools/source/contnr/svcontnr.src b/svtools/source/contnr/svcontnr.src new file mode 100644 index 000000000000..e0449fc3f644 --- /dev/null +++ b/svtools/source/contnr/svcontnr.src @@ -0,0 +1,76 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <svtools/svtools.hrc> + +Image RID_IMG_TREENODE_COLLAPSED +{ + ImageBitmap = Bitmap { File = "plus.bmp"; } ; + MaskColor = Color { Red = 0xFF00; Green = 0x0000; Blue = 0xFF00; }; +}; + +Image RID_IMG_TREENODE_EXPANDED +{ + ImageBitmap = Bitmap { File = "minus.bmp"; } ; + MaskColor = Color { Red = 0xFF00; Green = 0x0000; Blue = 0xFF00; }; +}; + +Image RID_IMG_TREENODE_COLLAPSED_HC +{ + ImageBitmap = Bitmap { File = "plus_sch.bmp"; } ; + MaskColor = Color { Red = 0xFF00; Green = 0x0000; Blue = 0xFF00; }; +}; + +Image RID_IMG_TREENODE_EXPANDED_HC +{ + ImageBitmap = Bitmap { File = "minus_sch.bmp"; } ; + MaskColor = Color { Red = 0xFF00; Green = 0x0000; Blue = 0xFF00; }; +}; + +// descriptions of accessible objects + +String STR_SVT_ACC_DESC_TABLISTBOX +{ + Text [ en-US ] = "Row: %1, Column: %2"; +}; +String STR_SVT_ACC_DESC_FILEVIEW +{ + Text [ en-US ] = ", Type: %1, URL: %2"; +}; +String STR_SVT_ACC_DESC_FOLDER +{ + Text [ en-US ] = "Folder"; +}; +String STR_SVT_ACC_DESC_FILE +{ + Text [ en-US ] = "File"; +}; +String STR_SVT_ACC_EMPTY_FIELD +{ + Text [ en-US ] = "Empty Field"; +}; + diff --git a/svtools/source/contnr/svicnvw.cxx b/svtools/source/contnr/svicnvw.cxx new file mode 100644 index 000000000000..72768dd01746 --- /dev/null +++ b/svtools/source/contnr/svicnvw.cxx @@ -0,0 +1,829 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <svtools/svlbox.hxx> +#include <svtools/svicnvw.hxx> +#include <svimpicn.hxx> +#include <svtools/svlbitm.hxx> + +#ifndef GCC +#endif + +#define ICNVW_BLOCK_ENTRYINS 0x0001 + +SvIcnVwDataEntry::SvIcnVwDataEntry() + : nIcnVwFlags(0),eTextMode(ShowTextDontKnow) +{ +} + +SvIcnVwDataEntry::~SvIcnVwDataEntry() +{ +} + +SvIconView::SvIconView( Window* pParent, WinBits nWinStyle ) : + SvLBox( pParent, nWinStyle | WB_BORDER ) +{ + nIcnVwFlags = 0; + pImp = new SvImpIconView( this, GetModel(), nWinStyle | WB_ICON ); + pImp->mpViewData = 0; + SetSelectionMode( SINGLE_SELECTION ); + SetLineColor(); + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) ); + SetDefaultFont(); +} + +SvIconView::SvIconView( Window* pParent , const ResId& rResId ) : + SvLBox( pParent, rResId ) +{ + pImp = new SvImpIconView( this, GetModel(), WB_BORDER | WB_ICON ); + nIcnVwFlags = 0; + pImp->mpViewData = 0; + SetLineColor(); + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + SetBackground( Wallpaper( rStyleSettings.GetFieldColor() ) ); + SetDefaultFont(); + pImp->SetSelectionMode( GetSelectionMode() ); +} + +SvIconView::~SvIconView() +{ + delete pImp; +} + +void SvIconView::SetDefaultFont() +{ + SetFont( GetFont() ); +} + +SvLBoxEntry* SvIconView::CreateEntry( const XubString& rStr, + const Image& rCollEntryBmp, const Image& rExpEntryBmp ) +{ + SvLBoxEntry* pEntry = new SvLBoxEntry; + + SvLBoxContextBmp* pContextBmp = + new SvLBoxContextBmp( pEntry,0, rCollEntryBmp,rExpEntryBmp, 0xffff ); + pEntry->AddItem( pContextBmp ); + + SvLBoxString* pString = new SvLBoxString( pEntry, 0, rStr ); + pEntry->AddItem( pString ); + + return pEntry; +} + +void SvIconView::DisconnectFromModel() +{ + SvLBox::DisconnectFromModel(); + pImp->SetModel( GetModel(), 0 ); +} + + +SvLBoxEntry* SvIconView::InsertEntry( const XubString& rText, + SvLBoxEntry* pParent, sal_Bool bChildsOnDemand, sal_uLong nPos ) +{ + SvLBoxEntry* pEntry = CreateEntry( + rText, aCollapsedEntryBmp, aExpandedEntryBmp ); + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + + if ( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + return pEntry; +} + +SvLBoxEntry* SvIconView::InsertEntry( const XubString& rText, + const Image& rExpEntryBmp, + const Image& rCollEntryBmp, + SvLBoxEntry* pParent, sal_Bool bChildsOnDemand, sal_uLong nPos) +{ + SvLBoxEntry* pEntry = CreateEntry( + rText, rCollEntryBmp, rExpEntryBmp ); + + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + if ( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + return pEntry; +} + + +void SvIconView::SetEntryText(SvLBoxEntry* pEntry, const XubString& rStr) +{ + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if ( pItem ) + { + pItem->SetText( pEntry, rStr ); + GetModel()->InvalidateEntry( pEntry ); + } +} + +void SvIconView::SetExpandedEntryBmp(SvLBoxEntry* pEntry, const Image& rBmp) +{ + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + { + pItem->SetBitmap2( rBmp ); + GetModel()->InvalidateEntry( pEntry ); + } +} + +void SvIconView::SetCollapsedEntryBmp(SvLBoxEntry* pEntry, + const Image& rBmp ) +{ + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + { + pItem->SetBitmap1( rBmp ); + GetModel()->InvalidateEntry( pEntry ); + } +} + +XubString SvIconView::GetEntryText(SvLBoxEntry* pEntry ) const +{ + XubString aStr; + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if ( pItem ) + aStr = pItem->GetText(); + return aStr; +} + +Image SvIconView::GetExpandedEntryBmp(SvLBoxEntry* pEntry) const +{ + Image aBmp; + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + aBmp = pItem->GetBitmap2(); + return aBmp; +} + +Image SvIconView::GetCollapsedEntryBmp(SvLBoxEntry* pEntry) const +{ + Image aBmp; + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pItem ) + aBmp = pItem->GetBitmap1(); + return aBmp; +} + + +SvLBoxEntry* SvIconView::CloneEntry( SvLBoxEntry* pSource ) +{ + XubString aStr; + Image aCollEntryBmp; + Image aExpEntryBmp; + + SvLBoxString* pStringItem = (SvLBoxString*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if ( pStringItem ) + aStr = pStringItem->GetText(); + SvLBoxContextBmp* pBmpItem =(SvLBoxContextBmp*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if ( pBmpItem ) + { + aCollEntryBmp = pBmpItem->GetBitmap1(); + aExpEntryBmp = pBmpItem->GetBitmap2(); + } + SvLBoxEntry* pEntry = CreateEntry( aStr, aCollEntryBmp, aExpEntryBmp ); + pEntry->SvListEntry::Clone( pSource ); + pEntry->EnableChildsOnDemand( pSource->HasChildsOnDemand() ); + pEntry->SetUserData( pSource->GetUserData() ); + return pEntry; +} + + +sal_uInt16 SvIconView::IsA() +{ + return SV_LISTBOX_ID_ICONVIEW; +} + +void SvIconView::RequestingChilds( SvLBoxEntry* pParent ) +{ + if ( !pParent->HasChilds() ) + InsertEntry( String::CreateFromAscii("<dummy>"), pParent, sal_False, LIST_APPEND ); +} + +void __EXPORT SvIconView::Paint( const Rectangle& rRect ) +{ + pImp->Paint( rRect ); +} + +void __EXPORT SvIconView::MouseButtonDown( const MouseEvent& rMEvt ) +{ + pImp->MouseButtonDown( rMEvt ); +} + +void __EXPORT SvIconView::MouseButtonUp( const MouseEvent& rMEvt ) +{ + pImp->MouseButtonUp( rMEvt ); +} + +void __EXPORT SvIconView::MouseMove( const MouseEvent& rMEvt ) +{ + pImp->MouseMove( rMEvt ); +} + +void __EXPORT SvIconView::KeyInput( const KeyEvent& rKEvt ) +{ + // unter OS/2 bekommen wir auch beim Editieren Key-Up/Down + if( IsEditingActive() ) + return; + + nImpFlags |= SVLBOX_IS_TRAVELSELECT; + sal_Bool bKeyUsed = pImp->KeyInput( rKEvt ); + if ( !bKeyUsed ) + SvLBox::KeyInput( rKEvt ); + nImpFlags &= ~SVLBOX_IS_TRAVELSELECT; +} + +void __EXPORT SvIconView::Resize() +{ + pImp->Resize(); + SvLBox::Resize(); +} + +void __EXPORT SvIconView::GetFocus() +{ + pImp->GetFocus(); + SvLBox::GetFocus(); +} + +void __EXPORT SvIconView::LoseFocus() +{ + pImp->LoseFocus(); + SvLBox::LoseFocus(); +} + +void SvIconView::SetUpdateMode( sal_Bool bUpdate ) +{ + Control::SetUpdateMode( bUpdate ); + if ( bUpdate ) + pImp->UpdateAll(); +} + +void SvIconView::SetModel( SvLBoxTreeList* ) +{ +} + +void SvIconView::SetModel( SvLBoxTreeList* pNewModel, SvLBoxEntry* pParent ) +{ + nIcnVwFlags |= ICNVW_BLOCK_ENTRYINS; + SvLBox::SetModel( pNewModel ); + nIcnVwFlags &= (~ICNVW_BLOCK_ENTRYINS); + if ( pParent && pParent->HasChildsOnDemand() ) + RequestingChilds( pParent ); + pImp->SetModel( pNewModel, pParent ); +} + +void __EXPORT SvIconView::ModelHasCleared() +{ + SvLBox::ModelHasCleared(); + pImp->Clear(); +} + +void __EXPORT SvIconView::ModelHasInserted( SvListEntry* pEntry ) +{ + if( !(nIcnVwFlags & ICNVW_BLOCK_ENTRYINS ) ) + pImp->EntryInserted( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvIconView::ModelHasInsertedTree( SvListEntry* pEntry ) +{ + pImp->TreeInserted( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvIconView::ModelIsMoving(SvListEntry* pSource, + SvListEntry* /* pTargetParent */ , sal_uLong /* nChildPos */ ) +{ + pImp->MovingEntry( (SvLBoxEntry*)pSource ); +} + +void __EXPORT SvIconView::ModelHasMoved(SvListEntry* pSource ) +{ + pImp->EntryMoved( (SvLBoxEntry*)pSource ); +} + +void __EXPORT SvIconView::ModelIsRemoving( SvListEntry* pEntry ) +{ + pImp->RemovingEntry( (SvLBoxEntry*)pEntry ); + NotifyRemoving( (SvLBoxEntry*)pEntry ); +} + +void __EXPORT SvIconView::ModelHasRemoved( SvListEntry* /* pEntry */ ) +{ + pImp->EntryRemoved(); +} + +void __EXPORT SvIconView::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + // die einzelnen Items des Entries reinitialisieren + SvLBox::ModelHasEntryInvalidated( pEntry ); + // painten + pImp->ModelHasEntryInvalidated( pEntry ); +} + +void SvIconView::ShowTargetEmphasis( SvLBoxEntry* pEntry, sal_Bool bShow ) +{ + pImp->ShowTargetEmphasis( pEntry, bShow ); +} + +Point SvIconView::GetEntryPosition( SvLBoxEntry* pEntry ) const +{ + return ((SvIconView*)this)->pImp->GetEntryPosition( pEntry ); +} + +void SvIconView::SetEntryPosition( SvLBoxEntry* pEntry, const Point& rPos) +{ + pImp->SetEntryPosition( pEntry, rPos, sal_False, sal_True ); +} + +void SvIconView::SetEntryPosition( SvLBoxEntry* pEntry, const Point& rPos, sal_Bool bAdjustAtGrid ) +{ + pImp->SetEntryPosition( pEntry, rPos, bAdjustAtGrid ); +} + +void SvIconView::SetFont( const Font& rFont ) +{ + Font aTempFont( rFont ); + aTempFont.SetTransparent( sal_True ); + SvLBox::SetFont( aTempFont ); + RecalcViewData(); + pImp->ChangedFont(); +} + +void SvIconView::ViewDataInitialized( SvLBoxEntry* pEntry ) +{ + pImp->ViewDataInitialized( pEntry ); +} + +SvLBoxEntry* SvIconView::GetDropTarget( const Point& rPos ) +{ + return pImp->GetDropTarget( rPos ); +} + +SvLBoxEntry* SvIconView::GetEntry( const Point& rPixPos, sal_Bool ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvIconView*)this)->pImp->GetEntry( aPos ); +} + +SvLBoxEntry* SvIconView::GetEntryFromLogicPos( const Point& rDocPos ) const +{ + return ((SvIconView*)this)->pImp->GetEntry( rDocPos ); +} + + +void SvIconView::StateChanged( StateChangedType i_nStateChange ) +{ + SvLBox::StateChanged( i_nStateChange ); + if ( i_nStateChange == STATE_CHANGE_STYLE ) + pImp->SetStyle( GetStyle() ); +} + +void SvIconView::PaintEntry( SvLBoxEntry* pEntry ) +{ + pImp->PaintEntry( pEntry ); +} + + +void SvIconView::PaintEntry( SvLBoxEntry* pEntry, const Point& rPos ) +{ + pImp->PaintEntry( pEntry, rPos ); +} + +Rectangle SvIconView::GetFocusRect( SvLBoxEntry* pEntry ) +{ + return pImp->CalcFocusRect( pEntry ); +} + +void SvIconView::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + pImp->InvalidateEntry( pEntry ); +} + +void SvIconView::SetDragDropMode( DragDropMode nDDMode ) +{ + SvLBox::SetDragDropMode( nDDMode ); + pImp->SetDragDropMode( nDDMode ); +} + +void SvIconView::SetSelectionMode( SelectionMode eSelectMode ) +{ + SvLBox::SetSelectionMode( eSelectMode ); + pImp->SetSelectionMode( eSelectMode ); +} + +sal_Bool SvIconView::Select( SvLBoxEntry* pEntry, sal_Bool bSelect ) +{ + EndEditing(); + sal_Bool bRetVal = SvListView::Select( pEntry, bSelect ); + if( bRetVal ) + { + pImp->EntrySelected( pEntry, bSelect ); + pHdlEntry = pEntry; + SelectHdl(); + } + return bRetVal; +} + +void SvIconView::SelectAll( sal_Bool bSelect, sal_Bool ) +{ + SvLBoxEntry* pEntry = pImp->GetCurParent(); + pEntry = FirstChild( pEntry ); + while( pEntry ) + { + Select( pEntry, bSelect ); + pEntry = NextSibling( pEntry ); + } +} + +void SvIconView::SetCurEntry( SvLBoxEntry* _pEntry ) +{ + pImp->SetCursor( _pEntry ); + OnCurrentEntryChanged(); +} + +SvLBoxEntry* SvIconView::GetCurEntry() const +{ + return pImp->GetCurEntry(); +} + +void SvIconView::Arrange() +{ +#ifdef DBG_UTIL + sal_uInt16 n=1; + if( n == 1 && n-1 == 0 ) + { + pImp->Arrange(); + } + else + { + pImp->AdjustAtGrid(); + } +#else + pImp->Arrange(); +#endif +} + + +void SvIconView::SetSpaceBetweenEntries( long nX, long nY ) +{ + pImp->SetSpaceBetweenEntries( nX, nY ); +} + +sal_Bool SvIconView::NotifyMoving( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewParent, sal_uLong& rNewChildPos ) +{ + return pImp->NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos); +} + +sal_Bool SvIconView::NotifyCopying( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewParent, sal_uLong& rNewChildPos ) +{ + return pImp->NotifyCopying(pTarget,pEntry,rpNewParent,rNewChildPos); +} + + +void SvIconView::EnableInplaceEditing( sal_Bool bEnable ) +{ + SvLBox::EnableInplaceEditing( bEnable ); +} + +void SvIconView::EditingRequest( SvLBoxEntry* pEntry, SvLBoxItem* pItem, + const Point& ) +{ + if ( pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if ( EditingEntry( pEntry, aSel ) ) + { + SelectAll( sal_False ); + EditItemText( pEntry, (SvLBoxString*)pItem, aSel ); + } + } +} + + +void SvIconView::EditItemText( SvLBoxEntry* pEntry, SvLBoxItem* pItem, + const Selection& rSel ) +{ + DBG_ASSERT(pEntry&&pItem,"EditItemText:Params?"); + pCurEdEntry = pEntry; + pCurEdItem = pItem; + Rectangle aRect( pImp->CalcTextRect( pEntry, (SvLBoxString*)pItem,0,sal_True )); + + aRect.Bottom() += 4; + pImp->MakeVisible( aRect ); // vor der Umrechnung in Pixel-Koord. rufen! + aRect.Bottom() -= 4; + + Point aPos( aRect.TopLeft() ); + aPos += GetMapMode().GetOrigin(); // Dok-Koord. -> Window-Koord. + aRect.SetPos( aPos ); + + aRect.Bottom() += 2; // sieht huebscher aus + +#ifdef OS2 + +#if OS2_SINGLE_LINE_EDIT + aRect.Left() -= 3; + aRect.Right() += 3; + aRect.Top() -= 3; + aRect.Bottom() += 3; +#else + aRect.Left() -= 10; + aRect.Right() += 10; + aRect.Top() -= 5; + aRect.Bottom() += 5; +#endif + +#endif // OS2 + EditText( ((SvLBoxString*)pItem)->GetText(), aRect, rSel, sal_True ); +} + +void SvIconView::EditEntry( SvLBoxEntry* pEntry ) +{ + if( !pEntry ) + pEntry = pImp->GetCurEntry(); + if( pEntry ) + { + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pItem ) + { + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if( EditingEntry( pEntry, aSel ) ) + { + SelectAll( sal_False ); + EditItemText( pEntry, pItem, aSel ); + } + } + } +} + +void SvIconView::EditedText( const XubString& rStr ) +{ + XubString aRefStr( ((SvLBoxString*)pCurEdItem)->GetText() ); + if ( EditedEntry( pCurEdEntry, rStr ) ) + { + ((SvLBoxString*)pCurEdItem)->SetText( pCurEdEntry, rStr ); + pModel->InvalidateEntry( pCurEdEntry ); + } + if( GetSelectionMode()==SINGLE_SELECTION && !GetSelectionCount()) + Select( pCurEdEntry ); +} + + +sal_Bool SvIconView::EditingEntry( SvLBoxEntry*, Selection& ) +{ + return sal_True; +} + +sal_Bool SvIconView::EditedEntry( SvLBoxEntry*, const XubString& ) +{ + return sal_True; +} + + +void SvIconView::WriteDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo) +{ + pImp->WriteDragServerInfo( rPos, pInfo ); +} + +void SvIconView::ReadDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo ) +{ + pImp->ReadDragServerInfo( rPos, pInfo ); +} + +void SvIconView::Command( const CommandEvent& rCEvt ) +{ + pImp->PrepareCommandEvent( rCEvt.GetMousePosPixel() ); +} + +void SvIconView::SetCurParent( SvLBoxEntry* pNewParent ) +{ + if ( pNewParent && pNewParent->HasChildsOnDemand() ) + RequestingChilds( pNewParent ); + pImp->SetCurParent( pNewParent ); +} + +SvLBoxEntry* SvIconView::GetCurParent() const +{ + return pImp->GetCurParent(); +} + +SvViewData* SvIconView::CreateViewData( SvListEntry* ) +{ + SvIcnVwDataEntry* pEntryData = new SvIcnVwDataEntry; + return (SvViewData*)pEntryData; +} + +void SvIconView::InitViewData( SvViewData* pData, SvListEntry* pEntry ) +{ + SvLBox::InitViewData( pData, pEntry ); + pImp->InvalidateBoundingRect( ((SvIcnVwDataEntry*)pData)->aRect ); +} + +Region SvIconView::GetDragRegion() const +{ + Rectangle aRect; + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + aRect = pImp->GetBoundingRect( pEntry ); + Region aRegion( aRect ); + return aRegion; +} + +sal_uLong SvIconView::GetSelectionCount() const +{ + return (sal_uLong)(pImp->GetSelectionCount()); +} + +void SvIconView::SetGrid( long nDX, long nDY ) +{ + pImp->SetGrid( nDX, nDY ); +} + +void SvIconView::ModelNotification( sal_uInt16 nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, sal_uLong nPos ) +{ + SvLBox::ModelNotification( nActionId, pEntry1, pEntry2, nPos ); + switch( nActionId ) + { + case LISTACTION_RESORTING: + SetUpdateMode( sal_False ); + break; + + case LISTACTION_RESORTED: + SetUpdateMode( sal_True ); + Arrange(); + break; + + case LISTACTION_CLEARED: + if( IsUpdateMode() ) + Update(); + break; + } +} + + +void SvIconView::Scroll( long nDeltaX, long nDeltaY, sal_uInt16 ) +{ + pImp->Scroll( nDeltaX, nDeltaY, sal_False ); +} + +void SvIconView::PrepareCommandEvent( const CommandEvent& rCEvt ) +{ + pImp->PrepareCommandEvent( rCEvt.GetMousePosPixel() ); +} + +void SvIconView::StartDrag( sal_Int8 nAction, const Point& rPos ) +{ + pImp->SttDrag( rPos ); + SvLBoxEntry* pEntry = GetEntry( rPos, sal_True ); + pImp->mpViewData = pEntry; + SvLBox::StartDrag( nAction, rPos ); +} + +void SvIconView::DragFinished( sal_Int8 ) +{ + pImp->EndDrag(); +} + +sal_Int8 SvIconView::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + if( pImp->mpViewData ) + pImp->HideDDIcon(); + sal_Int8 nRet = SvLBox::AcceptDrop( rEvt ); + if( DND_ACTION_NONE != nRet ) + pImp->ShowDDIcon( pImp->mpViewData, rEvt.maPosPixel ); + + return nRet; +} + +sal_Int8 SvIconView::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + if( pImp->mpViewData ) + { + pImp->HideDDIcon(); + pImp->mpViewData = 0; + } + return SvLBox::ExecuteDrop( rEvt ); +} + +void SvIconView::ShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPos ) +{ + pImp->ShowDDIcon( pRefEntry, rPos ); +} + +void SvIconView::HideDDIcon() +{ + pImp->HideDDIcon(); +} + +void SvIconView::HideShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPos ) +{ + pImp->HideShowDDIcon( pRefEntry, rPos ); +} + +void SvIconView::SelectRect( const Rectangle& rRect, sal_Bool bAdd, + SvPtrarr* pRects, short nOffs ) +{ + pImp->SelectRect( rRect, bAdd, pRects, nOffs ); +} + +void SvIconView::CalcScrollOffsets( const Point& rRefPosPixel, long& rX, long& rY, + sal_Bool b, sal_uInt16 nBorderWidth ) +{ + pImp->CalcScrollOffsets( rRefPosPixel, rX, rY, b, nBorderWidth ); +} + +void SvIconView::EndTracking() +{ + pImp->EndTracking(); +} + +void SvIconView::MakeVisible( SvLBoxEntry* pEntry ) +{ + pImp->MakeVisible( pEntry ); +} + +void SvIconView::PreparePaint( SvLBoxEntry* ) +{ +} + +void SvIconView::AdjustAtGrid( SvLBoxEntry* pEntry ) +{ + pImp->AdjustAtGrid( pEntry ); +} + +void SvIconView::LockEntryPos( SvLBoxEntry* pEntry, sal_Bool bLock ) +{ + SvIcnVwDataEntry* pViewData = (SvIcnVwDataEntry*)GetViewData( pEntry ); + if( bLock ) + pViewData->SetVwFlags( ICNVW_FLAG_POS_LOCKED ); + else + pViewData->ClearVwFlags( ICNVW_FLAG_POS_LOCKED ); +} + +sal_Bool SvIconView::IsEntryPosLocked( const SvLBoxEntry* pEntry ) const +{ + const SvIcnVwDataEntry* pViewData = (const SvIcnVwDataEntry*)GetViewData( (SvListEntry*)pEntry ); + return pViewData->IsEntryPosLocked(); +} + +void SvIconView::SetTextMode( SvIconViewTextMode eMode, SvLBoxEntry* pEntry ) +{ + pImp->SetTextMode( eMode, pEntry ); +} + +SvIconViewTextMode SvIconView::GetTextMode( const SvLBoxEntry* pEntry ) const +{ + return pImp->GetTextMode( pEntry ); +} + +SvLBoxEntry* SvIconView::GetNextEntry( const Point& rPixPos, SvLBoxEntry* pCurEntry, sal_Bool ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvIconView*)this)->pImp->GetNextEntry( aPos, pCurEntry ); +} + +SvLBoxEntry* SvIconView::GetPrevEntry( const Point& rPixPos, SvLBoxEntry* pCurEntry, sal_Bool ) const +{ + Point aPos( rPixPos ); + aPos -= GetMapMode().GetOrigin(); + return ((SvIconView*)this)->pImp->GetPrevEntry( aPos, pCurEntry ); +} + +void SvIconView::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + pImp->ShowFocusRect( pEntry ); +} + + diff --git a/svtools/source/contnr/svimpbox.cxx b/svtools/source/contnr/svimpbox.cxx new file mode 100644 index 000000000000..7d63304203cd --- /dev/null +++ b/svtools/source/contnr/svimpbox.cxx @@ -0,0 +1,3630 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" +#include <vcl/svapp.hxx> +#include <vcl/salnativewidgets.hxx> +#include <vcl/help.hxx> +#include <svtools/tabbar.hxx> + +#include <stack> + +#define _SVTREEBX_CXX +#include <svtools/svtreebx.hxx> +#include <svtools/svlbox.hxx> +#include <svimpbox.hxx> +#include <rtl/instance.hxx> +#include <svtools/svtdata.hxx> +#include <tools/wintypes.hxx> +#include <svtools/svtools.hrc> +#include <comphelper/processfactory.hxx> + +#define NODE_BMP_TABDIST_NOTVALID -2000000 +#define FIRST_ENTRY_TAB 1 + +// #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors +Image* SvImpLBox::s_pDefCollapsed = NULL; +Image* SvImpLBox::s_pDefExpanded = NULL; +Image* SvImpLBox::s_pDefCollapsedHC = NULL; +Image* SvImpLBox::s_pDefExpandedHC = NULL; +sal_Int32 SvImpLBox::s_nImageRefCount = 0; + +SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvLBoxTreeList* pLBTree, WinBits nWinStyle) : + + pTabBar( NULL ), + aVerSBar( pLBView, WB_DRAG | WB_VSCROLL ), + aHorSBar( pLBView, WB_DRAG | WB_HSCROLL ), + aScrBarBox( pLBView ), + aOutputSize( 0, 0 ), + aSelEng( pLBView, (FunctionSet*)0 ), + aFctSet( this, &aSelEng, pLBView ), + nExtendedWinBits( 0 ), + bAreChildrenTransient( sal_True ), + pIntlWrapper( NULL ) // #102891# ----------------------- +{ + osl_incrementInterlockedCount(&s_nImageRefCount); + pView = pLBView; + pTree = pLBTree; + aSelEng.SetFunctionSet( (FunctionSet*)&aFctSet ); + aSelEng.ExpandSelectionOnMouseMove( sal_False ); + SetStyle( nWinStyle ); + SetSelectionMode( SINGLE_SELECTION ); + SetDragDropMode( 0 ); + + aVerSBar.SetScrollHdl( LINK( this, SvImpLBox, ScrollUpDownHdl ) ); + aHorSBar.SetScrollHdl( LINK( this, SvImpLBox, ScrollLeftRightHdl ) ); + aHorSBar.SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) ); + aVerSBar.SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) ); + aVerSBar.SetRange( Range(0,0) ); + aVerSBar.Hide(); + aHorSBar.SetRange( Range(0,0) ); + aHorSBar.SetPageSize( 24 ); // Pixel + aHorSBar.SetLineSize( 8 ); // Pixel + + nHorSBarHeight = (short)aHorSBar.GetSizePixel().Height(); + nVerSBarWidth = (short)aVerSBar.GetSizePixel().Width(); + + pStartEntry = 0; + pCursor = 0; + pAnchor = 0; + nVisibleCount = 0; // Anzahl Daten-Zeilen im Control + nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID; + nYoffsNodeBmp = 0; + nNodeBmpWidth = 0; + + bAsyncBeginDrag = sal_False; + aAsyncBeginDragTimer.SetTimeout( 0 ); + aAsyncBeginDragTimer.SetTimeoutHdl( LINK(this,SvImpLBox,BeginDragHdl)); + // Button-Animation in Listbox + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + + nFlags = 0; + nCurTabPos = FIRST_ENTRY_TAB; + + aEditTimer.SetTimeout( 800 ); + aEditTimer.SetTimeoutHdl( LINK(this,SvImpLBox,EditTimerCall) ); + + nMostRight = -1; + pMostRightEntry = 0; + nCurUserEvent = 0xffffffff; + + bUpdateMode = sal_True; + bInVScrollHdl = sal_False; + nFlags |= F_FILLING; + + bSubLstOpRet = bSubLstOpLR = bContextMenuHandling = bIsCellFocusEnabled = sal_False; +} + +SvImpLBox::~SvImpLBox() +{ + aEditTimer.Stop(); + StopUserEvent(); + + // #102891# --------------------- + if( pIntlWrapper ) + delete pIntlWrapper; + if ( osl_decrementInterlockedCount(&s_nImageRefCount) == 0 ) + { + DELETEZ(s_pDefCollapsed); + DELETEZ(s_pDefExpanded); + DELETEZ(s_pDefCollapsedHC); + DELETEZ(s_pDefExpandedHC); + } +} + +// #102891# -------------------- +void SvImpLBox::UpdateIntlWrapper() +{ + const ::com::sun::star::lang::Locale & aNewLocale = Application::GetSettings().GetLocale(); + if( !pIntlWrapper ) + pIntlWrapper = new IntlWrapper( ::comphelper::getProcessServiceFactory(), aNewLocale ); + else + { + const ::com::sun::star::lang::Locale &aLocale = pIntlWrapper->getLocale(); + if( aLocale.Language != aNewLocale.Language || // different Locale from the older one + aLocale.Country != aNewLocale.Country || + aLocale.Variant != aNewLocale.Variant ) + { + delete pIntlWrapper; + pIntlWrapper = new IntlWrapper( ::comphelper::getProcessServiceFactory(), aNewLocale ); + } + } +} + +// #97680# ---------------------- +short SvImpLBox::UpdateContextBmpWidthVector( SvLBoxEntry* pEntry, short nWidth ) +{ + DBG_ASSERT( pView->pModel, "View and Model aren't valid!" ); + + sal_uInt16 nDepth = pView->pModel->GetDepth( pEntry ); + // initialize vector if necessary + std::vector< short >::size_type nSize = aContextBmpWidthVector.size(); + while ( nDepth > nSize ) + { + aContextBmpWidthVector.resize( nSize + 1 ); + aContextBmpWidthVector.at( nSize ) = nWidth; + ++nSize; + } + if( aContextBmpWidthVector.size() == nDepth ) + { + aContextBmpWidthVector.resize( nDepth + 1 ); + aContextBmpWidthVector.at( nDepth ) = 0; + } + short nContextBmpWidth = aContextBmpWidthVector[ nDepth ]; + if( nContextBmpWidth < nWidth ) + { + aContextBmpWidthVector.at( nDepth ) = nWidth; + return nWidth; + } + else + return nContextBmpWidth; +} + +void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvLBoxEntry* pEntry ) +{ + DBG_ASSERT( pEntry, "Moved Entry is invalid!" ); + + SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) ); + short nExpWidth = (short)pBmpItem->GetBitmap1().GetSizePixel().Width(); + short nColWidth = (short)pBmpItem->GetBitmap2().GetSizePixel().Width(); + short nMax = Max(nExpWidth, nColWidth); + UpdateContextBmpWidthVector( pEntry, nMax ); + + if( pEntry->HasChilds() ) // recursive call, whether expanded or not + { + SvLBoxEntry* pChild = pView->FirstChild( pEntry ); + DBG_ASSERT( pChild, "The first child is invalid!" ); + do + { + UpdateContextBmpWidthVectorFromMovedEntry( pChild ); + pChild = pView->Next( pChild ); + } while ( pChild ); + } +} + +void SvImpLBox::UpdateContextBmpWidthMax( SvLBoxEntry* pEntry ) +{ + sal_uInt16 nDepth = pView->pModel->GetDepth( pEntry ); + if( aContextBmpWidthVector.size() < 1 ) + return; + short nWidth = aContextBmpWidthVector[ nDepth ]; + if( nWidth != pView->nContextBmpWidthMax ) { + pView->nContextBmpWidthMax = nWidth; + nFlags |= F_IGNORE_CHANGED_TABS; + pView->SetTabs(); + nFlags &= ~F_IGNORE_CHANGED_TABS; + } +} + +void SvImpLBox::CalcCellFocusRect( SvLBoxEntry* pEntry, Rectangle& rRect ) +{ + if ( pEntry && bIsCellFocusEnabled ) + { + if ( nCurTabPos > FIRST_ENTRY_TAB ) + { + SvLBoxItem* pItem = pCursor->GetItem( nCurTabPos ); + rRect.Left() = pView->GetTab( pCursor, pItem )->GetPos(); + } + if ( pCursor->ItemCount() > ( nCurTabPos + 1 ) ) + { + SvLBoxItem* pNextItem = pCursor->GetItem( nCurTabPos + 1 ); + long nRight = pView->GetTab( pCursor, pNextItem )->GetPos() - 1; + if ( nRight < rRect.Right() ) + rRect.Right() = nRight; + } + } +} + +void SvImpLBox::SetStyle( WinBits i_nWinStyle ) +{ + m_nStyle = i_nWinStyle; + if ( ( m_nStyle & WB_SIMPLEMODE) && ( aSelEng.GetSelectionMode() == MULTIPLE_SELECTION ) ) + aSelEng.AddAlways( sal_True ); +} + +void SvImpLBox::SetExtendedWindowBits( ExtendedWinBits _nBits ) +{ + nExtendedWinBits = _nBits; +} + +// Das Model darf hier nicht mehr angefasst werden +void SvImpLBox::Clear() +{ + StopUserEvent(); + pStartEntry = 0; + pAnchor = 0; + + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + + nMostRight = -1; + pMostRightEntry = 0; + + // Der Cursor darf hier nicht mehr angefasst werden! + if( pCursor ) + { + if( pView->HasFocus() ) + pView->HideFocus(); + pCursor = 0; + } + aVerSBar.Hide(); + aVerSBar.SetThumbPos( 0 ); + Range aRange( 0, 0 ); + aVerSBar.SetRange( aRange ); + aOutputSize = pView->Control::GetOutputSizePixel(); + nFlags &= ~(F_VER_SBARSIZE_WITH_HBAR | F_HOR_SBARSIZE_WITH_VBAR ); + if( pTabBar ) + { + aOutputSize.Height() -= nHorSBarHeight; + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + if( !pTabBar ) + aHorSBar.Hide(); + aHorSBar.SetThumbPos( 0 ); + MapMode aMapMode( pView->GetMapMode()); + aMapMode.SetOrigin( Point(0,0) ); + pView->Control::SetMapMode( aMapMode ); + aHorSBar.SetRange( aRange ); + aHorSBar.SetSizePixel(Size(aOutputSize.Width(),nHorSBarHeight)); + pView->SetClipRegion(); + if( GetUpdateMode() ) + pView->Invalidate( GetVisibleArea() ); + nFlags |= F_FILLING; + if( !aHorSBar.IsVisible() && !aVerSBar.IsVisible() ) + aScrBarBox.Hide(); + + // #97680# --------- + aContextBmpWidthVector.clear(); +} + +// ********************************************************************* +// Painten, Navigieren, Scrollen +// ********************************************************************* + +IMPL_LINK_INLINE_START( SvImpLBox, EndScrollHdl, ScrollBar *, EMPTYARG ) +{ + if( nFlags & F_ENDSCROLL_SET_VIS_SIZE ) + { + aVerSBar.SetVisibleSize( nNextVerVisSize ); + nFlags &= ~F_ENDSCROLL_SET_VIS_SIZE; + } + EndScroll(); + return 0; +} +IMPL_LINK_INLINE_END( SvImpLBox, EndScrollHdl, ScrollBar *, pScrollBar ) + + +// Handler vertikale ScrollBar + +IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar ) +{ + DBG_ASSERT(!bInVScrollHdl,"Scroll-Handler ueberholt sich!"); + long nDelta = pScrollBar->GetDelta(); + if( !nDelta ) + return 0; + + nFlags &= (~F_FILLING); + + bInVScrollHdl = sal_True; + + if( pView->IsEditingActive() ) + { + pView->EndEditing( sal_True ); // Cancel + pView->Update(); + } + BeginScroll(); + + if( nDelta > 0 ) + { + if( nDelta == 1 ) + CursorDown(); + else + PageDown( (sal_uInt16) nDelta ); + } + else + { + nDelta *= (-1); + if( nDelta == 1 ) + CursorUp(); + else + PageUp( (sal_uInt16) nDelta ); + } + bInVScrollHdl = sal_False; + return 0; +} + + +void SvImpLBox::CursorDown() +{ + SvLBoxEntry* pNextFirstToDraw = (SvLBoxEntry*)(pView->NextVisible( pStartEntry)); + if( pNextFirstToDraw ) + { + nFlags &= (~F_FILLING); + pView->NotifyScrolling( -1 ); + ShowCursor( sal_False ); + pView->Update(); + pStartEntry = pNextFirstToDraw; + Rectangle aArea( GetVisibleArea() ); + pView->Scroll( 0, -(pView->GetEntryHeight()), aArea, SCROLL_NOCHILDREN ); + pView->Update(); + ShowCursor( sal_True ); + pView->NotifyScrolled(); + } +} + +void SvImpLBox::CursorUp() +{ + SvLBoxEntry* pPrevFirstToDraw = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry)); + if( pPrevFirstToDraw ) + { + nFlags &= (~F_FILLING); + long nEntryHeight = pView->GetEntryHeight(); + pView->NotifyScrolling( 1 ); + ShowCursor( sal_False ); + pView->Update(); + pStartEntry = pPrevFirstToDraw; + Rectangle aArea( GetVisibleArea() ); + aArea.Bottom() -= nEntryHeight; + pView->Scroll( 0, nEntryHeight, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + ShowCursor( sal_True ); + pView->NotifyScrolled(); + } +} + +void SvImpLBox::PageDown( sal_uInt16 nDelta ) +{ + sal_uInt16 nRealDelta = nDelta; + + if( !nDelta ) + return; + + SvLBoxEntry* pNext; + pNext = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nRealDelta )); + if( (sal_uLong)pNext == (sal_uLong)pStartEntry ) + return; + + ShowCursor( sal_False ); + + nFlags &= (~F_FILLING); + pView->Update(); + pStartEntry = pNext; + + if( nRealDelta >= nVisibleCount ) + { + pView->Invalidate( GetVisibleArea() ); + pView->Update(); + } + else + { + long nScroll = nRealDelta * (-1); + pView->NotifyScrolling( nScroll ); + Rectangle aArea( GetVisibleArea() ); + nScroll = pView->GetEntryHeight()*nRealDelta; + nScroll = -nScroll; + pView->Update(); + pView->Scroll( 0, nScroll, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + pView->NotifyScrolled(); + } + + ShowCursor( sal_True ); +} + +void SvImpLBox::PageUp( sal_uInt16 nDelta ) +{ + sal_uInt16 nRealDelta = nDelta; + if( !nDelta ) + return; + + SvLBoxEntry* pPrev = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry, nRealDelta )); + if( (sal_uLong)pPrev == (sal_uLong)pStartEntry ) + return; + + nFlags &= (~F_FILLING); + ShowCursor( sal_False ); + + pView->Update(); + pStartEntry = pPrev; + if( nRealDelta >= nVisibleCount ) + { + pView->Invalidate( GetVisibleArea() ); + pView->Update(); + } + else + { + long nEntryHeight = pView->GetEntryHeight(); + pView->NotifyScrolling( (long)nRealDelta ); + Rectangle aArea( GetVisibleArea() ); + pView->Update(); + pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, SCROLL_NOCHILDREN ); + pView->Update(); + pView->NotifyScrolled(); + } + + ShowCursor( sal_True ); +} + +void SvImpLBox::KeyUp( sal_Bool bPageUp, sal_Bool bNotifyScroll ) +{ + if( !aVerSBar.IsVisible() ) + return; + + long nDelta; + if( bPageUp ) + nDelta = aVerSBar.GetPageSize(); + else + nDelta = 1; + + long nThumbPos = aVerSBar.GetThumbPos(); + + if( nThumbPos < nDelta ) + nDelta = nThumbPos; + + if( nDelta <= 0 ) + return; + + nFlags &= (~F_FILLING); + if( bNotifyScroll ) + BeginScroll(); + + aVerSBar.SetThumbPos( nThumbPos - nDelta ); + if( bPageUp ) + PageUp( (short)nDelta ); + else + CursorUp(); + + if( bNotifyScroll ) + EndScroll(); +} + + +void SvImpLBox::KeyDown( sal_Bool bPageDown, sal_Bool bNotifyScroll ) +{ + if( !aVerSBar.IsVisible() ) + return; + + long nDelta; + if( bPageDown ) + nDelta = aVerSBar.GetPageSize(); + else + nDelta = 1; + + long nThumbPos = aVerSBar.GetThumbPos(); + long nVisibleSize = aVerSBar.GetVisibleSize(); + long nRange = aVerSBar.GetRange().Len(); + + long nTmp = nThumbPos+nVisibleSize; + while( (nDelta > 0) && (nTmp+nDelta) >= nRange ) + nDelta--; + + if( nDelta <= 0 ) + return; + + nFlags &= (~F_FILLING); + if( bNotifyScroll ) + BeginScroll(); + + aVerSBar.SetThumbPos( nThumbPos+nDelta ); + if( bPageDown ) + PageDown( (short)nDelta ); + else + CursorDown(); + + if( bNotifyScroll ) + EndScroll(); +} + + + +void SvImpLBox::InvalidateEntriesFrom( long nY ) const +{ + if( !(nFlags & F_IN_PAINT )) + { + Rectangle aRect( GetVisibleArea() ); + aRect.Top() = nY; + pView->Invalidate( aRect ); + } +} + +void SvImpLBox::InvalidateEntry( long nY ) const +{ + if( !(nFlags & F_IN_PAINT )) + { + Rectangle aRect( GetVisibleArea() ); + long nMaxBottom = aRect.Bottom(); + aRect.Top() = nY; + aRect.Bottom() = nY; aRect.Bottom() += pView->GetEntryHeight(); + if( aRect.Top() > nMaxBottom ) + return; + if( aRect.Bottom() > nMaxBottom ) + aRect.Bottom() = nMaxBottom; + pView->Invalidate( aRect ); + } +} + +void SvImpLBox::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + if( GetUpdateMode() ) + { + long nPrev = nMostRight; + SetMostRight( pEntry ); + if( nPrev < nMostRight ) + ShowVerSBar(); + } + if( !(nFlags & F_IN_PAINT )) + { + sal_Bool bHasFocusRect = sal_False; + if( pEntry==pCursor && pView->HasFocus() ) + { + bHasFocusRect = sal_True; + ShowCursor( sal_False ); + } + InvalidateEntry( GetEntryLine( pEntry ) ); + if( bHasFocusRect ) + ShowCursor( sal_True ); + } +} + + +void SvImpLBox::RecalcFocusRect() +{ + if( pView->HasFocus() && pCursor ) + { + pView->HideFocus(); + long nY = GetEntryLine( pCursor ); + Rectangle aRect = pView->GetFocusRect( pCursor, nY ); + CalcCellFocusRect( pCursor, aRect ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + } +} + +// +// Setzt Cursor. Passt bei SingleSelection die Selektion an +// + +void SvImpLBox::SetCursor( SvLBoxEntry* pEntry, sal_Bool bForceNoSelect ) +{ + SvViewDataEntry* pViewDataNewCur = 0; + if( pEntry ) + pViewDataNewCur= pView->GetViewDataEntry(pEntry); + if( pEntry && + pEntry == pCursor && + pViewDataNewCur->HasFocus() && + pViewDataNewCur->IsSelected()) + { + return; + } + + // if this cursor is not selectable, find first visible that is and use it + while( pEntry && pViewDataNewCur && !pViewDataNewCur->IsSelectable() ) + { + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + pViewDataNewCur = pEntry ? pView->GetViewDataEntry(pEntry) : 0; + } + + SvLBoxEntry* pOldCursor = pCursor; + if( pCursor && pEntry != pCursor ) + { + pView->SetEntryFocus( pCursor, sal_False ); + if( bSimpleTravel ) + pView->Select( pCursor, sal_False ); + pView->HideFocus(); + } + pCursor = pEntry; + if( pCursor ) + { + pViewDataNewCur->SetFocus( sal_True ); + if(!bForceNoSelect && bSimpleTravel && !(nFlags & F_DESEL_ALL) && GetUpdateMode()) + { + pView->Select( pCursor, sal_True ); + } + // Mehrfachselektion: Im Cursor-Move selektieren, wenn + // nicht im Add-Mode (Ctrl-F8) + else if( GetUpdateMode() && + pView->GetSelectionMode() == MULTIPLE_SELECTION && + !(nFlags & F_DESEL_ALL) && !aSelEng.IsAddMode() && + !bForceNoSelect ) + { + pView->Select( pCursor, sal_True ); + } + else + { + ShowCursor( sal_True ); + } + + if( pAnchor ) + { + DBG_ASSERT(aSelEng.GetSelectionMode() != SINGLE_SELECTION,"Mode?"); + SetAnchorSelection( pOldCursor, pCursor ); + } + } + nFlags &= (~F_DESEL_ALL); + + pView->OnCurrentEntryChanged(); +} + +void SvImpLBox::ShowCursor( sal_Bool bShow ) +{ + if( !bShow || !pCursor || !pView->HasFocus() ) + { + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->HideFocus(); + pView->SetClipRegion( aOldClip ); + } + else + { + long nY = GetEntryLine( pCursor ); + Rectangle aRect = pView->GetFocusRect( pCursor, nY ); + CalcCellFocusRect( pCursor, aRect ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + } +} + + + +void SvImpLBox::UpdateAll( sal_Bool bInvalidateCompleteView, + sal_Bool bUpdateVerScrollBar ) +{ + if( bUpdateVerScrollBar ) + FindMostRight(0); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + SyncVerThumb(); + FillView(); + ShowVerSBar(); + if( bSimpleTravel && pCursor && pView->HasFocus() ) + pView->Select( pCursor, sal_True ); + ShowCursor( sal_True ); + if( bInvalidateCompleteView ) + pView->Invalidate(); + else + pView->Invalidate( GetVisibleArea() ); +} + +IMPL_LINK_INLINE_START( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) +{ + long nDelta = pScrollBar->GetDelta(); + if( nDelta ) + { + if( pView->IsEditingActive() ) + { + pView->EndEditing( sal_True ); // Cancel + pView->Update(); + } + pView->nFocusWidth = -1; + KeyLeftRight( nDelta ); + } + return 0; +} +IMPL_LINK_INLINE_END( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) + +void SvImpLBox::KeyLeftRight( long nDelta ) +{ + if( !(nFlags & F_IN_RESIZE) ) + pView->Update(); + BeginScroll(); + nFlags &= (~F_FILLING); + pView->NotifyScrolling( 0 ); // 0 == horizontales Scrolling + ShowCursor( sal_False ); + + // neuen Origin berechnen + long nPos = aHorSBar.GetThumbPos(); + Point aOrigin( -nPos, 0 ); + + MapMode aMapMode( pView->GetMapMode() ); + aMapMode.SetOrigin( aOrigin ); + pView->SetMapMode( aMapMode ); + + if( !(nFlags & F_IN_RESIZE) ) + { + Rectangle aRect( GetVisibleArea() ); + pView->Scroll( -nDelta, 0, aRect, SCROLL_NOCHILDREN ); + } + else + pView->Invalidate(); + RecalcFocusRect(); + ShowCursor( sal_True ); + pView->NotifyScrolled(); +} + + +// gibt letzten Eintrag zurueck, wenn Position unter +// dem letzten Eintrag ist +SvLBoxEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const +{ + DBG_ASSERT( pView->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" ); + if ( !pView->GetModel() ) + // this is quite impossible. Nevertheless, stack traces from the crash reporter + // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it + // reliably :-\ .... + // #122359# / 2005-05-23 / frank.schoenheit@sun.com + return NULL; + if( pView->GetEntryCount() == 0 || !pStartEntry || !pView->GetEntryHeight()) + return 0; + + sal_uInt16 nClickedEntry = (sal_uInt16)(rPoint.Y() / pView->GetEntryHeight() ); + sal_uInt16 nTemp = nClickedEntry; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp )); + return pEntry; +} + +// +// prueft, ob der Eintrag "richtig" getroffen wurde +// (Focusrect+ ContextBitmap bei TreeListBox) +// +sal_Bool SvImpLBox::EntryReallyHit(SvLBoxEntry* pEntry,const Point& rPosPixel,long nLine) +{ + sal_Bool bRet; + // bei "besonderen" Entries (mit CheckButtons usw.) sind wir + // nicht so pingelig + if( pEntry->ItemCount() >= 3 ) + return sal_True; + + Rectangle aRect( pView->GetFocusRect( pEntry, nLine )); + aRect.Right() = GetOutputSize().Width() - pView->GetMapMode().GetOrigin().X(); + if( pView->IsA() == SV_LISTBOX_ID_TREEBOX ) + { + SvLBoxContextBmp* pBmp = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + aRect.Left() -= pBmp->GetSize(pView,pEntry).Width(); + aRect.Left() -= 4; // etwas Speilraum lassen + } + Point aPos( rPosPixel ); + aPos -= pView->GetMapMode().GetOrigin(); + if( aRect.IsInside( aPos ) ) + bRet = sal_True; + else + bRet = sal_False; + return bRet; +} + + +// gibt 0 zurueck, wenn Position unter dem letzten Eintrag ist +SvLBoxEntry* SvImpLBox::GetEntry( const Point& rPoint ) const +{ + if( (pView->GetEntryCount() == 0) || !pStartEntry || + (rPoint.Y() > aOutputSize.Height()) + || !pView->GetEntryHeight()) + return 0; + + sal_uInt16 nClickedEntry = (sal_uInt16)(rPoint.Y() / pView->GetEntryHeight() ); + sal_uInt16 nTemp = nClickedEntry; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nTemp )); + if( nTemp != nClickedEntry ) + pEntry = 0; + return pEntry; +} + + +SvLBoxEntry* SvImpLBox::MakePointVisible(const Point& rPoint,sal_Bool bNotifyScroll) +{ + if( !pCursor ) + return 0; + long nY = rPoint.Y(); + SvLBoxEntry* pEntry = 0; + long nMax = aOutputSize.Height(); + if( nY < 0 || nY >= nMax ) // aOutputSize.Height() ) + { + if( nY < 0 ) + pEntry = (SvLBoxEntry*)(pView->PrevVisible( pCursor )); + else + pEntry = (SvLBoxEntry*)(pView->NextVisible( pCursor )); + + if( pEntry && pEntry != pCursor ) + pView->SetEntryFocus( pCursor, sal_False ); + + if( nY < 0 ) + KeyUp( sal_False, bNotifyScroll ); + else + KeyDown( sal_False, bNotifyScroll ); + } + else + { + pEntry = GetClickedEntry( rPoint ); + if( !pEntry ) + { + sal_uInt16 nSteps = 0xFFFF; + // LastVisible ist noch nicht implementiert! + pEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, nSteps )); + } + if( pEntry ) + { + if( pEntry != pCursor && + aSelEng.GetSelectionMode() == SINGLE_SELECTION + ) + pView->Select( pCursor, sal_False ); + } + } + return pEntry; +} + +Rectangle SvImpLBox::GetClipRegionRect() const +{ + Point aOrigin( pView->GetMapMode().GetOrigin() ); + aOrigin.X() *= -1; // Umrechnung Dokumentkoord. + Rectangle aClipRect( aOrigin, aOutputSize ); + aClipRect.Bottom()++; + return aClipRect; +} + + +void SvImpLBox::Paint( const Rectangle& rRect ) +{ + if( !pView->GetVisibleCount() ) + return; + + nFlags |= F_IN_PAINT; + + if( nFlags & F_FILLING ) + { + SvLBoxEntry* pFirst = pView->First(); + if( pFirst != pStartEntry ) + { + ShowCursor( sal_False ); + pStartEntry = pView->First(); + aVerSBar.SetThumbPos( 0 ); + StopUserEvent(); + ShowCursor( sal_True ); + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)1); + return; + } + } + + if( !pStartEntry ) + { + pStartEntry = pView->First(); + } + +#ifdef XX_OV + sal_uLong nXAbsPos = (sal_uInt16)pTree->GetAbsPos( pStartEntry ); + sal_uLong nXVisPos = pView->GetVisiblePos( pStartEntry ); + SvLBoxString* pXStr = (SvLBoxString*)pStartEntry->GetFirstItem( SV_ITEM_ID_LBOXSTRING); +#endif + + + + if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID ) + SetNodeBmpTabDistance(); + + long nRectHeight = rRect.GetHeight(); + long nEntryHeight = pView->GetEntryHeight(); + + // Bereich der zu zeichnenden Entries berechnen + sal_uInt16 nStartLine = (sal_uInt16)( rRect.Top() / nEntryHeight ); + sal_uInt16 nCount = (sal_uInt16)( nRectHeight / nEntryHeight ); + nCount += 2; // keine Zeile vergessen + + long nY = nStartLine * nEntryHeight; + SvLBoxEntry* pEntry = pStartEntry; + while( nStartLine && pEntry ) + { + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + nStartLine--; + } + + Region aClipRegion( GetClipRegionRect() ); + + // erst die Linien Zeichnen, dann clippen! + pView->SetClipRegion(); + if( m_nStyle & ( WB_HASLINES | WB_HASLINESATROOT ) ) + DrawNet(); + + pView->SetClipRegion( aClipRegion ); + + for( sal_uInt16 n=0; n< nCount && pEntry; n++ ) + { + /*long nMaxRight=*/ + pView->PaintEntry1( pEntry, nY, 0xffff, sal_True ); + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + + if ( !pCursor && ( ( nExtendedWinBits & EWB_NO_AUTO_CURENTRY ) == 0 ) ) + { + // do not select if multiselection or explicit set + sal_Bool bNotSelect = ( aSelEng.GetSelectionMode() == MULTIPLE_SELECTION ) + || ( ( m_nStyle & WB_NOINITIALSELECTION ) == WB_NOINITIALSELECTION ); + SetCursor( pStartEntry, bNotSelect ); + } + + nFlags &= (~F_DESEL_ALL); + pView->SetClipRegion(); + Rectangle aRect; + if( !(nFlags & F_PAINTED) ) + { + nFlags |= F_PAINTED; + RepaintScrollBars(); + } + nFlags &= (~F_IN_PAINT); +} + +void SvImpLBox::MakeVisible( SvLBoxEntry* pEntry, sal_Bool bMoveToTop ) +{ + if( !pEntry ) + return; + + sal_Bool bInView = IsEntryInView( pEntry ); + + if( bInView && (!bMoveToTop || pStartEntry == pEntry) ) + return; // ist schon sichtbar + + if( pStartEntry || (m_nStyle & WB_FORCE_MAKEVISIBLE) ) + nFlags &= (~F_FILLING); + if( !bInView ) + { + if( !pView->IsEntryVisible(pEntry) ) // Parent(s) zugeklappt ? + { + SvLBoxEntry* pParent = pView->GetParent( pEntry ); + while( pParent ) + { + if( !pView->IsExpanded( pParent ) ) + { + #ifdef DBG_UTIL + sal_Bool bRet = + #endif + pView->Expand( pParent ); + DBG_ASSERT(bRet,"Not expanded!"); + } + pParent = pView->GetParent( pParent ); + } + // Passen Childs der Parents in View oder muessen wir scrollen ? + if( IsEntryInView( pEntry ) && !bMoveToTop ) + return; // Scrollen nicht noetig -> tschuess + } + } + + pStartEntry = pEntry; + ShowCursor( sal_False ); + FillView(); + aVerSBar.SetThumbPos( (long)(pView->GetVisiblePos( pStartEntry )) ); + ShowCursor( sal_True ); + pView->Invalidate(); +} + + +void SvImpLBox::RepaintSelectionItems() +{ + if( !pView->GetVisibleCount() ) + return; + + if( !pStartEntry ) + pStartEntry = pView->First(); + + if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID ) + SetNodeBmpTabDistance(); + + ShowCursor( sal_False ); + + long nEntryHeight = pView->GetEntryHeight(); + + sal_uLong nCount = nVisibleCount; + long nY = 0; + SvLBoxEntry* pEntry = pStartEntry; + for( sal_uLong n=0; n< nCount && pEntry; n++ ) + { + pView->PaintEntry1( pEntry, nY, 0xffff ); //wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + + ShowCursor( sal_True ); +} + + +void SvImpLBox::DrawNet() +{ + if( pView->GetVisibleCount() < 2 && !pStartEntry->HasChildsOnDemand() && + !pStartEntry->HasChilds() ) + return; + + //for platforms who don't have nets, DrawNativeControl does nothing and return true + //so that SvImpLBox::DrawNet() doesn't draw anything too + if(pView->IsNativeControlSupported( CTRL_LISTNET, PART_ENTIRE_CONTROL)) { + ImplControlValue aControlValue; + Point aTemp(0,0); // temporary needed for g++ 3.3.5 + Rectangle aCtrlRegion( aTemp, Size( 0, 0 ) ); + ControlState nState = CTRL_STATE_ENABLED; + if( pView->DrawNativeControl( CTRL_LISTNET, PART_ENTIRE_CONTROL, + aCtrlRegion, nState, aControlValue, rtl::OUString() ) ) + { + return; + } + + } + + long nEntryHeight = pView->GetEntryHeight(); + long nEntryHeightDIV2 = nEntryHeight / 2; + if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001)) + nEntryHeightDIV2--; + + SvLBoxEntry* pChild; + SvLBoxEntry* pEntry = pStartEntry; + + SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab(); + while( pTree->GetDepth( pEntry ) > 0 ) + pEntry = pView->GetParent( pEntry ); + sal_uInt16 nOffs = (sal_uInt16)(pView->GetVisiblePos( pStartEntry ) - + pView->GetVisiblePos( pEntry )); + long nY = 0; + nY -= ( nOffs * nEntryHeight ); + + DBG_ASSERT(pFirstDynamicTab,"No Tree!"); + + Color aOldLineColor = pView->GetLineColor(); + const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings(); + Color aCol= rStyleSettings.GetFaceColor(); + + if( aCol.IsRGBEqual( pView->GetBackground().GetColor()) ) + aCol = rStyleSettings.GetShadowColor(); + pView->SetLineColor( aCol ); + Point aPos1, aPos2; + sal_uInt16 nDistance; + sal_uLong nMax = nVisibleCount + nOffs + 1; + + const Image& rExpandedNodeBitmap = GetExpandedNodeBmp(); + + for( sal_uLong n=0; n< nMax && pEntry; n++ ) + { + if( pView->IsExpanded(pEntry) ) + { + aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2; + + aPos1.Y() = nY; + aPos1.Y() += nEntryHeightDIV2; + + pChild = pView->FirstChild( pEntry ); + DBG_ASSERT(pChild,"Child?"); + pChild = pTree->LastSibling( pChild ); + nDistance = (sal_uInt16)(pView->GetVisiblePos(pChild) - + pView->GetVisiblePos(pEntry)); + aPos2 = aPos1; + aPos2.Y() += nDistance * nEntryHeight; + pView->DrawLine( aPos1, aPos2 ); + } + // Sichtbar im Control ? + if( n>= nOffs && ((m_nStyle & WB_HASLINESATROOT) || !pTree->IsAtRootDepth(pEntry))) + { + // kann aPos1 recyclet werden ? + if( !pView->IsExpanded(pEntry) ) + { + // njet + aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2; + aPos1.Y() = nY; + aPos1.Y() += nEntryHeightDIV2; + aPos2.X() = aPos1.X(); + } + aPos2.Y() = aPos1.Y(); + aPos2.X() -= pView->GetIndent(); + pView->DrawLine( aPos1, aPos2 ); + } + nY += nEntryHeight; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( m_nStyle & WB_HASLINESATROOT ) + { + pEntry = pView->First(); + aPos1.X() = pView->GetTabPos( pEntry, pFirstDynamicTab); + // wenn keine ContextBitmap, dann etwas nach rechts + // unter den ersten Text (Node.Bmp ebenfalls + if( !pView->nContextBmpWidthMax ) + aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2; + aPos1.X() -= pView->GetIndent(); + aPos1.Y() = GetEntryLine( pEntry ); + aPos1.Y() += nEntryHeightDIV2; + pChild = pTree->LastSibling( pEntry ); + aPos2.X() = aPos1.X(); + aPos2.Y() = GetEntryLine( pChild ); + aPos2.Y() += nEntryHeightDIV2; + pView->DrawLine( aPos1, aPos2 ); + } + pView->SetLineColor( aOldLineColor ); +} + + +static long GetOptSize( TabBar* pTabBar ) +{ + return pTabBar->CalcWindowSizePixel().Width(); +} + +void SvImpLBox::PositionScrollBars( Size& rSize, sal_uInt16 nMask ) +{ + long nOverlap = 0; + + Size aVerSize( nVerSBarWidth, rSize.Height() ); + Size aHorSize( rSize.Width(), nHorSBarHeight ); + long nTabBarWidth = 0; + if( pTabBar ) + { + nTabBarWidth = GetOptSize( pTabBar ); + long nMaxWidth = (rSize.Width() * 700) / 1000; + if( nTabBarWidth > nMaxWidth ) + { + nTabBarWidth = nMaxWidth; + pTabBar->SetStyle( pTabBar->GetStyle() | WB_MINSCROLL ); + } + else + { + WinBits nStyle = pTabBar->GetStyle(); + nStyle &= ~(WB_MINSCROLL); + pTabBar->SetStyle( nStyle ); + } + aHorSize.Width() -= nTabBarWidth; + Size aTabSize( pTabBar->GetSizePixel() ); + aTabSize.Width() = nTabBarWidth; + pTabBar->SetSizePixel( aTabSize ); + } + if( nMask & 0x0001 ) + aHorSize.Width() -= nVerSBarWidth; + if( nMask & 0x0002 ) + aVerSize.Height() -= nHorSBarHeight; + + aVerSize.Height() += 2 * nOverlap; + Point aVerPos( rSize.Width() - aVerSize.Width() + nOverlap, -nOverlap ); + aVerSBar.SetPosSizePixel( aVerPos, aVerSize ); + + aHorSize.Width() += 2 * nOverlap; + Point aHorPos( -nOverlap, rSize.Height() - aHorSize.Height() + nOverlap ); + if( pTabBar ) + pTabBar->SetPosPixel( aHorPos ); + aHorPos.X() += nTabBarWidth; + aHorSBar.SetPosSizePixel( aHorPos, aHorSize ); + + if( nMask & 0x0001 ) + rSize.Width() = aVerPos.X(); + if( nMask & 0x0002 ) + rSize.Height() = aHorPos.Y(); + if( pTabBar ) + pTabBar->Show(); + + if( (nMask & (0x0001|0x0002)) == (0x0001|0x0002) ) + aScrBarBox.Show(); + else + aScrBarBox.Hide(); + +} + +// nResult: Bit0 == VerSBar Bit1 == HorSBar +sal_uInt16 SvImpLBox::AdjustScrollBars( Size& rSize ) +{ + long nEntryHeight = pView->GetEntryHeight(); + if( !nEntryHeight ) + return 0; + + sal_uInt16 nResult = 0; + + Size aOSize( pView->Control::GetOutputSizePixel() ); + + const WinBits nWindowStyle = pView->GetStyle(); + sal_Bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0; + sal_Bool bHorBar = sal_False; + long nMaxRight = aOSize.Width(); //GetOutputSize().Width(); + Point aOrigin( pView->GetMapMode().GetOrigin() ); + aOrigin.X() *= -1; + nMaxRight += aOrigin.X() - 1; + long nVis = nMostRight - aOrigin.X(); + if( pTabBar || ( + (nWindowStyle & WB_HSCROLL) && + (nVis < nMostRight || nMaxRight < nMostRight) )) + bHorBar = sal_True; + + // Anzahl aller nicht eingeklappten Eintraege + sal_uLong nTotalCount = pView->GetVisibleCount(); + + // Anzahl in der View sichtbarer Eintraege + nVisibleCount = aOSize.Height() / nEntryHeight; + + // muessen wir eine vertikale Scrollbar einblenden? + if( bVerSBar || nTotalCount > nVisibleCount ) + { + nResult = 1; + nFlags |= F_HOR_SBARSIZE_WITH_VBAR; + nMaxRight -= nVerSBarWidth; + if( !bHorBar ) + { + if( (nWindowStyle & WB_HSCROLL) && + (nVis < nMostRight || nMaxRight < nMostRight) ) + bHorBar = sal_True; + } + } + + // muessen wir eine horizontale Scrollbar einblenden? + if( bHorBar ) + { + nResult |= 0x0002; + // die Anzahl der in der View sichtbaren Eintraege + // muss neu berechnet werden, da die horizontale + // ScrollBar eingeblendet wird + nVisibleCount = (aOSize.Height() - nHorSBarHeight) / nEntryHeight; + // eventuell brauchen wir jetzt doch eine vertikale ScrollBar + if( !(nResult & 0x0001) && + ((nTotalCount > nVisibleCount) || bVerSBar) ) + { + nResult = 3; + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + } + + PositionScrollBars( aOSize, nResult ); + + // Range, VisibleRange usw. anpassen + + // Output-Size aktualisieren, falls wir scrollen muessen + Rectangle aRect; + aRect.SetSize( aOSize ); + aSelEng.SetVisibleArea( aRect ); + + // Vertikale ScrollBar + long nTemp = (long)nVisibleCount; + nTemp--; + if( nTemp != aVerSBar.GetVisibleSize() ) + { + if( !bInVScrollHdl ) + { + aVerSBar.SetPageSize( nTemp - 1 ); + aVerSBar.SetVisibleSize( nTemp ); + } + else + { + nFlags |= F_ENDSCROLL_SET_VIS_SIZE; + nNextVerVisSize = nTemp; + } + } + + // Horizontale ScrollBar + nTemp = aHorSBar.GetThumbPos(); + aHorSBar.SetVisibleSize( aOSize.Width() ); + long nNewThumbPos = aHorSBar.GetThumbPos(); + Range aRange( aHorSBar.GetRange() ); + if( aRange.Max() < nMostRight+25 ) + { + aRange.Max() = nMostRight+25; + aHorSBar.SetRange( aRange ); + } + + if( nTemp != nNewThumbPos ) + { + nTemp = nNewThumbPos - nTemp; + if( pView->IsEditingActive() ) + { + pView->EndEditing( sal_True ); // Cancel + pView->Update(); + } + pView->nFocusWidth = -1; + KeyLeftRight( nTemp ); + } + + if( nResult & 0x0001 ) + aVerSBar.Show(); + else + aVerSBar.Hide(); + + if( nResult & 0x0002 ) + aHorSBar.Show(); + else + { + if( !pTabBar ) + aHorSBar.Hide(); + } + rSize = aOSize; + return nResult; +} + +void SvImpLBox::InitScrollBarBox() +{ + aScrBarBox.SetSizePixel( Size(nVerSBarWidth, nHorSBarHeight) ); + Size aSize( pView->Control::GetOutputSizePixel() ); + aScrBarBox.SetPosPixel( Point(aSize.Width()-nVerSBarWidth, aSize.Height()-nHorSBarHeight)); +} + +void SvImpLBox::Resize() +{ + Size aSize( pView->Control::GetOutputSizePixel()); + if( aSize.Width() <= 0 || aSize.Height() <= 0 ) + return; + nFlags |= F_IN_RESIZE; + InitScrollBarBox(); + + if( pView->GetEntryHeight()) + { + AdjustScrollBars( aOutputSize ); + FillView(); + } + // !!!HACK, da in Floating- & Docking-Windows nach Resizes + // die Scrollbars nicht richtig, bzw. ueberhaupt nicht gezeichnet werden + if( aHorSBar.IsVisible()) + aHorSBar.Invalidate(); + if( aVerSBar.IsVisible()) + aVerSBar.Invalidate(); + nFlags &= (~(F_IN_RESIZE | F_PAINTED)); +} + +void SvImpLBox::FillView() +{ + if( !pStartEntry ) + { + sal_uInt16 nVisibleViewCount = (sal_uInt16)(pView->GetVisibleCount()); + sal_uInt16 nTempThumb = (sal_uInt16)aVerSBar.GetThumbPos(); + if( nTempThumb >= nVisibleViewCount ) + nTempThumb = nVisibleViewCount - 1; + pStartEntry = (SvLBoxEntry*)(pView->GetEntryAtVisPos(nTempThumb)); + } + if( pStartEntry ) + { + sal_uInt16 nLast = (sal_uInt16)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible()))); + sal_uInt16 nThumb = (sal_uInt16)(pView->GetVisiblePos( pStartEntry )); + sal_uInt16 nCurDispEntries = nLast-nThumb+1; + if( nCurDispEntries < nVisibleCount ) + { + ShowCursor( sal_False ); + // Fenster fuellen, indem der Thumb schrittweise + // nach oben bewegt wird + sal_Bool bFound = sal_False; + SvLBoxEntry* pTemp = pStartEntry; + while( nCurDispEntries < nVisibleCount && pTemp ) + { + pTemp = (SvLBoxEntry*)(pView->PrevVisible(pStartEntry)); + if( pTemp ) + { + nThumb--; + pStartEntry = pTemp; + nCurDispEntries++; + bFound = sal_True; + } + } + if( bFound ) + { + aVerSBar.SetThumbPos( nThumb ); + ShowCursor( sal_True ); // Focusrect neu berechnen + pView->Invalidate(); + } + } + } +} + + + + +void SvImpLBox::ShowVerSBar() +{ + sal_Bool bVerBar = ( pView->GetStyle() & WB_VSCROLL ) != 0; + sal_uLong nVis = 0; + if( !bVerBar ) + nVis = pView->GetVisibleCount(); + if( bVerBar || (nVisibleCount && nVis > (sal_uLong)(nVisibleCount-1)) ) + { + if( !aVerSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + if( GetUpdateMode() ) + aVerSBar.Update(); + } + } + else + { + if( aVerSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + } + } + + long nMaxRight = GetOutputSize().Width(); + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; // Umrechnung Dokumentkoord. + nMaxRight = nMaxRight + aPos.X() - 1; + if( nMaxRight < nMostRight ) + { + if( !aHorSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + if( GetUpdateMode() ) + aHorSBar.Update(); + } + else + { + Range aRange( aHorSBar.GetRange() ); + if( aRange.Max() < nMostRight+25 ) + { + aRange.Max() = nMostRight+25; + aHorSBar.SetRange( aRange ); + } + else + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + } + } + } + else + { + if( aHorSBar.IsVisible() ) + { + pView->nFocusWidth = -1; + AdjustScrollBars( aOutputSize ); + } + } +} + + +void SvImpLBox::SyncVerThumb() +{ + if( pStartEntry ) + { + long nEntryPos = pView->GetVisiblePos( pStartEntry ); + aVerSBar.SetThumbPos( nEntryPos ); + } + else + aVerSBar.SetThumbPos( 0 ); +} + +sal_Bool SvImpLBox::IsEntryInView( SvLBoxEntry* pEntry ) const +{ + // Parent eingeklappt + if( !pView->IsEntryVisible(pEntry) ) + return sal_False; + long nY = GetEntryLine( pEntry ); + if( nY < 0 ) + return sal_False; + long nMax = nVisibleCount * pView->GetEntryHeight(); + if( nY >= nMax ) + return sal_False; + return sal_True; +} + + +long SvImpLBox::GetEntryLine( SvLBoxEntry* pEntry ) const +{ + if(!pStartEntry ) + return -1; // unsichtbare Position + + long nFirstVisPos = pView->GetVisiblePos( pStartEntry ); + long nEntryVisPos = pView->GetVisiblePos( pEntry ); + nFirstVisPos = nEntryVisPos - nFirstVisPos; + nFirstVisPos *= pView->GetEntryHeight(); + return nFirstVisPos; +} + +void SvImpLBox::SetEntryHeight( short /* nHeight */ ) +{ + SetNodeBmpYOffset( GetExpandedNodeBmp() ); + SetNodeBmpYOffset( GetCollapsedNodeBmp() ); + if(!pView->HasViewData()) // stehen wir im Clear? + { + Size aSize = pView->Control::GetOutputSizePixel(); + AdjustScrollBars( aSize ); + } + else + { + Resize(); + if( GetUpdateMode() ) + pView->Invalidate(); + } +} + + + +// *********************************************************************** +// Callback-Functions +// *********************************************************************** + +void SvImpLBox::IndentChanged( short /* nIndentPixel */ ) {} + +void SvImpLBox::EntryExpanded( SvLBoxEntry* pEntry ) +{ + // SelAllDestrAnch( sal_False, sal_True ); //DeselectAll(); + if( GetUpdateMode() ) + { + ShowCursor( sal_False ); + long nY = GetEntryLine( pEntry ); + if( IsLineVisible(nY) ) + { + InvalidateEntriesFrom( nY ); + FindMostRight( pEntry, 0 ); + } + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + // falls vor dem Thumb expandiert wurde, muss + // die Thumb-Position korrigiert werden. + SyncVerThumb(); + ShowVerSBar(); + ShowCursor( sal_True ); + } +} + +void SvImpLBox::EntryCollapsed( SvLBoxEntry* pEntry ) +{ + if( !pView->IsEntryVisible( pEntry ) ) + return; + + ShowCursor( sal_False ); + + if( !pMostRightEntry || pTree->IsChild( pEntry,pMostRightEntry ) ) + { + FindMostRight(0); + } + + if( pStartEntry ) + { + long nOldThumbPos = aVerSBar.GetThumbPos(); + sal_uLong nVisList = pView->GetVisibleCount(); + aVerSBar.SetRange( Range(0, nVisList-1) ); + long nNewThumbPos = aVerSBar.GetThumbPos(); + if( nNewThumbPos != nOldThumbPos ) + { + pStartEntry = pView->First(); + sal_uInt16 nDistance = (sal_uInt16)nNewThumbPos; + if( nDistance ) + pStartEntry = (SvLBoxEntry*)(pView->NextVisible( pStartEntry, + nDistance)); + if( GetUpdateMode() ) + pView->Invalidate(); + } + else + SyncVerThumb(); + ShowVerSBar(); + } + // wurde Cursor eingeklappt ? + if( pTree->IsChild( pEntry, pCursor ) ) + SetCursor( pEntry ); + if( GetUpdateMode() ) + ShowVerSBar(); + ShowCursor( sal_True ); + if( GetUpdateMode() && pCursor ) + pView->Select( pCursor, sal_True ); +} + +void SvImpLBox::CollapsingEntry( SvLBoxEntry* pEntry ) +{ + if( !pView->IsEntryVisible( pEntry ) || !pStartEntry ) + return; + + SelAllDestrAnch( sal_False, sal_True ); // deselectall + + // ist der eingeklappte Parent sichtbar ? + long nY = GetEntryLine( pEntry ); + if( IsLineVisible(nY) ) + { + if( GetUpdateMode() ) + InvalidateEntriesFrom( nY ); + } + else + { + if( pTree->IsChild(pEntry, pStartEntry) ) + { + pStartEntry = pEntry; + if( GetUpdateMode() ) + pView->Invalidate(); + } + } +} + + +void SvImpLBox::SetNodeBmpYOffset( const Image& rBmp ) +{ + Size aSize; + nYoffsNodeBmp = pView->GetHeightOffset( rBmp, aSize ); + nNodeBmpWidth = aSize.Width(); +} + +void SvImpLBox::SetNodeBmpTabDistance() +{ + nNodeBmpTabDistance = -pView->GetIndent(); + if( pView->nContextBmpWidthMax ) + { + // nur, wenn der erste dynamische Tab zentriert ist + // (setze ich momentan voraus) + Size aSize = GetExpandedNodeBmp().GetSizePixel(); + nNodeBmpTabDistance -= aSize.Width() / 2; + } +} + +// +// korrigiert bei SingleSelection den Cursor +// +void SvImpLBox::EntrySelected( SvLBoxEntry* pEntry, sal_Bool bSelect ) +{ + if( nFlags & F_IGNORE_SELECT ) + return; + + /* + if( (m_nStyle & WB_HIDESELECTION) && pEntry && !pView->HasFocus() ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + pViewData->SetCursored( bSelect ); + } + */ + + nFlags &= (~F_DESEL_ALL); + if( bSelect && + aSelEng.GetSelectionMode() == SINGLE_SELECTION && + pEntry != pCursor ) + { + SetCursor( pEntry ); + DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?"); + } + + if( GetUpdateMode() && pView->IsEntryVisible(pEntry) ) + { + long nY = GetEntryLine( pEntry ); + if( IsLineVisible( nY ) ) + { + ShowCursor( sal_False ); + pView->PaintEntry1( pEntry, nY, 0xffff ); // wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + ShowCursor( sal_True ); + } + } +} + + +void SvImpLBox::RemovingEntry( SvLBoxEntry* pEntry ) +{ + DestroyAnchor(); + + if( !pView->IsEntryVisible( pEntry ) ) + { + // wenn Parent eingeklappt, dann tschuess + nFlags |= F_REMOVED_ENTRY_INVISIBLE; + return; + } + + if( pEntry == pMostRightEntry || ( + pEntry->HasChilds() && pView->IsExpanded(pEntry) && + pTree->IsChild(pEntry, pMostRightEntry))) + { + nFlags |= F_REMOVED_RECALC_MOST_RIGHT; + } + + SvLBoxEntry* pOldStartEntry = pStartEntry; + + SvLBoxEntry* pParent = (SvLBoxEntry*)(pView->GetModel()->GetParent(pEntry)); + + if( pParent && pView->GetModel()->GetChildList(pParent)->Count() == 1 ) + { + DBG_ASSERT( pView->IsExpanded( pParent ), "Parent not expanded"); + pParent->SetFlags( pParent->GetFlags() | SV_ENTRYFLAG_NO_NODEBMP); + InvalidateEntry( pParent ); + } + + if( pCursor && pTree->IsChild( pEntry, pCursor) ) + pCursor = pEntry; + if( pStartEntry && pTree->IsChild(pEntry,pStartEntry) ) + pStartEntry = pEntry; + + SvLBoxEntry* pTemp; + if( pCursor && pCursor == pEntry ) + { + if( bSimpleTravel ) + pView->Select( pCursor, sal_False ); + ShowCursor( sal_False ); // Focus-Rect weg + // NextSibling, weil auch Childs des Cursors geloescht werden + pTemp = pView->NextSibling( pCursor ); + if( !pTemp ) + pTemp = (SvLBoxEntry*)(pView->PrevVisible( pCursor )); + + SetCursor( pTemp, sal_True ); + } + if( pStartEntry && pStartEntry == pEntry ) + { + pTemp = pView->NextSibling( pStartEntry ); + if( !pTemp ) + pTemp = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry )); + pStartEntry = pTemp; + } + if( GetUpdateMode()) + { + // wenns der letzte ist, muss invalidiert werden, damit die Linien + // richtig gezeichnet (in diesem Fall geloescht) werden. + if( pStartEntry && (pStartEntry != pOldStartEntry || pEntry == (SvLBoxEntry*)pView->GetModel()->Last()) ) + { + aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry )); + pView->Invalidate( GetVisibleArea() ); + } + else + InvalidateEntriesFrom( GetEntryLine( pEntry ) ); + } +} + +void SvImpLBox::EntryRemoved() +{ + if( nFlags & F_REMOVED_ENTRY_INVISIBLE ) + { + nFlags &= (~F_REMOVED_ENTRY_INVISIBLE); + return; + } + if( !pStartEntry ) + pStartEntry = pTree->First(); + if( !pCursor ) + SetCursor( pStartEntry, sal_True ); + + if( pCursor && (bSimpleTravel || !pView->GetSelectionCount() )) + pView->Select( pCursor, sal_True ); + + if( GetUpdateMode()) + { + if( nFlags & F_REMOVED_RECALC_MOST_RIGHT ) + FindMostRight(0); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) ); + FillView(); + if( pStartEntry ) + // falls ueber dem Thumb geloescht wurde + aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry) ); + + ShowVerSBar(); + if( pCursor && pView->HasFocus() && !pView->IsSelected(pCursor) ) + { + if( pView->GetSelectionCount() ) + { + // ist ein benachbarter Eintrag selektiert? + SvLBoxEntry* pNextCursor = (SvLBoxEntry*)pView->PrevVisible( pCursor ); + if( !pNextCursor || !pView->IsSelected( pNextCursor )) + pNextCursor = (SvLBoxEntry*)pView->NextVisible( pCursor ); + if( !pNextCursor || !pView->IsSelected( pNextCursor )) + // kein Nachbar selektiert: Ersten selektierten nehmen + pNextCursor = pView->FirstSelected(); + SetCursor( pNextCursor ); + MakeVisible( pCursor ); + } + else + pView->Select( pCursor, sal_True ); + } + ShowCursor( sal_True ); + } + nFlags &= (~F_REMOVED_RECALC_MOST_RIGHT); +} + + +void SvImpLBox::MovingEntry( SvLBoxEntry* pEntry ) +{ + int bDeselAll = nFlags & F_DESEL_ALL; + SelAllDestrAnch( sal_False, sal_True ); // DeselectAll(); + if( !bDeselAll ) + nFlags &= (~F_DESEL_ALL); + + if( pEntry == pCursor ) + ShowCursor( sal_False ); + if( IsEntryInView( pEntry ) ) + pView->Invalidate(); + if( pEntry == pStartEntry ) + { + SvLBoxEntry* pNew = 0; + if( !pEntry->HasChilds() ) + { + pNew = (SvLBoxEntry*)(pView->NextVisible( pStartEntry )); + if( !pNew ) + pNew = (SvLBoxEntry*)(pView->PrevVisible( pStartEntry )); + } + else + { + pNew = pTree->NextSibling( pEntry ); + if( !pNew ) + pNew = pTree->PrevSibling( pEntry ); + } + pStartEntry = pNew; + } +} + +void SvImpLBox::EntryMoved( SvLBoxEntry* pEntry ) +{ + // #97680# -------------- + UpdateContextBmpWidthVectorFromMovedEntry( pEntry ); + + if ( !pStartEntry ) + // this might happen if the only entry in the view is moved to its very same position + // #i97346# + pStartEntry = pView->First(); + + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1)); + sal_uInt16 nFirstPos = (sal_uInt16)pTree->GetAbsPos( pStartEntry ); + sal_uInt16 nNewPos = (sal_uInt16)pTree->GetAbsPos( pEntry ); + FindMostRight(0); + if( nNewPos < nFirstPos ) //!!!Notloesung + pStartEntry = pEntry; + // #97702# --------------- + SyncVerThumb(); + if( pEntry == pCursor ) + { + if( pView->IsEntryVisible( pCursor ) ) + ShowCursor( sal_True ); + else + { + SvLBoxEntry* pParent = pEntry; + do { + pParent = pTree->GetParent( pParent ); + } + while( !pView->IsEntryVisible( pParent ) ); + SetCursor( pParent ); + } + } + if( IsEntryInView( pEntry ) ) + pView->Invalidate(); +} + + + +void SvImpLBox::EntryInserted( SvLBoxEntry* pEntry ) +{ + if( GetUpdateMode() ) + { + SvLBoxEntry* pParent = (SvLBoxEntry*)pTree->GetParent(pEntry); + if( pParent && pTree->GetChildList(pParent)->Count() == 1 ) + // Pluszeichen zeichnen + pTree->InvalidateEntry( pParent ); + + if( !pView->IsEntryVisible( pEntry ) ) + return; + int bDeselAll = nFlags & F_DESEL_ALL; + if( bDeselAll ) + SelAllDestrAnch( sal_False, sal_True ); + else + DestroyAnchor(); + // nFlags &= (~F_DESEL_ALL); +// ShowCursor( sal_False ); // falls sich Cursor nach unten verschiebt + long nY = GetEntryLine( pEntry ); + sal_Bool bEntryVisible = IsLineVisible( nY ); + if( bEntryVisible ) + { + ShowCursor( sal_False ); // falls sich Cursor nach unten verschiebt + nY -= pView->GetEntryHeight(); // wg. Linien + InvalidateEntriesFrom( nY ); + } + else if( pStartEntry && nY < GetEntryLine(pStartEntry) ) + { + // pruefen, ob die View komplett gefuellt ist. Wenn + // nicht, dann pStartEntry und den Cursor anpassen + // (automatisches scrollen) + sal_uInt16 nLast = (sal_uInt16)(pView->GetVisiblePos( (SvLBoxEntry*)(pView->LastVisible()))); + sal_uInt16 nThumb = (sal_uInt16)(pView->GetVisiblePos( pStartEntry )); + sal_uInt16 nCurDispEntries = nLast-nThumb+1; + if( nCurDispEntries < nVisibleCount ) + { + // beim naechsten Paint-Event setzen + pStartEntry = 0; + SetCursor( 0 ); + pView->Invalidate(); + } + } + else if( !pStartEntry ) + pView->Invalidate(); + + // die Linien invalidieren + /* + if( (bEntryVisible || bPrevEntryVisible) && + (m_nStyle & ( WB_HASLINES | WB_HASLINESATROOT )) ) + { + SvLBoxTab* pTab = pView->GetFirstDynamicTab(); + if( pTab ) + { + long nDX = pView->GetTabPos( pEntry, pTab ); + Point aTmpPoint; + Size aSize( nDX, nY ); + Rectangle aRect( aTmpPoint, aSize ); + pView->Invalidate( aRect ); + } + } + */ + + SetMostRight( pEntry ); + aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1)); + SyncVerThumb(); // falls vor Thumb eingefuegt wurde + ShowVerSBar(); + ShowCursor( sal_True ); + if( pStartEntry != pView->First() && (nFlags & F_FILLING) ) + pView->Update(); + } +} + + + +// ******************************************************************** +// Eventhandler +// ******************************************************************** + + +// ****** Steuerung der Controlanimation + +sal_Bool SvImpLBox::ButtonDownCheckCtrl(const MouseEvent& rMEvt, SvLBoxEntry* pEntry, + long nY ) +{ + SvLBoxItem* pItem = pView->GetItem(pEntry,rMEvt.GetPosPixel().X(),&pActiveTab); + if( pItem && (pItem->IsA()==SV_ITEM_ID_LBOXBUTTON)) + { + pActiveButton = (SvLBoxButton*)pItem; + pActiveEntry = pEntry; + if( pCursor == pActiveEntry ) + pView->HideFocus(); + pView->CaptureMouse(); + pActiveButton->SetStateHilighted( sal_True ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + return sal_True; + } + else + pActiveButton = 0; + return sal_False; +} + +sal_Bool SvImpLBox::MouseMoveCheckCtrl( const MouseEvent& rMEvt, SvLBoxEntry* pEntry) +{ + if( pActiveButton ) + { + long nY; + long nMouseX = rMEvt.GetPosPixel().X(); + if( pEntry == pActiveEntry && + pView->GetItem(pActiveEntry, nMouseX) == pActiveButton ) + { + if( !pActiveButton->IsStateHilighted() ) + { + pActiveButton->SetStateHilighted(sal_True ); + nY = GetEntryLine( pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + } + } + else + { + if( pActiveButton->IsStateHilighted() ) + { + pActiveButton->SetStateHilighted(sal_False ); + nY = GetEntryLine( pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, SV_LBOXTAB_PUSHABLE ); + } + } + return sal_True; + } + return sal_False; +} + +sal_Bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt ) +{ + if( pActiveButton ) + { + pView->ReleaseMouse(); + SvLBoxEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() ); + long nY = GetEntryLine( pActiveEntry ); + pActiveButton->SetStateHilighted( sal_False ); + long nMouseX = rMEvt.GetPosPixel().X(); + if( pEntry == pActiveEntry && + pView->GetItem( pActiveEntry, nMouseX ) == pActiveButton ) + pActiveButton->ClickHdl( pView, pActiveEntry ); + pView->PaintEntry1( pActiveEntry, nY, + SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER | + SV_LBOXTAB_ADJUST_RIGHT ); + if( pCursor == pActiveEntry ) + ShowCursor( sal_True ); + pActiveButton = 0; + pActiveEntry = 0; + pActiveTab = 0; + return sal_True; + } + return sal_False; +} + +// ******* Steuerung Plus/Minus-Button zum Expandieren/Kollabieren + +// sal_False == kein Expand/Collapse-Button getroffen +sal_Bool SvImpLBox::IsNodeButton( const Point& rPosPixel, SvLBoxEntry* pEntry ) const +{ + if( !pEntry->HasChilds() && !pEntry->HasChildsOnDemand() ) + return sal_False; + + SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab(); + if( !pFirstDynamicTab ) + return sal_False; + + long nMouseX = rPosPixel.X(); + // in Doc-Koords umrechnen + Point aOrigin( pView->GetMapMode().GetOrigin() ); + nMouseX -= aOrigin.X(); + + long nX = pView->GetTabPos( pEntry, pFirstDynamicTab); + nX += nNodeBmpTabDistance; + if( nMouseX < nX ) + return sal_False; + nX += nNodeBmpWidth; + if( nMouseX > nX ) + return sal_False; + return sal_True; +} + +// sal_False == hit no node button +sal_Bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, SvLBoxEntry* pEntry, long /* nY */ ) +{ + sal_Bool bRet = sal_False; + + if ( pView->IsEditingActive() && pEntry == pView->pEdEntry ) + // inplace editing -> nothing to do + bRet = sal_True; + else if ( IsNodeButton( rMEvt.GetPosPixel(), pEntry ) ) + { + if ( pView->IsExpanded( pEntry ) ) + { + pView->EndEditing( sal_True ); + pView->Collapse( pEntry ); + } + else + { + // you can expand an entry, which is in editing + pView->Expand( pEntry ); + } + bRet = sal_True; + } + + return bRet; +} + +void SvImpLBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( !rMEvt.IsLeft() && !rMEvt.IsRight()) + return; + +#ifdef OS2 + // unter OS/2 kommt zwischen MouseButtonDown und + // MouseButtonUp ein MouseMove + nFlags |= F_IGNORE_NEXT_MOUSEMOVE; +#endif + aEditTimer.Stop(); + Point aPos( rMEvt.GetPosPixel()); + + if( aPos.X() > aOutputSize.Width() || aPos.Y() > aOutputSize.Height() ) + return; + + SvLBoxEntry* pEntry = GetEntry( aPos ); + if ( pEntry != pCursor ) + // new entry selected -> reset current tab position to first tab + nCurTabPos = FIRST_ENTRY_TAB; + nFlags &= (~F_FILLING); + pView->GrabFocus(); + // #120417# the entry can still be invalid! + if( !pEntry || !pView->GetViewData( pEntry )) + return; + + long nY = GetEntryLine( pEntry ); + // Node-Button? + if( ButtonDownCheckExpand( rMEvt, pEntry, nY ) ) + return; + + if( !EntryReallyHit(pEntry,aPos,nY)) + return; + + SvLBoxItem* pXItem = pView->GetItem( pEntry, aPos.X() ); + if( pXItem ) + { + SvLBoxTab* pXTab = pView->GetTab( pEntry, pXItem ); + if ( !rMEvt.IsMod1() && !rMEvt.IsMod2() && rMEvt.IsLeft() && pXTab->IsEditable() + && pEntry == pView->FirstSelected() && NULL == pView->NextSelected( pEntry ) ) + // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected + nFlags |= F_START_EDITTIMER; + if ( !pView->IsSelected( pEntry ) ) + nFlags &= ~F_START_EDITTIMER; + } + + + if( (rMEvt.GetClicks() % 2) == 0 ) + { + nFlags &= (~F_START_EDITTIMER); + pView->pHdlEntry = pEntry; + if( pView->DoubleClickHdl() ) + { + // falls im Handler der Eintrag geloescht wurde + pEntry = GetClickedEntry( aPos ); + if( !pEntry ) + return; + if( pEntry != pView->pHdlEntry ) + { + // neu selektieren & tschuess + if( !bSimpleTravel && !aSelEng.IsAlwaysAdding()) + SelAllDestrAnch( sal_False, sal_True ); // DeselectAll(); + SetCursor( pEntry ); + + return; + } + if( pEntry->HasChilds() || pEntry->HasChildsOnDemand() ) + { + if( pView->IsExpanded(pEntry) ) + pView->Collapse( pEntry ); + else + pView->Expand( pEntry ); + if( pEntry == pCursor ) // nur wenn Entryitem angeklickt wurde + // (Nodebutton ist kein Entryitem!) + pView->Select( pCursor, sal_True ); + return; + } + } + } + else + { + // CheckButton? (TreeListBox: Check + Info) + if( ButtonDownCheckCtrl(rMEvt, pEntry, nY) == sal_True) + return; + // Inplace-Editing? +#if 0 + if( rMEvt.IsMod2() && pView->IsInplaceEditingEnabled() ) + { + SvLBoxItem* pItem = pView->GetItem( pEntry, aPos.X() ); + if( pItem ) + pView->EditingRequest( pEntry, pItem, aPos ); + return; + } +#endif + } + if ( aSelEng.GetSelectionMode() != NO_SELECTION ) + aSelEng.SelMouseButtonDown( rMEvt ); +} + +void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt) +{ +#ifdef OS2 + nFlags &= (~F_IGNORE_NEXT_MOUSEMOVE); +#endif + if ( !ButtonUpCheckCtrl( rMEvt ) && ( aSelEng.GetSelectionMode() != NO_SELECTION ) ) + aSelEng.SelMouseButtonUp( rMEvt ); + EndScroll(); + if( nFlags & F_START_EDITTIMER ) + { + nFlags &= (~F_START_EDITTIMER); + aEditClickPos = rMEvt.GetPosPixel(); + aEditTimer.Start(); + } + + return; +} + +void SvImpLBox::MouseMove( const MouseEvent& rMEvt) +{ +#ifdef OS2 + if( nFlags & F_IGNORE_NEXT_MOUSEMOVE ) + { + nFlags &= (~F_IGNORE_NEXT_MOUSEMOVE); + return; + } +#endif + SvLBoxEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() ); + if ( !MouseMoveCheckCtrl( rMEvt, pEntry ) && ( aSelEng.GetSelectionMode() != NO_SELECTION ) ) + aSelEng.SelMouseMove( rMEvt ); + return; +} + +sal_Bool SvImpLBox::KeyInput( const KeyEvent& rKEvt) +{ + aEditTimer.Stop(); + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + + if( rKeyCode.IsMod2() ) + return sal_False; // Alt-Taste nicht auswerten + + nFlags &= (~F_FILLING); + + if( !pCursor ) + pCursor = pStartEntry; + if( !pCursor ) + return sal_False; + + sal_Bool bKeyUsed = sal_True; + + sal_uInt16 nDelta = (sal_uInt16)aVerSBar.GetPageSize(); + sal_uInt16 aCode = rKeyCode.GetCode(); + + sal_Bool bShift = rKeyCode.IsShift(); + sal_Bool bMod1 = rKeyCode.IsMod1(); + + SvLBoxEntry* pNewCursor; + + const WinBits nWindowStyle = pView->GetStyle(); + switch( aCode ) + { + case KEY_UP: + if( !IsEntryInView( pCursor ) ) + MakeVisible( pCursor ); + + pNewCursor = pCursor; + do + { + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pNewCursor )); + } while( pNewCursor && !IsSelectable(pNewCursor) ); + + if ( pNewCursor ) + // new entry selected -> reset current tab position to first tab + nCurTabPos = FIRST_ENTRY_TAB; + // if there is no next entry, take the current one + // this ensures that in case of _one_ entry in the list, this entry is selected when pressing + // the cursor key + // 06.09.20001 - 83416 - fs@openoffice.org + if ( !pNewCursor && pCursor ) + pNewCursor = pCursor; + + if( pNewCursor ) + { + aSelEng.CursorPosChanging( bShift, bMod1 ); + SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on + if( !IsEntryInView( pNewCursor ) ) + KeyUp( sal_False ); + } + break; + + case KEY_DOWN: + if( !IsEntryInView( pCursor ) ) + MakeVisible( pCursor ); + + pNewCursor = pCursor; + do + { + pNewCursor = (SvLBoxEntry*)(pView->NextVisible( pNewCursor )); + } while( pNewCursor && !IsSelectable(pNewCursor) ); + + if ( pNewCursor ) + // new entry selected -> reset current tab position to first tab + nCurTabPos = FIRST_ENTRY_TAB; + + // if there is no next entry, take the current one + // this ensures that in case of _one_ entry in the list, this entry is selected when pressing + // the cursor key + // 06.09.20001 - 83416 - frank.schoenheit@sun.com + if ( !pNewCursor && pCursor ) + pNewCursor = pCursor; + + if( pNewCursor ) + { + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on + else + { + if( pCursor ) + pView->Select( pCursor, sal_False ); + KeyDown( sal_False ); + SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on + } + } + else + KeyDown( sal_False ); // weil ScrollBar-Range evtl. noch + // scrollen erlaubt + break; + + case KEY_RIGHT: + { + if( bSubLstOpLR && IsNowExpandable() ) + pView->Expand( pCursor ); + else if ( bIsCellFocusEnabled && pCursor ) + { + if ( nCurTabPos < ( pView->TabCount() - 1 /*!2*/ ) ) + { + ++nCurTabPos; + ShowCursor( sal_True ); + CallEventListeners( VCLEVENT_LISTBOX_SELECT, pCursor ); + } + } + else if( nWindowStyle & WB_HSCROLL ) + { + long nThumb = aHorSBar.GetThumbPos(); + nThumb += aHorSBar.GetLineSize(); + long nOldThumb = aHorSBar.GetThumbPos(); + aHorSBar.SetThumbPos( nThumb ); + nThumb = nOldThumb; + nThumb -= aHorSBar.GetThumbPos(); + nThumb *= -1; + if( nThumb ) + { + KeyLeftRight( nThumb ); + EndScroll(); + } + } + else + bKeyUsed = sal_False; + break; + } + + case KEY_LEFT: + { + if ( bIsCellFocusEnabled ) + { + if ( nCurTabPos > FIRST_ENTRY_TAB ) + { + --nCurTabPos; + ShowCursor( sal_True ); + CallEventListeners( VCLEVENT_LISTBOX_SELECT, pCursor ); + } + } + else if ( nWindowStyle & WB_HSCROLL ) + { + long nThumb = aHorSBar.GetThumbPos(); + nThumb -= aHorSBar.GetLineSize(); + long nOldThumb = aHorSBar.GetThumbPos(); + aHorSBar.SetThumbPos( nThumb ); + nThumb = nOldThumb; + nThumb -= aHorSBar.GetThumbPos(); + if( nThumb ) + { + KeyLeftRight( -nThumb ); + EndScroll(); + } + else if( bSubLstOpLR ) + { + if( IsExpandable() && pView->IsExpanded( pCursor ) ) + pView->Collapse( pCursor ); + else + { + pNewCursor = pView->GetParent( pCursor ); + if( pNewCursor ) + SetCursor( pNewCursor ); + } + } + } + else if( bSubLstOpLR && IsExpandable() ) + pView->Collapse( pCursor ); + else + bKeyUsed = sal_False; + break; + } + + case KEY_PAGEUP: + if( !bMod1 ) + { + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pCursor, nDelta )); + + while( nDelta && pNewCursor && !IsSelectable(pNewCursor) ) + { + pNewCursor = (SvLBoxEntry*)(pView->NextVisible( pNewCursor )); + nDelta--; + } + + if( nDelta ) + { + DBG_ASSERT(pNewCursor&&(sal_uLong)pNewCursor!=(sal_uLong)pCursor,"Cursor?"); + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor ); + else + { + SetCursor( pNewCursor ); + KeyUp( sal_True ); + } + } + } + else + bKeyUsed = sal_False; + break; + + case KEY_PAGEDOWN: + if( !bMod1 ) + { + pNewCursor= (SvLBoxEntry*)(pView->NextVisible( pCursor, nDelta )); + + while( nDelta && pNewCursor && !IsSelectable(pNewCursor) ) + { + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pNewCursor )); + nDelta--; + } + + if( nDelta ) + { + DBG_ASSERT(pNewCursor&&(sal_uLong)pNewCursor!=(sal_uLong)pCursor,"Cursor?"); + aSelEng.CursorPosChanging( bShift, bMod1 ); + if( IsEntryInView( pNewCursor ) ) + SetCursor( pNewCursor ); + else + { + SetCursor( pNewCursor ); + KeyDown( sal_True ); + } + } + else + KeyDown( sal_False ); // siehe KEY_DOWN + } + else + bKeyUsed = sal_False; + break; + + case KEY_SPACE: + if ( pView->GetSelectionMode() != NO_SELECTION ) + { + if ( bMod1 ) + { + if ( pView->GetSelectionMode() == MULTIPLE_SELECTION && !bShift ) + // toggle selection + pView->Select( pCursor, !pView->IsSelected( pCursor ) ); + } + else if ( !bShift /*&& !bMod1*/ ) + { + if ( aSelEng.IsAddMode() ) + { + // toggle selection + pView->Select( pCursor, !pView->IsSelected( pCursor ) ); + } + else if ( !pView->IsSelected( pCursor ) ) + { + SelAllDestrAnch( sal_False ); + pView->Select( pCursor, sal_True ); + } + else + bKeyUsed = sal_False; + } + else + bKeyUsed = sal_False; + } + else + bKeyUsed = sal_False; + break; + + case KEY_RETURN: + if( bSubLstOpRet && IsExpandable() ) + { + if( pView->IsExpanded( pCursor ) ) + pView->Collapse( pCursor ); + else + pView->Expand( pCursor ); + } + else + bKeyUsed = sal_False; + break; + + case KEY_F2: + if( !bShift && !bMod1 ) + { + aEditClickPos = Point( -1, -1 ); + EditTimerCall( 0 ); + } + else + bKeyUsed = sal_False; + break; + + case KEY_F8: + if( bShift && pView->GetSelectionMode()==MULTIPLE_SELECTION && + !(m_nStyle & WB_SIMPLEMODE)) + { + if( aSelEng.IsAlwaysAdding() ) + aSelEng.AddAlways( sal_False ); + else + aSelEng.AddAlways( sal_True ); + } + else + bKeyUsed = sal_False; + break; + + +#ifdef OV_DEBUG + case KEY_F9: + MakeVisible( pCursor ); + break; + case KEY_F10: + pView->RemoveSelection(); + break; + case KEY_DELETE: + pView->RemoveEntry( pCursor ); + break; +#endif + + case KEY_ADD: + if( pCursor ) + { + if( !pView->IsExpanded(pCursor)) + pView->Expand( pCursor ); + if( bMod1 ) + { + sal_uInt16 nRefDepth = pTree->GetDepth( pCursor ); + SvLBoxEntry* pCur = pTree->Next( pCursor ); + while( pCur && pTree->GetDepth(pCur) > nRefDepth ) + { + if( pCur->HasChilds() && !pView->IsExpanded(pCur)) + pView->Expand( pCur ); + pCur = pTree->Next( pCur ); + } + } + } + else + bKeyUsed = sal_False; + break; + + case KEY_A: + if( bMod1 ) + SelAllDestrAnch( sal_True ); + else + bKeyUsed = sal_False; + break; + + case KEY_SUBTRACT: + if( pCursor ) + { + if( pView->IsExpanded(pCursor)) + pView->Collapse( pCursor ); + if( bMod1 ) + { + // bis zur Root alle Parents einklappen + SvLBoxEntry* pParentToCollapse = (SvLBoxEntry*)pTree->GetRootLevelParent(pCursor); + if( pParentToCollapse ) + { + sal_uInt16 nRefDepth; + // Sonderbehandlung Explorer: Befindet sich auf der + // Root nur ein Eintrag,dann den Root-Entry nicht + // einklappen + if( pTree->GetChildList(0)->Count() < 2 ) + { + nRefDepth = 1; + pParentToCollapse = pCursor; + while( pTree->GetParent(pParentToCollapse) && + pTree->GetDepth( pTree->GetParent(pParentToCollapse)) > 0) + { + pParentToCollapse = pTree->GetParent(pParentToCollapse); + } + } + else + nRefDepth = 0; + + if( pView->IsExpanded(pParentToCollapse) ) + pView->Collapse( pParentToCollapse ); + SvLBoxEntry* pCur = pTree->Next( pParentToCollapse ); + while( pCur && pTree->GetDepth(pCur) > nRefDepth ) + { + if( pCur->HasChilds() && pView->IsExpanded(pCur) ) + pView->Collapse( pCur ); + pCur = pTree->Next( pCur ); + } + } + } + } + else + bKeyUsed = sal_False; + break; + + case KEY_DIVIDE : + if( bMod1 ) + SelAllDestrAnch( sal_True ); + else + bKeyUsed = sal_False; + break; + + case KEY_COMMA : + if( bMod1 ) + SelAllDestrAnch( sal_False ); + else + bKeyUsed = sal_False; + break; + + case KEY_HOME : + pNewCursor = pView->GetModel()->First(); + + while( pNewCursor && !IsSelectable(pNewCursor) ) + { + pNewCursor = (SvLBoxEntry*)(pView->NextVisible( pNewCursor )); + } + + if( pNewCursor && pNewCursor != pCursor ) + { +// SelAllDestrAnch( sal_False ); + aSelEng.CursorPosChanging( bShift, bMod1 ); + SetCursor( pNewCursor ); + if( !IsEntryInView( pNewCursor ) ) + MakeVisible( pNewCursor ); + } + else + bKeyUsed = sal_False; + break; + + case KEY_END : + pNewCursor = pView->GetModel()->Last(); + + while( pNewCursor && !IsSelectable(pNewCursor) ) + { + pNewCursor = (SvLBoxEntry*)(pView->PrevVisible( pNewCursor )); + } + + if( pNewCursor && pNewCursor != pCursor) + { +// SelAllDestrAnch( sal_False ); + aSelEng.CursorPosChanging( bShift, bMod1 ); + SetCursor( pNewCursor ); + if( !IsEntryInView( pNewCursor ) ) + MakeVisible( pNewCursor ); + } + else + bKeyUsed = sal_False; + break; + + case KEY_ESCAPE: + case KEY_TAB: + case KEY_DELETE: + case KEY_BACKSPACE: + // #105907# must not be handled because this quits dialogs and does other magic things... + // if there are other single keys which should not be handled, they can be added here + bKeyUsed = sal_False; + break; + + default: + // is there any reason why we should eat the events here? The only place where this is called + // is from SvTreeListBox::KeyInput. If we set bKeyUsed to sal_True here, then the key input + // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection + // handling. + // (The old code here which intentionally set bKeyUsed to TRUE said this was because of "quick search" + // handling, but actually there was no quick search handling anymore. We just re-implemented it.) + // #i31275# / 2009-06-16 / frank.schoenheit@sun.com + bKeyUsed = sal_False; + break; + } + return bKeyUsed; +} + +void __EXPORT SvImpLBox::GetFocus() +{ + if( pCursor ) + { + pView->SetEntryFocus( pCursor, sal_True ); + ShowCursor( sal_True ); +// auskommentiert wg. deselectall +// if( bSimpleTravel && !pView->IsSelected(pCursor) ) +// pView->Select( pCursor, sal_True ); + } + if( m_nStyle & WB_HIDESELECTION ) + { + SvLBoxEntry* pEntry = pView->FirstSelected(); + while( pEntry ) + { + InvalidateEntry( pEntry ); + pEntry = pView->NextSelected( pEntry ); + } + /* + SvLBoxEntry* pEntry = pView->GetModel()->First(); + while( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + if( pViewData->IsCursored() ) + { + pViewData->SetCursored( sal_False ); + InvalidateEntry( pEntry ); + } + pEntry = pView->GetModel()->Next( pEntry ); + } + */ + + + } +} + +void __EXPORT SvImpLBox::LoseFocus() +{ + aEditTimer.Stop(); + if( pCursor ) + pView->SetEntryFocus( pCursor,sal_False ); + ShowCursor( sal_False ); + + if( m_nStyle & WB_HIDESELECTION ) + { + SvLBoxEntry* pEntry = pView->FirstSelected(); + while( pEntry ) + { + //SvViewData* pViewData = pView->GetViewData( pEntry ); + //pViewData->SetCursored( sal_True ); + InvalidateEntry( pEntry ); + pEntry = pView->NextSelected( pEntry ); + } + } +} + + +// ******************************************************************** +// SelectionEngine +// ******************************************************************** + +inline void SvImpLBox::SelectEntry( SvLBoxEntry* pEntry, sal_Bool bSelect ) +{ + pView->Select( pEntry, bSelect ); +} + +__EXPORT ImpLBSelEng::ImpLBSelEng( SvImpLBox* pImpl, SelectionEngine* pSEng, + SvTreeListBox* pV ) +{ + pImp = pImpl; + pSelEng = pSEng; + pView = pV; +} + +__EXPORT ImpLBSelEng::~ImpLBSelEng() +{ +} + +void __EXPORT ImpLBSelEng::BeginDrag() +{ + pImp->BeginDrag(); +} + +/* +void __EXPORT ImpLBSelEng::EndDrag( const Point& ) +{ +} +*/ + +void __EXPORT ImpLBSelEng::CreateAnchor() +{ + pImp->pAnchor = pImp->pCursor; +} + +void __EXPORT ImpLBSelEng::DestroyAnchor() +{ + pImp->pAnchor = 0; +} + +/* +void __EXPORT ImpLBSelEng::CreateCursor() +{ + pImp->pAnchor = 0; +} +*/ + + +sal_Bool __EXPORT ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, sal_Bool bDontSelectAtCursor) +{ + SvLBoxEntry* pNewCursor = pImp->MakePointVisible( rPoint ); + if( pNewCursor != pImp->pCursor ) + pImp->BeginScroll(); + + if( pNewCursor ) + { + // bei SimpleTravel wird in SetCursor selektiert und + // der Select-Handler gerufen + //if( !bDontSelectAtCursor && !pImp->bSimpleTravel ) + // pImp->SelectEntry( pNewCursor, sal_True ); + pImp->SetCursor( pNewCursor, bDontSelectAtCursor ); + return sal_True; + } + return sal_False; +} + +sal_Bool __EXPORT ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( pEntry ) + return pView->IsSelected(pEntry); + return sal_False; +} + +void __EXPORT ImpLBSelEng::DeselectAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( !pEntry ) + return; + pImp->SelectEntry( pEntry, sal_False ); +} + +/* +void __EXPORT ImpLBSelEng::SelectAtPoint( const Point& rPoint ) +{ + SvLBoxEntry* pEntry = pImp->MakePointVisible( rPoint ); + if( !pEntry ) + return; + pImp->SelectEntry( pEntry, sal_True ); +} +*/ + +void __EXPORT ImpLBSelEng::DeselectAll() +{ + pImp->SelAllDestrAnch( sal_False, sal_False ); // SelectionEngine nicht resetten! + pImp->nFlags &= (~F_DESEL_ALL); +} + +// *********************************************************************** +// Selektion +// *********************************************************************** + +void SvImpLBox::SetAnchorSelection(SvLBoxEntry* pOldCursor,SvLBoxEntry* pNewCursor) +{ + SvLBoxEntry* pEntry; + sal_uLong nAnchorVisPos = pView->GetVisiblePos( pAnchor ); + sal_uLong nOldVisPos = pView->GetVisiblePos( pOldCursor ); + sal_uLong nNewVisPos = pView->GetVisiblePos( pNewCursor ); + + if( nOldVisPos > nAnchorVisPos || + ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) ) + { + if( nNewVisPos > nOldVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, sal_True ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, sal_True ); + return; + } + + if( nNewVisPos < nAnchorVisPos ) + { + pEntry = pAnchor; + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, sal_False ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, sal_False ); + + pEntry = pNewCursor; + while( pEntry && pEntry != pAnchor ) + { + pView->Select( pEntry, sal_True ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, sal_True ); + return; + } + + if( nNewVisPos < nOldVisPos ) + { + pEntry = pNewCursor; + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, sal_False ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, sal_False ); + return; + } + } + else + { + if( nNewVisPos < nOldVisPos ) // Vergroessern der Selektion + { + pEntry = pNewCursor; + while( pEntry && pEntry != pOldCursor ) + { + pView->Select( pEntry, sal_True ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, sal_True ); + return; + } + + if( nNewVisPos > nAnchorVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pAnchor ) + { + pView->Select( pEntry, sal_False ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, sal_False ); + pEntry = pAnchor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, sal_True ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + if( pEntry ) + pView->Select( pEntry, sal_True ); + return; + } + + if( nNewVisPos > nOldVisPos ) + { + pEntry = pOldCursor; + while( pEntry && pEntry != pNewCursor ) + { + pView->Select( pEntry, sal_False ); + pEntry = (SvLBoxEntry*)(pView->NextVisible( pEntry )); + } + return; + } + } +} + +void SvImpLBox::SelAllDestrAnch( sal_Bool bSelect, sal_Bool bDestroyAnchor, + sal_Bool bSingleSelToo ) +{ + SvLBoxEntry* pEntry; + nFlags &= (~F_DESEL_ALL); + if( bSelect && bSimpleTravel ) + { + if( pCursor && !pView->IsSelected( pCursor )) + { + pView->Select( pCursor, sal_True ); + } + return; + } + if( !bSelect && pView->GetSelectionCount() == 0 ) + { + if( bSimpleTravel && ( !GetUpdateMode() || !pCursor) ) + nFlags |= F_DESEL_ALL; + return; + } + if( bSelect && pView->GetSelectionCount() == pView->GetEntryCount()) + return; + if( !bSingleSelToo && bSimpleTravel ) + return; + + if( !bSelect && pView->GetSelectionCount()==1 && pCursor && + pView->IsSelected( pCursor )) + { + pView->Select( pCursor, sal_False ); + if( bDestroyAnchor ) + DestroyAnchor(); // Anker loeschen & SelectionEngine zuruecksetzen + else + pAnchor = 0; // internen Anker immer loeschen + return; + } + + if( bSimpleTravel && !pCursor && !GetUpdateMode() ) + nFlags |= F_DESEL_ALL; + + ShowCursor( sal_False ); + sal_Bool bUpdate = GetUpdateMode(); + + nFlags |= F_IGNORE_SELECT; // EntryInserted soll nix tun + pEntry = pTree->First(); + while( pEntry ) + { + if( pView->Select( pEntry, bSelect ) ) + { + if( bUpdate && pView->IsEntryVisible(pEntry) ) + { + long nY = GetEntryLine( pEntry ); + if( IsLineVisible( nY ) ) + pView->PaintEntry1( pEntry, nY, 0xffff ); // wg. ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION ); + } + } + pEntry = pTree->Next( pEntry ); + } + nFlags &= ~F_IGNORE_SELECT; + + if( bDestroyAnchor ) + DestroyAnchor(); // Anker loeschen & SelectionEngine zuruecksetzen + else + pAnchor = 0; // internen Anker immer loeschen + ShowCursor( sal_True ); +} + +void SvImpLBox::SetSelectionMode( SelectionMode eSelMode ) +{ + aSelEng.SetSelectionMode( eSelMode); + if( eSelMode == SINGLE_SELECTION ) + bSimpleTravel = sal_True; + else + bSimpleTravel = sal_False; + if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == MULTIPLE_SELECTION) ) + aSelEng.AddAlways( sal_True ); +} + +// *********************************************************************** +// Drag & Drop +// *********************************************************************** + +void SvImpLBox::SetDragDropMode( DragDropMode eDDMode ) +{ + if( eDDMode && eDDMode != SV_DRAGDROP_APP_DROP ) + { + aSelEng.ExpandSelectionOnMouseMove( sal_False ); + aSelEng.EnableDrag( sal_True ); + } + else + { + aSelEng.ExpandSelectionOnMouseMove( sal_True ); + aSelEng.EnableDrag( sal_False ); + } +} + +void SvImpLBox::BeginDrag() +{ + nFlags &= (~F_FILLING); + if( !bAsyncBeginDrag ) + { + BeginScroll(); + pView->StartDrag( 0, aSelEng.GetMousePosPixel() ); + EndScroll(); + } + else + { + aAsyncBeginDragPos = aSelEng.GetMousePosPixel(); + aAsyncBeginDragTimer.Start(); + } +} + +IMPL_LINK( SvImpLBox, BeginDragHdl, void*, EMPTYARG ) +{ + pView->StartDrag( 0, aAsyncBeginDragPos ); + return 0; +} + +void SvImpLBox::PaintDDCursor( SvLBoxEntry* pInsertionPos ) +{ + long nY; + if( pInsertionPos ) + { + nY = GetEntryLine( pInsertionPos ); + nY += pView->GetEntryHeight(); + } + else + nY = 1; + RasterOp eOldOp = pView->GetRasterOp(); + pView->SetRasterOp( ROP_INVERT ); + Color aOldLineColor = pView->GetLineColor(); + pView->SetLineColor( Color( COL_BLACK ) ); + pView->DrawLine( Point( 0, nY ), Point( aOutputSize.Width(), nY ) ); + pView->SetLineColor( aOldLineColor ); + pView->SetRasterOp( eOldOp ); +} +/* -----------------26.08.2003 12:52----------------- + Delete all sub menues of a PopupMenu, recursively + --------------------------------------------------*/ +void lcl_DeleteSubPopups(PopupMenu* pPopup) +{ + for(sal_uInt16 i = 0; i < pPopup->GetItemCount(); i++) + { + PopupMenu* pSubPopup = pPopup->GetPopupMenu( pPopup->GetItemId( i )); + if(pSubPopup) + { + lcl_DeleteSubPopups(pSubPopup); + delete pSubPopup; + } + } +} + +void SvImpLBox::Command( const CommandEvent& rCEvt ) +{ + sal_uInt16 nCommand = rCEvt.GetCommand(); + + if( nCommand == COMMAND_CONTEXTMENU ) + aEditTimer.Stop(); + + // Rollmaus-Event? + if( ( ( nCommand == COMMAND_WHEEL ) || ( nCommand == COMMAND_STARTAUTOSCROLL ) || ( nCommand == COMMAND_AUTOSCROLL ) ) + && pView->HandleScrollCommand( rCEvt, &aHorSBar, &aVerSBar ) ) + return; + + if( bContextMenuHandling && nCommand == COMMAND_CONTEXTMENU ) + { + Point aPopupPos; + sal_Bool bClickedIsFreePlace = sal_False; + std::stack<SvLBoxEntry*> aSelRestore; + + if( rCEvt.IsMouseEvent() ) + { // change selection, if mouse pos doesn't fit to selection + + aPopupPos = rCEvt.GetMousePosPixel(); + + SvLBoxEntry* pClickedEntry = GetEntry( aPopupPos ); + if( pClickedEntry ) + { // mouse in non empty area + sal_Bool bClickedIsSelected = sal_False; + + // collect the currently selected entries + SvLBoxEntry* pSelected = pView->FirstSelected(); + while( pSelected ) + { + bClickedIsSelected |= ( pClickedEntry == pSelected ); + pSelected = pView->NextSelected( pSelected ); + } + + // if the entry which the user clicked at is not selected + if( !bClickedIsSelected ) + { // deselect all other and select the clicked one + pView->SelectAll( sal_False ); + pView->SetCursor( pClickedEntry ); + } + } + else if( aSelEng.GetSelectionMode() == SINGLE_SELECTION ) + {//modified by BerryJia for fixing Bug102739 2002-9-9 17:00(Beijing Time) + bClickedIsFreePlace = sal_True; + sal_Int32 nSelectedEntries = pView->GetSelectionCount(); + SvLBoxEntry* pSelected = pView->FirstSelected(); + for(sal_uInt16 nSel = 0; nSel < nSelectedEntries; nSel++ ) + { + aSelRestore.push(pSelected); + pSelected = pView->NextSelected( pSelected ); + } + pView->SelectAll( sal_False ); + } + else + { // deselect all + pView->SelectAll( sal_False ); + } + + + } + else + { // key event (or at least no mouse event) + sal_Int32 nSelectionCount = pView->GetSelectionCount(); + + if( nSelectionCount ) + { // now allways take first visible as base for positioning the menu + SvLBoxEntry* pSelected = pView->FirstSelected(); + while( pSelected ) + { + if( IsEntryInView( pSelected ) ) + break; + + pSelected = pView->NextSelected( pSelected ); + } + + if( !pSelected ) + { + // no one was visible + pSelected = pView->FirstSelected(); + pView->MakeVisible( pSelected ); + } + + aPopupPos = pView->GetFocusRect( pSelected, pView->GetEntryPosition( pSelected ).Y() ).Center(); + } + else + aPopupPos = Point( 0, 0 ); + } + + PopupMenu* pPopup = pView->CreateContextMenu(); + + if( pPopup ) + { + // do action for selected entry in popup menu + sal_uInt16 nMenuAction = pPopup->Execute( pView, aPopupPos ); + if ( nMenuAction ) + pView->ExcecuteContextMenuAction( nMenuAction ); + lcl_DeleteSubPopups(pPopup); + delete pPopup; + } + //added by BerryJia for fixing Bug102739 2002-9-9 17:00(Beijing Time) + if( bClickedIsFreePlace ) + { + while(!aSelRestore.empty()) + { + SvLBoxEntry* pEntry = aSelRestore.top(); + //#i19717# the entry is maybe already deleted + bool bFound = false; + for(sal_uLong nEntry = 0; nEntry < pView->GetEntryCount(); nEntry++) + if(pEntry == pView->GetEntry(nEntry)) + { + bFound = true; + break; + } + if(bFound) + SetCurEntry( pEntry ); + aSelRestore.pop(); + } + } + } +#ifndef NOCOMMAND + else + { + const Point& rPos = rCEvt.GetMousePosPixel(); + if( rPos.X() < aOutputSize.Width() && rPos.Y() < aOutputSize.Height() ) + aSelEng.Command( rCEvt ); + } +#endif +} + +void SvImpLBox::BeginScroll() +{ + if( !(nFlags & F_IN_SCROLLING)) + { + pView->NotifyBeginScroll(); + nFlags |= F_IN_SCROLLING; + } +} + +void SvImpLBox::EndScroll() +{ + if( nFlags & F_IN_SCROLLING) + { + pView->NotifyEndScroll(); + nFlags &= (~F_IN_SCROLLING); + } +} + + +Rectangle SvImpLBox::GetVisibleArea() const +{ + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; + Rectangle aRect( aPos, aOutputSize ); + return aRect; +} + +void SvImpLBox::Invalidate() +{ + pView->SetClipRegion(); +} + +void SvImpLBox::SetCurEntry( SvLBoxEntry* pEntry ) +{ + if ( ( aSelEng.GetSelectionMode() != SINGLE_SELECTION ) + && ( aSelEng.GetSelectionMode() != NO_SELECTION ) + ) + SelAllDestrAnch( sal_False, sal_True, sal_False ); + if ( pEntry ) + MakeVisible( pEntry ); + SetCursor( pEntry ); + if ( pEntry && ( aSelEng.GetSelectionMode() != NO_SELECTION ) ) + pView->Select( pEntry, sal_True ); +} + +IMPL_LINK( SvImpLBox, EditTimerCall, Timer *, EMPTYARG ) +{ + if( pView->IsInplaceEditingEnabled() ) + { + sal_Bool bIsMouseTriggered = aEditClickPos.X() >= 0; + if ( bIsMouseTriggered ) + { + Point aCurrentMousePos = pView->GetPointerPosPixel(); + if ( ( abs( aCurrentMousePos.X() - aEditClickPos.X() ) > 5 ) + || ( abs( aCurrentMousePos.Y() - aEditClickPos.Y() ) > 5 ) + ) + { + return 0L; + } + } + + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + { + ShowCursor( sal_False ); + pView->ImplEditEntry( pEntry ); + ShowCursor( sal_True ); + } + } + return 0; +} + +sal_Bool SvImpLBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if( rHEvt.GetMode() & HELPMODE_QUICK ) + { + Point aPos( pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() )); + if( !GetVisibleArea().IsInside( aPos )) + return sal_False; + + SvLBoxEntry* pEntry = GetEntry( aPos ); + if( pEntry ) + { + // Rechteck des Textes berechnen + SvLBoxTab* pTab; + SvLBoxString* pItem = (SvLBoxString*)(pView->GetItem( pEntry, aPos.X(), &pTab )); + if( !pItem || pItem->IsA() != SV_ITEM_ID_LBOXSTRING ) + return sal_False; + + aPos = GetEntryPosition( pEntry ); + aPos.X() = pView->GetTabPos( pEntry, pTab ); //pTab->GetPos(); + Size aSize( pItem->GetSize( pView, pEntry ) ); + SvLBoxTab* pNextTab = NextTab( pTab ); + sal_Bool bItemClipped = sal_False; + // wurde das Item von seinem rechten Nachbarn abgeschnitten? + if( pNextTab && pView->GetTabPos(pEntry,pNextTab) < aPos.X()+aSize.Width() ) + { + aSize.Width() = pNextTab->GetPos() - pTab->GetPos(); + bItemClipped = sal_True; + } + Rectangle aItemRect( aPos, aSize ); + + Rectangle aViewRect( GetVisibleArea() ); + + if( bItemClipped || !aViewRect.IsInside( aItemRect ) ) + { + // rechten Item-Rand am View-Rand clippen + //if( aItemRect.Right() > aViewRect.Right() ) + // aItemRect.Right() = aViewRect.Right(); + + Point aPt = pView->OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.Left() = aPt.X(); + aItemRect.Top() = aPt.Y(); + aPt = pView->OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.Right() = aPt.X(); + aItemRect.Bottom() = aPt.Y(); + + Help::ShowQuickHelp( pView, aItemRect, + pItem->GetText(), QUICKHELP_LEFT | QUICKHELP_VCENTER ); + return sal_True; + } + } + } + return sal_False; +} + +SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab* pTab ) +{ + sal_uInt16 nTabCount = pView->TabCount(); + if( nTabCount <= 1 ) + return 0; + for( sal_uInt16 nTab=0; nTab < (nTabCount-1); nTab++) + { + if( pView->aTabs[nTab]==pTab ) + return (SvLBoxTab*)(pView->aTabs[nTab+1]); + } + return 0; +} + +void SvImpLBox::EndSelection() +{ + DestroyAnchor(); + nFlags &= ~F_START_EDITTIMER; +} + +void SvImpLBox::RepaintScrollBars() +{ +} + +void SvImpLBox::SetUpdateMode( sal_Bool bMode ) +{ + if( bUpdateMode != bMode ) + { + bUpdateMode = bMode; + if( bUpdateMode ) + UpdateAll( sal_False ); + } +} + +void SvImpLBox::SetUpdateModeFast( sal_Bool bMode ) +{ + if( bUpdateMode != bMode ) + { + bUpdateMode = bMode; + if( bUpdateMode ) + UpdateAll( sal_False, sal_False ); + } +} + + +sal_Bool SvImpLBox::SetMostRight( SvLBoxEntry* pEntry ) +{ + if( pView->nTreeFlags & TREEFLAG_RECALCTABS ) + { + nFlags |= F_IGNORE_CHANGED_TABS; + pView->SetTabs(); + nFlags &= ~F_IGNORE_CHANGED_TABS; + } + + sal_uInt16 nLastTab = pView->aTabs.Count() - 1; + sal_uInt16 nLastItem = pEntry->ItemCount() - 1; + if( nLastTab != USHRT_MAX && nLastItem != USHRT_MAX ) + { + if( nLastItem < nLastTab ) + nLastTab = nLastItem; + + SvLBoxTab* pTab = (SvLBoxTab*)pView->aTabs[ nLastTab ]; + SvLBoxItem* pItem = pEntry->GetItem( nLastTab ); + + long nTabPos = pView->GetTabPos( pEntry, pTab ); + + long nMaxRight = GetOutputSize().Width(); + Point aPos( pView->GetMapMode().GetOrigin() ); + aPos.X() *= -1; // Umrechnung Dokumentkoord. + nMaxRight = nMaxRight + aPos.X() - 1; + + long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50; + long nTabWidth = nNextTab - nTabPos + 1; + long nItemSize = pItem->GetSize(pView,pEntry).Width(); + long nOffset = pTab->CalcOffset( nItemSize, nTabWidth ); + + long nRight = nTabPos + nOffset + nItemSize; + if( nRight > nMostRight ) + { + nMostRight = nRight; + pMostRightEntry = pEntry; + return sal_True; + } + } + return sal_False; +} + +void SvImpLBox::FindMostRight( SvLBoxEntry* pEntryToIgnore ) +{ + nMostRight = -1; + pMostRightEntry = 0; + if( !pView->GetModel() ) + return; + + SvLBoxEntry* pEntry = (SvLBoxEntry*)pView->FirstVisible(); + while( pEntry ) + { + if( pEntry != pEntryToIgnore ) + SetMostRight( pEntry ); + pEntry = (SvLBoxEntry*)pView->NextVisible( pEntry ); + } +} + +void SvImpLBox::FindMostRight( SvLBoxEntry* pParent, SvLBoxEntry* pEntryToIgnore ) +{ + if( !pParent ) + FindMostRight( pEntryToIgnore ); + else + FindMostRight_Impl( pParent, pEntryToIgnore ); +} + +void SvImpLBox::FindMostRight_Impl( SvLBoxEntry* pParent, SvLBoxEntry* pEntryToIgnore ) +{ + SvTreeEntryList* pList = pTree->GetChildList( pParent ); + + if( !pList ) + return; + + sal_uLong nCount = pList->Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pChild = (SvLBoxEntry*)pList->GetObject( nCur ); + if( pChild != pEntryToIgnore ) + { + SetMostRight( pChild ); + if( pChild->HasChilds() && pView->IsExpanded( pChild )) + FindMostRight_Impl( pChild, pEntryToIgnore ); + } + } +} + +void SvImpLBox::NotifyTabsChanged() +{ + if( GetUpdateMode() && !(nFlags & F_IGNORE_CHANGED_TABS ) && + nCurUserEvent == 0xffffffff ) + { + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)0); + } +} + +IMPL_LINK(SvImpLBox,MyUserEvent,void*, pArg ) +{ + nCurUserEvent = 0xffffffff; + if( !pArg ) + { + pView->Invalidate(); + pView->Update(); + } + else + { + FindMostRight( 0 ); + ShowVerSBar(); + pView->Invalidate( GetVisibleArea() ); + } + return 0; +} + + +void SvImpLBox::StopUserEvent() +{ + if( nCurUserEvent != 0xffffffff ) + { + Application::RemoveUserEvent( nCurUserEvent ); + nCurUserEvent = 0xffffffff; + } +} + +void SvImpLBox::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + if( pEntry ) + { + long nY = GetEntryLine( (SvLBoxEntry*)pEntry ); + Rectangle aRect = pView->GetFocusRect( (SvLBoxEntry*)pEntry, nY ); + Region aOldClip( pView->GetClipRegion()); + Region aClipRegion( GetClipRegionRect() ); + pView->SetClipRegion( aClipRegion ); + pView->ShowFocus( aRect ); + pView->SetClipRegion( aOldClip ); + + } + else + { + pView->HideFocus(); + } +} + +void SvImpLBox::SetTabBar( TabBar* _pTabBar ) +{ + pTabBar = _pTabBar; +} + +void SvImpLBox::CancelPendingEdit() +{ + if( aEditTimer.IsActive() ) + aEditTimer.Stop(); + nFlags &= ~F_START_EDITTIMER; +} + +// ----------------------------------------------------------------------- +void SvImpLBox::implInitDefaultNodeImages() +{ + if ( s_pDefCollapsed ) + // assume that all or nothing is initialized + return; + + s_pDefCollapsed = new Image( SvtResId( RID_IMG_TREENODE_COLLAPSED ) ); + s_pDefCollapsedHC = new Image( SvtResId( RID_IMG_TREENODE_COLLAPSED_HC ) ); + s_pDefExpanded = new Image( SvtResId( RID_IMG_TREENODE_EXPANDED ) ); + s_pDefExpandedHC = new Image( SvtResId( RID_IMG_TREENODE_EXPANDED_HC ) ); +} + +// ----------------------------------------------------------------------- +const Image& SvImpLBox::GetDefaultExpandedNodeImage( BmpColorMode _eMode ) +{ + implInitDefaultNodeImages(); + return ( BMP_COLOR_NORMAL == _eMode ) ? *s_pDefExpanded : *s_pDefExpandedHC; +} + +// ----------------------------------------------------------------------- +const Image& SvImpLBox::GetDefaultCollapsedNodeImage( BmpColorMode _eMode ) +{ + implInitDefaultNodeImages(); + return ( BMP_COLOR_NORMAL == _eMode ) ? *s_pDefCollapsed : *s_pDefCollapsedHC; +} + +// ----------------------------------------------------------------------- +void SvImpLBox::CallEventListeners( sal_uLong nEvent, void* pData ) +{ + if ( pView ) + pView->CallImplEventListeners( nEvent, pData); +} + +// ----------------------------------------------------------------------- + +bool SvImpLBox::SetCurrentTabPos( sal_uInt16 _nNewPos ) +{ + bool bRet = false; + + if ( pView && _nNewPos < ( pView->TabCount() - 2 ) ) + { + nCurTabPos = _nNewPos; + ShowCursor( sal_True ); + bRet = true; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +bool SvImpLBox::IsSelectable( const SvLBoxEntry* pEntry ) +{ + if( pEntry ) + { + SvViewDataEntry* pViewDataNewCur = pView->GetViewDataEntry(const_cast<SvLBoxEntry*>(pEntry)); + return (pViewDataNewCur == 0) || pViewDataNewCur->IsSelectable(); + } + else + { + return false; + } +} + diff --git a/svtools/source/contnr/svimpicn.cxx b/svtools/source/contnr/svimpicn.cxx new file mode 100644 index 000000000000..420c0fcd2162 --- /dev/null +++ b/svtools/source/contnr/svimpicn.cxx @@ -0,0 +1,4161 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#include <limits.h> +#ifndef _METRIC_HXX +#include <vcl/metric.hxx> +#endif +#include <vcl/svapp.hxx> +#ifdef DBG_UTIL +#include <vcl/sound.hxx> +#endif + +#include <svtools/svlbox.hxx> +#include <svtools/svicnvw.hxx> +#include <svimpicn.hxx> +#ifndef _SVLBITM_HXX +#include <svtools/svlbitm.hxx> +#endif +#include <svl/svarray.hxx> + + + +#define VIEWMODE_ICON 0x0001 // Text unter Bitmap +#define VIEWMODE_NAME 0x0002 // Text rechts neben Bitmap +#define VIEWMODE_TEXT 0x0004 // Text ohne Bitmap + +#define DD_SCROLL_PIXEL 10 + +// alle Angaben in Pixel + +#define ICONVIEW_OFFS_BMP_STRING 3 + +// fuer das Bounding-Rectangle +#define LROFFS_BOUND 2 +#define TBOFFS_BOUND 2 + +// fuer das Focus-Rectangle um Icons +#define LROFFS_ICON 2 +#define TBOFFS_ICON 2 + +#define NAMEVIEW_OFFS_BMP_STRING 3 + +// Abstaende von Fensterraendern +#define LROFFS_WINBORDER 4 +#define TBOFFS_WINBORDER 4 + +// Breitenoffset Highlight-Rect bei Text +#define LROFFS_TEXT 2 + + +#define ICNVIEWDATA(xPtr) (SvIcnVwDataEntry*)(pView->GetViewDataEntry(xPtr)) +#define ICNVIEWDATA2(xPtr) (SvIcnVwDataEntry*)(pView->pView->GetViewDataEntry(xPtr)) + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +// ------------------------------------------------------------------------- +// Hilfsfunktionen von Thomas Hosemann zur mehrzeiligen Ausgabe von +// Strings. Die Funktionen werden spaeter in StarView integriert. +// ------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + +// keine doppelten Defines +#ifdef TEXT_DRAW_CLIP +#undef TEXT_DRAW_CLIP +#endif +#ifdef TEXT_DRAW_MULTILINE +#undef TEXT_DRAW_MULTILINE +#endif +#ifdef TEXT_DRAW_WORDBREAK +#undef TEXT_DRAW_WORDBREAK +#endif + +// #define TEXT_DRAW_DISABLE ((sal_uInt16)0x0001) +// #define TEXT_DRAW_3DLOOK ((sal_uInt16)0x0002) +// #define TEXT_DRAW_MNEMONIC ((sal_uInt16)0x0004) +#define TEXT_DRAW_LEFT ((sal_uInt16)0x0010) +#define TEXT_DRAW_CENTER ((sal_uInt16)0x0020) +#define TEXT_DRAW_RIGHT ((sal_uInt16)0x0040) +#define TEXT_DRAW_TOP ((sal_uInt16)0x0080) +#define TEXT_DRAW_VCENTER ((sal_uInt16)0x0100) +#define TEXT_DRAW_BOTTOM ((sal_uInt16)0x0200) +#define TEXT_DRAW_ENDELLIPSIS ((sal_uInt16)0x0400) +#define TEXT_DRAW_PATHELLIPSIS ((sal_uInt16)0x0800) +#define TEXT_DRAW_CLIP ((sal_uInt16)0x1000) +#define TEXT_DRAW_MULTILINE ((sal_uInt16)0x2000) +#define TEXT_DRAW_WORDBREAK ((sal_uInt16)0x4000) + +XubString GetEllipsisString( OutputDevice* pDev, + const XubString& rStr, long nMaxWidth, + sal_uInt16 nStyle = TEXT_DRAW_ENDELLIPSIS ) +{ + XubString aStr = rStr; + + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + sal_uInt16 nIndex = pDev->GetTextBreak( rStr, nMaxWidth ); + if ( nIndex != STRING_LEN ) + { + aStr.Erase( nIndex ); + if ( nIndex > 1 ) + { + aStr.AppendAscii("..."); + while ( aStr.Len() && + (pDev->GetTextWidth( aStr ) > nMaxWidth) ) + { + if ( (nIndex > 1) || (nIndex == aStr.Len()) ) + nIndex--; + aStr.Erase( nIndex, 1 ); + } + } + + if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) ) + aStr += rStr.GetChar( 0 ); + } + } + + return aStr; +} + +class TextLineInfo +{ +private: + long mnWidth; + sal_uInt16 mnIndex; + sal_uInt16 mnLen; + +public: + TextLineInfo( long nWidth, sal_uInt16 nIndex, sal_uInt16 nLen ) + { + mnWidth = nWidth; + mnIndex = nIndex; + mnLen = nLen; + } + + long GetWidth() const { return mnWidth; } + sal_uInt16 GetIndex() const { return mnIndex; } + sal_uInt16 GetLen() const { return mnLen; } +}; + +#define MULTITEXTLINEINFO_RESIZE 16 +typedef TextLineInfo* PTextLineInfo; + +class MultiTextLineInfo +{ +private: + PTextLineInfo* mpLines; + sal_uInt16 mnLines; + sal_uInt16 mnSize; + +public: + MultiTextLineInfo(); + ~MultiTextLineInfo(); + + void AddLine( TextLineInfo* pLine ); + void Clear(); + + TextLineInfo* GetLine( sal_uInt16 nLine ) const + { return mpLines[nLine]; } + sal_uInt16 Count() const { return mnLines; } + +private: + MultiTextLineInfo( const MultiTextLineInfo& ); + MultiTextLineInfo& operator=( const MultiTextLineInfo& ); +}; + +MultiTextLineInfo::MultiTextLineInfo() +{ + mpLines = new PTextLineInfo[MULTITEXTLINEINFO_RESIZE]; + mnLines = 0; + mnSize = MULTITEXTLINEINFO_RESIZE; +} + +MultiTextLineInfo::~MultiTextLineInfo() +{ + for ( sal_uInt16 i = 0; i < mnLines; i++ ) + delete mpLines[i]; + delete [] mpLines; +} + +void MultiTextLineInfo::AddLine( TextLineInfo* pLine ) +{ + if ( mnSize == mnLines ) + { + mnSize += MULTITEXTLINEINFO_RESIZE; + PTextLineInfo* pNewLines = new PTextLineInfo[mnSize]; + memcpy( pNewLines, mpLines, mnLines*sizeof(PTextLineInfo) ); + mpLines = pNewLines; + } + + mpLines[mnLines] = pLine; + mnLines++; +} + +void MultiTextLineInfo::Clear() +{ + for ( sal_uInt16 i = 0; i < mnLines; i++ ) + delete mpLines[i]; + mnLines = 0; +} + +// ----------------------------------------------------------------------- + +long GetTextLines( OutputDevice* pDev, MultiTextLineInfo& rLineInfo, + long nWidth, const XubString& rStr, + sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK ) +{ + rLineInfo.Clear(); + if ( !rStr.Len() ) + return 0; + if ( nWidth <= 0 ) + nWidth = 1; + + sal_uInt16 nStartPos = 0; // Start-Position der Zeile + sal_uInt16 nLastLineLen = 0; // Zeilenlaenge bis zum vorherigen Wort + sal_uInt16 nLastWordPos = 0; // Position des letzten Wortanfangs + sal_uInt16 i = 0; + sal_uInt16 nPos; // StartPositon der Zeile (nur Temp) + sal_uInt16 nLen; // Laenge der Zeile (nur Temp) + sal_uInt16 nStrLen = rStr.Len(); + long nMaxLineWidth = 0; // Maximale Zeilenlaenge + long nLineWidth; // Aktuelle Zeilenlaenge + long nLastLineWidth = 0; // Zeilenlaenge der letzten Zeile + xub_Unicode c; + xub_Unicode c2; + const xub_Unicode* pStr = rStr.GetBuffer(); + sal_Bool bHardBreak = sal_False; + + do + { + c = pStr[i]; + + // Auf Zeilenende ermitteln + if ( (c == _CR) || (c == _LF) ) + bHardBreak = sal_True; + else + bHardBreak = sal_False; + + // Testen, ob ein Wortende erreicht ist + if ( bHardBreak || (i == nStrLen) || + (((c == ' ') || (c == '-')) && (nStyle & TEXT_DRAW_WORDBREAK)) ) + { + nLen = i-nStartPos; + if ( c == '-' ) + nLen++; + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen ); + + // Findet ein Zeilenumbruch statt + if ( bHardBreak || (i == nStrLen) || + ((nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK)) ) + { + nPos = nStartPos; + + if ( (nLineWidth >= nWidth) && (nStyle & TEXT_DRAW_WORDBREAK) ) + { + nLineWidth = nLastLineWidth; + nLen = nLastLineLen; + nStartPos = nLastWordPos; + nLastLineLen = i-nStartPos; + nLastWordPos = nStartPos+nLastLineLen+1; + if ( c == '-' ) + nLastLineLen++; + else if ( bHardBreak && (i > nStartPos) ) + i--; + } + else + { + nStartPos = i; + // Zeilenende-Zeichen und '-' beruecksichtigen + if ( bHardBreak ) + { + nStartPos++; + c2 = pStr[i+1]; + if ( (c != c2) && ((c2 == _CR) || (c2 == _LF)) ) + { + nStartPos++; + i++; + } + } + else if ( c != '-' ) + nStartPos++; + nLastWordPos = nStartPos; + nLastLineLen = 0; + } + + if ( nLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLineWidth; + + if ( nLen || bHardBreak ) + rLineInfo.AddLine( new TextLineInfo( nLineWidth, nPos, nLen ) ); + + // Testen, ob aktuelles Wort noch auf die Zeile passt, + // denn ansonsten mueessen wir es auftrennen + if ( nLastLineLen ) + { + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen ); + if ( nLineWidth > nWidth ) + { + // Wenn ein Wortumbruch in einem Wort stattfindet, + // ist die maximale Zeilenlaenge die Laenge + // des laengsten Wortes + if ( nLineWidth > nMaxLineWidth ) + nMaxLineWidth = nLineWidth; + + // Solange Wort auftrennen, bis es auf eine Zeile passt + do + { + nPos = pDev->GetTextBreak( rStr, nWidth, nStartPos, nLastLineLen ); + nLen = nPos-nStartPos; + if ( !nLen ) + { + nPos++; + nLen++; + } + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLen ); + rLineInfo.AddLine( new TextLineInfo( nLineWidth, nStartPos, nLen ) ); + nStartPos = nPos; + nLastLineLen = nLastLineLen - nLen; + nLineWidth = pDev->GetTextWidth( rStr, nStartPos, nLastLineLen ); + } + while ( nLineWidth > nWidth ); + } + nLastLineWidth = nLineWidth; + + // Bei Stringende muessen wir die letzte Zeile auch noch + // dranhaengen + if ( (i == nStrLen) && nLastLineLen ) + rLineInfo.AddLine( new TextLineInfo( nLastLineWidth, nStartPos, nLastLineLen ) ); + } + else + nLastLineWidth = 0; + } + else + { + nLastLineWidth = nLineWidth; + nLastLineLen = nLen; + nLastWordPos = nStartPos+nLastLineLen; + if ( c != '-' ) + nLastWordPos++; + } + } + + i++; + } + while ( i <= nStrLen ); + + return nMaxLineWidth; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 GetTextLines( OutputDevice* pDev, const Rectangle& rRect, + const XubString& rStr, + sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK, + long* pMaxWidth = NULL ) +{ + MultiTextLineInfo aMultiLineInfo; + long nMaxWidth = GetTextLines( pDev, aMultiLineInfo, + rRect.GetWidth(), rStr, nStyle ); + if ( pMaxWidth ) + *pMaxWidth = nMaxWidth; + return aMultiLineInfo.Count(); +} + +// ----------------------------------------------------------------------- + +Rectangle GetTextRect( OutputDevice* pDev, const Rectangle& rRect, + const XubString& rStr, + sal_uInt16 nStyle = TEXT_DRAW_WORDBREAK ) +{ + Rectangle aRect = rRect; + sal_uInt16 nLines; + long nWidth = rRect.GetWidth(); + long nMaxWidth; + long nTextHeight; + + if ( nStyle & TEXT_DRAW_MULTILINE ) + { + MultiTextLineInfo aMultiLineInfo; + TextLineInfo* pLineInfo; + sal_uInt16 nFormatLines; + + nMaxWidth = 0; + GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle ); + nFormatLines = aMultiLineInfo.Count(); + nTextHeight = pDev->GetTextHeight(); + nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight); + if ( nFormatLines <= nLines ) + nLines = nFormatLines; + else + { + if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) ) + nLines = nFormatLines; + else + nMaxWidth = nWidth; + } + for ( sal_uInt16 i = 0; i < nLines; i++ ) + { + pLineInfo = aMultiLineInfo.GetLine( i ); + if ( pLineInfo->GetWidth() > nMaxWidth ) + nMaxWidth = pLineInfo->GetWidth(); + } + } + else + { + nLines = 1; + nMaxWidth = pDev->GetTextWidth( rStr ); + nTextHeight = pDev->GetTextHeight(); + if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ENDELLIPSIS) ) + nMaxWidth = nWidth; + } + + if ( nStyle & TEXT_DRAW_RIGHT ) + aRect.Left() = aRect.Right()-nMaxWidth+1; + else if ( nStyle & TEXT_DRAW_CENTER ) + { + aRect.Left() += (nWidth-nMaxWidth)/2; + aRect.Right() = aRect.Left()+nMaxWidth-1; + } + else + aRect.Right() = aRect.Left()+nMaxWidth-1; + + if ( nStyle & TEXT_DRAW_BOTTOM ) + aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1; + else if ( nStyle & TEXT_DRAW_VCENTER ) + { + aRect.Top() += (aRect.GetHeight()-(nTextHeight*nLines))/2; + aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; + } + else + aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1; + + return aRect; +} + +// ----------------------------------------------------------------------- + +void DrawText( OutputDevice* pDev, const Rectangle& rRect, + const XubString& rStr, sal_uInt16 nStyle = 0 ) +{ + if ( !rStr.Len() || rRect.IsEmpty() ) + return; + + Point aPos = rRect.TopLeft(); + long nWidth = rRect.GetWidth(); + long nHeight = rRect.GetHeight(); + FontAlign eAlign = pDev->GetFont().GetAlign(); + + if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) ) + return; + + // Mehrzeiligen Text behandeln wir anders + if ( nStyle & TEXT_DRAW_MULTILINE ) + { + String aLastLine; + Region aOldRegion; + MultiTextLineInfo aMultiLineInfo; + TextLineInfo* pLineInfo; + long nTextHeight = pDev->GetTextHeight(); + long nMaxTextWidth; + sal_uInt16 i; + sal_uInt16 nLines = (sal_uInt16)(nHeight/nTextHeight); + sal_uInt16 nFormatLines; + sal_Bool bIsClipRegion = sal_False; + nMaxTextWidth = GetTextLines( pDev, aMultiLineInfo, nWidth, rStr, nStyle ); + + nFormatLines = aMultiLineInfo.Count(); + if ( nFormatLines > nLines ) + { + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + // Letzte Zeile zusammenbauen und kuerzen + nFormatLines = nLines-1; + pLineInfo = aMultiLineInfo.GetLine( nFormatLines ); + aLastLine = rStr.Copy( pLineInfo->GetIndex() ); + aLastLine.ConvertLineEnd( LINEEND_LF ); + aLastLine.SearchAndReplace( _LF, ' ' ); + aLastLine = GetEllipsisString( pDev, aLastLine, nWidth, nStyle ); + nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM); + nStyle |= TEXT_DRAW_TOP; + } + } + else + { + if ( nMaxTextWidth <= nWidth ) + nStyle &= ~TEXT_DRAW_CLIP; + } + + // Clipping setzen + if ( nStyle & TEXT_DRAW_CLIP ) + { + bIsClipRegion = pDev->IsClipRegion(); + if ( bIsClipRegion ) + { + aOldRegion = pDev->GetClipRegion(); + pDev->IntersectClipRegion( rRect ); + } + else + { + Region aRegion( rRect ); + pDev->SetClipRegion( aRegion ); + } + } + + // Vertikales Alignment + if ( nStyle & TEXT_DRAW_BOTTOM ) + aPos.Y() += nHeight-(nFormatLines*nTextHeight); + else if ( nStyle & TEXT_DRAW_VCENTER ) + aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2; + + // Font Alignment + if ( eAlign == ALIGN_BOTTOM ) + aPos.Y() += nTextHeight; + else if ( eAlign == ALIGN_BASELINE ) + aPos.Y() += pDev->GetFontMetric().GetAscent(); + + // Alle Zeilen ausgeben, bis auf die letzte + for ( i = 0; i < nFormatLines; i++ ) + { + pLineInfo = aMultiLineInfo.GetLine( i ); + if ( nStyle & TEXT_DRAW_RIGHT ) + aPos.X() += nWidth-pLineInfo->GetWidth(); + else if ( nStyle & TEXT_DRAW_CENTER ) + aPos.X() += (nWidth-pLineInfo->GetWidth())/2; + pDev->DrawText( aPos, rStr, pLineInfo->GetIndex(), pLineInfo->GetLen() ); + aPos.Y() += nTextHeight; + aPos.X() = rRect.Left(); + } + + // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben, + // da die Zeile gekuerzt wurde + if ( aLastLine.Len() ) + pDev->DrawText( aPos, aLastLine ); + + // Clipping zuruecksetzen + if ( nStyle & TEXT_DRAW_CLIP ) + { + if ( bIsClipRegion ) + pDev->SetClipRegion( aOldRegion ); + else + pDev->SetClipRegion(); + } + } + else + { + XubString aStr = rStr; + Size aTextSize(pDev->GetTextWidth( aStr ), pDev->GetTextHeight()); + + // Evt. Text kuerzen + if ( aTextSize.Width() > nWidth ) + { + if ( nStyle & TEXT_DRAW_ENDELLIPSIS ) + { + aStr = GetEllipsisString( pDev, rStr, nWidth, nStyle ); + nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT); + nStyle |= TEXT_DRAW_LEFT; + aTextSize.Width() = pDev->GetTextWidth(aStr); + } + } + else + { + if ( aTextSize.Height() <= nHeight ) + nStyle &= ~TEXT_DRAW_CLIP; + } + + // Vertikales Alignment + if ( nStyle & TEXT_DRAW_RIGHT ) + aPos.X() += nWidth-aTextSize.Width(); + else if ( nStyle & TEXT_DRAW_CENTER ) + aPos.X() += (nWidth-aTextSize.Width())/2; + + // Font Alignment + if ( eAlign == ALIGN_BOTTOM ) + aPos.Y() += aTextSize.Height(); + else if ( eAlign == ALIGN_BASELINE ) + aPos.Y() += pDev->GetFontMetric().GetAscent(); + + if ( nStyle & TEXT_DRAW_BOTTOM ) + aPos.Y() += nHeight-aTextSize.Height(); + else if ( nStyle & TEXT_DRAW_VCENTER ) + aPos.Y() += (nHeight-aTextSize.Height())/2; + + if ( nStyle & TEXT_DRAW_CLIP ) + { + sal_Bool bIsClipRegion = pDev->IsClipRegion(); + if ( bIsClipRegion ) + { + Region aOldRegion = pDev->GetClipRegion(); + pDev->IntersectClipRegion( rRect ); + pDev->DrawText( aPos, aStr ); + pDev->SetClipRegion( aOldRegion ); + } + else + { + Region aRegion( rRect ); + pDev->SetClipRegion( aRegion ); + pDev->DrawText( aPos, aStr ); + pDev->SetClipRegion(); + } + } + else + pDev->DrawText( aPos, aStr ); + } +} + +// ----------------------------------------------------------------------- + + +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- +//-------------------------------------------------------------------------- + + +#define DRAWTEXT_FLAGS (TEXT_DRAW_CENTER|TEXT_DRAW_TOP|TEXT_DRAW_ENDELLIPSIS|\ + TEXT_DRAW_CLIP|TEXT_DRAW_MULTILINE|TEXT_DRAW_WORDBREAK) + + +class ImpIcnCursor +{ + SvImpIconView* pView; + SvPtrarr* pColumns; + SvPtrarr* pRows; + sal_Bool* pGridMap; + long nGridDX, nGridDY; + long nGridCols, nGridRows; + long nCols; + long nRows; + short nDeltaWidth; + short nDeltaHeight; + SvLBoxEntry* pCurEntry; + void SetDeltas(); + void ImplCreate(); + void Create() { if( !pColumns ) ImplCreate(); } + + sal_uInt16 GetSortListPos( SvPtrarr* pList, long nValue, int bVertical); + SvLBoxEntry* SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom,sal_uInt16 nPref, + sal_Bool bDown, sal_Bool bSimple ); + SvLBoxEntry* SearchRow(sal_uInt16 nRow,sal_uInt16 nRight,sal_uInt16 nLeft,sal_uInt16 nPref, + sal_Bool bRight, sal_Bool bSimple ); + + void ExpandGrid(); + void CreateGridMap(); + // Rueckgabe sal_False: Eintrag liegt nicht in der GridMap. rGridx,y werden + // dann an nGridCols, nGridRows geclippt + sal_Bool GetGrid( const Point& rDocPos, sal_uInt16& rGridX, sal_uInt16& rGridY ) const; + void SetGridUsed( sal_uInt16 nDX, sal_uInt16 nDY, sal_Bool bUsed ) + { + pGridMap[ (nDY * nGridCols) + nDX ] = bUsed; + } + sal_Bool IsGridUsed( sal_uInt16 nDX, sal_uInt16 nDY ) + { + return pGridMap[ (nDY * nGridCols) + nDX ]; + } +public: + ImpIcnCursor( SvImpIconView* pOwner ); + ~ImpIcnCursor(); + void Clear( sal_Bool bGridToo = sal_True ); + + // fuer Cursortravelling usw. + SvLBoxEntry* GoLeftRight( SvLBoxEntry*, sal_Bool bRight ); + SvLBoxEntry* GoUpDown( SvLBoxEntry*, sal_Bool bDown ); + + // Rueckgaebe: sal_False == Das leere Rect steht hinter dem letzten + // Eintrag; d.h. beim naechsten Einfuegen ergibt sich das naechste + // leere Rechteck durch Addition. Hinweis: Das Rechteck kann dann + // ausserhalb des View-Space liegen + sal_Bool FindEmptyGridRect( Rectangle& rRect ); + + // Erzeugt fuer jede Zeile (Hoehe=nGridDY) eine nach BoundRect.Left() + // sortierte Liste der Eintraege, die in ihr stehen. Eine Liste kann + // leer sein. Die Listen gehen in das Eigentum des Rufenden ueber und + // muessen mit DestroyGridAdjustData geloescht werden + void CreateGridAjustData( SvPtrarr& pLists, SvLBoxEntry* pRow=0); + static void DestroyGridAdjustData( SvPtrarr& rLists ); + void SetGridUsed( const Rectangle&, sal_Bool bUsed = sal_True ); +}; + + + + +SvImpIconView::SvImpIconView( SvIconView* pCurView, SvLBoxTreeList* pTree, + WinBits i_nWinStyle ) : + aVerSBar( pCurView, WB_DRAG | WB_VSCROLL ), + aHorSBar( pCurView, WB_DRAG | WB_HSCROLL ) +{ + pView = pCurView; + pModel = pTree; + pCurParent = 0; + pZOrderList = new SvPtrarr; + SetStyle( i_nWinStyle ); + nHorDist = 0; + nVerDist = 0; + nFlags = 0; + nCurUserEvent = 0; + nMaxVirtWidth = 200; + pDDRefEntry = 0; + pDDDev = 0; + pDDBufDev = 0; + pDDTempDev = 0; + eTextMode = ShowTextShort; + pImpCursor = new ImpIcnCursor( this ); + + aVerSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollUpDownHdl ) ); + aHorSBar.SetScrollHdl( LINK( this, SvImpIconView, ScrollLeftRightHdl ) ); + nHorSBarHeight = aHorSBar.GetSizePixel().Height(); + nVerSBarWidth = aVerSBar.GetSizePixel().Width(); + + aMouseMoveTimer.SetTimeout( 20 ); + aMouseMoveTimer.SetTimeoutHdl(LINK(this,SvImpIconView,MouseMoveTimeoutHdl)); + + aEditTimer.SetTimeout( 800 ); + aEditTimer.SetTimeoutHdl(LINK(this,SvImpIconView,EditTimeoutHdl)); + + Clear( sal_True ); +} + +SvImpIconView::~SvImpIconView() +{ + StopEditTimer(); + CancelUserEvent(); + delete pZOrderList; + delete pImpCursor; + delete pDDDev; + delete pDDBufDev; + delete pDDTempDev; + ClearSelectedRectList(); +} + +void SvImpIconView::Clear( sal_Bool bInCtor ) +{ + StopEditTimer(); + CancelUserEvent(); + nMaxBmpWidth = 0; + nMaxBmpHeight = 0; + nMaxTextWidth = 0; + bMustRecalcBoundingRects = sal_False; + nMaxBoundHeight = 0; + + //XXX + nFlags |= F_GRID_INSERT; + nFlags &= ~F_PAINTED; + SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) ); + pCursor = 0; + if( !bInCtor ) + { + pImpCursor->Clear(); + aVirtOutputSize.Width() = 0; + aVirtOutputSize.Height() = 0; + pZOrderList->Remove(0,pZOrderList->Count()); + MapMode aMapMode( pView->GetMapMode()); + aMapMode.SetOrigin( Point() ); + pView->SetMapMode( aMapMode ); + if( pView->IsUpdateMode() ) + pView->Invalidate(); + } + AdjustScrollBars(); +} + +void SvImpIconView::SetStyle( const WinBits i_nWinStyle ) +{ + nViewMode = VIEWMODE_TEXT; + if( i_nWinStyle & WB_NAME ) + nViewMode = VIEWMODE_NAME; + if( i_nWinStyle & WB_ICON ) + nViewMode = VIEWMODE_ICON; +} + + +IMPL_LINK( SvImpIconView, ScrollUpDownHdl, ScrollBar *, pScrollBar ) +{ + pView->EndEditing( sal_True ); + // Pfeil hoch: delta=-1; Pfeil runter: delta=+1 + Scroll( 0, pScrollBar->GetDelta(), sal_True ); + return 0; +} + +IMPL_LINK( SvImpIconView, ScrollLeftRightHdl, ScrollBar *, pScrollBar ) +{ + pView->EndEditing( sal_True ); + // Pfeil links: delta=-1; Pfeil rechts: delta=+1 + Scroll( pScrollBar->GetDelta(), 0, sal_True ); + return 0; +} + +void SvImpIconView::ChangedFont() +{ + StopEditTimer(); + ImpArrange(); +} + + +void SvImpIconView::CheckAllSizes() +{ + nMaxTextWidth = 0; + nMaxBmpWidth = 0; + nMaxBmpHeight = 0; + SvLBoxEntry* pEntry = pModel->First(); + while( pEntry ) + { + CheckSizes( pEntry ); + pEntry = pModel->Next( pEntry ); + } +} + +void SvImpIconView::CheckSizes( SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) +{ + Size aSize; + + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pStringItem ) + { + aSize = GetItemSize( pView, pEntry, pStringItem, pViewData ); + if( aSize.Width() > nMaxTextWidth ) + { + nMaxTextWidth = aSize.Width(); + if( !(nFlags & F_GRIDMODE ) ) + bMustRecalcBoundingRects = sal_True; + } + } + SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if( pBmpItem ) + { + aSize = GetItemSize( pView, pEntry, pBmpItem, pViewData ); + if( aSize.Width() > nMaxBmpWidth ) + { + nMaxBmpWidth = aSize.Width(); + nMaxBmpWidth += (2*LROFFS_ICON); + if( !(nFlags & F_GRIDMODE ) ) + bMustRecalcBoundingRects = sal_True; + } + if( aSize.Height() > nMaxBmpHeight ) + { + nMaxBmpHeight = aSize.Height(); + nMaxBmpHeight += (2*TBOFFS_ICON);; + if( !(nFlags & F_GRIDMODE ) ) + bMustRecalcBoundingRects = sal_True; + } + } +} + +void SvImpIconView::EntryInserted( SvLBoxEntry* pEntry ) +{ + if( pModel->GetParent(pEntry) == pCurParent ) + { + StopEditTimer(); + DBG_ASSERT(pZOrderList->GetPos(pEntry)==0xffff,"EntryInserted:ZOrder?"); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + if( nFlags & F_GRIDMODE ) + pImpCursor->Clear( sal_False ); + else + pImpCursor->Clear( sal_True ); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + CheckSizes( pEntry, pViewData ); + if( pView->IsUpdateMode() ) + { + FindBoundingRect( pEntry, pViewData ); + PaintEntry( pEntry, pViewData ); + } + else + InvalidateBoundingRect( pViewData->aRect ); + } +} + +void SvImpIconView::RemovingEntry( SvLBoxEntry* pEntry ) +{ + if( pModel->GetParent(pEntry) == pCurParent) + { + StopEditTimer(); + DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"RemovingEntry:ZOrder?"); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( IsBoundingRectValid( pViewData->aRect ) ) + { + // bei gueltigem Bounding-Rect muss in EntryRemoved eine + // Sonderbehandlung erfolgen + nFlags |= F_ENTRY_REMOVED; + pView->Invalidate( pViewData->aRect ); + } + if( pEntry == pCursor ) + { + SvLBoxEntry* pNewCursor = GetNewCursor(); + ShowCursor( sal_False ); + pCursor = 0; // damit er nicht deselektiert wird + SetCursor( pNewCursor ); + } + sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos, 1 ); + pImpCursor->Clear(); + } +} + +void SvImpIconView::EntryRemoved() +{ + if( (nFlags & (F_ENTRY_REMOVED | F_PAINTED)) == (F_ENTRY_REMOVED | F_PAINTED)) + { + // Ein Eintrag mit gueltigem BoundRect wurde geloescht und wir + // haben schon mal gepaintet. In diesem Fall muessen wir die + // Position des naechsten Eintrags, der eingefuegt wird oder noch + // kein gueltiges BoundRect hat, "suchen" d.h. ein "Loch" in + // der View auffuellen. + nFlags &= ~( F_ENTRY_REMOVED | F_GRID_INSERT ); + } +} + + +void SvImpIconView::MovingEntry( SvLBoxEntry* pEntry ) +{ + DBG_ASSERT(pEntry,"MovingEntry: 0!"); + pNextCursor = 0; + StopEditTimer(); + if( pModel->GetParent(pEntry) == pCurParent ) + { + DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"MovingEntry:ZOrder?"); + nFlags |= F_MOVING_SIBLING; + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( IsBoundingRectValid( pViewData->aRect ) ) + pView->Invalidate( pViewData->aRect ); + // falls Eintrag seinen Parent wechselt vorsichtshalber + // die neue Cursorposition berechnen + if( pEntry == pCursor ) + pNextCursor = GetNewCursor(); + pImpCursor->Clear(); + } +} + + +void SvImpIconView::EntryMoved( SvLBoxEntry* pEntry ) +{ + ShowCursor( sal_False ); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pModel->GetParent(pEntry)==pCurParent ) + { + if( nFlags & F_MOVING_SIBLING ) + { + // die Neu-Positionierung eines Eintrags bei D&D innerhalb + // einer IconView findet bereits in NotifyMoving statt + // (MovingEntry/EntryMoved wird dann nicht mehr gerufen) + ToTop( pEntry ); + } + else + { + pImpCursor->Clear(); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + DBG_ASSERT(pZOrderList->Count()==pModel->GetChildCount(pCurParent),"EntryMoved:Bad zorder count"); + FindBoundingRect( pEntry, pViewData ); + } + PaintEntry( pEntry, pViewData ); + } + else + { + if( pEntry == pCursor ) + { + DBG_ASSERT(pNextCursor,"EntryMoved: Next cursor bad"); + SetCursor( pNextCursor ); + } + pImpCursor->Clear(); + sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos, 1 ); + pView->Select( pEntry, sal_False ); + // wenn er nochmal in dieser View auftaucht, muss sein + // Bounding-Rect neu berechnet werden + InvalidateBoundingRect( pViewData->aRect ); + } + nFlags &= (~F_MOVING_SIBLING); +} + +void SvImpIconView::TreeInserted( SvLBoxEntry* pEntry ) +{ + EntryMoved( pEntry ); // vorlaeufig +} + +void SvImpIconView::EntryExpanded( SvLBoxEntry* ) +{ +} + +void SvImpIconView::EntryCollapsed( SvLBoxEntry*) +{ +} + +void SvImpIconView::CollapsingEntry( SvLBoxEntry* ) +{ +} + +void SvImpIconView::EntrySelected( SvLBoxEntry* pEntry, sal_Bool bSelect ) +{ + if( pModel->GetParent(pEntry) != pCurParent ) + return; + + // bei SingleSelection dafuer sorgen, dass der Cursor immer + // auf dem (einzigen) selektierten Eintrag steht + if( bSelect && pCursor && + pView->GetSelectionMode() == SINGLE_SELECTION && + pEntry != pCursor ) + { + SetCursor( pEntry ); + DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?"); + } + // bei Gummibandselektion ist uns das zu teuer + if( !(nFlags & F_RUBBERING )) + ToTop( pEntry ); + if( pView->IsUpdateMode() ) + { + if( pEntry == pCursor ) + ShowCursor( sal_False ); + if( nFlags & F_RUBBERING ) + PaintEntry( pEntry ); + else + pView->Invalidate( GetBoundingRect( pEntry ) ); + if( pEntry == pCursor ) + ShowCursor( sal_True ); + } +} + +void SvImpIconView::SetNextEntryPos(const Point& rPos) +{ + aPrevBoundRect.SetPos( rPos ); + aPrevBoundRect.Right() = LONG_MAX; // dont know +} + +Point SvImpIconView::FindNextEntryPos( const Size& rBoundSize ) +{ + if( nFlags & F_GRIDMODE ) + { + if( nFlags & F_GRID_INSERT ) + { + if( aPrevBoundRect.Right() != LONG_MAX ) + { + // passt der naechste Entry noch in die Zeile ? + long nNextWidth = aPrevBoundRect.Right() + nGridDX + LROFFS_WINBORDER; + if( nNextWidth > aVirtOutputSize.Width() ) + { + // darf aVirtOutputSize verbreitert werden ? + if( nNextWidth < nMaxVirtWidth ) + { + // verbreitern & in Zeile aufnehmen + aPrevBoundRect.Left() += nGridDX; + } + else + { + // erhoehen & neue Zeile beginnen + aPrevBoundRect.Top() += nGridDY; + aPrevBoundRect.Left() = LROFFS_WINBORDER; + } + } + else + { + // in die Zeile aufnehmen + aPrevBoundRect.Left() += nGridDX; + } + } + aPrevBoundRect.SetSize( Size( nGridDX, nGridDY ) ); + } + else + { + if( !pImpCursor->FindEmptyGridRect( aPrevBoundRect ) ) + { + // mitten in den Entries gibts keine Loecher mehr, + // wir koennen also wieder ins "Fast Insert" springen + nFlags |= F_GRID_INSERT; + } + } + } + else + { + if( aPrevBoundRect.Right() != LONG_MAX ) + { + // passt der naechste Entry noch in die Zeile ? + long nNextWidth=aPrevBoundRect.Right()+rBoundSize.Width()+LROFFS_BOUND+nHorDist; + if( nNextWidth > aVirtOutputSize.Width() ) + { + // darf aVirtOutputSize verbreitert werden ? + if( nNextWidth < nMaxVirtWidth ) + { + // verbreitern & in Zeile aufnehmen + aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() ); + aPrevBoundRect.Left() += nHorDist; + } + else + { + // erhoehen & neue Zeile beginnen + aPrevBoundRect.Top() += nMaxBoundHeight + nVerDist + TBOFFS_BOUND; + aPrevBoundRect.Left() = LROFFS_WINBORDER; + } + } + else + { + // in die Zeile aufnehmen + aPrevBoundRect.SetPos( aPrevBoundRect.TopRight() ); + aPrevBoundRect.Left() += nHorDist; + } + } + aPrevBoundRect.SetSize( rBoundSize ); + } + return aPrevBoundRect.TopLeft(); +} + +void SvImpIconView::ResetVirtSize() +{ + StopEditTimer(); + aVirtOutputSize.Width() = 0; + aVirtOutputSize.Height() = 0; + sal_Bool bLockedEntryFound = sal_False; + nFlags &= (~F_GRID_INSERT); + SvLBoxEntry* pCur = pModel->FirstChild( pCurParent ); + while( pCur ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur); + if( pViewData->IsEntryPosLocked() ) + { + // VirtSize u.a. anpassen + if( !IsBoundingRectValid( pViewData->aRect ) ) + FindBoundingRect( pCur, pViewData ); + else + AdjustVirtSize( pViewData->aRect ); + bLockedEntryFound = sal_True; + } + else + InvalidateBoundingRect( pViewData->aRect ); + + pCur = pModel->NextSibling( pCur ); + } + if( !bLockedEntryFound ) + { + //XXX + nFlags |= F_GRID_INSERT; + } + + SetNextEntryPos( Point( LROFFS_WINBORDER, TBOFFS_WINBORDER ) ); + pImpCursor->Clear(); +} + + +void SvImpIconView::AdjustVirtSize( const Rectangle& rRect ) +{ + long nHeightOffs = 0; + long nWidthOffs = 0; + + if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) ) + nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width(); + + if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) ) + nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height(); + + if( nWidthOffs || nHeightOffs ) + { + Range aRange; + aVirtOutputSize.Width() += nWidthOffs; + aRange.Max() = aVirtOutputSize.Width(); + aHorSBar.SetRange( aRange ); + + aVirtOutputSize.Height() += nHeightOffs; + aRange.Max() = aVirtOutputSize.Height(); + aVerSBar.SetRange( aRange ); + + pImpCursor->Clear(); + AdjustScrollBars(); + } +} + +void SvImpIconView::Arrange() +{ + nMaxVirtWidth = aOutputSize.Width(); + ImpArrange(); +} + +void SvImpIconView::ImpArrange() +{ + StopEditTimer(); + ShowCursor( sal_False ); + ResetVirtSize(); + bMustRecalcBoundingRects = sal_False; + MapMode aMapMode( pView->GetMapMode()); + aMapMode.SetOrigin( Point() ); + pView->SetMapMode( aMapMode ); + CheckAllSizes(); + RecalcAllBoundingRectsSmart(); + pView->Invalidate(); + ShowCursor( sal_True ); +} + +void SvImpIconView::Paint( const Rectangle& rRect ) +{ + if( !pView->IsUpdateMode() ) + return; + +#if defined(DBG_UTIL) && defined(OV_DRAWGRID) + if( nFlags & F_GRIDMODE ) + { + Color aOldColor = pView->GetLineColor(); + Color aNewColor( COL_BLACK ); + pView->SetLineColor( aNewColor ); + Point aOffs( pView->GetMapMode().GetOrigin()); + Size aXSize( pView->GetOutputSizePixel() ); + for( long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX ) + { + Point aStart( nDX+LROFFS_BOUND, 0 ); + Point aEnd( nDX+LROFFS_BOUND, aXSize.Height()); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + for( long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY ) + { + Point aStart( 0, nDY+TBOFFS_BOUND ); + Point aEnd( aXSize.Width(), nDY+TBOFFS_BOUND ); + aStart -= aOffs; + aEnd -= aOffs; + pView->DrawLine( aStart, aEnd ); + } + pView->SetLineColor( aOldColor ); + } +#endif + nFlags |= F_PAINTED; + + if( !(pModel->HasChilds( pCurParent ) )) + return; + if( !pCursor ) + pCursor = pModel->FirstChild( pCurParent ); + + sal_uInt16 nCount = pZOrderList->Count(); + if( !nCount ) + return; + + SvPtrarr* pNewZOrderList = new SvPtrarr; + SvPtrarr* pPaintedEntries = new SvPtrarr; + + sal_uInt16 nPos = 0; + while( nCount ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos )); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + const Rectangle& rBoundRect = GetBoundingRect( pEntry, pViewData ); + if( rRect.IsOver( rBoundRect ) ) + { + PaintEntry( pEntry, rBoundRect.TopLeft(), pViewData ); + // Eintraege, die neu gezeichnet werden, auf Top setzen + pPaintedEntries->Insert( pEntry, pPaintedEntries->Count() ); + } + else + pNewZOrderList->Insert( pEntry, pNewZOrderList->Count() ); + + nCount--; + nPos++; + } + delete pZOrderList; + pZOrderList = pNewZOrderList; + nCount = pPaintedEntries->Count(); + if( nCount ) + { + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + pZOrderList->Insert( pPaintedEntries->GetObject( nCur ),pZOrderList->Count()); + } + delete pPaintedEntries; + + Rectangle aRect; + if( GetResizeRect( aRect )) + PaintResizeRect( aRect ); +} + +sal_Bool SvImpIconView::GetResizeRect( Rectangle& rRect ) +{ + if( aHorSBar.IsVisible() && aVerSBar.IsVisible() ) + { + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin()); + aOrigin *= -1; + aOrigin.X() += aOutputSize.Width(); + aOrigin.Y() += aOutputSize.Height(); + rRect.SetPos( aOrigin ); + rRect.SetSize( Size( nVerSBarWidth, nHorSBarHeight)); + return sal_True; + } + return sal_False; +} + +void SvImpIconView::PaintResizeRect( const Rectangle& rRect ) +{ + const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings(); + Color aNewColor = rStyleSettings.GetFaceColor(); + Color aOldColor = pView->GetFillColor(); + pView->SetFillColor( aNewColor ); + pView->DrawRect( rRect ); + pView->SetFillColor( aOldColor ); +} + +void SvImpIconView::RepaintSelectionItems() +{ + DBG_ERROR("RepaintSelectionItems"); + pView->Invalidate(); // vorlaeufig +} + +SvLBoxItem* SvImpIconView::GetItem( SvLBoxEntry* pEntry, + const Point& rAbsPos ) +{ + Rectangle aRect; + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pStringItem ) + { + aRect = CalcTextRect( pEntry, pStringItem ); + if( aRect.IsInside( rAbsPos ) ) + return pStringItem; + } + SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if( pBmpItem ) + { + aRect = CalcBmpRect( pEntry ); + if( aRect.IsInside( rAbsPos ) ) + return pBmpItem; + } + return 0; +} + +void SvImpIconView::CalcDocPos( Point& aMaeuschenPos ) +{ + aMaeuschenPos -= pView->GetMapMode().GetOrigin(); +} + +void SvImpIconView::MouseButtonDown( const MouseEvent& rMEvt) +{ + StopEditTimer(); + pView->GrabFocus(); + Point aDocPos( rMEvt.GetPosPixel() ); + if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height()) + return; + CalcDocPos( aDocPos ); + SvLBoxEntry* pEntry = GetEntry( aDocPos ); + if( !pEntry ) + { + if( pView->GetSelectionMode() != SINGLE_SELECTION ) + { + if( !rMEvt.IsMod1() ) // Ctrl + { + pView->SelectAll( sal_False ); + ClearSelectedRectList(); + } + else + nFlags |= F_ADD_MODE; + nFlags |= F_RUBBERING; + aCurSelectionRect.SetPos( aDocPos ); + pView->CaptureMouse(); + } + return; + } + + sal_Bool bSelected = pView->IsSelected( pEntry ); + sal_Bool bEditingEnabled = pView->IsInplaceEditingEnabled(); + + if( rMEvt.GetClicks() == 2 ) + { + DeselectAllBut( pEntry ); + pView->pHdlEntry = pEntry; + pView->DoubleClickHdl(); + } + else + { + // Inplace-Editing ? + if( rMEvt.IsMod2() ) // Alt? + { + if( bEditingEnabled ) + { + SvLBoxItem* pItem = GetItem(pEntry,aDocPos); + if( pItem ) + pView->EditingRequest( pEntry, pItem, aDocPos); + } + } + else if( pView->GetSelectionMode() == SINGLE_SELECTION ) + { + DeselectAllBut( pEntry ); + SetCursor( pEntry ); + pView->Select( pEntry, sal_True ); + if( bEditingEnabled && bSelected && !rMEvt.GetModifier() && + rMEvt.IsLeft() && IsTextHit( pEntry, aDocPos ) ) + { + nFlags |= F_START_EDITTIMER_IN_MOUSEUP; + } + } + else + { + if( !rMEvt.GetModifier() ) + { + if( !bSelected ) + { + DeselectAllBut( pEntry ); + SetCursor( pEntry ); + pView->Select( pEntry, sal_True ); + } + else + { + // erst im Up deselektieren, falls Move per D&D! + nFlags |= F_DOWN_DESELECT; + if( bEditingEnabled && IsTextHit( pEntry, aDocPos ) && + rMEvt.IsLeft()) + { + nFlags |= F_START_EDITTIMER_IN_MOUSEUP; + } + } + } + else if( rMEvt.IsMod1() ) + nFlags |= F_DOWN_CTRL; + } + } +} + +void SvImpIconView::MouseButtonUp( const MouseEvent& rMEvt ) +{ + aMouseMoveTimer.Stop(); + pView->ReleaseMouse(); + // HACK, da Einar noch nicht PrepareCommandEvent aufruft + if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) )) + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + + if( nFlags & F_RUBBERING ) + { + aMouseMoveTimer.Stop(); + AddSelectedRect( aCurSelectionRect ); + HideSelectionRect(); + nFlags &= ~(F_RUBBERING | F_ADD_MODE); + } + + SvLBoxEntry* pEntry = pView->GetEntry( rMEvt.GetPosPixel(), sal_True ); + if( pEntry ) + { + if( nFlags & F_DOWN_CTRL ) + { + // Ctrl & MultiSelection + ToggleSelection( pEntry ); + SetCursor( pEntry ); + } + else if( nFlags & F_DOWN_DESELECT ) + { + DeselectAllBut( pEntry ); + SetCursor( pEntry ); + pView->Select( pEntry, sal_True ); + } + } + + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); + if( nFlags & F_START_EDITTIMER_IN_MOUSEUP ) + { + StartEditTimer(); + nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP; + } +} + +void SvImpIconView::MouseMove( const MouseEvent& rMEvt ) +{ + if( nFlags & F_RUBBERING ) + { + const Point& rPosPixel = rMEvt.GetPosPixel(); + if( !aMouseMoveTimer.IsActive() ) + { + aMouseMoveEvent = rMEvt; + aMouseMoveTimer.Start(); + // ausserhalb des Fensters liegende Move-Events muessen + // vom Timer kommen, damit die Scrollgeschwindigkeit + // unabhaengig von Mausbewegungen ist. + if( rPosPixel.X() < 0 || rPosPixel.Y() < 0 ) + return; + const Size& rSize = pView->GetOutputSizePixel(); + if( rPosPixel.X() > rSize.Width() || rPosPixel.Y() > rSize.Height()) + return; + } + + if( &rMEvt != &aMouseMoveEvent ) + aMouseMoveEvent = rMEvt; + + long nScrollDX, nScrollDY; + + CalcScrollOffsets(rMEvt.GetPosPixel(),nScrollDX,nScrollDY,sal_False ); + sal_Bool bSelRectHidden = sal_False; + if( nScrollDX || nScrollDY ) + { + HideSelectionRect(); + bSelRectHidden = sal_True; + pView->Scroll( nScrollDX, nScrollDY ); + } + Point aDocPos( rMEvt.GetPosPixel() ); + aDocPos = pView->PixelToLogic( aDocPos ); + Rectangle aRect( aCurSelectionRect.TopLeft(), aDocPos ); + if( aRect != aCurSelectionRect ) + { + HideSelectionRect(); + bSelRectHidden = sal_True; + sal_Bool bAdd = (nFlags & F_ADD_MODE) ? sal_True : sal_False; + SelectRect( aRect, bAdd, &aSelectedRectList ); + } + if( bSelRectHidden ) + DrawSelectionRect( aRect ); + } +} + +sal_Bool SvImpIconView::KeyInput( const KeyEvent& rKEvt ) +{ + StopEditTimer(); + sal_Bool bKeyUsed = sal_True; + sal_Bool bMod1 = rKEvt.GetKeyCode().IsMod1(); + sal_Bool bInAddMode = (sal_Bool)((nFlags & F_ADD_MODE) != 0); + int bDeselAll = (pView->GetSelectionMode() != SINGLE_SELECTION) && + !bInAddMode; + SvLBoxEntry* pNewCursor; + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + switch( nCode ) + { + case KEY_UP: + if( pCursor ) + { + MakeVisible( pCursor ); + pNewCursor = pImpCursor->GoUpDown(pCursor,sal_False); + if( pNewCursor ) + { + if( bDeselAll ) + pView->SelectAll( sal_False ); + ShowCursor( sal_False ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, sal_True ); + } + else + { + Rectangle aRect( GetBoundingRect( pCursor ) ); + if( aRect.Top()) + { + aRect.Bottom() -= aRect.Top(); + aRect.Top() = 0; + MakeVisible( aRect ); + } + } + } + break; + + case KEY_DOWN: + if( pCursor ) + { + pNewCursor=pImpCursor->GoUpDown( pCursor,sal_True ); + if( pNewCursor ) + { + MakeVisible( pCursor ); + if( bDeselAll ) + pView->SelectAll( sal_False ); + ShowCursor( sal_False ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, sal_True ); + } + } + break; + + case KEY_RIGHT: + if( pCursor ) + { + pNewCursor=pImpCursor->GoLeftRight(pCursor,sal_True ); + if( pNewCursor ) + { + MakeVisible( pCursor ); + if( bDeselAll ) + pView->SelectAll( sal_False ); + ShowCursor( sal_False ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, sal_True ); + } + } + break; + + case KEY_LEFT: + if( pCursor ) + { + MakeVisible( pCursor ); + pNewCursor = pImpCursor->GoLeftRight(pCursor,sal_False ); + if( pNewCursor ) + { + if( bDeselAll ) + pView->SelectAll( sal_False ); + ShowCursor( sal_False ); + MakeVisible( pNewCursor ); + SetCursor( pNewCursor ); + if( !bInAddMode ) + pView->Select( pCursor, sal_True ); + } + else + { + Rectangle aRect( GetBoundingRect(pCursor)); + if( aRect.Left() ) + { + aRect.Right() -= aRect.Left(); + aRect.Left() = 0; + MakeVisible( aRect ); + } + } + } + break; + + case KEY_ESCAPE: + if( nFlags & F_RUBBERING ) + { + HideSelectionRect(); + pView->SelectAll( sal_False ); + nFlags &= ~F_RUBBERING; + } + break; + + case KEY_F8: + if( rKEvt.GetKeyCode().IsShift() ) + { + if( nFlags & F_ADD_MODE ) + nFlags &= (~F_ADD_MODE); + else + nFlags |= F_ADD_MODE; + } + break; + +#ifdef OS2 + case KEY_F9: + if( rKEvt.GetKeyCode().IsShift() ) + { + if( pCursor && pView->IsInplaceEditingEnabled() ) + pView->EditEntry( pCursor ); + } + break; +#endif + + case KEY_SPACE: + if( pCursor ) + { + ToggleSelection( pCursor ); + } + break; + + + case KEY_PAGEDOWN: + break; + case KEY_PAGEUP: + break; + + case KEY_ADD: + case KEY_DIVIDE : + if( bMod1 ) + pView->SelectAll( sal_True ); + break; + + case KEY_SUBTRACT: + case KEY_COMMA : + if( bMod1 ) + pView->SelectAll( sal_False ); + break; + + case KEY_RETURN: + if( bMod1 ) + { + if( pCursor && pView->IsInplaceEditingEnabled() ) + pView->EditEntry( pCursor ); + } + break; + + default: + bKeyUsed = sal_False; + + } + return bKeyUsed; +} + + +void SvImpIconView::PositionScrollBars( long nRealWidth, long nRealHeight ) +{ + // hor scrollbar + Point aPos( 0, nRealHeight ); + aPos.Y() -= nHorSBarHeight; + +#ifdef OS2 + aPos.Y()++; +#endif + if( aHorSBar.GetPosPixel() != aPos ) + aHorSBar.SetPosPixel( aPos ); + + // ver scrollbar + aPos.X() = nRealWidth; aPos.Y() = 0; + aPos.X() -= nVerSBarWidth; + +#if defined(WNT) + aPos.X()++; + aPos.Y()--; +#endif + +#ifdef OS2 + aPos.Y()--; + aPos.X()++; +#endif + + if( aVerSBar.GetPosPixel() != aPos ) + aVerSBar.SetPosPixel( aPos ); +} + + + +void SvImpIconView::AdjustScrollBars() +{ + long nVirtHeight = aVirtOutputSize.Height(); + long nVirtWidth = aVirtOutputSize.Width(); + + Size aOSize( pView->Control::GetOutputSizePixel() ); + long nRealHeight = aOSize.Height(); + long nRealWidth = aOSize.Width(); + + PositionScrollBars( nRealWidth, nRealHeight ); + + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + + long nVisibleWidth; + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + long nVisibleHeight; + if( nRealHeight > nVirtHeight ) + nVisibleHeight = nVirtHeight + aOrigin.Y(); + else + nVisibleHeight = nRealHeight; + + bool bVerSBar = (pView->GetStyle() & WB_VSCROLL) ? true : false; + bool bHorSBar = (pView->GetStyle() & WB_HSCROLL) ? true : false; + + sal_uInt16 nResult = 0; + if( nVirtHeight ) + { + // activate ver scrollbar ? + if( bVerSBar || ( nVirtHeight > nVisibleHeight) ) + { + nResult = 0x0001; + nRealWidth -= nVerSBarWidth; + + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + nFlags |= F_HOR_SBARSIZE_WITH_VBAR; + } + // activate hor scrollbar ? + if( bHorSBar || (nVirtWidth > nVisibleWidth) ) + { + nResult |= 0x0002; + nRealHeight -= nHorSBarHeight; + + if( nRealHeight > nVirtHeight ) + nVisibleHeight = nVirtHeight + aOrigin.Y(); + else + nVisibleHeight = nRealHeight; + + // brauchen wir jetzt doch eine senkrechte Scrollbar ? + if( !(nResult & 0x0001) && // nur wenn nicht schon da + ( (nVirtHeight > nVisibleHeight) || bVerSBar) ) + { + nResult = 3; // both are active + nRealWidth -= nVerSBarWidth; + + if( nRealWidth > nVirtWidth ) + nVisibleWidth = nVirtWidth + aOrigin.X(); + else + nVisibleWidth = nRealWidth; + + nFlags |= F_VER_SBARSIZE_WITH_HBAR; + } + } + } + + // size ver scrollbar + long nThumb = aVerSBar.GetThumbPos(); + Size aSize( nVerSBarWidth, nRealHeight ); +#if defined(WNT) + aSize.Height() += 2; +#endif +#ifdef OS2 + aSize.Height() += 3; +#endif + if( aSize != aVerSBar.GetSizePixel() ) + aVerSBar.SetSizePixel( aSize ); + aVerSBar.SetVisibleSize( nVisibleHeight ); + aVerSBar.SetPageSize( (nVisibleHeight*75)/100 ); + if( nResult & 0x0001 ) + { + aVerSBar.SetThumbPos( nThumb ); + aVerSBar.Show(); + } + else + { + aVerSBar.SetThumbPos( 0 ); + aVerSBar.Hide(); + } + + // size hor scrollbar + nThumb = aHorSBar.GetThumbPos(); + aSize.Width() = nRealWidth; + aSize.Height() = nHorSBarHeight; +#if defined(WNT) + aSize.Width()++; +#endif +#ifdef OS2 + aSize.Width() += 3; + if( nResult & 0x0001 ) // vertikale Scrollbar ? + aSize.Width()--; +#endif +#if defined(WNT) + if( nResult & 0x0001 ) // vertikale Scrollbar ? + { + aSize.Width()++; + nRealWidth++; + } +#endif + if( aSize != aHorSBar.GetSizePixel() ) + aHorSBar.SetSizePixel( aSize ); + aHorSBar.SetVisibleSize( nVisibleWidth ); //nRealWidth ); + aHorSBar.SetPageSize( (nVisibleWidth*75)/100 ); + if( nResult & 0x0002 ) + { + aHorSBar.SetThumbPos( nThumb ); + aHorSBar.Show(); + } + else + { + aHorSBar.SetThumbPos( 0 ); + aHorSBar.Hide(); + } + +#ifdef OS2 + nRealWidth++; +#endif + aOutputSize.Width() = nRealWidth; +#if defined(WNT) + if( nResult & 0x0002 ) // hor scrollbar ? + nRealHeight++; // weil unterer Rand geclippt wird +#endif +#ifdef OS2 + if( nResult & 0x0002 ) // hor scrollbar ? + nRealHeight++; +#endif + aOutputSize.Height() = nRealHeight; +} + +void __EXPORT SvImpIconView::Resize() +{ + StopEditTimer(); + Rectangle aRect; + if( GetResizeRect(aRect) ) + pView->Invalidate( aRect ); + aOutputSize = pView->GetOutputSizePixel(); + pImpCursor->Clear(); + +#if 1 + const Size& rSize = pView->Control::GetOutputSizePixel(); + PositionScrollBars( rSize.Width(), rSize.Height() ); + // Die ScrollBars werden asynchron ein/ausgeblendet, damit abgeleitete + // Klassen im Resize ein Arrange durchfuehren koennen, ohne dass + // die ScrollBars aufblitzen (SfxExplorerIconView!) + nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpIconView,UserEventHdl),0); +#else + AdjustScrollBars(); + if( GetResizeRect(aRect) ) + PaintResizeRect( aRect ); +#endif +} + +sal_Bool SvImpIconView::CheckHorScrollBar() +{ + if( !pZOrderList || !aHorSBar.IsVisible() ) + return sal_False; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!(pView->GetStyle() & WB_HSCROLL) && !aOrigin.X() ) + { + long nWidth = aOutputSize.Width(); + sal_uInt16 nCount = pZOrderList->Count(); + long nMostRight = 0; + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur); + long nRight = GetBoundingRect(pEntry).Right(); + if( nRight > nWidth ) + return sal_False; + if( nRight > nMostRight ) + nMostRight = nRight; + } + aHorSBar.Hide(); + aOutputSize.Height() += nHorSBarHeight; + aVirtOutputSize.Width() = nMostRight; + aHorSBar.SetThumbPos( 0 ); + Range aRange; + aRange.Max() = nMostRight - 1; + aHorSBar.SetRange( aRange ); + if( aVerSBar.IsVisible() ) + { + Size aSize( aVerSBar.GetSizePixel()); + aSize.Height() += nHorSBarHeight; + aVerSBar.SetSizePixel( aSize ); + } + return sal_True; + } + return sal_False; +} + +sal_Bool SvImpIconView::CheckVerScrollBar() +{ + if( !pZOrderList || !aVerSBar.IsVisible() ) + return sal_False; + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + if(!(pView->GetStyle() & WB_VSCROLL) && !aOrigin.Y() ) + { + long nDeepest = 0; + long nHeight = aOutputSize.Height(); + sal_uInt16 nCount = pZOrderList->Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pZOrderList->operator[](nCur); + long nBottom = GetBoundingRect(pEntry).Bottom(); + if( nBottom > nHeight ) + return sal_False; + if( nBottom > nDeepest ) + nDeepest = nBottom; + } + aVerSBar.Hide(); + aOutputSize.Width() += nVerSBarWidth; + aVirtOutputSize.Height() = nDeepest; + aVerSBar.SetThumbPos( 0 ); + Range aRange; + aRange.Max() = nDeepest - 1; + aVerSBar.SetRange( aRange ); + if( aHorSBar.IsVisible() ) + { + Size aSize( aHorSBar.GetSizePixel()); + aSize.Width() += nVerSBarWidth; + aHorSBar.SetSizePixel( aSize ); + } + return sal_True; + } + return sal_False; +} + + +// blendet Scrollbars aus, wenn sie nicht mehr benoetigt werden +void SvImpIconView::CheckScrollBars() +{ + CheckVerScrollBar(); + if( CheckHorScrollBar() ) + CheckVerScrollBar(); +} + + +void __EXPORT SvImpIconView::GetFocus() +{ + if( pCursor ) + { + pView->SetEntryFocus( pCursor, sal_True ); + ShowCursor( sal_True ); + } +} + +void __EXPORT SvImpIconView::LoseFocus() +{ + StopEditTimer(); + if( pCursor ) + pView->SetEntryFocus( pCursor,sal_False ); + ShowCursor( sal_False ); +} + +void SvImpIconView::UpdateAll() +{ + AdjustScrollBars(); + pImpCursor->Clear(); + pView->Invalidate(); +} + +void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData ) +{ + Point aPos( GetEntryPosition( pEntry ) ); + PaintEntry( pEntry, aPos, pViewData ); +} + +void SvImpIconView::PaintEmphasis( const Rectangle& rRect, sal_Bool bSelected, + sal_Bool bCursored, OutputDevice* pOut ) +{ + // HACK fuer D&D + if( nFlags & F_NO_EMPHASIS ) + return; + + if( !pOut ) + pOut = pView; + + // Selektion painten + Color aOldFillColor = pOut->GetFillColor(); + Color aOldLineColor = pOut->GetLineColor(); + Color aNewColor; + const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings(); + if( bSelected ) + { + aNewColor = rStyleSettings.GetHighlightColor(); + } + else + { +#ifndef OS2 + aNewColor =rStyleSettings.GetFieldColor(); +#else + aNewColor = pOut->GetBackground().GetColor(); +#endif + } + + if( bCursored ) + { + pOut->SetLineColor( Color( COL_BLACK ) ); + } + pOut->SetFillColor( aNewColor ); + pOut->DrawRect( rRect ); + pOut->SetFillColor( aOldFillColor ); + pOut->SetLineColor( aOldLineColor ); +} + +void SvImpIconView::PaintItem( const Rectangle& rRect, + SvLBoxItem* pItem, SvLBoxEntry* pEntry, sal_uInt16 nPaintFlags, + OutputDevice* pOut ) +{ + if( nViewMode == VIEWMODE_ICON && pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + const String& rStr = ((SvLBoxString*)pItem)->GetText(); + DrawText( pOut, rRect, rStr, DRAWTEXT_FLAGS ); + } + else + { + Point aPos( rRect.TopLeft() ); + const Size& rSize = GetItemSize( pView, pEntry, pItem ); + if( nPaintFlags & PAINTFLAG_HOR_CENTERED ) + aPos.X() += (rRect.GetWidth() - rSize.Width() ) / 2; + if( nPaintFlags & PAINTFLAG_VER_CENTERED ) + aPos.Y() += (rRect.GetHeight() - rSize.Height() ) / 2; + pItem->Paint( aPos, *(SvLBox*)pOut, 0, pEntry ); + } +} + +void SvImpIconView::PaintEntry( SvLBoxEntry* pEntry, const Point& rPos, + SvIcnVwDataEntry* pViewData, OutputDevice* pOut ) +{ + if( !pView->IsUpdateMode() ) + return; + + if( !pOut ) + pOut = pView; + + SvLBoxContextBmp* pBmpItem; + + pView->PreparePaint( pEntry ); + + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + + sal_Bool bSelected = pViewData->IsSelected(); + sal_Bool bCursored = pViewData->IsCursored(); + + Font aTempFont( pOut->GetFont() ); + // waehrend D&D nicht die Fontfarbe wechseln, da sonst auch die + // Emphasis gezeichnet werden muss! (weisser Adler auf weissem Grund) + if( bSelected && !(nFlags & F_NO_EMPHASIS) ) + { + const StyleSettings& rStyleSettings = pOut->GetSettings().GetStyleSettings(); + Font aNewFont( aTempFont ); + aNewFont.SetColor( rStyleSettings.GetHighlightTextColor() ); + pOut->SetFont( aNewFont ); + } + Rectangle aTextRect( CalcTextRect(pEntry,pStringItem,&rPos,sal_False,pViewData)); + Rectangle aBmpRect( CalcBmpRect(pEntry, &rPos, pViewData ) ); + + switch( nViewMode ) + { + case VIEWMODE_ICON: + pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + PaintEmphasis( aBmpRect, bSelected, bCursored, pOut ); + PaintItem( aBmpRect, pBmpItem, pEntry, + PAINTFLAG_HOR_CENTERED | PAINTFLAG_VER_CENTERED, pOut ); + PaintEmphasis( aTextRect, bSelected, sal_False, pOut ); + PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_HOR_CENTERED, pOut ); + break; + + case VIEWMODE_NAME: + pBmpItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + PaintEmphasis( aBmpRect, bSelected, bCursored, pOut ); + PaintItem( aBmpRect, pBmpItem, pEntry, PAINTFLAG_VER_CENTERED, pOut ); + PaintEmphasis( aTextRect, bSelected, sal_False, pOut ); + PaintItem( aTextRect, pStringItem, pEntry,PAINTFLAG_VER_CENTERED, pOut ); + break; + + case VIEWMODE_TEXT: + PaintEmphasis( aTextRect, bSelected, bCursored, pOut ); + PaintItem( aTextRect, pStringItem, pEntry, PAINTFLAG_VER_CENTERED, pOut ); + break; + } + pOut->SetFont( aTempFont ); +} + +void SvImpIconView::SetEntryPosition( SvLBoxEntry* pEntry, const Point& rPos, + sal_Bool bAdjustAtGrid, sal_Bool bCheckScrollBars ) +{ + if( pModel->GetParent(pEntry) == pCurParent ) + { + ShowCursor( sal_False ); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + Rectangle aBoundRect( GetBoundingRect( pEntry, pViewData )); + pView->Invalidate( aBoundRect ); + ToTop( pEntry ); + if( rPos != aBoundRect.TopLeft() ) + { + Point aGridOffs = pViewData->aGridRect.TopLeft() - + pViewData->aRect.TopLeft(); + pImpCursor->Clear(); + nFlags &= ~F_GRID_INSERT; + aBoundRect.SetPos( rPos ); + pViewData->aRect = aBoundRect; + pViewData->aGridRect.SetPos( rPos + aGridOffs ); + AdjustVirtSize( aBoundRect ); + } + //HACK(Billigloesung, die noch verbessert werden muss) + if( bAdjustAtGrid ) + { + AdjustAtGrid( pEntry ); + ToTop( pEntry ); + } + if( bCheckScrollBars && pView->IsUpdateMode() ) + CheckScrollBars(); + + PaintEntry( pEntry, pViewData ); + ShowCursor( sal_True ); + } +} + +void SvImpIconView::ViewDataInitialized( SvLBoxEntry*) +{ +} + +void SvImpIconView::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + if( pEntry == pCursor ) + ShowCursor( sal_False ); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + pView->Invalidate( pViewData->aRect ); + + if( nFlags & F_GRIDMODE ) + Center( (SvLBoxEntry*)pEntry, pViewData ); + else + pViewData->aRect.SetSize( CalcBoundingSize( + (SvLBoxEntry*)pEntry, pViewData ) ); + + ViewDataInitialized( (SvLBoxEntry*)pEntry ); + pView->Invalidate( pViewData->aRect ); + if( pEntry == pCursor ) + ShowCursor( sal_True ); +} + + +void SvImpIconView::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + const Rectangle& rRect = GetBoundingRect( pEntry ); + pView->Invalidate( rRect ); +} + +void SvImpIconView::SetNoSelection() +{ +} + +void SvImpIconView::SetDragDropMode( DragDropMode ) +{ +} + +void SvImpIconView::SetSelectionMode( SelectionMode ) +{ +} + +sal_Bool SvImpIconView::IsEntryInView( SvLBoxEntry* ) +{ + return sal_False; +} + +SvLBoxEntry* SvImpIconView::GetDropTarget( const Point& rPos ) +{ + Point aDocPos( rPos ); + CalcDocPos( aDocPos ); + SvLBoxEntry* pTarget = GetEntry( aDocPos ); + if( !pTarget || !pTarget->HasChilds() ) + pTarget = pCurParent; + return pTarget; +} + +SvLBoxEntry* SvImpIconView::GetEntry( const Point& rDocPos ) +{ + CheckBoundingRects(); + SvLBoxEntry* pTarget = 0; + // Z-Order-Liste vom Ende her absuchen + sal_uInt16 nCount = pZOrderList->Count(); + while( nCount ) + { + nCount--; + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCount)); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } + return pTarget; +} + +SvLBoxEntry* SvImpIconView::GetNextEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry ) +{ + CheckBoundingRects(); + SvLBoxEntry* pTarget = 0; + sal_uInt16 nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); + if( nStartPos != USHRT_MAX ) + { + sal_uInt16 nCount = pZOrderList->Count(); + for( sal_uInt16 nCur = nStartPos+1; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nCur)); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } + } + return pTarget; +} + +SvLBoxEntry* SvImpIconView::GetPrevEntry( const Point& rDocPos, SvLBoxEntry* pCurEntry ) +{ + CheckBoundingRects(); + SvLBoxEntry* pTarget = 0; + sal_uInt16 nStartPos = pZOrderList->GetPos( (void*)pCurEntry ); + if( nStartPos != USHRT_MAX && nStartPos != 0 ) + { + nStartPos--; + do + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nStartPos)); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->aRect.IsInside( rDocPos ) ) + { + pTarget = pEntry; + break; + } + } while( nStartPos > 0 ); + } + return pTarget; +} + + +Point SvImpIconView::GetEntryPosition( SvLBoxEntry* pEntry ) +{ + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + DBG_ASSERT(pViewData,"Entry not in model"); + return pViewData->aRect.TopLeft(); +} + +const Rectangle& SvImpIconView::GetBoundingRect( SvLBoxEntry* pEntry, SvIcnVwDataEntry* pViewData ) +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + DBG_ASSERT(pViewData,"Entry not in model"); + if( !IsBoundingRectValid( pViewData->aRect )) + FindBoundingRect( pEntry, pViewData ); + return pViewData->aRect; +} + +void SvImpIconView::SetSpaceBetweenEntries( long nHor, long nVer ) +{ + nHorDist = nHor; + nVerDist = nVer; +} + +Rectangle SvImpIconView::CalcBmpRect( SvLBoxEntry* pEntry, const Point* pPos, + SvIcnVwDataEntry* pViewData ) +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + Rectangle aBound = GetBoundingRect( pEntry, pViewData ); + if( pPos ) + aBound.SetPos( *pPos ); + Point aPos( aBound.TopLeft() ); + + switch( nViewMode ) + { + case VIEWMODE_ICON: + { + aPos.X() += ( aBound.GetWidth() - nMaxBmpWidth ) / 2; + Size aSize( nMaxBmpWidth, nMaxBmpHeight ); + // das Bitmap-Rechteck soll nicht das TextRect beruehren + aSize.Height() -= 3; + return Rectangle( aPos, aSize ); + } + + case VIEWMODE_NAME: + return Rectangle( aPos, + Size( nMaxBmpWidth, aBound.GetHeight() )); + + case VIEWMODE_TEXT: + return Rectangle( aPos, aBound.GetSize() ); + + default: + { + Rectangle aRect; + return aRect; + } + } +} + +Rectangle SvImpIconView::CalcTextRect( SvLBoxEntry* pEntry, + SvLBoxString* pItem, const Point* pPos, sal_Bool bForInplaceEdit, + SvIcnVwDataEntry* pViewData ) +{ + long nBmpHeight, nBmpWidth; + + if( !pItem ) + pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + Size aTextSize( GetItemSize( pView, pEntry, pItem, pViewData )); + aTextSize.Width() += 2*LROFFS_TEXT; + + Size aContextBmpSize(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry)); + Rectangle aBound = GetBoundingRect( pEntry, pViewData ); + if( pPos ) + aBound.SetPos( *pPos ); + Point aPos( aBound.TopLeft() ); + + switch( nViewMode ) + { + case VIEWMODE_ICON: + nBmpHeight = aContextBmpSize.Height(); + if( nBmpHeight < nMaxBmpHeight ) + nBmpHeight = nMaxBmpHeight; + aPos.Y() += nBmpHeight; + + // beim Inplace-Editieren, spendieren wir ein bisschen mehr Platz + if( bForInplaceEdit ) + { + // 20% rauf + long nMinWidth = (( (aContextBmpSize.Width()*10) / 100 ) * 2 ) + + aContextBmpSize.Width(); + if( nMinWidth > aBound.GetWidth() ) + nMinWidth = aBound.GetWidth(); + + if( aTextSize.Width() < nMinWidth ) + aTextSize.Width() = nMinWidth; + + // beim Inplace-Ed. darfs auch untere Eintraege ueberlappen + Rectangle aMaxGridTextRect = CalcMaxTextRect(pEntry, pViewData); + Size aOptSize = aMaxGridTextRect.GetSize(); + if( aOptSize.Height() > aTextSize.Height() ) + aTextSize.Height() = aOptSize.Height(); + } + + + aPos.X() += ( aBound.GetWidth() - aTextSize.Width() ) / 2; + break; + + case VIEWMODE_NAME: + nBmpWidth = aContextBmpSize.Width(); + if( nBmpWidth < nMaxBmpWidth ) + nBmpWidth = nMaxBmpWidth; + aPos.X() += nBmpWidth; + // vertikal ausrichten + aPos.Y() += ( nBmpWidth - aTextSize.Height() ) / 2; + break; + } + + Rectangle aRect( aPos, aTextSize ); +// KNALLT BEIM D&D, WENN GECLIPPT WIRD (In DrawText von Thomas) +// ClipAtVirtOutRect( aRect ); + return aRect; +} + + +long SvImpIconView::CalcBoundingWidth( SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps"); + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text"); + long nStringWidth = GetItemSize( pView, pEntry, pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Width(); + nStringWidth += 2*LROFFS_TEXT; + long nBmpWidth = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Width(); + long nWidth = 0; + + switch( nViewMode ) + { + case VIEWMODE_ICON: + nWidth = Max( nStringWidth, nBmpWidth ); + nWidth = Max( nWidth, nMaxBmpWidth ); + break; + + case VIEWMODE_NAME: + nWidth = Max( nBmpWidth, nMaxBmpWidth ); + nWidth += NAMEVIEW_OFFS_BMP_STRING; // Abstand Bitmap String + nWidth += nStringWidth; + break; + + case VIEWMODE_TEXT: + nWidth = nStringWidth; + break; + } + return nWidth; +} + +long SvImpIconView::CalcBoundingHeight( SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP),"No Bitmaps"); + DBG_ASSERT(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),"No Text"); + long nStringHeight = GetItemSize(pView,pEntry,pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING),pViewData).Height(); + long nBmpHeight = pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,pEntry).Height(); + long nHeight = 0; + + switch( nViewMode ) + { + case VIEWMODE_ICON: + nHeight = Max( nBmpHeight, nMaxBmpHeight ); + nHeight += ICONVIEW_OFFS_BMP_STRING; // Abstand Bitmap String + nHeight += nStringHeight; + break; + + case VIEWMODE_NAME: + nHeight = Max( nBmpHeight, nMaxBmpHeight ); + nHeight = Max( nHeight, nStringHeight ); + break; + + case VIEWMODE_TEXT: + nHeight = nStringHeight; + break; + } + if( nHeight > nMaxBoundHeight ) + { + ((SvImpIconView*)this)->nMaxBoundHeight = nHeight; + ((SvImpIconView*)this)->aHorSBar.SetLineSize( nHeight / 2 ); + ((SvImpIconView*)this)->aVerSBar.SetLineSize( nHeight / 2 ); + } + return nHeight; +} + +Size SvImpIconView::CalcBoundingSize( SvLBoxEntry* pEntry, + SvIcnVwDataEntry* pViewData ) const +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + return Size( CalcBoundingWidth(pEntry,pViewData), + CalcBoundingHeight(pEntry,pViewData) ); +} + +void SvImpIconView::RecalcAllBoundingRects() +{ + nMaxBoundHeight = 0; + pZOrderList->Remove(0, pZOrderList->Count() ); + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + FindBoundingRect( pEntry ); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + pEntry = pModel->NextSibling( pEntry ); + } + bMustRecalcBoundingRects = sal_False; + AdjustScrollBars(); +} + +void SvImpIconView::RecalcAllBoundingRectsSmart() +{ + nMaxBoundHeight = 0; + pZOrderList->Remove(0, pZOrderList->Count() ); + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( IsBoundingRectValid( pViewData->aRect )) + { + Size aBoundSize( pViewData->aRect.GetSize() ); + if( aBoundSize.Height() > nMaxBoundHeight ) + nMaxBoundHeight = aBoundSize.Height(); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + } + else + { + FindBoundingRect( pEntry, pViewData ); + } + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + pEntry = pModel->NextSibling( pEntry ); + } + AdjustScrollBars(); +} + +void SvImpIconView::UpdateBoundingRects() +{ + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + GetBoundingRect( pEntry ); + pEntry = pModel->NextSibling( pEntry ); + } +} + +void SvImpIconView::FindBoundingRect( SvLBoxEntry* pEntry, + SvIcnVwDataEntry* pViewData ) +{ + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + + Size aSize( CalcBoundingSize( pEntry, pViewData ) ); + Point aPos; + + DBG_ASSERT(!pViewData->IsEntryPosLocked(),"Locked entry pos in FindBoundingRect"); + // damits in der IconView nicht drunter & drueber geht + if( pViewData->IsEntryPosLocked() && IsBoundingRectValid(pViewData->aRect) ) + { + AdjustVirtSize( pViewData->aRect ); + return; + } + + aPos = FindNextEntryPos( aSize ); + + if( nFlags & F_GRIDMODE ) + { + Rectangle aGridRect( aPos, Size(nGridDX, nGridDY) ); + pViewData->aGridRect = aGridRect; + Center( pEntry, pViewData ); + AdjustVirtSize( pViewData->aRect ); + pImpCursor->SetGridUsed( pViewData->aRect ); + } + else + { + pViewData->aRect = Rectangle( aPos, aSize ); + AdjustVirtSize( pViewData->aRect ); + } +} + + +void SvImpIconView::SetCursor( SvLBoxEntry* pEntry ) +{ + if( pEntry == pCursor ) + return; + + ShowCursor( sal_False ); + if( pCursor ) + { + pView->SetEntryFocus( pCursor, sal_False ); + if( pView->GetSelectionMode() == SINGLE_SELECTION ) + pView->Select( pCursor, sal_False ); + } + pCursor = pEntry; + ToTop( pCursor ); + if( pCursor ) + { + pView->SetEntryFocus(pCursor, sal_True ); + if( pView->GetSelectionMode() == SINGLE_SELECTION ) + pView->Select( pCursor, sal_True ); + ShowCursor( sal_True ); + } +} + + +void SvImpIconView::ShowCursor( sal_Bool bShow ) +{ + if( !pCursor || !bShow || !pView->HasFocus() ) + { + pView->HideFocus(); + return; + } + Rectangle aRect ( CalcFocusRect( pCursor ) ); + pView->ShowFocus( aRect ); +} + + +void SvImpIconView::HideDDIcon() +{ + pView->Update(); + ImpHideDDIcon(); + pDDBufDev = pDDDev; + pDDDev = 0; +} + +void SvImpIconView::ImpHideDDIcon() +{ + if( pDDDev ) + { + Size aSize( pDDDev->GetOutputSizePixel() ); + // pView restaurieren + pView->DrawOutDev( aDDLastRectPos, aSize, Point(), aSize, *pDDDev ); + } +} + + +void SvImpIconView::ShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPosPix ) +{ + pView->Update(); + if( pRefEntry != pDDRefEntry ) + { + DELETEZ(pDDDev); + DELETEZ(pDDBufDev); + } + sal_Bool bSelected = pView->SvListView::Select( pRefEntry, sal_False ); + if( !pDDDev ) + { + if( pDDBufDev ) + { + // nicht bei jedem Move ein Device anlegen, da dies besonders + // auf Remote-Clients zu langsam ist + pDDDev = pDDBufDev; + pDDBufDev = 0; + } + else + { + pDDDev = new VirtualDevice( *pView ); + pDDDev->SetFont( pView->GetFont() ); + } + } + else + { + ImpHideDDIcon(); + } + const Rectangle& rRect = GetBoundingRect( pRefEntry ); + pDDDev->SetOutputSizePixel( rRect.GetSize() ); + + Point aPos( rPosPix ); + CalcDocPos( aPos ); + + Size aSize( pDDDev->GetOutputSizePixel() ); + pDDRefEntry = pRefEntry; + aDDLastEntryPos = aPos; + aDDLastRectPos = aPos; + + // Hintergrund sichern + pDDDev->DrawOutDev( Point(), aSize, aPos, aSize, *pView ); + // Icon in pView malen + nFlags |= F_NO_EMPHASIS; + PaintEntry( pRefEntry, aPos ); + nFlags &= ~F_NO_EMPHASIS; + if( bSelected ) + pView->SvListView::Select( pRefEntry, sal_True ); +} + +void SvImpIconView::HideShowDDIcon( SvLBoxEntry* pRefEntry, const Point& rPosPix ) +{ +/* In Notfaellen folgenden flackernden Code aktivieren: + + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; +*/ + if( !pDDDev ) + { + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + if( pRefEntry != pDDRefEntry ) + { + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + Point aEmptyPoint; + + Point aCurEntryPos( rPosPix ); + CalcDocPos( aCurEntryPos ); + + const Rectangle& rRect = GetBoundingRect( pRefEntry ); + Size aEntrySize( rRect.GetSize() ); + Rectangle aPrevEntryRect( aDDLastEntryPos, aEntrySize ); + Rectangle aCurEntryRect( aCurEntryPos, aEntrySize ); + + if( !aPrevEntryRect.IsOver( aCurEntryRect ) ) + { + HideDDIcon(); + ShowDDIcon( pRefEntry, rPosPix ); + return; + } + + // Ueberlappung des neuen und alten D&D-Pointers! + + Rectangle aFullRect( aPrevEntryRect.Union( aCurEntryRect ) ); + if( !pDDTempDev ) + { + pDDTempDev = new VirtualDevice( *pView ); + pDDTempDev->SetFont( pView->GetFont() ); + } + + Size aFullSize( aFullRect.GetSize() ); + Point aFullPos( aFullRect.TopLeft() ); + + pDDTempDev->SetOutputSizePixel( aFullSize ); + + // Hintergrund (mit dem alten D&D-Pointer!) sichern + pDDTempDev->DrawOutDev( aEmptyPoint, aFullSize, aFullPos, aFullSize, *pView ); + // den alten Buffer in den neuen Buffer pasten + aDDLastRectPos = aDDLastRectPos - aFullPos; + + pDDTempDev->DrawOutDev( + aDDLastRectPos, + pDDDev->GetOutputSizePixel(), + aEmptyPoint, + pDDDev->GetOutputSizePixel(), + *pDDDev ); + + // Swap + VirtualDevice* pTemp = pDDDev; + pDDDev = pDDTempDev; + pDDTempDev = pTemp; + + // in den restaurierten Hintergrund den neuen D&D-Pointer zeichnen + pDDTempDev->SetOutputSizePixel( pDDDev->GetOutputSizePixel() ); + pDDTempDev->DrawOutDev( + aEmptyPoint, aFullSize, aEmptyPoint, aFullSize, *pDDDev ); + Point aRelPos = aCurEntryPos - aFullPos; + nFlags |= F_NO_EMPHASIS; + PaintEntry( pRefEntry, aRelPos, 0, pDDTempDev ); + nFlags &= ~F_NO_EMPHASIS; + + aDDLastRectPos = aFullPos; + aDDLastEntryPos = aCurEntryPos; + + pView->DrawOutDev( + aDDLastRectPos, + pDDDev->GetOutputSizePixel(), + aEmptyPoint, + pDDDev->GetOutputSizePixel(), + *pDDTempDev ); + + sal_Bool bSelected = pView->SvListView::Select( pRefEntry, sal_False ); + if( bSelected ) + pView->SvListView::Select( pRefEntry, sal_True ); +} + +void SvImpIconView::ShowTargetEmphasis( SvLBoxEntry* pEntry, sal_Bool ) +{ + CheckBoundingRects(); + Rectangle aRect; + if( pEntry != pCurParent && + (pEntry->HasChilds() || pEntry->HasChildsOnDemand()) ) + aRect = CalcBmpRect( pEntry ); + else + { + aRect.SetSize( aOutputSize ); + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin()); + aOrigin *= -1; // in Doc-Koord wandeln + aRect.SetPos( aOrigin ); + aRect.Left()++; aRect.Top()++; + aRect.Right()--; aRect.Bottom()--; + } + ImpDrawXORRect( aRect ); +} + +sal_Bool SvImpIconView::NotifyMoving( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewPar, sal_uLong& rNewChildPos ) +{ + if( pTarget == pCurParent && pModel->GetParent(pEntry) == pCurParent ) + { + // D&D innerhalb einer Childlist + StopEditTimer(); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + Size aSize( pViewData->aRect.GetSize() ); + Point aNewPos = FindNextEntryPos( aSize ); + AdjustVirtSize( Rectangle( aNewPos, aSize ) ); + SetEntryPosition( pEntry, aNewPos, sal_False, sal_True ); + return sal_False; + } + return pView->SvLBox::NotifyMoving(pTarget,pEntry,rpNewPar,rNewChildPos); +} + +sal_Bool SvImpIconView::NotifyCopying( SvLBoxEntry* pTarget, SvLBoxEntry* pEntry, + SvLBoxEntry*& rpNewParent, sal_uLong& rNewChildPos ) +{ + return pView->SvLBox::NotifyCopying(pTarget,pEntry,rpNewParent,rNewChildPos); +} + +void SvImpIconView::WriteDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo) +{ + SvLBoxEntry* pCurEntry = GetCurEntry(); + Point aEntryPos; + if( pCurEntry ) + { + aEntryPos = rPos; + aEntryPos -= GetEntryPosition( pCurEntry ); + } + pInfo->nMouseRelX = aEntryPos.X(); + pInfo->nMouseRelY = aEntryPos.Y(); +} + +void SvImpIconView::ReadDragServerInfo( const Point& rPos, SvLBoxDDInfo* pInfo ) +{ + Point aDropPos( rPos ); + aDropPos.X() -= pInfo->nMouseRelX; + aDropPos.Y() -= pInfo->nMouseRelY; + SetNextEntryPos( aDropPos ); +} + +void SvImpIconView::InvalidateBoundingRect( SvLBoxEntry* pEntry ) +{ + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + InvalidateBoundingRect( pViewData->aRect ); +} + +void SvImpIconView::PrepareCommandEvent( const Point& rPt ) +{ + aMouseMoveTimer.Stop(); + StopEditTimer(); + nFlags |= F_CMD_ARRIVED; + SvLBoxEntry* pEntry = pView->GetEntry( rPt, sal_True ); + if( (nFlags & F_DOWN_CTRL) && pEntry && !pView->IsSelected(pEntry) ) + pView->Select( pEntry, sal_True ); + nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT); +} + +void SvImpIconView::SttDrag( const Point& rPos ) +{ + PrepareCommandEvent( rPos ); + + nFlags |= F_DRAG_SOURCE; + ShowCursor( sal_False ); +} + +void SvImpIconView::EndDrag() +{ + ShowCursor( sal_True ); + nFlags &= (~F_DRAG_SOURCE); +} + +void SvImpIconView::ToTop( SvLBoxEntry* pEntry ) +{ + DBG_ASSERT(pZOrderList->GetPos(pEntry)!=0xffff,"ToTop:ZOrder?"); + if( pZOrderList->GetObject( pZOrderList->Count() -1 ) != pEntry ) + { + sal_uInt16 nPos = pZOrderList->GetPos( (void*)pEntry ); + pZOrderList->Remove( nPos, 1 ); + pZOrderList->Insert( pEntry, pZOrderList->Count() ); + } +} + +void SvImpIconView::SetCurParent( SvLBoxEntry* pNewParent ) +{ + Clear(); + pCurParent = pNewParent; + ImpArrange(); +} + +void SvImpIconView::ClipAtVirtOutRect( Rectangle& rRect ) const +{ + if( rRect.Bottom() >= aVirtOutputSize.Height() ) + rRect.Bottom() = aVirtOutputSize.Height() - 1; + if( rRect.Right() >= aVirtOutputSize.Width() ) + rRect.Right() = aVirtOutputSize.Width() - 1; + if( rRect.Top() < 0 ) + rRect.Top() = 0; + if( rRect.Left() < 0 ) + rRect.Left() = 0; +} + +// rRect: Bereich des Dokumentes (in Dokumentkoordinaten), der +// sichtbar gemacht werden soll. +// bScrBar == sal_True: Das Rect wurde aufgrund eines ScrollBar-Events berechnet + +void SvImpIconView::MakeVisible( const Rectangle& rRect, sal_Bool bScrBar ) +{ + Rectangle aRect( rRect ); + ClipAtVirtOutRect( aRect ); + MapMode aMapMode( pView->GetMapMode() ); + Point aOrigin( aMapMode.GetOrigin() ); + // in Dokumentkoordinate umwandeln + aOrigin *= -1; + + Rectangle aOutputArea( aOrigin, aOutputSize ); + if( aOutputArea.IsInside( aRect ) ) + return; // ist schon sichtbar + + long nDy; + if( aRect.Top() < aOutputArea.Top() ) + { + // nach oben scrollen (nDy < 0) + nDy = aRect.Top() - aOutputArea.Top(); + } + else if( aRect.Bottom() > aOutputArea.Bottom() ) + { + // nach unten scrollen (nDy > 0) + nDy = aRect.Bottom() - aOutputArea.Bottom(); + } + else + nDy = 0; + + long nDx; + if( aRect.Left() < aOutputArea.Left() ) + { + // nach links scrollen (nDx < 0) + nDx = aRect.Left() - aOutputArea.Left(); + } + else if( aRect.Right() > aOutputArea.Right() ) + { + // nach rechts scrollen (nDx > 0) + nDx = aRect.Right() - aOutputArea.Right(); + } + else + nDx = 0; + + aOrigin.X() += nDx; + aOrigin.Y() += nDy; + aOutputArea.SetPos( aOrigin ); + + pView->Update(); + + // Origin fuer SV invertieren (damit wir in + // Dokumentkoordinaten scrollen/painten koennen) + aOrigin *= -1; + aMapMode.SetOrigin( aOrigin ); + pView->SetMapMode( aMapMode ); + + // in umgekehrte Richtung scrollen! + pView->Control::Scroll( -nDx, -nDy, aOutputArea, sal_True ); + if( aHorSBar.IsVisible() || aVerSBar.IsVisible() ) + { + if( !bScrBar ) + { + aOrigin *= -1; + // Thumbs korrigieren + if(aHorSBar.IsVisible() && aHorSBar.GetThumbPos() != aOrigin.X()) + aHorSBar.SetThumbPos( aOrigin.X() ); + if(aVerSBar.IsVisible() && aVerSBar.GetThumbPos() != aOrigin.Y()) + aVerSBar.SetThumbPos( aOrigin.Y() ); + } + } + // pruefen, ob ScrollBars noch benoetigt werden + CheckScrollBars(); + pView->Update(); +} + + +SvLBoxEntry* SvImpIconView::GetNewCursor() +{ + SvLBoxEntry* pNewCursor; + if( pCursor ) + { + pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_False ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoLeftRight( pCursor, sal_True ); + if( !pNewCursor ) + { + pNewCursor = pImpCursor->GoUpDown( pCursor, sal_False ); + if( !pNewCursor ) + pNewCursor = pImpCursor->GoUpDown( pCursor, sal_True ); + } + } + } + else + pNewCursor = pModel->FirstChild( pCurParent ); + DBG_ASSERT(!pNewCursor|| (pCursor&&pCursor!=pNewCursor),"GetNewCursor failed"); + return pNewCursor; +} + + +sal_uInt16 SvImpIconView:: GetSelectionCount() const +{ + sal_uInt16 nSelected = 0; + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent); + while( pEntry ) + { + if( pView->IsSelected( pEntry ) ) + nSelected++; + pEntry = pModel->NextSibling( pEntry ); + } + return nSelected; +} + + +void SvImpIconView::ToggleSelection( SvLBoxEntry* pEntry ) +{ + sal_Bool bSel; + if( pView->IsSelected( pEntry ) ) + bSel = sal_False; + else + bSel = sal_True; + pView->Select( pEntry, bSel ); +} + +void SvImpIconView::DeselectAllBut( SvLBoxEntry* pThisEntryNot ) +{ + ClearSelectedRectList(); + SvLBoxEntry* pEntry = pModel->FirstChild( pCurParent ); + while( pEntry ) + { + if( pEntry != pThisEntryNot && pView->IsSelected( pEntry )) + pView->Select( pEntry, sal_False ); + pEntry = pModel->NextSibling( pEntry ); + } +} + +#define ICN_ROWS 50 +#define ICN_COLS 30 + +ImpIcnCursor::ImpIcnCursor( SvImpIconView* pOwner ) +{ + pView = pOwner; + pColumns = 0; + pRows = 0; + pCurEntry = 0; + nDeltaWidth = 0; + nDeltaHeight= 0; + nCols = 0; + nRows = 0; + nGridCols = 0; + nGridRows = 0; + pGridMap = 0; +} + +ImpIcnCursor::~ImpIcnCursor() +{ + delete[] pColumns; + delete[] pRows; + delete pGridMap; +} + +sal_uInt16 ImpIcnCursor::GetSortListPos( SvPtrarr* pList, long nValue, + int bVertical ) +{ + sal_uInt16 nCount = (sal_uInt16)pList->Count(); + if( !nCount ) + return 0; + + sal_uInt16 nCurPos = 0; + long nPrevValue = LONG_MIN; + while( nCount ) + { + const Rectangle& rRect= + pView->GetBoundingRect((SvLBoxEntry*)(pList->GetObject(nCurPos))); + long nCurValue; + if( bVertical ) + nCurValue = rRect.Top(); + else + nCurValue = rRect.Left(); + if( nValue >= nPrevValue && nValue <= nCurValue ) + return (sal_uInt16)nCurPos; + nPrevValue = nCurValue; + nCount--; + nCurPos++; + } + return pList->Count(); +} + +void ImpIcnCursor::ImplCreate() +{ + pView->CheckBoundingRects(); + DBG_ASSERT(pColumns==0&&pRows==0,"ImplCreate: Not cleared"); + + SetDeltas(); + + pColumns = new SvPtrarr[ nCols ]; + pRows = new SvPtrarr[ nRows ]; + + DELETEZ(pGridMap); + + SvLBoxTreeList* pModel = pView->pModel; + SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + // const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + Rectangle rRect( pView->CalcBmpRect( pEntry,0,pViewData ) ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / nDeltaHeight ); + short nX = (short)( ((rRect.Left()+rRect.Right())/2) / nDeltaWidth ); + + // Rundungsfehler abfangen + if( nY >= nRows ) + nY = sal::static_int_cast< short >(nRows - 1); + if( nX >= nCols ) + nX = sal::static_int_cast< short >(nCols - 1); + + sal_uInt16 nIns = GetSortListPos( &pColumns[nX], rRect.Top(), sal_True ); + pColumns[ nX ].Insert( pEntry, nIns ); + + nIns = GetSortListPos( &pRows[nY], rRect.Left(), sal_False ); + pRows[ nY ].Insert( pEntry, nIns ); + + pViewData->nX = nX; + pViewData->nY = nY; + + pEntry = pModel->NextSibling( pEntry ); + } +} + +void ImpIcnCursor::CreateGridMap() +{ + if( pGridMap ) + return; + + const Size& rSize = pView->aVirtOutputSize; + long nWidth = rSize.Width(); + if( nWidth < pView->nMaxVirtWidth ) + nWidth = pView->nMaxVirtWidth; + nWidth -= 2*LROFFS_WINBORDER; + if( nWidth <= 0 ) + nWidth = 1; + + nGridDX = pView->nGridDX; + nGridDY = pView->nGridDY; + + // Hinweis: Wegen der Abrundung bei Berechnung von nGridCols + // ist es moeglich, dass Eintrage nicht im Grid liegen. Diese + // wurden typischerweise manuell verschoben und gelockt + nGridCols = nWidth / nGridDX; + if( !nGridCols ) nGridCols = 1; + + nGridRows = rSize.Height() / nGridDY; + // nRows nicht abrunden, da zur Vermeidung von Ueberlappungen + // das gesamte BoundingRect des Eintrags zur Markierung im Grid + // herangezogen wird. + if( (nGridRows * nGridDY) < rSize.Height() ) + nGridRows++; + else if( !nGridRows ) + nGridRows = 1; + + //XXX + //nGridRows += 50; // in fuenfziger-Schritten + + pGridMap = new sal_Bool[ nGridRows*nGridCols]; + memset( (void*)pGridMap, 0, nGridRows*nGridCols ); + + SvLBoxTreeList* pModel = pView->pModel; + SvLBoxEntry* pEntry = pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + const Rectangle& rRect = pViewData->aRect; + // nur, wenn der Entry schon plaziert ist + if( pView->IsBoundingRectValid( rRect )) + { + // Alle vom Eintrag beruehrten Grids kennzeichnen + SetGridUsed( pView->GetBoundingRect( pEntry, pViewData ) ); + } + pEntry = pModel->NextSibling( pEntry ); + } +} + +sal_Bool ImpIcnCursor::GetGrid( const Point& rDocPos, sal_uInt16& rGridX, sal_uInt16& rGridY ) const +{ + Point aPos( rDocPos ); + aPos.X() -= LROFFS_WINBORDER; + aPos.Y() -= TBOFFS_WINBORDER; + rGridX = (sal_uInt16)(aPos.X() / nGridDX); + rGridY = (sal_uInt16)(aPos.Y() / nGridDY); + sal_Bool bInGrid = sal_True; + if( rGridX >= nGridCols ) + { + rGridX = sal::static_int_cast< sal_uInt16 >(nGridCols - 1); + bInGrid = sal_False; + } + if( rGridY >= nGridRows ) + { + rGridY = sal::static_int_cast< sal_uInt16 >(nGridRows - 1); + if( !bInGrid ) + return sal_False; // beide Koordinaten nicht im Grid + } + return sal_True; +} + +void ImpIcnCursor::SetGridUsed( const Rectangle& rRect, sal_Bool bUsed ) +{ + CreateGridMap(); + sal_uInt16 nTLX, nTLY, nBRX, nBRY; + + sal_Bool bTLInGrid = GetGrid( rRect.TopLeft(), nTLX, nTLY ); + sal_Bool bBRInGrid = GetGrid( rRect.BottomRight(), nBRX, nBRY ); + + if( !bTLInGrid && !bBRInGrid ) + return; + + for( sal_uInt16 nCurY = nTLY; nCurY <= nBRY; nCurY++ ) + { + for( sal_uInt16 nCurX = nTLX; nCurX <= nBRX; nCurX++ ) + { + SetGridUsed( nCurX, nCurY, bUsed ); + } + } +} + +void ImpIcnCursor::Clear( sal_Bool bGridToo ) +{ + if( pColumns ) + { + delete[] pColumns; + delete[] pRows; + pColumns = 0; + pRows = 0; + pCurEntry = 0; + nDeltaWidth = 0; + nDeltaHeight = 0; + } + if( bGridToo && pGridMap ) + { + DELETEZ(pGridMap); + nGridRows = 0; + nGridCols = 0; + } +} + +SvLBoxEntry* ImpIcnCursor::SearchCol(sal_uInt16 nCol,sal_uInt16 nTop,sal_uInt16 nBottom, + sal_uInt16, sal_Bool bDown, sal_Bool bSimple ) +{ + DBG_ASSERT(pCurEntry,"SearchCol: No reference entry"); + SvPtrarr* pList = &(pColumns[ nCol ]); + sal_uInt16 nCount = pList->Count(); + if( !nCount ) + return 0; + + const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry); + + if( bSimple ) + { + sal_uInt16 nListPos = pList->GetPos( pCurEntry ); + DBG_ASSERT(nListPos!=0xffff,"Entry not in Col-List"); + if( bDown ) + { + while( nListPos < nCount-1 ) + { + nListPos++; + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Top() > rRefRect.Top() ) + return pEntry; + } + return 0; + } + else + { + while( nListPos ) + { + nListPos--; + if( nListPos < nCount ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Top() < rRefRect.Top() ) + return pEntry; + } + } + return 0; + } + } + + if( nTop > nBottom ) + { + sal_uInt16 nTemp = nTop; + nTop = nBottom; + nBottom = nTemp; + } + long nMinDistance = LONG_MAX; + SvLBoxEntry* pResult = 0; + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur )); + if( pEntry != pCurEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + sal_uInt16 nY = pViewData->nY; + if( nY >= nTop && nY <= nBottom ) + { + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + long nDistance = rRect.Top() - rRefRect.Top(); + if( nDistance < 0 ) + nDistance *= -1; + if( nDistance && nDistance < nMinDistance ) + { + nMinDistance = nDistance; + pResult = pEntry; + } + } + } + } + return pResult; +} + +SvLBoxEntry* ImpIcnCursor::SearchRow(sal_uInt16 nRow,sal_uInt16 nLeft,sal_uInt16 nRight, + sal_uInt16, sal_Bool bRight, sal_Bool bSimple ) +{ + DBG_ASSERT(pCurEntry,"SearchRow: No reference entry"); + SvPtrarr* pList = &(pRows[ nRow ]); + sal_uInt16 nCount = pList->Count(); + if( !nCount ) + return 0; + + const Rectangle& rRefRect = pView->GetBoundingRect(pCurEntry); + + if( bSimple ) + { + sal_uInt16 nListPos = pList->GetPos( pCurEntry ); + DBG_ASSERT(nListPos!=0xffff,"Entry not in Row-List"); + if( bRight ) + { + while( nListPos < nCount-1 ) + { + nListPos++; + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Left() > rRefRect.Left() ) + return pEntry; + } + return 0; + } + else + { + while( nListPos ) + { + nListPos--; + if( nListPos < nCount ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)pList->GetObject( nListPos ); + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + if( rRect.Left() < rRefRect.Left() ) + return pEntry; + } + } + return 0; + } + + } + if( nRight < nLeft ) + { + sal_uInt16 nTemp = nRight; + nRight = nLeft; + nLeft = nTemp; + } + long nMinDistance = LONG_MAX; + SvLBoxEntry* pResult = 0; + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pList->GetObject( nCur )); + if( pEntry != pCurEntry ) + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pEntry); + sal_uInt16 nX = pViewData->nX; + if( nX >= nLeft && nX <= nRight ) + { + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + long nDistance = rRect.Left() - rRefRect.Left(); + if( nDistance < 0 ) + nDistance *= -1; + if( nDistance && nDistance < nMinDistance ) + { + nMinDistance = nDistance; + pResult = pEntry; + } + } + } + } + return pResult; +} + + + +/* + Sucht ab dem uebergebenen Eintrag den naechsten rechts- bzw. + linksstehenden. Suchverfahren am Beispiel bRight = sal_True: + + c + b c + a b c + S 1 1 1 ====> Suchrichtung + a b c + b c + c + + S : Startposition + 1 : erstes Suchrechteck + a,b,c : 2., 3., 4. Suchrechteck +*/ + +SvLBoxEntry* ImpIcnCursor::GoLeftRight( SvLBoxEntry* pIcnEntry, sal_Bool bRight ) +{ + SvLBoxEntry* pResult; + pCurEntry = pIcnEntry; + Create(); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pIcnEntry); + sal_uInt16 nY = pViewData->nY; + sal_uInt16 nX = pViewData->nX; + DBG_ASSERT(nY< nRows,"GoLeftRight:Bad column"); + DBG_ASSERT(nX< nCols,"GoLeftRight:Bad row"); + // Nachbar auf gleicher Zeile ? + if( bRight ) + pResult = SearchRow( + nY, nX, sal::static_int_cast< sal_uInt16 >(nCols-1), nX, sal_True, sal_True ); + else + pResult = SearchRow( nY, nX ,0, nX, sal_False, sal_True ); + if( pResult ) + return pResult; + + long nCurCol = nX; + + long nColOffs, nLastCol; + if( bRight ) + { + nColOffs = 1; + nLastCol = nCols; + } + else + { + nColOffs = -1; + nLastCol = -1; // 0-1 + } + + sal_uInt16 nRowMin = nY; + sal_uInt16 nRowMax = nY; + do + { + SvLBoxEntry* pEntry = SearchCol((sal_uInt16)nCurCol,nRowMin,nRowMax,nY,sal_True, sal_False); + if( pEntry ) + return pEntry; + if( nRowMin ) + nRowMin--; + if( nRowMax < (nRows-1)) + nRowMax++; + nCurCol += nColOffs; + } while( nCurCol != nLastCol ); + return 0; +} + +SvLBoxEntry* ImpIcnCursor::GoUpDown( SvLBoxEntry* pIcnEntry, sal_Bool bDown) +{ + SvLBoxEntry* pResult; + pCurEntry = pIcnEntry; + Create(); + SvIcnVwDataEntry* pViewData = ICNVIEWDATA2(pIcnEntry); + sal_uInt16 nY = pViewData->nY; + sal_uInt16 nX = pViewData->nX; + DBG_ASSERT(nY<nRows,"GoUpDown:Bad column"); + DBG_ASSERT(nX<nCols,"GoUpDown:Bad row"); + + // Nachbar in gleicher Spalte ? + if( bDown ) + pResult = SearchCol( + nX, nY, sal::static_int_cast< sal_uInt16 >(nRows-1), nY, sal_True, sal_True ); + else + pResult = SearchCol( nX, nY ,0, nY, sal_False, sal_True ); + if( pResult ) + return pResult; + + long nCurRow = nY; + + long nRowOffs, nLastRow; + if( bDown ) + { + nRowOffs = 1; + nLastRow = nRows; + } + else + { + nRowOffs = -1; + nLastRow = -1; // 0-1 + } + + sal_uInt16 nColMin = nX; + sal_uInt16 nColMax = nX; + do + { + SvLBoxEntry* pEntry = SearchRow((sal_uInt16)nCurRow,nColMin,nColMax,nX,sal_True, sal_False); + if( pEntry ) + return pEntry; + if( nColMin ) + nColMin--; + if( nColMax < (nCols-1)) + nColMax++; + nCurRow += nRowOffs; + } while( nCurRow != nLastRow ); + return 0; +} + +void ImpIcnCursor::SetDeltas() +{ + const Size& rSize = pView->aVirtOutputSize; + if( pView->nFlags & F_GRIDMODE ) + { + nGridDX = pView->nGridDX; + nGridDY = pView->nGridDY; + } + else + { + nGridDX = 20; + nGridDY = 20; + } + nCols = rSize.Width() / nGridDX; + if( !nCols ) + nCols = 1; + nRows = rSize.Height() / nGridDY; + if( (nRows * nGridDY) < rSize.Height() ) + nRows++; + if( !nRows ) + nRows = 1; + + nDeltaWidth = (short)(rSize.Width() / nCols); + nDeltaHeight = (short)(rSize.Height() / nRows); + if( !nDeltaHeight ) + { + nDeltaHeight = 1; + DBG_WARNING("SetDeltas:Bad height"); + } + if( !nDeltaWidth ) + { + nDeltaWidth = 1; + DBG_WARNING("SetDeltas:Bad width"); + } +} + + +void ImpIcnCursor::ExpandGrid() +{ + if( pGridMap ) + { + long nNewGridRows = nGridRows + 20; + unsigned char* pTempMap = new unsigned char[ nNewGridRows * nGridCols ]; + memcpy( pTempMap, pGridMap, nGridRows * nGridCols ); + delete pGridMap; + pGridMap = pTempMap; + nGridRows = nNewGridRows; + } +} + +sal_Bool ImpIcnCursor::FindEmptyGridRect( Rectangle& rRect ) +{ + CreateGridMap(); + sal_uInt16 nCount = (sal_uInt16)(nGridCols * nGridRows); + if( !nCount ) + return sal_False; + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + if( !pGridMap[ nCur ] ) + { + sal_uInt16 nCol = (sal_uInt16)(nCur % nGridCols); + sal_uInt16 nRow = (sal_uInt16)(nCur / nGridCols); + rRect.Top() = nRow * nGridDY + TBOFFS_WINBORDER; + rRect.Bottom() = rRect.Top() + nGridDY; + rRect.Left() = nCol * nGridDX+ LROFFS_WINBORDER; + rRect.Right() = rRect.Left() + nGridDX; + SetGridUsed( nCol, nRow, sal_True ); + + //XXX + //if( nRow + 5 > nGridRows ) + // ExpandGrid(); + DBG_ASSERT(pGridMap[nCur],"SetGridUsed failed"); + return sal_True; + } + } + // Gridmap ist voll: Um eine Zeile erweitern + rRect.Top() = nGridRows * nGridDY + TBOFFS_WINBORDER; + rRect.Bottom() = rRect.Top() + nGridDY; + rRect.Left() = LROFFS_WINBORDER; + rRect.Right() = rRect.Left() + nGridDX; + return sal_False; + //XXX + //ExpandGrid(); + //return sal_True; +} + +void ImpIcnCursor::CreateGridAjustData( SvPtrarr& rLists, SvLBoxEntry* pRefEntry) +{ + if( !pRefEntry ) + { + sal_uInt16 nAdjustRows = (sal_uInt16)(pView->aVirtOutputSize.Height() / pView->nGridDY); + nAdjustRows++; // wg. Abrundung! + + if( !nAdjustRows ) + return; + for( sal_uInt16 nCurList = 0; nCurList < nAdjustRows; nCurList++ ) + { + SvPtrarr* pRow = new SvPtrarr; + rLists.Insert( (void*)pRow, nCurList ); + } + SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); + sal_uInt16 nIns = GetSortListPos((SvPtrarr*)rLists[nY],rRect.Left(),sal_False); + ((SvPtrarr*)rLists[ nY ])->Insert( pEntry, nIns ); + pEntry = pView->pModel->NextSibling( pEntry ); + } + } + else + { + // Aufbau eines hor. "Schlauchs" auf der RefEntry-Zeile + + // UEBERLEGEN: BoundingRect nehmen wg. Ueberlappungen??? + + Rectangle rRefRect( pView->CalcBmpRect( pRefEntry ) ); + //const Rectangle& rRefRect = pView->GetBoundingRect( pRefEntry ); + short nRefRow = (short)( ((rRefRect.Top()+rRefRect.Bottom())/2) / pView->nGridDY ); + SvPtrarr* pRow = new SvPtrarr; + rLists.Insert( (void*)pRow, 0 ); + SvLBoxEntry* pEntry = pView->pModel->FirstChild( pView->pCurParent ); + while( pEntry ) + { + Rectangle rRect( pView->CalcBmpRect(pEntry) ); + //const Rectangle& rRect = pView->GetBoundingRect( pEntry ); + short nY = (short)( ((rRect.Top()+rRect.Bottom())/2) / pView->nGridDY ); + if( nY == nRefRow ) + { + sal_uInt16 nIns = GetSortListPos( pRow, rRect.Left(), sal_False ); + pRow->Insert( pEntry, nIns ); + } + pEntry = pView->pModel->NextSibling( pEntry ); + } + } +} + +//static +void ImpIcnCursor::DestroyGridAdjustData( SvPtrarr& rLists ) +{ + sal_uInt16 nCount = rLists.Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + SvPtrarr* pArr = (SvPtrarr*)rLists[ nCur ]; + delete pArr; + } + rLists.Remove( 0, rLists.Count() ); +} + +void SvImpIconView::SetGrid( long nDX, long nDY ) +{ + nGridDX = nDX; + nGridDY = nDY; + nFlags |= F_GRIDMODE; +} + +Rectangle SvImpIconView::CalcMaxTextRect( const SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + Rectangle aRect = pViewData->aGridRect; + long nBmpHeight = ((SvLBoxEntry*)pEntry)->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)->GetSize(pView,(SvLBoxEntry*)pEntry).Height(); + aRect.Top() += nBmpHeight; + aRect.Top() += ICONVIEW_OFFS_BMP_STRING; + if( aRect.Top() > aRect.Bottom()) + aRect.Top() = aRect.Bottom(); + aRect.Left() += LROFFS_BOUND; + aRect.Left()++; + aRect.Right() -= LROFFS_BOUND; + aRect.Right()--; + if( aRect.Left() > aRect.Right()) + aRect.Left() = aRect.Right(); + if( GetTextMode( pEntry, pViewData ) == ShowTextFull ) + aRect.Bottom() = LONG_MAX; + return aRect; +} + +void SvImpIconView::Center( SvLBoxEntry* pEntry, + SvIcnVwDataEntry* pViewData ) const +{ + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + const String& rEntryText = pStringItem->GetText(); + + Rectangle aTextRect = CalcMaxTextRect(pEntry,pViewData); + aTextRect = GetTextRect( pView, aTextRect, rEntryText, DRAWTEXT_FLAGS ); + pViewData->aTextSize = aTextRect.GetSize(); + + pViewData->aRect = pViewData->aGridRect; + Size aSize( CalcBoundingSize( pEntry, pViewData ) ); + long nBorder = pViewData->aGridRect.GetWidth() - aSize.Width(); + pViewData->aRect.Left() += nBorder / 2; + pViewData->aRect.Right() -= nBorder / 2; + pViewData->aRect.Bottom() = pViewData->aRect.Top() + aSize.Height(); +} + + +// Die Deltas entsprechen Offsets, um die die View auf dem Doc verschoben wird +// links, hoch: Offsets < 0 +// rechts, runter: Offsets > 0 +void SvImpIconView::Scroll( long nDeltaX, long nDeltaY, sal_Bool bScrollBar ) +{ + const MapMode& rMapMode = pView->GetMapMode(); + Point aOrigin( rMapMode.GetOrigin() ); + // in Dokumentkoordinate umwandeln + aOrigin *= -1; + aOrigin.Y() += nDeltaY; + aOrigin.X() += nDeltaX; + Rectangle aRect( aOrigin, aOutputSize ); + MakeVisible( aRect, bScrollBar ); +} + + +const Size& SvImpIconView::GetItemSize( SvIconView* pIconView, + SvLBoxEntry* pEntry, SvLBoxItem* pItem, const SvIcnVwDataEntry* pViewData) const +{ + if( (nFlags & F_GRIDMODE) && pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + if( !pViewData ) + pViewData = ICNVIEWDATA(pEntry); + return pViewData->aTextSize; + } + else + return pItem->GetSize( pIconView, pEntry ); +} + +Rectangle SvImpIconView::CalcFocusRect( SvLBoxEntry* pEntry ) +{ +#if !defined(OS2) + SvLBoxString* pStringItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + DBG_ASSERT(pStringItem,"Text not set"); + return CalcTextRect( pEntry, pStringItem ); +#else + return CalcBmpRect( pEntry ); +#endif +} + + +void SvImpIconView::SelectRect( const Rectangle& rRect, sal_Bool bAdd, + SvPtrarr* pOtherRects, short nBorderOffs ) +{ + if( !pZOrderList || !pZOrderList->Count() ) + return; + + CheckBoundingRects(); + pView->Update(); + sal_uInt16 nCount = pZOrderList->Count(); + + Rectangle aRect( rRect ); + aRect.Justify(); + if( nBorderOffs ) + { + aRect.Left() -= nBorderOffs; + aRect.Right() += nBorderOffs; + aRect.Top() -= nBorderOffs; + aRect.Bottom() += nBorderOffs; + } + sal_Bool bCalcOverlap = (bAdd && pOtherRects && pOtherRects->Count()) ? sal_True : sal_False; + + for( sal_uInt16 nPos = 0; nPos < nCount; nPos++ ) + { + SvLBoxEntry* pEntry = (SvLBoxEntry*)(pZOrderList->GetObject(nPos )); + + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + DBG_ASSERT(pViewData,"Entry not in model"); + if( !IsBoundingRectValid( pViewData->aRect )) + FindBoundingRect( pEntry, pViewData ); + const Rectangle& rBoundRect = pViewData->aRect; + sal_Bool bSelected = pViewData->IsSelected(); + + sal_Bool bOverlaps; + if( bCalcOverlap ) + bOverlaps = IsOver( pOtherRects, rBoundRect ); + else + bOverlaps = sal_False; + sal_Bool bOver = aRect.IsOver( rBoundRect ); + + if( bOver && !bOverlaps ) + { + // Ist im neuen Selektionsrechteck und in keinem alten + // => selektieren + if( !bSelected ) + pView->Select( pEntry, sal_True ); + } + else if( !bAdd ) + { + // ist ausserhalb des Selektionsrechtecks + // => Selektion entfernen + if( bSelected ) + pView->Select( pEntry, sal_False ); + } + else if( bAdd && bOverlaps ) + { + // Der Eintrag befindet sich in einem alten (=>Aufspannen + // mehrerer Rechtecke mit Ctrl!) Selektionsrechteck + + // Hier ist noch ein Bug! Der Selektionsstatus eines Eintrags + // in einem vorherigen Rechteck, muss restauriert werden, wenn + // er vom aktuellen Selektionsrechteck beruehrt wurde, jetzt aber + // nicht mehr in ihm liegt. Ich gehe hier der Einfachheit halber + // pauschal davon aus, dass die Eintraege in den alten Rechtecken + // alle selektiert sind. Ebenso ist es falsch, die Schnittmenge + // nur zu deselektieren. + // Loesungsmoeglichkeit: Snapshot der Selektion vor dem Auf- + // spannen des Rechtecks merken + if( rBoundRect.IsOver( rRect)) + { + // Schnittmenge zwischen alten Rects & aktuellem Rect desel. + if( bSelected ) + pView->Select( pEntry, sal_False ); + } + else + { + // Eintrag eines alten Rects selektieren + if( !bSelected ) + pView->Select( pEntry, sal_True ); + } + } + else if( !bOver && bSelected ) + { + // Der Eintrag liegt voellig ausserhalb und wird deshalb desel. + pView->Select( pEntry, sal_False ); + } + } + pView->Update(); +} + +sal_Bool SvImpIconView::IsOver( SvPtrarr* pRectList, const Rectangle& rBoundRect ) const +{ + sal_uInt16 nCount = pRectList->Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + Rectangle* pRect = (Rectangle*)pRectList->GetObject( nCur ); + if( rBoundRect.IsOver( *pRect )) + return sal_True; + } + return sal_False; +} + +void SvImpIconView::AddSelectedRect( const Rectangle& rRect, short nBorderOffs ) +{ + Rectangle* pRect = new Rectangle( rRect ); + pRect->Justify(); + if( nBorderOffs ) + { + pRect->Left() -= nBorderOffs; + pRect->Right() += nBorderOffs; + pRect->Top() -= nBorderOffs; + pRect->Bottom() += nBorderOffs; + } + aSelectedRectList.Insert( (void*)pRect, aSelectedRectList.Count() ); +} + +void SvImpIconView::ClearSelectedRectList() +{ + sal_uInt16 nCount = aSelectedRectList.Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + Rectangle* pRect = (Rectangle*)aSelectedRectList.GetObject( nCur ); + delete pRect; + } + aSelectedRectList.Remove( 0, aSelectedRectList.Count() ); +} + + +void SvImpIconView::DrawSelectionRect( const Rectangle& rRect ) +{ + pView->HideTracking(); + nFlags |= F_SELRECT_VISIBLE; + pView->ShowTracking( rRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW ); + aCurSelectionRect = rRect; +} + +void SvImpIconView::HideSelectionRect() +{ + if( nFlags & F_SELRECT_VISIBLE ) + { + pView->HideTracking(); + nFlags &= ~F_SELRECT_VISIBLE; + } +} + +void SvImpIconView::ImpDrawXORRect( const Rectangle& rRect ) +{ + RasterOp eOldOp = pView->GetRasterOp(); + pView->SetRasterOp( ROP_XOR ); + Color aOldColor = pView->GetFillColor(); + pView->SetFillColor(); + pView->DrawRect( rRect ); + pView->SetFillColor( aOldColor ); + pView->SetRasterOp( eOldOp ); +} + +void SvImpIconView::CalcScrollOffsets( const Point& rPosPixel, + long& rX, long& rY, sal_Bool bInDragDrop, sal_uInt16 nBorderWidth) +{ + // Scrolling der View, falls sich der Mauszeiger im Grenzbereich des + // Fensters befindet + long nPixelToScrollX = 0; + long nPixelToScrollY = 0; + Size aWndSize = aOutputSize; + + nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Height()-1), (long)nBorderWidth )); + nBorderWidth = (sal_uInt16)(Min( (long)(aWndSize.Width()-1), (long)nBorderWidth )); + + if ( rPosPixel.X() < nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollX = -DD_SCROLL_PIXEL; + else + nPixelToScrollX = rPosPixel.X()- nBorderWidth; + } + else if ( rPosPixel.X() > aWndSize.Width() - nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollX = DD_SCROLL_PIXEL; + else + nPixelToScrollX = rPosPixel.X() - (aWndSize.Width() - nBorderWidth); + } + if ( rPosPixel.Y() < nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollY = -DD_SCROLL_PIXEL; + else + nPixelToScrollY = rPosPixel.Y() - nBorderWidth; + } + else if ( rPosPixel.Y() > aWndSize.Height() - nBorderWidth ) + { + if( bInDragDrop ) + nPixelToScrollY = DD_SCROLL_PIXEL; + else + nPixelToScrollY = rPosPixel.Y() - (aWndSize.Height() - nBorderWidth); + } + + rX = nPixelToScrollX; + rY = nPixelToScrollY; +} + +IMPL_LINK(SvImpIconView, MouseMoveTimeoutHdl, Timer*, pTimer ) +{ + pTimer->Start(); + MouseMove( aMouseMoveEvent ); + return 0; +} + +void SvImpIconView::EndTracking() +{ + pView->ReleaseMouse(); + if( nFlags & F_RUBBERING ) + { + aMouseMoveTimer.Stop(); + nFlags &= ~(F_RUBBERING | F_ADD_MODE); + } +} + +sal_Bool SvImpIconView::IsTextHit( SvLBoxEntry* pEntry, const Point& rDocPos ) +{ + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pItem ) + { + Rectangle aRect( CalcTextRect( pEntry, pItem )); + if( aRect.IsInside( rDocPos ) ) + return sal_True; + } + return sal_False; +} + +IMPL_LINK(SvImpIconView, EditTimeoutHdl, Timer*, EMPTYARG ) +{ + SvLBoxEntry* pEntry = GetCurEntry(); + if( pView->IsInplaceEditingEnabled() && pEntry && + pView->IsSelected( pEntry )) + { + pView->EditEntry( pEntry ); + } + return 0; +} + + +// +// Funktionen zum Ausrichten der Eintraege am Grid +// + +// pStart == 0: Alle Eintraege werden ausgerichtet +// sonst: Alle Eintraege der Zeile ab einschliesslich pStart werden ausgerichtet +void SvImpIconView::AdjustAtGrid( SvLBoxEntry* pStart ) +{ + SvPtrarr aLists; + pImpCursor->CreateGridAjustData( aLists, pStart ); + sal_uInt16 nCount = aLists.Count(); + for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ ) + { + AdjustAtGrid( *(SvPtrarr*)aLists[ nCur ], pStart ); + } + ImpIcnCursor::DestroyGridAdjustData( aLists ); + CheckScrollBars(); +} + +// Richtet eine Zeile aus, erweitert ggf. die Breite; Bricht die Zeile nicht um +void SvImpIconView::AdjustAtGrid( const SvPtrarr& rRow, SvLBoxEntry* pStart ) +{ + if( !rRow.Count() ) + return; + + sal_Bool bGo; + if( !pStart ) + bGo = sal_True; + else + bGo = sal_False; + + long nCurRight = 0; + for( sal_uInt16 nCur = 0; nCur < rRow.Count(); nCur++ ) + { + SvLBoxEntry* pCur = (SvLBoxEntry*)rRow[ nCur ]; + if( !bGo && pCur == pStart ) + bGo = sal_True; + + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur); + // Massgebend (fuer das menschliche Auge) ist die Bitmap, da sonst + // durch lange Texte der Eintrag stark springen kann + const Rectangle& rBoundRect = GetBoundingRect( pCur, pViewData ); + Rectangle aCenterRect( CalcBmpRect( pCur, 0, pViewData )); + if( bGo && !pViewData->IsEntryPosLocked() ) + { + long nWidth = aCenterRect.GetSize().Width(); + Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) ); + while( aNewPos.X() < nCurRight ) + aNewPos.X() += nGridDX; + if( aNewPos != rBoundRect.TopLeft() ) + SetEntryPosition( pCur, aNewPos ); + nCurRight = aNewPos.X() + nWidth; + } + else + { + nCurRight = rBoundRect.Right(); + } + } +} + +// Richtet Rect am Grid aus, garantiert jedoch nicht, dass die +// neue Pos. frei ist. Die Pos. kann fuer SetEntryPos verwendet werden. +// Das CenterRect beschreibt den Teil des BoundRects, der fuer +// die Berechnung des Ziel-Rechtecks verwendet wird. +Point SvImpIconView::AdjustAtGrid( const Rectangle& rCenterRect, + const Rectangle& rBoundRect ) const +{ + Point aPos( rCenterRect.TopLeft() ); + Size aSize( rCenterRect.GetSize() ); + + aPos.X() -= LROFFS_WINBORDER; + aPos.Y() -= TBOFFS_WINBORDER; + + // align (ref ist mitte des rects) + short nGridX = (short)((aPos.X()+(aSize.Width()/2)) / nGridDX); + short nGridY = (short)((aPos.Y()+(aSize.Height()/2)) / nGridDY); + aPos.X() = nGridX * nGridDX; + aPos.Y() = nGridY * nGridDY; + // hor. center + aPos.X() += (nGridDX - rBoundRect.GetSize().Width() ) / 2; + + aPos.X() += LROFFS_WINBORDER; + aPos.Y() += TBOFFS_WINBORDER; + + return aPos; +} + + +void SvImpIconView::SetTextMode( SvIconViewTextMode eMode, SvLBoxEntry* pEntry ) +{ + if( !pEntry ) + { + if( eTextMode != eMode ) + { + if( eTextMode == ShowTextDontKnow ) + eTextMode = ShowTextShort; + eTextMode = eMode; + pView->Arrange(); + } + } + else + { + SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pEntry); + if( pViewData->eTextMode != eMode ) + { + pViewData->eTextMode = eMode; + pModel->InvalidateEntry( pEntry ); + AdjustVirtSize( pViewData->aRect ); + } + } +} + +SvIconViewTextMode SvImpIconView::GetTextMode( const SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + if( !pEntry ) + return eTextMode; + else + { + if( !pViewData ) + pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry)); + return pViewData->GetTextMode(); + } +} + +SvIconViewTextMode SvImpIconView::GetEntryTextModeSmart( const SvLBoxEntry* pEntry, + const SvIcnVwDataEntry* pViewData ) const +{ + DBG_ASSERT(pEntry,"GetEntryTextModeSmart: Entry not set"); + if( !pViewData ) + pViewData = ICNVIEWDATA(((SvLBoxEntry*)pEntry)); + SvIconViewTextMode eMode = pViewData->GetTextMode(); + if( eMode == ShowTextDontKnow ) + return eTextMode; + return eMode; +} + +void SvImpIconView::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + if( !pEntry ) + pView->HideFocus(); + else + { + Rectangle aRect ( CalcFocusRect( (SvLBoxEntry*)pEntry ) ); + pView->ShowFocus( aRect ); + } +} + +IMPL_LINK(SvImpIconView, UserEventHdl, void*, EMPTYARG ) +{ + nCurUserEvent = 0; + AdjustScrollBars(); + Rectangle aRect; + if( GetResizeRect(aRect) ) + PaintResizeRect( aRect ); + return 0; +} + +void SvImpIconView::CancelUserEvent() +{ + if( nCurUserEvent ) + { + Application::RemoveUserEvent( nCurUserEvent ); + nCurUserEvent = 0; + } +} + + diff --git a/svtools/source/contnr/svlbitm.cxx b/svtools/source/contnr/svlbitm.cxx new file mode 100644 index 000000000000..89e888de0318 --- /dev/null +++ b/svtools/source/contnr/svlbitm.cxx @@ -0,0 +1,651 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + + +#include <svtools/svlbox.hxx> +#include <svtools/svlbitm.hxx> +#include <vcl/svapp.hxx> +#ifndef _SV_BUTTON_HXX +#include <vcl/button.hxx> +#endif +#include <vcl/decoview.hxx> +#include <vcl/sound.hxx> +#include <vcl/salnativewidgets.hxx> + +#define TABOFFS_NOT_VALID -2000000 + +struct SvLBoxButtonData_Impl +{ + SvLBoxEntry* pEntry; + sal_Bool bDefaultImages; + sal_Bool bShowRadioButton; + + SvLBoxButtonData_Impl() : pEntry( NULL ), bDefaultImages( sal_False ), bShowRadioButton( sal_False ) {} +}; + + +DBG_NAME(SvLBoxButtonData) + +void SvLBoxButtonData::InitData( sal_Bool bImagesFromDefault, bool _bRadioBtn, const Control* pCtrl ) +{ + pImpl = new SvLBoxButtonData_Impl; + + bDataOk = sal_False; + eState = SV_BUTTON_UNCHECKED; + pImpl->bDefaultImages = bImagesFromDefault; + pImpl->bShowRadioButton = ( _bRadioBtn != false ); + + if ( bImagesFromDefault ) + SetDefaultImages( pCtrl ); +} + +SvLBoxButtonData::SvLBoxButtonData( const Control* pControlForSettings ) +{ + DBG_CTOR(SvLBoxButtonData,0); + + InitData( sal_True, false, pControlForSettings ); +} + +SvLBoxButtonData::SvLBoxButtonData( const Control* pControlForSettings, bool _bRadioBtn ) +{ + DBG_CTOR(SvLBoxButtonData,0); + + InitData( sal_True, _bRadioBtn, pControlForSettings ); +} + +SvLBoxButtonData::SvLBoxButtonData() +{ + DBG_CTOR(SvLBoxButtonData,0); + + InitData( sal_False, false ); +} + +SvLBoxButtonData::~SvLBoxButtonData() +{ + DBG_DTOR(SvLBoxButtonData,0); + + delete pImpl; +#ifdef DBG_UTIL + pImpl = NULL; +#endif +} + +void SvLBoxButtonData::CallLink() +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + aLink.Call( this ); +} + +sal_uInt16 SvLBoxButtonData::GetIndex( sal_uInt16 nItemState ) +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + nItemState &= 0x000F; + sal_uInt16 nIdx; + switch( nItemState ) + { + case SV_ITEMSTATE_UNCHECKED: + nIdx = SV_BMP_UNCHECKED; break; + case SV_ITEMSTATE_CHECKED: + nIdx = SV_BMP_CHECKED; break; + case SV_ITEMSTATE_TRISTATE: + nIdx = SV_BMP_TRISTATE; break; + case SV_ITEMSTATE_UNCHECKED | SV_ITEMSTATE_HILIGHTED: + nIdx = SV_BMP_HIUNCHECKED; break; + case SV_ITEMSTATE_CHECKED | SV_ITEMSTATE_HILIGHTED: + nIdx = SV_BMP_HICHECKED; break; + case SV_ITEMSTATE_TRISTATE | SV_ITEMSTATE_HILIGHTED: + nIdx = SV_BMP_HITRISTATE; break; + default: + nIdx = SV_BMP_UNCHECKED; + } + return nIdx; +} + +void SvLBoxButtonData::SetWidthAndHeight() +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + Size aSize = aBmps[0].GetSizePixel(); + nWidth = aSize.Width(); + nHeight = aSize.Height(); + bDataOk = sal_True; +} + + +void SvLBoxButtonData::StoreButtonState( SvLBoxEntry* pActEntry, sal_uInt16 nItemFlags ) +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + pImpl->pEntry = pActEntry; + eState = ConvertToButtonState( nItemFlags ); +} + +SvButtonState SvLBoxButtonData::ConvertToButtonState( sal_uInt16 nItemFlags ) const +{ + DBG_CHKTHIS(SvLBoxButtonData,0); + nItemFlags &= (SV_ITEMSTATE_UNCHECKED | + SV_ITEMSTATE_CHECKED | + SV_ITEMSTATE_TRISTATE); + switch( nItemFlags ) + { + case SV_ITEMSTATE_UNCHECKED: + return SV_BUTTON_UNCHECKED; + + case SV_ITEMSTATE_CHECKED: + return SV_BUTTON_CHECKED; + + case SV_ITEMSTATE_TRISTATE: + return SV_BUTTON_TRISTATE; + default: + return SV_BUTTON_UNCHECKED; + } +} + +SvLBoxEntry* SvLBoxButtonData::GetActEntry() const +{ + DBG_ASSERT( pImpl, "-SvLBoxButtonData::GetActEntry(): don't use me that way!" ); + return pImpl->pEntry; +} + +void SvLBoxButtonData::SetDefaultImages( const Control* pCtrl ) +{ + const AllSettings& rSettings = pCtrl? pCtrl->GetSettings() : Application::GetSettings(); + + if ( pImpl->bShowRadioButton ) + { + aBmps[ SV_BMP_UNCHECKED ] = RadioButton::GetRadioImage( rSettings, BUTTON_DRAW_DEFAULT ); + aBmps[ SV_BMP_CHECKED ] = RadioButton::GetRadioImage( rSettings, BUTTON_DRAW_CHECKED ); + aBmps[ SV_BMP_HICHECKED ] = RadioButton::GetRadioImage( rSettings, BUTTON_DRAW_CHECKED | BUTTON_DRAW_PRESSED ); + aBmps[ SV_BMP_HIUNCHECKED ] = RadioButton::GetRadioImage( rSettings, BUTTON_DRAW_DEFAULT | BUTTON_DRAW_PRESSED ); + aBmps[ SV_BMP_TRISTATE ] = RadioButton::GetRadioImage( rSettings, BUTTON_DRAW_DONTKNOW ); + aBmps[ SV_BMP_HITRISTATE ] = RadioButton::GetRadioImage( rSettings, BUTTON_DRAW_DONTKNOW | BUTTON_DRAW_PRESSED ); + } + else + { + aBmps[ SV_BMP_UNCHECKED ] = CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_DEFAULT ); + aBmps[ SV_BMP_CHECKED ] = CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_CHECKED ); + aBmps[ SV_BMP_HICHECKED ] = CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_CHECKED | BUTTON_DRAW_PRESSED ); + aBmps[ SV_BMP_HIUNCHECKED ] = CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_DEFAULT | BUTTON_DRAW_PRESSED ); + aBmps[ SV_BMP_TRISTATE ] = CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_DONTKNOW ); + aBmps[ SV_BMP_HITRISTATE ] = CheckBox::GetCheckImage( rSettings, BUTTON_DRAW_DONTKNOW | BUTTON_DRAW_PRESSED ); + } +} + +sal_Bool SvLBoxButtonData::HasDefaultImages( void ) const +{ + return pImpl->bDefaultImages; +} + +sal_Bool SvLBoxButtonData::IsRadio() { + return pImpl->bShowRadioButton; +} + +// *************************************************************** +// class SvLBoxString +// *************************************************************** + +DBG_NAME(SvLBoxString); + +SvLBoxString::SvLBoxString( SvLBoxEntry* pEntry,sal_uInt16 nFlags,const XubString& rStr) : + SvLBoxItem( pEntry, nFlags ) +{ + DBG_CTOR(SvLBoxString,0); + SetText( pEntry, rStr ); +} + +SvLBoxString::SvLBoxString() : SvLBoxItem() +{ + DBG_CTOR(SvLBoxString,0); +} + +SvLBoxString::~SvLBoxString() +{ + DBG_DTOR(SvLBoxString,0); +} + +sal_uInt16 SvLBoxString::IsA() +{ + DBG_CHKTHIS(SvLBoxString,0); + return SV_ITEM_ID_LBOXSTRING; +} + +void SvLBoxString::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 /* nFlags */, + SvLBoxEntry* _pEntry) +{ + DBG_CHKTHIS(SvLBoxString,0); + if ( _pEntry ) + { + sal_uInt16 nStyle = rDev.IsEnabled() ? 0 : TEXT_DRAW_DISABLE; + if ( rDev.IsEntryMnemonicsEnabled() ) + nStyle |= TEXT_DRAW_MNEMONIC; + rDev.DrawText( Rectangle(rPos,GetSize(&rDev,_pEntry)),aStr,nStyle); + } + else + rDev.DrawText( rPos, aStr); + +} + +SvLBoxItem* SvLBoxString::Create() const +{ + DBG_CHKTHIS(SvLBoxString,0); + return new SvLBoxString; +} + +void SvLBoxString::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxString,0); + aStr = ((SvLBoxString*)pSource)->aStr; +} + +void SvLBoxString::SetText( SvLBoxEntry*, const XubString& rStr ) +{ + DBG_CHKTHIS(SvLBoxString,0); + aStr = rStr; +} + +void SvLBoxString::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData) +{ + DBG_CHKTHIS(SvLBoxString,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + pViewData->aSize = Size(pView->GetTextWidth( aStr ), pView->GetTextHeight()); +} + +// *************************************************************** +// class SvLBoxBmp +// *************************************************************** + +DBG_NAME(SvLBoxBmp); + +SvLBoxBmp::SvLBoxBmp( SvLBoxEntry* pEntry, sal_uInt16 nFlags, Image aBitmap ) : + SvLBoxItem( pEntry, nFlags ) +{ + DBG_CTOR(SvLBoxBmp,0); + SetBitmap( pEntry, aBitmap); +} + +SvLBoxBmp::SvLBoxBmp() : SvLBoxItem() +{ + DBG_CTOR(SvLBoxBmp,0); +} + +SvLBoxBmp::~SvLBoxBmp() +{ + DBG_DTOR(SvLBoxBmp,0); +} + +sal_uInt16 SvLBoxBmp::IsA() +{ + DBG_CHKTHIS(SvLBoxBmp,0); + return SV_ITEM_ID_LBOXBMP; +} + +void SvLBoxBmp::SetBitmap( SvLBoxEntry*, Image aBitmap) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + aBmp = aBitmap; +} + +void SvLBoxBmp::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + pViewData->aSize = aBmp.GetSizePixel(); +} + +void SvLBoxBmp::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 /* nFlags */, + SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + sal_uInt16 nStyle = rDev.IsEnabled() ? 0 : IMAGE_DRAW_DISABLE; + rDev.DrawImage( rPos, aBmp ,nStyle); +} + +SvLBoxItem* SvLBoxBmp::Create() const +{ + DBG_CHKTHIS(SvLBoxBmp,0); + return new SvLBoxBmp; +} + +void SvLBoxBmp::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxBmp,0); + aBmp = ((SvLBoxBmp*)pSource)->aBmp; +} + +// *************************************************************** +// class SvLBoxButton +// *************************************************************** + +DBG_NAME(SvLBoxButton); + +SvLBoxButton::SvLBoxButton( SvLBoxEntry* pEntry, SvLBoxButtonKind eTheKind, + sal_uInt16 nFlags, SvLBoxButtonData* pBData ) + : SvLBoxItem( pEntry, nFlags ) +{ + DBG_CTOR(SvLBoxButton,0); + eKind = eTheKind; + nBaseOffs = 0; + nItemFlags = 0; + SetStateUnchecked(); + pData = pBData; +} + +SvLBoxButton::SvLBoxButton() : SvLBoxItem() +{ + DBG_CTOR(SvLBoxButton,0); + eKind = SvLBoxButtonKind_enabledCheckbox; + nItemFlags = 0; + SetStateUnchecked(); +} + +SvLBoxButton::~SvLBoxButton() +{ + DBG_DTOR(SvLBoxButton,0); +} + +sal_uInt16 SvLBoxButton::IsA() +{ + DBG_CHKTHIS(SvLBoxButton,0); + return SV_ITEM_ID_LBOXBUTTON; +} + +void SvLBoxButton::Check(SvLBox*, SvLBoxEntry*, sal_Bool bOn) +{ + DBG_CHKTHIS(SvLBoxButton,0); + if ( bOn != IsStateChecked() ) + { + if ( bOn ) + SetStateChecked(); + else + SetStateUnchecked(); + } +} + +sal_Bool SvLBoxButton::ClickHdl( SvLBox*, SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + if ( CheckModification() ) + { + if ( IsStateChecked() ) + SetStateUnchecked(); + else + SetStateChecked(); + pData->StoreButtonState( pEntry, nItemFlags ); + pData->CallLink(); + } + return sal_False; +} + +void SvLBoxButton::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 /* nFlags */, + SvLBoxEntry* /*pEntry*/ ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + sal_uInt16 nIndex = eKind == SvLBoxButtonKind_staticImage + ? SV_BMP_STATICIMAGE : pData->GetIndex( nItemFlags ); + sal_uInt16 nStyle = eKind != SvLBoxButtonKind_disabledCheckbox && + rDev.IsEnabled() ? 0 : IMAGE_DRAW_DISABLE; + +/// +//Native drawing +/// + sal_Bool bNativeOK = sal_False; + ControlType eCtrlType = (pData->IsRadio())? CTRL_RADIOBUTTON : CTRL_CHECKBOX; + if ( nIndex != SV_BMP_STATICIMAGE && rDev.IsNativeControlSupported( eCtrlType, PART_ENTIRE_CONTROL) ) + { + Size aSize(pData->Width(), pData->Height()); + ImplAdjustBoxSize( aSize, eCtrlType, &rDev ); + ImplControlValue aControlValue; + Rectangle aCtrlRegion( rPos, aSize ); + ControlState nState = 0; + + //states CTRL_STATE_DEFAULT, CTRL_STATE_PRESSED and CTRL_STATE_ROLLOVER are not implemented + if ( IsStateHilighted() ) nState |= CTRL_STATE_FOCUSED; + if ( nStyle != IMAGE_DRAW_DISABLE ) nState |= CTRL_STATE_ENABLED; + + if ( IsStateChecked() ) + aControlValue.setTristateVal( BUTTONVALUE_ON ); + else if ( IsStateUnchecked() ) + aControlValue.setTristateVal( BUTTONVALUE_OFF ); + else if ( IsStateTristate() ) + aControlValue.setTristateVal( BUTTONVALUE_MIXED ); + + bNativeOK = rDev.DrawNativeControl( eCtrlType, PART_ENTIRE_CONTROL, + aCtrlRegion, nState, aControlValue, rtl::OUString() ); + } + + if( !bNativeOK) + rDev.DrawImage( rPos, pData->aBmps[nIndex + nBaseOffs] ,nStyle); +} + +SvLBoxItem* SvLBoxButton::Create() const +{ + DBG_CHKTHIS(SvLBoxButton,0); + return new SvLBoxButton; +} + +void SvLBoxButton::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + pData = ((SvLBoxButton*)pSource)->pData; +} + +void SvLBoxButton::ImplAdjustBoxSize( Size& io_rSize, ControlType i_eType, Window* i_pParent ) +{ + if ( i_pParent->IsNativeControlSupported( i_eType, PART_ENTIRE_CONTROL) ) + { + ImplControlValue aControlValue; + Rectangle aCtrlRegion( Point( 0, 0 ), io_rSize ); + ControlState nState = CTRL_STATE_ENABLED; + + aControlValue.setTristateVal( BUTTONVALUE_ON ); + + Rectangle aNativeBounds, aNativeContent; + bool bNativeOK = i_pParent->GetNativeControlRegion( i_eType, + PART_ENTIRE_CONTROL, + aCtrlRegion, + nState, + aControlValue, + rtl::OUString(), + aNativeBounds, + aNativeContent ); + if( bNativeOK ) + { + Size aContentSize( aNativeContent.GetSize() ); + // leave a little space around the box image (looks better + if( aContentSize.Height() + 2 > io_rSize.Height() ) + io_rSize.Height() = aContentSize.Height() + 2; + } + } +} + +void SvLBoxButton::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData ) +{ + DBG_CHKTHIS(SvLBoxButton,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + Size aSize( pData->Width(), pData->Height() ); + + ControlType eCtrlType = (pData->IsRadio())? CTRL_RADIOBUTTON : CTRL_CHECKBOX; + if ( eKind != SvLBoxButtonKind_staticImage && pView ) + ImplAdjustBoxSize( aSize, eCtrlType, pView ); + pViewData->aSize = aSize; +} + +bool SvLBoxButton::CheckModification() const +{ + if( eKind == SvLBoxButtonKind_disabledCheckbox ) + Sound::Beep(); + return eKind == SvLBoxButtonKind_enabledCheckbox; +} + +// *************************************************************** +// class SvLBoxContextBmp +// *************************************************************** + +struct SvLBoxContextBmp_Impl +{ + Image m_aImage1; + Image m_aImage2; + + Image m_aImage1_hc; + Image m_aImage2_hc; + + sal_uInt16 m_nB2IndicatorFlags; +}; + +// *************************************************************** +DBG_NAME(SvLBoxContextBmp) + +SvLBoxContextBmp::SvLBoxContextBmp( SvLBoxEntry* pEntry, sal_uInt16 nItemFlags, + Image aBmp1, Image aBmp2, sal_uInt16 nEntryFlags ) + :SvLBoxItem( pEntry, nItemFlags ) + ,m_pImpl( new SvLBoxContextBmp_Impl ) +{ + DBG_CTOR(SvLBoxContextBmp,0); + + m_pImpl->m_nB2IndicatorFlags = nEntryFlags; + SetModeImages( aBmp1, aBmp2 ); +} + +SvLBoxContextBmp::SvLBoxContextBmp() + :SvLBoxItem( ) + ,m_pImpl( new SvLBoxContextBmp_Impl ) +{ + m_pImpl->m_nB2IndicatorFlags = 0; + DBG_CTOR(SvLBoxContextBmp,0); +} + +SvLBoxContextBmp::~SvLBoxContextBmp() +{ + delete m_pImpl; + DBG_DTOR(SvLBoxContextBmp,0); +} + +sal_uInt16 SvLBoxContextBmp::IsA() +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + return SV_ITEM_ID_LBOXCONTEXTBMP; +} + +sal_Bool SvLBoxContextBmp::SetModeImages( const Image& _rBitmap1, const Image& _rBitmap2, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + + sal_Bool bSuccess = sal_True; + switch ( _eMode ) + { + case BMP_COLOR_NORMAL: + m_pImpl->m_aImage1 = _rBitmap1; + m_pImpl->m_aImage2 = _rBitmap2; + break; + + case BMP_COLOR_HIGHCONTRAST: + m_pImpl->m_aImage1_hc = _rBitmap1; + m_pImpl->m_aImage2_hc = _rBitmap2; + break; + + default: + DBG_ERROR( "SvLBoxContextBmp::SetModeImages: unexpected mode!"); + bSuccess = sal_False; + break; + } + return bSuccess; +} + +Image& SvLBoxContextBmp::implGetImageStore( sal_Bool _bFirst, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + + switch ( _eMode ) + { + case BMP_COLOR_NORMAL: + return _bFirst ? m_pImpl->m_aImage1 : m_pImpl->m_aImage2; + + case BMP_COLOR_HIGHCONTRAST: + return _bFirst ? m_pImpl->m_aImage1_hc : m_pImpl->m_aImage2_hc; + + default: + DBG_ERROR( "SvLBoxContextBmp::implGetImageStore: unexpected mode!"); + } + + // OJ: #i27071# wrong mode so we just return the normal images + return _bFirst ? m_pImpl->m_aImage1 : m_pImpl->m_aImage2; +} + +void SvLBoxContextBmp::InitViewData( SvLBox* pView,SvLBoxEntry* pEntry, + SvViewDataItem* pViewData) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + if( !pViewData ) + pViewData = pView->GetViewDataItem( pEntry, this ); + pViewData->aSize = m_pImpl->m_aImage1.GetSizePixel(); +} + +void SvLBoxContextBmp::Paint( const Point& _rPos, SvLBox& _rDev, + sal_uInt16 _nViewDataEntryFlags, SvLBoxEntry* _pEntry ) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + + // determine the image set + BmpColorMode eMode( BMP_COLOR_NORMAL ); + if ( !!m_pImpl->m_aImage1_hc ) + { // we really have HC images + if ( _rDev.GetSettings().GetStyleSettings().GetHighContrastMode() ) + eMode = BMP_COLOR_HIGHCONTRAST; + } + + // get the image + const Image& rImage = implGetImageStore( 0 == ( _nViewDataEntryFlags & m_pImpl->m_nB2IndicatorFlags ), eMode ); + + sal_Bool _bSemiTransparent = _pEntry && ( 0 != ( SV_ENTRYFLAG_SEMITRANSPARENT & _pEntry->GetFlags( ) ) ); + // draw + sal_uInt16 nStyle = _rDev.IsEnabled() ? 0 : IMAGE_DRAW_DISABLE; + if ( _bSemiTransparent ) + nStyle |= IMAGE_DRAW_SEMITRANSPARENT; + _rDev.DrawImage( _rPos, rImage, nStyle); +} + +SvLBoxItem* SvLBoxContextBmp::Create() const +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + return new SvLBoxContextBmp; +} + +void SvLBoxContextBmp::Clone( SvLBoxItem* pSource ) +{ + DBG_CHKTHIS(SvLBoxContextBmp,0); + m_pImpl->m_aImage1 = static_cast< SvLBoxContextBmp* >( pSource )->m_pImpl->m_aImage1; + m_pImpl->m_aImage2 = static_cast< SvLBoxContextBmp* >( pSource )->m_pImpl->m_aImage2; + m_pImpl->m_nB2IndicatorFlags = static_cast< SvLBoxContextBmp* >( pSource )->m_pImpl->m_nB2IndicatorFlags; +} + diff --git a/svtools/source/contnr/svlbox.cxx b/svtools/source/contnr/svlbox.cxx new file mode 100644 index 000000000000..e34ed061cd69 --- /dev/null +++ b/svtools/source/contnr/svlbox.cxx @@ -0,0 +1,1983 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +/* + Todo: + - Anker loeschen in SelectionEngine bei manuellem Selektieren + - SelectAll( sal_False ), nur die deselektierten Entries repainten +*/ + +#include <string.h> +#include <svtools/svlbox.hxx> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <vcl/svapp.hxx> +#include <vcl/accel.hxx> +#include <vcl/i18nhelp.hxx> +#include <sot/formats.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <rtl/instance.hxx> + +#define _SVSTDARR_ULONGSSORT +#include <svl/svstdarr.hxx> + +#ifndef _SVEDI_HXX +#include <svtools/svmedit.hxx> +#endif +#include <svtools/svlbitm.hxx> + +using namespace ::com::sun::star::accessibility; + +// Drag&Drop +static SvLBox* pDDSource = NULL; +static SvLBox* pDDTarget = NULL; + +DBG_NAME(SvInplaceEdit) +DBG_NAME(SvInplaceEdit2) + +#define SVLBOX_ACC_RETURN 1 +#define SVLBOX_ACC_ESCAPE 2 + +SvInplaceEdit::SvInplaceEdit +( + Window* pParent, + const Point& rPos, + const Size& rSize, + const String& rData, + const Link& rNotifyEditEnd, + const Selection& rSelection +) : + + Edit( pParent, WB_LEFT ), + + aCallBackHdl ( rNotifyEditEnd ), + bCanceled ( sal_False ), + bAlreadyInCallBack ( sal_False ) + +{ + DBG_CTOR(SvInplaceEdit,0); + + Font aFont( pParent->GetFont() ); + aFont.SetTransparent( sal_False ); + Color aColor( pParent->GetBackground().GetColor() ); + aFont.SetFillColor(aColor ); + SetFont( aFont ); + SetBackground( pParent->GetBackground() ); + SetPosPixel( rPos ); + SetSizePixel( rSize ); + SetText( rData ); + SetSelection( rSelection ); + SaveValue(); + + aAccReturn.InsertItem( SVLBOX_ACC_RETURN, KeyCode(KEY_RETURN) ); + aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, KeyCode(KEY_ESCAPE) ); + + aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit, ReturnHdl_Impl) ); + aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit, EscapeHdl_Impl) ); + GetpApp()->InsertAccel( &aAccReturn ); + GetpApp()->InsertAccel( &aAccEscape ); + + Show(); + GrabFocus(); +} + +SvInplaceEdit::~SvInplaceEdit() +{ + DBG_DTOR(SvInplaceEdit,0); + if( !bAlreadyInCallBack ) + { + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + } +} + +IMPL_LINK_INLINE_START( SvInplaceEdit, ReturnHdl_Impl, Accelerator *, EMPTYARG ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + bCanceled = sal_False; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit, ReturnHdl_Impl, Accelerator *, EMPTYARG ) + +IMPL_LINK_INLINE_START( SvInplaceEdit, EscapeHdl_Impl, Accelerator *, EMPTYARG ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + bCanceled = sal_True; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit, EscapeHdl_Impl, Accelerator *, EMPTYARG ) + +void SvInplaceEdit::KeyInput( const KeyEvent& rKEvt ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + switch ( nCode ) + { + case KEY_ESCAPE: + bCanceled = sal_True; + CallCallBackHdl_Impl(); + break; + + case KEY_RETURN: + bCanceled = sal_False; + CallCallBackHdl_Impl(); + break; + + default: + Edit::KeyInput( rKEvt ); + } +} + +void SvInplaceEdit::StopEditing( sal_Bool bCancel ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + if ( !bAlreadyInCallBack ) + { + bCanceled = bCancel; + CallCallBackHdl_Impl(); + } +} + +void SvInplaceEdit::LoseFocus() +{ + DBG_CHKTHIS(SvInplaceEdit,0); + if ( !bAlreadyInCallBack ) + { + bCanceled = sal_False; + aTimer.SetTimeout(10); + aTimer.SetTimeoutHdl(LINK(this,SvInplaceEdit,Timeout_Impl)); + aTimer.Start(); + } +} + +IMPL_LINK_INLINE_START( SvInplaceEdit, Timeout_Impl, Timer *, EMPTYARG ) +{ + DBG_CHKTHIS(SvInplaceEdit,0); + CallCallBackHdl_Impl(); + return 0; +} +IMPL_LINK_INLINE_END( SvInplaceEdit, Timeout_Impl, Timer *, EMPTYARG ) + +void SvInplaceEdit::CallCallBackHdl_Impl() +{ + DBG_CHKTHIS(SvInplaceEdit,0); + aTimer.Stop(); + if ( !bAlreadyInCallBack ) + { + bAlreadyInCallBack = sal_True; + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + Hide(); + aCallBackHdl.Call( this ); + // bAlreadyInCallBack = sal_False; + } +} + + +// *************************************************************** + +class MyEdit_Impl : public Edit +{ + SvInplaceEdit2* pOwner; +public: + MyEdit_Impl( Window* pParent, SvInplaceEdit2* pOwner ); + virtual void KeyInput( const KeyEvent& rKEvt ); + virtual void LoseFocus(); +}; + +class MyMultiEdit_Impl : public MultiLineEdit +{ + SvInplaceEdit2* pOwner; +public: + MyMultiEdit_Impl( Window* pParent, SvInplaceEdit2* pOwner ); + virtual void KeyInput( const KeyEvent& rKEvt ); + virtual void LoseFocus(); +}; + +MyEdit_Impl::MyEdit_Impl( Window* pParent, SvInplaceEdit2* _pOwner ) : + + Edit( pParent, WB_LEFT ), + + pOwner( _pOwner ) + +{ +} + +void MyEdit_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + if( !pOwner->KeyInput( rKEvt )) + Edit::KeyInput( rKEvt ); +} + +void MyEdit_Impl::LoseFocus() +{ + pOwner->LoseFocus(); +} + +MyMultiEdit_Impl::MyMultiEdit_Impl( Window* pParent, SvInplaceEdit2* _pOwner ) + : MultiLineEdit( pParent, + WB_CENTER + ), pOwner(_pOwner) +{ +} + +void MyMultiEdit_Impl::KeyInput( const KeyEvent& rKEvt ) +{ + if( !pOwner->KeyInput( rKEvt )) + MultiLineEdit::KeyInput( rKEvt ); +} + +void MyMultiEdit_Impl::LoseFocus() +{ + pOwner->LoseFocus(); +} + + +SvInplaceEdit2::SvInplaceEdit2 +( + Window* pParent, const Point& rPos, + const Size& rSize, + const String& rData, + const Link& rNotifyEditEnd, + const Selection& rSelection, + sal_Bool bMulti +) : + + aCallBackHdl ( rNotifyEditEnd ), + bCanceled ( sal_False ), + bAlreadyInCallBack ( sal_False ), + bMultiLine ( bMulti ) + +{ + DBG_CTOR(SvInplaceEdit2,0); + + if( bMulti ) + pEdit = new MyMultiEdit_Impl( pParent, this ); + else + pEdit = new MyEdit_Impl( pParent, this ); + + Font aFont( pParent->GetFont() ); + aFont.SetTransparent( sal_False ); + Color aColor( pParent->GetBackground().GetColor() ); + aFont.SetFillColor(aColor ); + pEdit->SetFont( aFont ); + pEdit->SetBackground( pParent->GetBackground() ); + pEdit->SetPosPixel( rPos ); + pEdit->SetSizePixel( rSize ); + pEdit->SetText( rData ); + pEdit->SetSelection( rSelection ); + pEdit->SaveValue(); + + aAccReturn.InsertItem( SVLBOX_ACC_RETURN, KeyCode(KEY_RETURN) ); + aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, KeyCode(KEY_ESCAPE) ); + + aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit2, ReturnHdl_Impl) ); + aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit2, EscapeHdl_Impl) ); + GetpApp()->InsertAccel( &aAccReturn ); + GetpApp()->InsertAccel( &aAccEscape ); + + pEdit->Show(); + pEdit->GrabFocus(); +} + +SvInplaceEdit2::~SvInplaceEdit2() +{ + DBG_DTOR(SvInplaceEdit2,0); + if( !bAlreadyInCallBack ) + { + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + } + delete pEdit; +} + +String SvInplaceEdit2::GetSavedValue() const +{ + return pEdit->GetSavedValue(); +} + +void SvInplaceEdit2::Hide() +{ + pEdit->Hide(); +} + + +IMPL_LINK_INLINE_START( SvInplaceEdit2, ReturnHdl_Impl, Accelerator *, EMPTYARG ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + bCanceled = sal_False; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit2, ReturnHdl_Impl, Accelerator *, EMPTYARG ) + +IMPL_LINK_INLINE_START( SvInplaceEdit2, EscapeHdl_Impl, Accelerator *, EMPTYARG ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + bCanceled = sal_True; + CallCallBackHdl_Impl(); + return 1; +} +IMPL_LINK_INLINE_END( SvInplaceEdit2, EscapeHdl_Impl, Accelerator *, EMPTYARG ) + + +sal_Bool SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + KeyCode aCode = rKEvt.GetKeyCode(); + sal_uInt16 nCode = aCode.GetCode(); + + switch ( nCode ) + { + case KEY_ESCAPE: + bCanceled = sal_True; + CallCallBackHdl_Impl(); + return sal_True; + + case KEY_RETURN: + bCanceled = sal_False; + CallCallBackHdl_Impl(); + return sal_True; + } + return sal_False; +} + +void SvInplaceEdit2::StopEditing( sal_Bool bCancel ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + if ( !bAlreadyInCallBack ) + { + bCanceled = bCancel; + CallCallBackHdl_Impl(); + } +} + +void SvInplaceEdit2::LoseFocus() +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + if ( !bAlreadyInCallBack + && ((!Application::GetFocusWindow()) || !pEdit->IsChild( Application::GetFocusWindow()) ) + ) + { + bCanceled = sal_False; + aTimer.SetTimeout(10); + aTimer.SetTimeoutHdl(LINK(this,SvInplaceEdit2,Timeout_Impl)); + aTimer.Start(); + } +} + +IMPL_LINK_INLINE_START( SvInplaceEdit2, Timeout_Impl, Timer *, EMPTYARG ) +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + CallCallBackHdl_Impl(); + return 0; +} +IMPL_LINK_INLINE_END( SvInplaceEdit2, Timeout_Impl, Timer *, EMPTYARG ) + +void SvInplaceEdit2::CallCallBackHdl_Impl() +{ + DBG_CHKTHIS(SvInplaceEdit2,0); + aTimer.Stop(); + if ( !bAlreadyInCallBack ) + { + bAlreadyInCallBack = sal_True; + GetpApp()->RemoveAccel( &aAccReturn ); + GetpApp()->RemoveAccel( &aAccEscape ); + pEdit->Hide(); + aCallBackHdl.Call( this ); + } +} + +String SvInplaceEdit2::GetText() const +{ + return pEdit->GetText(); +} + +// *************************************************************** +// class SvLBoxTab +// *************************************************************** + +DBG_NAME(SvLBoxTab); + +SvLBoxTab::SvLBoxTab() +{ + DBG_CTOR(SvLBoxTab,0); + nPos = 0; + pUserData = 0; + nFlags = 0; +} + +SvLBoxTab::SvLBoxTab( long nPosition, sal_uInt16 nTabFlags ) +{ + DBG_CTOR(SvLBoxTab,0); + nPos = nPosition; + pUserData = 0; + nFlags = nTabFlags; +} + +SvLBoxTab::SvLBoxTab( const SvLBoxTab& rTab ) +{ + DBG_CTOR(SvLBoxTab,0); + nPos = rTab.nPos; + pUserData = rTab.pUserData; + nFlags = rTab.nFlags; +} + +SvLBoxTab::~SvLBoxTab() +{ + DBG_DTOR(SvLBoxTab,0); +} + + +long SvLBoxTab::CalcOffset( long nItemWidth, long nTabWidth ) +{ + DBG_CHKTHIS(SvLBoxTab,0); + long nOffset = 0; + if ( nFlags & SV_LBOXTAB_ADJUST_RIGHT ) + { + nOffset = nTabWidth - nItemWidth; + if( nOffset < 0 ) + nOffset = 0; + } + else if ( nFlags & SV_LBOXTAB_ADJUST_CENTER ) + { + if( nFlags & SV_LBOXTAB_FORCE ) + { + //richtige Implementierung der Zentrierung + nOffset = ( nTabWidth - nItemWidth ) / 2; + if( nOffset < 0 ) + nOffset = 0; + } + else + { + // historisch gewachsene falsche Berechnung des Tabs, auf die sich + // Abo-Tabbox, Extras/Optionen/Anpassen etc. verlassen + nItemWidth++; + nOffset = -( nItemWidth / 2 ); + } + } + return nOffset; +} + +/* +long SvLBoxTab::CalcOffset( const String& rStr, const OutputDevice& rOutDev ) +{ + DBG_CHKTHIS(SvLBoxTab,0); + long nWidth; + if ( nFlags & SV_LBOXTAB_ADJUST_NUMERIC ) + { + sal_uInt16 nPos = rStr.Search( '.' ); + if ( nPos == STRING_NOTFOUND ) + nPos = rStr.Search( ',' ); + if ( nPos == STRING_NOTFOUND ) + nPos = STRING_LEN; + + nWidth = rOutDev.GetTextSize( rStr, 0, nPos ).Width(); + nWidth *= -1; + } + else + { + nWidth = rOutDev.GetTextSize( rStr ).Width(); + nWidth = CalcOffset( nWidth ); + } + return nWidth; +} +*/ + +// *************************************************************** +// class SvLBoxItem +// *************************************************************** + +DBG_NAME(SvLBoxItem); + +SvLBoxItem::SvLBoxItem( SvLBoxEntry*, sal_uInt16 ) +{ + DBG_CTOR(SvLBoxItem,0); +} + +SvLBoxItem::SvLBoxItem() +{ + DBG_CTOR(SvLBoxItem,0); +} + +SvLBoxItem::~SvLBoxItem() +{ + DBG_DTOR(SvLBoxItem,0); +} + +const Size& SvLBoxItem::GetSize( SvLBox* pView,SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBoxItem,0); + SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this ); + return pViewData->aSize; +} + +const Size& SvLBoxItem::GetSize( SvLBoxEntry* pEntry, SvViewDataEntry* pViewData) +{ + DBG_CHKTHIS(SvLBoxItem,0); + sal_uInt16 nItemPos = pEntry->GetPos( this ); + SvViewDataItem* pItemData = pViewData->pItemData+nItemPos; + return pItemData->aSize; +} + +DBG_NAME(SvViewDataItem); + +SvViewDataItem::SvViewDataItem() +{ + DBG_CTOR(SvViewDataItem,0); +} + +SvViewDataItem::~SvViewDataItem() +{ + DBG_DTOR(SvViewDataItem,0); +} + + + +// *************************************************************** +// class SvLBoxEntry +// *************************************************************** + +DBG_NAME(SvLBoxEntry); + +SvLBoxEntry::SvLBoxEntry() : aItems() +{ + DBG_CTOR(SvLBoxEntry,0); + nEntryFlags = 0; + pUserData = 0; +} + +SvLBoxEntry::~SvLBoxEntry() +{ + DBG_DTOR(SvLBoxEntry,0); + DeleteItems_Impl(); +} + +void SvLBoxEntry::DeleteItems_Impl() +{ + DBG_CHKTHIS(SvLBoxEntry,0); + sal_uInt16 nCount = aItems.Count(); + while( nCount ) + { + nCount--; + SvLBoxItem* pItem = (SvLBoxItem*)aItems.GetObject( nCount ); + delete pItem; + } + aItems.Remove(0, aItems.Count() ); +} + + +void SvLBoxEntry::AddItem( SvLBoxItem* pItem ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + aItems.Insert( pItem, aItems.Count() ); +} + +void SvLBoxEntry::Clone( SvListEntry* pSource ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + SvListEntry::Clone( pSource ); + SvLBoxItem* pNewItem; + DeleteItems_Impl(); + sal_uInt16 nCount = ((SvLBoxEntry*)pSource)->ItemCount(); + sal_uInt16 nCurPos = 0; + while( nCurPos < nCount ) + { + SvLBoxItem* pItem = ((SvLBoxEntry*)pSource)->GetItem( nCurPos ); + pNewItem = pItem->Create(); + pNewItem->Clone( pItem ); + AddItem( pNewItem ); + nCurPos++; + } + pUserData = ((SvLBoxEntry*)pSource)->GetUserData(); + nEntryFlags = ((SvLBoxEntry*)pSource)->nEntryFlags; +} + +void SvLBoxEntry::EnableChildsOnDemand( sal_Bool bEnable ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + if ( bEnable ) + nEntryFlags |= SV_ENTRYFLAG_CHILDS_ON_DEMAND; + else + nEntryFlags &= (~SV_ENTRYFLAG_CHILDS_ON_DEMAND); +} + +void SvLBoxEntry::ReplaceItem( SvLBoxItem* pNewItem, sal_uInt16 nPos ) +{ + DBG_CHKTHIS(SvLBoxEntry,0); + DBG_ASSERT(pNewItem,"ReplaceItem:No Item"); + SvLBoxItem* pOld = GetItem( nPos ); + if ( pOld ) + { + aItems.Remove( nPos ); + aItems.Insert( pNewItem, nPos ); + delete pOld; + } +} + +SvLBoxItem* SvLBoxEntry::GetFirstItem( sal_uInt16 nId ) +{ + sal_uInt16 nCount = aItems.Count(); + sal_uInt16 nCur = 0; + SvLBoxItem* pItem; + while( nCur < nCount ) + { + pItem = GetItem( nCur ); + if( pItem->IsA() == nId ) + return pItem; + nCur++; + } + return 0; +} + +// *************************************************************** +// class SvLBoxViewData +// *************************************************************** + +DBG_NAME(SvViewDataEntry); + +SvViewDataEntry::SvViewDataEntry() + : SvViewData() +{ + DBG_CTOR(SvViewDataEntry,0); + pItemData = 0; +} + +SvViewDataEntry::~SvViewDataEntry() +{ + DBG_DTOR(SvViewDataEntry,0); + delete [] pItemData; +} + +// *************************************************************** +// struct SvLBox_Impl +// *************************************************************** +SvLBox_Impl::SvLBox_Impl( SvLBox& _rBox ) + :m_bIsEmptyTextAllowed( true ) + ,m_bEntryMnemonicsEnabled( false ) + ,m_pLink( NULL ) + ,m_aMnemonicEngine( _rBox ) + ,m_aQuickSelectionEngine( _rBox ) +{ +} + +// *************************************************************** +// class SvLBox +// *************************************************************** + +DBG_NAME(SvLBox); + +SvLBox::SvLBox( Window* pParent, WinBits nWinStyle ) : + Control( pParent, nWinStyle | WB_CLIPCHILDREN ), + DropTargetHelper( this ), DragSourceHelper( this ), eSelMode( NO_SELECTION ) +{ + DBG_CTOR(SvLBox,0); + nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK; + nImpFlags = 0; + pTargetEntry = 0; + nDragDropMode = 0; + pLBoxImpl = new SvLBox_Impl( *this ); + SvLBoxTreeList* pTempModel = new SvLBoxTreeList; + pTempModel->SetRefCount( 0 ); + SetModel( pTempModel ); + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + pModel->InsertView( this ); + pHdlEntry = 0; + pEdCtrl = 0; + SetSelectionMode( SINGLE_SELECTION ); // pruefen ob TreeListBox gecallt wird + SetDragDropMode( SV_DRAGDROP_NONE ); + SetType(WINDOW_TREELISTBOX); +} + +SvLBox::SvLBox( Window* pParent, const ResId& rResId ) : + Control( pParent, rResId ), + DropTargetHelper( this ), DragSourceHelper( this ), eSelMode( NO_SELECTION ) +{ + DBG_CTOR(SvLBox,0); + pTargetEntry = 0; + nImpFlags = 0; + pLBoxImpl = new SvLBox_Impl( *this ); + nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK; + nDragDropMode = 0; + SvLBoxTreeList* pTempModel = new SvLBoxTreeList; + pTempModel->SetRefCount( 0 ); + SetModel( pTempModel ); + pModel->InsertView( this ); + pHdlEntry = 0; + pEdCtrl = 0; + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + SetType(WINDOW_TREELISTBOX); +} + +__EXPORT SvLBox::~SvLBox() +{ + DBG_DTOR(SvLBox,0); + delete pEdCtrl; + pEdCtrl = 0; + pModel->RemoveView( this ); + if ( pModel->GetRefCount() == 0 ) + { + pModel->Clear(); + delete pModel; + pModel = NULL; + } + + SvLBox::RemoveBoxFromDDList_Impl( *this ); + + if( this == pDDSource ) + pDDSource = 0; + if( this == pDDTarget ) + pDDTarget = 0; + delete pLBoxImpl; +} + +void SvLBox::SetModel( SvLBoxTreeList* pNewModel ) +{ + DBG_CHKTHIS(SvLBox,0); + // erledigt das ganz CleanUp + SvListView::SetModel( pNewModel ); + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + SvLBoxEntry* pEntry = First(); + while( pEntry ) + { + ModelHasInserted( pEntry ); + pEntry = Next( pEntry ); + } +} + +void SvLBox::DisconnectFromModel() +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxTreeList* pNewModel = new SvLBoxTreeList; + pNewModel->SetRefCount( 0 ); // else this will never be deleted + SvListView::SetModel( pNewModel ); +} + +void SvLBox::Clear() +{ + DBG_CHKTHIS(SvLBox,0); + pModel->Clear(); // Model ruft SvLBox::ModelHasCleared() auf +} + +void SvLBox::EnableEntryMnemonics( bool _bEnable ) +{ + if ( _bEnable == IsEntryMnemonicsEnabled() ) + return; + + pLBoxImpl->m_bEntryMnemonicsEnabled = _bEnable; + Invalidate(); +} + +bool SvLBox::IsEntryMnemonicsEnabled() const +{ + return pLBoxImpl->m_bEntryMnemonicsEnabled; +} + +sal_uInt16 SvLBox::IsA() +{ + DBG_CHKTHIS(SvLBox,0); + return SVLISTBOX_ID_LBOX; +} + +IMPL_LINK_INLINE_START( SvLBox, CloneHdl_Impl, SvListEntry*, pEntry ) +{ + DBG_CHKTHIS(SvLBox,0); + return (long)(CloneEntry((SvLBoxEntry*)pEntry)); +} +IMPL_LINK_INLINE_END( SvLBox, CloneHdl_Impl, SvListEntry*, pEntry ) + +sal_uLong SvLBox::Insert( SvLBoxEntry* pEntry, SvLBoxEntry* pParent, sal_uLong nPos ) +{ + DBG_CHKTHIS(SvLBox,0); + sal_uLong nInsPos = pModel->Insert( pEntry, pParent, nPos ); + return nInsPos; +} + +sal_uLong SvLBox::Insert( SvLBoxEntry* pEntry,sal_uLong nRootPos ) +{ + DBG_CHKTHIS(SvLBox,0); + sal_uLong nInsPos = pModel->Insert( pEntry, nRootPos ); + return nInsPos; +} + +long SvLBox::ExpandingHdl() +{ + DBG_CHKTHIS(SvLBox,0); + return aExpandingHdl.IsSet() ? aExpandingHdl.Call( this ) : 1; +} + +void SvLBox::ExpandedHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aExpandedHdl.Call( this ); +} + +void SvLBox::SelectHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aSelectHdl.Call( this ); +} + +void SvLBox::DeselectHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aDeselectHdl.Call( this ); +} + +sal_Bool SvLBox::DoubleClickHdl() +{ + DBG_CHKTHIS(SvLBox,0); + aDoubleClickHdl.Call( this ); + return sal_True; +} + + +sal_Bool SvLBox::CheckDragAndDropMode( SvLBox* pSource, sal_Int8 nAction ) +{ + DBG_CHKTHIS(SvLBox,0); + if ( pSource == this ) + { + if ( !(nDragDropMode & (SV_DRAGDROP_CTRL_MOVE | SV_DRAGDROP_CTRL_COPY) ) ) + return sal_False; // D&D innerhalb der Liste gesperrt + if( DND_ACTION_MOVE == nAction ) + { + if ( !(nDragDropMode & SV_DRAGDROP_CTRL_MOVE) ) + return sal_False; // kein lokales Move + } + else + { + if ( !(nDragDropMode & SV_DRAGDROP_CTRL_COPY)) + return sal_False; // kein lokales Copy + } + } + else + { + if ( !(nDragDropMode & SV_DRAGDROP_APP_DROP ) ) + return sal_False; // kein Drop + if ( DND_ACTION_MOVE == nAction ) + { + if ( !(nDragDropMode & SV_DRAGDROP_APP_MOVE) ) + return sal_False; // kein globales Move + } + else + { + if ( !(nDragDropMode & SV_DRAGDROP_APP_COPY)) + return sal_False; // kein globales Copy + } + } + return sal_True; +} + + + + +void SvLBox::NotifyRemoving( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +/* + NotifyMoving/Copying + ==================== + + Standard-Verhalten: + + 1. Target hat keine Childs + - Entry wird Sibling des Targets. Entry steht hinter dem + Target (->Fenster: Unter dem Target) + 2. Target ist ein aufgeklappter Parent + - Entry wird an den Anfang der Target-Childlist gehaengt + 3. Target ist ein zugeklappter Parent + - Entry wird an das Ende der Target-Childlist gehaengt +*/ +#ifdef DBG_UTIL +sal_Bool SvLBox::NotifyMoving( + SvLBoxEntry* pTarget, // D&D-Drop-Position in this->GetModel() + SvLBoxEntry* pEntry, // Zu verschiebender Entry aus + // GetSourceListBox()->GetModel() + SvLBoxEntry*& rpNewParent, // Neuer Target-Parent + sal_uLong& rNewChildPos) // Position in Childlist des Target-Parents +#else +sal_Bool SvLBox::NotifyMoving( + SvLBoxEntry* pTarget, // D&D-Drop-Position in this->GetModel() + SvLBoxEntry*, // Zu verschiebender Entry aus + // GetSourceListBox()->GetModel() + SvLBoxEntry*& rpNewParent, // Neuer Target-Parent + sal_uLong& rNewChildPos) // Position in Childlist des Target-Parents +#endif +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"NotifyMoving:SoureEntry?"); + if( !pTarget ) + { + rpNewParent = 0; + rNewChildPos = 0; + return sal_True; + } + if ( !pTarget->HasChilds() && !pTarget->HasChildsOnDemand() ) + { + // Fall 1 + rpNewParent = GetParent( pTarget ); + rNewChildPos = pModel->GetRelPos( pTarget ) + 1; + rNewChildPos += nCurEntrySelPos; + nCurEntrySelPos++; + } + else + { + // Faelle 2 & 3 + rpNewParent = pTarget; + if( IsExpanded(pTarget)) + rNewChildPos = 0; + else + rNewChildPos = LIST_APPEND; + } + return sal_True; +} + +sal_Bool SvLBox::NotifyCopying( + SvLBoxEntry* pTarget, // D&D-Drop-Position in this->GetModel() + SvLBoxEntry* pEntry, // Zu kopierender Entry aus + // GetSourceListBox()->GetModel() + SvLBoxEntry*& rpNewParent, // Neuer Target-Parent + sal_uLong& rNewChildPos) // Position in Childlist des Target-Parents +{ + DBG_CHKTHIS(SvLBox,0); + return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos); + /* + DBG_ASSERT(pEntry,"NotifyCopying:SourceEntry?"); + if( !pTarget ) + { + rpNewParent = 0; + rNewChildPos = 0; + return sal_True; + } + if ( !pTarget->HasChilds() && !pTarget->HasChildsOnDemand() ) + { + // Fall 1 + rpNewParent = GetParent( pTarget ); + rNewChildPos = GetRelPos( pTarget ) + 1; + } + else + { + // Faelle 2 & 3 + rpNewParent = pTarget; + if( IsExpanded(pTarget)) + rNewChildPos = 0; + else + rNewChildPos = LIST_APPEND; + } + return sal_True; + */ +} + +SvLBoxEntry* SvLBox::CloneEntry( SvLBoxEntry* pSource ) +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxEntry* pEntry = (SvLBoxEntry*)CreateEntry(); // new SvLBoxEntry; + pEntry->Clone( (SvListEntry*)pSource ); + return pEntry; +} + + +// Rueckgabe: Alle Entries wurden kopiert +sal_Bool SvLBox::CopySelection( SvLBox* pSource, SvLBoxEntry* pTarget ) +{ + DBG_CHKTHIS(SvLBox,0); + nCurEntrySelPos = 0; // Selektionszaehler fuer NotifyMoving/Copying + sal_Bool bSuccess = sal_True; + SvTreeEntryList aList; + sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() ); + Link aCloneLink( pModel->GetCloneLink() ); + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + + // Selektion zwischenspeichern, um bei D&D-Austausch + // innerhalb der gleichen Listbox das Iterieren ueber + // die Selektion zu vereinfachen + SvLBoxEntry* pSourceEntry = pSource->FirstSelected(); + while ( pSourceEntry ) + { + // Childs werden automatisch mitkopiert + pSource->SelectChilds( pSourceEntry, sal_False ); + aList.Insert( pSourceEntry, LIST_APPEND ); + pSourceEntry = pSource->NextSelected( pSourceEntry ); + } + + pSourceEntry = (SvLBoxEntry*)aList.First(); + while ( pSourceEntry ) + { + SvLBoxEntry* pNewParent = 0; + sal_uLong nInsertionPos = LIST_APPEND; + sal_Bool bOk=NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos); + if ( bOk ) + { + if ( bClone ) + { + sal_uLong nCloneCount = 0; + pSourceEntry = (SvLBoxEntry*) + pModel->Clone( (SvListEntry*)pSourceEntry, nCloneCount ); + pModel->InsertTree( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + } + else + { + sal_uLong nListPos = pModel->Copy( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + pSourceEntry = GetEntry( pNewParent, nListPos ); + } + } + else + bSuccess = sal_False; + + if( bOk == (sal_Bool)2 ) // !!!HACK verschobenen Entry sichtbar machen? + MakeVisible( pSourceEntry ); + + pSourceEntry = (SvLBoxEntry*)aList.Next(); + } + pModel->SetCloneLink( aCloneLink ); + return bSuccess; +} + +// Rueckgabe: Alle Entries wurden verschoben +sal_Bool SvLBox::MoveSelection( SvLBox* pSource, SvLBoxEntry* pTarget ) +{ + return MoveSelectionCopyFallbackPossible( pSource, pTarget, sal_False ); +} + +sal_Bool SvLBox::MoveSelectionCopyFallbackPossible( SvLBox* pSource, SvLBoxEntry* pTarget, sal_Bool bAllowCopyFallback ) +{ + DBG_CHKTHIS(SvLBox,0); + nCurEntrySelPos = 0; // Selektionszaehler fuer NotifyMoving/Copying + sal_Bool bSuccess = sal_True; + SvTreeEntryList aList; + sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() ); + Link aCloneLink( pModel->GetCloneLink() ); + if ( bClone ) + pModel->SetCloneLink( LINK(this, SvLBox, CloneHdl_Impl )); + + SvLBoxEntry* pSourceEntry = pSource->FirstSelected(); + while ( pSourceEntry ) + { + // Childs werden automatisch mitbewegt + pSource->SelectChilds( pSourceEntry, sal_False ); + aList.Insert( pSourceEntry, LIST_APPEND ); + pSourceEntry = pSource->NextSelected( pSourceEntry ); + } + + pSourceEntry = (SvLBoxEntry*)aList.First(); + while ( pSourceEntry ) + { + SvLBoxEntry* pNewParent = 0; + sal_uLong nInsertionPos = LIST_APPEND; + sal_Bool bOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos); + sal_Bool bCopyOk = bOk; + if ( !bOk && bAllowCopyFallback ) + { + nInsertionPos = LIST_APPEND; + bCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos); + } + + if ( bOk || bCopyOk ) + { + if ( bClone ) + { + sal_uLong nCloneCount = 0; + pSourceEntry = (SvLBoxEntry*) + pModel->Clone( (SvListEntry*)pSourceEntry, nCloneCount ); + pModel->InsertTree( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + } + else + { + if ( bOk ) + pModel->Move( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + else + pModel->Copy( (SvListEntry*)pSourceEntry, + (SvListEntry*)pNewParent, nInsertionPos ); + } + } + else + bSuccess = sal_False; + + if( bOk == (sal_Bool)2 ) // !!!HACK verschobenen Entry sichtbar machen? + MakeVisible( pSourceEntry ); + + pSourceEntry = (SvLBoxEntry*)aList.Next(); + } + pModel->SetCloneLink( aCloneLink ); + return bSuccess; +} + +void SvLBox::RemoveSelection() +{ + DBG_CHKTHIS(SvLBox,0); + SvTreeEntryList aList; + // Selektion zwischenspeichern, da die Impl bei + // dem ersten Remove alles deselektiert! + SvLBoxEntry* pEntry = FirstSelected(); + while ( pEntry ) + { + aList.Insert( pEntry ); + if ( pEntry->HasChilds() ) + // Remove loescht Childs automatisch + SelectChilds( pEntry, sal_False ); + pEntry = NextSelected( pEntry ); + } + pEntry = (SvLBoxEntry*)aList.First(); + while ( pEntry ) + { + pModel->Remove( pEntry ); + pEntry = (SvLBoxEntry*)aList.Next(); + } +} + +SvLBox* SvLBox::GetSourceView() const +{ + return pDDSource; +} + +SvLBox* SvLBox::GetTargetView() const +{ + return pDDTarget; +} + +void SvLBox::RequestingChilds( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ERROR("Child-Request-Hdl not implemented!"); +} + +void SvLBox::RecalcViewData() +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxEntry* pEntry = First(); + while( pEntry ) + { + sal_uInt16 nCount = pEntry->ItemCount(); + sal_uInt16 nCurPos = 0; + while ( nCurPos < nCount ) + { + SvLBoxItem* pItem = pEntry->GetItem( nCurPos ); + pItem->InitViewData( this, pEntry ); + nCurPos++; + } + ViewDataInitialized( pEntry ); + pEntry = Next( pEntry ); + } +} + +void SvLBox::ViewDataInitialized( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +void SvLBox::StateChanged( StateChangedType eType ) +{ + if( eType == STATE_CHANGE_ENABLE ) + Invalidate( INVALIDATE_CHILDREN ); + Control::StateChanged( eType ); +} + +void SvLBox::ImplShowTargetEmphasis( SvLBoxEntry* pEntry, sal_Bool bShow) +{ + DBG_CHKTHIS(SvLBox,0); + if ( bShow && (nImpFlags & SVLBOX_TARGEMPH_VIS) ) + return; + if ( !bShow && !(nImpFlags & SVLBOX_TARGEMPH_VIS) ) + return; + ShowTargetEmphasis( pEntry, bShow ); + if( bShow ) + nImpFlags |= SVLBOX_TARGEMPH_VIS; + else + nImpFlags &= ~SVLBOX_TARGEMPH_VIS; +} + +void SvLBox::ShowTargetEmphasis( SvLBoxEntry*, sal_Bool /* bShow */ ) +{ + DBG_CHKTHIS(SvLBox,0); +} + + +sal_Bool SvLBox::Expand( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return sal_True; +} + +sal_Bool SvLBox::Collapse( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return sal_True; +} + +sal_Bool SvLBox::Select( SvLBoxEntry*, sal_Bool ) +{ + DBG_CHKTHIS(SvLBox,0); + return sal_False; +} + +sal_uLong SvLBox::SelectChilds( SvLBoxEntry* , sal_Bool ) +{ + DBG_CHKTHIS(SvLBox,0); + return 0; +} + +void SvLBox::OnCurrentEntryChanged() +{ + if ( !pLBoxImpl->m_bDoingQuickSelection ) + pLBoxImpl->m_aQuickSelectionEngine.Reset(); +} + +void SvLBox::SelectAll( sal_Bool /* bSelect */ , sal_Bool /* bPaint */ ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +SvLBoxEntry* SvLBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const +{ + DBG_CHKTHIS(SvLBox,0); + + SvLBoxEntry* pEntry = NULL; + SvLBoxEntry* pParent = NULL; + for( ::std::deque< sal_Int32 >::const_iterator pItem = _rPath.begin(); pItem != _rPath.end(); ++pItem ) + { + pEntry = GetEntry( pParent, *pItem ); + if ( !pEntry ) + break; + pParent = pEntry; + } + + return pEntry; +} + +void SvLBox::FillEntryPath( SvLBoxEntry* pEntry, ::std::deque< sal_Int32 >& _rPath ) const +{ + DBG_CHKTHIS(SvLBox,0); + + if ( pEntry ) + { + SvLBoxEntry* pParentEntry = GetParent( pEntry ); + while ( sal_True ) + { + sal_uLong i, nCount = GetLevelChildCount( pParentEntry ); + for ( i = 0; i < nCount; ++i ) + { + SvLBoxEntry* pTemp = GetEntry( pParentEntry, i ); + DBG_ASSERT( pEntry, "invalid entry" ); + if ( pEntry == pTemp ) + { + _rPath.push_front( (sal_Int32)i ); + break; + } + } + + if ( pParentEntry ) + { + pEntry = pParentEntry; + pParentEntry = GetParent( pParentEntry ); + } + else + break; + } + } +} + +String SvLBox::GetEntryText( SvLBoxEntry* ) const +{ + DBG_CHKTHIS(SvLBox,0); + + return String(); +} + +sal_uLong SvLBox::GetLevelChildCount( SvLBoxEntry* _pParent ) const +{ + DBG_CHKTHIS(SvLBox,0); + + sal_uLong nCount = 0; + SvLBoxEntry* pEntry = FirstChild( _pParent ); + while ( pEntry ) + { + ++nCount; + pEntry = NextSibling( pEntry ); + } + + return nCount; +} + +void SvLBox::SetSelectionMode( SelectionMode eSelectMode ) +{ + DBG_CHKTHIS(SvLBox,0); + eSelMode = eSelectMode; +} + +void SvLBox::SetDragDropMode( DragDropMode nDDMode ) +{ + DBG_CHKTHIS(SvLBox,0); + nDragDropMode = nDDMode; +} + +SvViewData* SvLBox::CreateViewData( SvListEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + SvViewDataEntry* pEntryData = new SvViewDataEntry; + return (SvViewData*)pEntryData; +} + +void SvLBox::InitViewData( SvViewData* pData, SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBox,0); + SvLBoxEntry* pInhEntry = (SvLBoxEntry*)pEntry; + SvViewDataEntry* pEntryData = (SvViewDataEntry*)pData; + + pEntryData->pItemData = new SvViewDataItem[ pInhEntry->ItemCount() ]; + SvViewDataItem* pItemData = pEntryData->pItemData; + pEntryData->nItmCnt = pInhEntry->ItemCount(); // Anzahl Items fuer delete + sal_uInt16 nCount = pInhEntry->ItemCount(); + sal_uInt16 nCurPos = 0; + while( nCurPos < nCount ) + { + SvLBoxItem* pItem = pInhEntry->GetItem( nCurPos ); + pItem->InitViewData( this, pInhEntry, pItemData ); + pItemData++; + nCurPos++; + } +} + + + +void SvLBox::EnableSelectionAsDropTarget( sal_Bool bEnable, sal_Bool bWithChilds ) +{ + DBG_CHKTHIS(SvLBox,0); + sal_uInt16 nRefDepth; + SvLBoxEntry* pTemp; + + SvLBoxEntry* pSelEntry = FirstSelected(); + while( pSelEntry ) + { + if ( !bEnable ) + { + pSelEntry->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP; + if ( bWithChilds ) + { + nRefDepth = pModel->GetDepth( pSelEntry ); + pTemp = Next( pSelEntry ); + while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth ) + { + pTemp->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP; + pTemp = Next( pTemp ); + } + } + } + else + { + pSelEntry->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP); + if ( bWithChilds ) + { + nRefDepth = pModel->GetDepth( pSelEntry ); + pTemp = Next( pSelEntry ); + while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth ) + { + pTemp->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP); + pTemp = Next( pTemp ); + } + } + } + pSelEntry = NextSelected( pSelEntry ); + } +} + +SvLBoxEntry* SvLBox::GetDropTarget( const Point& ) +{ + DBG_CHKTHIS(SvLBox,0); + return 0; +} + +// ****************************************************************** +// InplaceEditing +// ****************************************************************** + +void SvLBox::EditText( const String& rStr, const Rectangle& rRect, + const Selection& rSel ) +{ + EditText( rStr, rRect, rSel, sal_False ); +} + +void SvLBox::EditText( const String& rStr, const Rectangle& rRect, + const Selection& rSel, sal_Bool bMulti ) +{ + DBG_CHKTHIS(SvLBox,0); + if( pEdCtrl ) + delete pEdCtrl; + nImpFlags |= SVLBOX_IN_EDT; + nImpFlags &= ~SVLBOX_EDTEND_CALLED; + HideFocus(); + pEdCtrl = new SvInplaceEdit2( + this, rRect.TopLeft(), rRect.GetSize(), rStr, + LINK( this, SvLBox, TextEditEndedHdl_Impl ), + rSel, bMulti ); +} + +IMPL_LINK( SvLBox, TextEditEndedHdl_Impl, SvInplaceEdit2 *, EMPTYARG ) +{ + DBG_CHKTHIS(SvLBox,0); + if ( nImpFlags & SVLBOX_EDTEND_CALLED ) // Nesting verhindern + return 0; + nImpFlags |= SVLBOX_EDTEND_CALLED; + String aStr; + if ( !pEdCtrl->EditingCanceled() ) + aStr = pEdCtrl->GetText(); + else + aStr = pEdCtrl->GetSavedValue(); + if ( IsEmptyTextAllowed() || aStr.Len() > 0 ) + EditedText( aStr ); + // Hide darf erst gerufen werden, nachdem der neue Text in den + // Entry gesetzt wurde, damit im GetFocus der ListBox nicht + // der Selecthandler mit dem alten EntryText gerufen wird. + pEdCtrl->Hide(); + // delete pEdCtrl; + // pEdCtrl = 0; + nImpFlags &= (~SVLBOX_IN_EDT); + GrabFocus(); + return 0; +} + +void SvLBox::CancelTextEditing() +{ + DBG_CHKTHIS(SvLBox,0); + if ( pEdCtrl ) + pEdCtrl->StopEditing( sal_True ); + nImpFlags &= (~SVLBOX_IN_EDT); +} + +void SvLBox::EndEditing( sal_Bool bCancel ) +{ + DBG_CHKTHIS(SvLBox,0); + if( pEdCtrl ) + pEdCtrl->StopEditing( bCancel ); + nImpFlags &= (~SVLBOX_IN_EDT); +} + + +bool SvLBox::IsEmptyTextAllowed() const +{ + DBG_CHKTHIS(SvLBox,0); + return pLBoxImpl->m_bIsEmptyTextAllowed; +} + +void SvLBox::ForbidEmptyText() +{ + DBG_CHKTHIS(SvLBox,0); + pLBoxImpl->m_bIsEmptyTextAllowed = false; +} + +void SvLBox::EditedText( const String& ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +void SvLBox::EditingRequest( SvLBoxEntry*, SvLBoxItem*,const Point& ) +{ + DBG_CHKTHIS(SvLBox,0); +} + + +SvLBoxEntry* SvLBox::CreateEntry() const +{ + DBG_CHKTHIS(SvLBox,0); + return new SvLBoxEntry; +} + +void SvLBox::MakeVisible( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +void SvLBox::Command( const CommandEvent& i_rCommandEvent ) +{ + DBG_CHKTHIS(SvLBox,0); + + if ( COMMAND_STARTDRAG == i_rCommandEvent.GetCommand() ) + { + Point aEventPos( i_rCommandEvent.GetMousePosPixel() ); + MouseEvent aMouseEvt( aEventPos, 1, MOUSE_SELECT, MOUSE_LEFT ); + MouseButtonUp( aMouseEvt ); + } + Control::Command( i_rCommandEvent ); +} + +void SvLBox::KeyInput( const KeyEvent& rKEvt ) +{ + bool bHandled = HandleKeyInput( rKEvt ); + if ( !bHandled ) + Control::KeyInput( rKEvt ); +} + +const void* SvLBox::FirstSearchEntry( String& _rEntryText ) const +{ + SvLBoxEntry* pEntry = GetCurEntry(); + if ( pEntry ) + pEntry = const_cast< SvLBoxEntry* >( static_cast< const SvLBoxEntry* >( NextSearchEntry( pEntry, _rEntryText ) ) ); + else + { + pEntry = FirstSelected(); + if ( !pEntry ) + pEntry = First(); + } + + if ( pEntry ) + _rEntryText = GetEntryText( pEntry ); + + return pEntry; +} + +const void* SvLBox::NextSearchEntry( const void* _pCurrentSearchEntry, String& _rEntryText ) const +{ + SvLBoxEntry* pEntry = const_cast< SvLBoxEntry* >( static_cast< const SvLBoxEntry* >( _pCurrentSearchEntry ) ); + + if ( ( ( GetChildCount( pEntry ) > 0 ) + || ( pEntry->HasChildsOnDemand() ) + ) + && !IsExpanded( pEntry ) + ) + { + pEntry = NextSibling( pEntry ); + } + else + { + pEntry = Next( pEntry ); + } + + if ( !pEntry ) + pEntry = First(); + + if ( pEntry ) + _rEntryText = GetEntryText( pEntry ); + + return pEntry; +} + +void SvLBox::SelectSearchEntry( const void* _pEntry ) +{ + SvLBoxEntry* pEntry = const_cast< SvLBoxEntry* >( static_cast< const SvLBoxEntry* >( _pEntry ) ); + DBG_ASSERT( pEntry, "SvLBox::SelectSearchEntry: invalid entry!" ); + if ( !pEntry ) + return; + + SelectAll( sal_False ); + SetCurEntry( pEntry ); + Select( pEntry ); +} + +void SvLBox::ExecuteSearchEntry( const void* /*_pEntry*/ ) const +{ + // nothing to do here, we have no "execution" +} + +::vcl::StringEntryIdentifier SvLBox::CurrentEntry( String& _out_entryText ) const +{ + // always accept the current entry if there is one + SvLBoxEntry* pCurrentEntry( GetCurEntry() ); + if ( pCurrentEntry ) + { + _out_entryText = GetEntryText( pCurrentEntry ); + return pCurrentEntry; + } + return FirstSearchEntry( _out_entryText ); +} + +::vcl::StringEntryIdentifier SvLBox::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, String& _out_entryText ) const +{ + return NextSearchEntry( _currentEntry, _out_entryText ); +} + +void SvLBox::SelectEntry( ::vcl::StringEntryIdentifier _entry ) +{ + SelectSearchEntry( _entry ); +} + +bool SvLBox::HandleKeyInput( const KeyEvent& _rKEvt ) +{ + if ( IsEntryMnemonicsEnabled() + && pLBoxImpl->m_aMnemonicEngine.HandleKeyEvent( _rKEvt ) + ) + return true; + + if ( ( GetStyle() & WB_QUICK_SEARCH ) != 0 ) + { + pLBoxImpl->m_bDoingQuickSelection = true; + const bool bHandled = pLBoxImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt ); + pLBoxImpl->m_bDoingQuickSelection = false; + if ( bHandled ) + return true; + } + + return false; +} + +SvLBoxEntry* SvLBox::GetEntry( const Point&, sal_Bool ) const +{ + DBG_CHKTHIS(SvLBox,0); + return 0; +} + +void SvLBox::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvLBox,0); + sal_uInt16 nCount = ((SvLBoxEntry*)pEntry)->ItemCount(); + for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++ ) + { + SvLBoxItem* pItem = ((SvLBoxEntry*)pEntry)->GetItem( nIdx ); + pItem->InitViewData( this, (SvLBoxEntry*)pEntry, 0 ); + } +} + +void SvLBox::SetInUseEmphasis( SvLBoxEntry* pEntry, sal_Bool bInUse ) +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"SetInUseEmphasis:No Entry"); + if( bInUse ) + { + if( !pEntry->HasInUseEmphasis() ) + { + pEntry->nEntryFlags |= SV_ENTRYFLAG_IN_USE; + pModel->InvalidateEntry( pEntry ); + } + } + else + { + if( pEntry->HasInUseEmphasis() ) + { + pEntry->nEntryFlags &= (~SV_ENTRYFLAG_IN_USE); + pModel->InvalidateEntry( pEntry ); + } + } +} + +void SvLBox::SetCursorEmphasis( SvLBoxEntry* pEntry, sal_Bool bCursored ) +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"SetInUseEmphasis:No Entry"); + SvViewDataEntry* pViewData = GetViewDataEntry( pEntry ); + if( pViewData && (bCursored != pViewData->IsCursored()) ) + { + pViewData->SetCursored( bCursored ); + // paintet in allen Views + // pModel->InvalidateEntry( pEntry ); + // invalidiert nur in dieser View + ModelHasEntryInvalidated( pEntry ); + } +} + +sal_Bool SvLBox::HasCursorEmphasis( SvLBoxEntry* pEntry ) const +{ + DBG_CHKTHIS(SvLBox,0); + DBG_ASSERT(pEntry,"SetInUseEmphasis:No Entry"); + SvViewDataEntry* pViewData = GetViewDataEntry( pEntry ); + DBG_ASSERT(pViewData,"Entry not in View"); + return pViewData->IsCursored(); +} + +void SvLBox::WriteDragServerInfo( const Point&, SvLBoxDDInfo* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +void SvLBox::ReadDragServerInfo(const Point&, SvLBoxDDInfo* ) +{ + DBG_CHKTHIS(SvLBox,0); +} + +sal_Bool SvLBox::EditingCanceled() const +{ + if( pEdCtrl && pEdCtrl->EditingCanceled() ) + return sal_True; + return sal_False; +} + + +//JP 28.3.2001: new Drag & Drop API +sal_Int8 SvLBox::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + DBG_CHKTHIS(SvLBox,0); + sal_Int8 nRet = DND_ACTION_NONE; + + if( rEvt.mbLeaving || !CheckDragAndDropMode( pDDSource, rEvt.mnAction ) ) + { + ImplShowTargetEmphasis( pTargetEntry, sal_False ); + } + else if( !nDragDropMode ) + { + DBG_ERRORFILE( "SvLBox::QueryDrop(): no target" ); + } + else + { + SvLBoxEntry* pEntry = GetDropTarget( rEvt.maPosPixel ); + if( !IsDropFormatSupported( SOT_FORMATSTR_ID_TREELISTBOX ) ) + { + DBG_ERRORFILE( "SvLBox::QueryDrop(): no format" ); + } + else + { + DBG_ASSERT( pDDSource, "SvLBox::QueryDrop(): SourceBox == 0 (__EXPORT?)" ); + if( !( pEntry && pDDSource->GetModel() == this->GetModel() + && DND_ACTION_MOVE == rEvt.mnAction + && ( pEntry->nEntryFlags & SV_ENTRYFLAG_DISABLE_DROP ) )) + { + if( NotifyAcceptDrop( pEntry )) + nRet = rEvt.mnAction; + } + } + + // **** Emphasis zeichnen **** + if( DND_ACTION_NONE == nRet ) + ImplShowTargetEmphasis( pTargetEntry, sal_False ); + else if( pEntry != pTargetEntry || !(nImpFlags & SVLBOX_TARGEMPH_VIS) ) + { + ImplShowTargetEmphasis( pTargetEntry, sal_False ); + pTargetEntry = pEntry; + ImplShowTargetEmphasis( pTargetEntry, sal_True ); + } + } + return nRet; +} + +sal_Int8 SvLBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvLBox* pSourceView ) +{ + DBG_CHKTHIS(SvLBox,0); + sal_Int8 nRet = DND_ACTION_NONE; + + DBG_ASSERT( pSourceView, "SvLBox::ExecuteDrop(): no source view" ); + pSourceView->EnableSelectionAsDropTarget( sal_True, sal_True ); + + ImplShowTargetEmphasis( pTargetEntry, sal_False ); + pDDTarget = this; + + SvLBoxDDInfo aDDInfo; + + TransferableDataHelper aData( rEvt.maDropEvent.Transferable ); + if( aData.HasFormat( SOT_FORMATSTR_ID_TREELISTBOX )) + { + ::com::sun::star::uno::Sequence< sal_Int8 > aSeq; + if( aData.GetSequence( SOT_FORMATSTR_ID_TREELISTBOX, aSeq ) && + sizeof(SvLBoxDDInfo) == aSeq.getLength() ) + { + memcpy( &aDDInfo, aSeq.getConstArray(), sizeof(SvLBoxDDInfo) ); + nRet = rEvt.mnAction; + } + } + + if( DND_ACTION_NONE != nRet ) + { + nRet = DND_ACTION_NONE; + + ReadDragServerInfo( rEvt.maPosPixel, &aDDInfo ); + + SvLBoxEntry* pTarget = pTargetEntry; // !!! kann 0 sein !!! + + if( DND_ACTION_COPY == rEvt.mnAction ) + { + if ( CopySelection( aDDInfo.pSource, pTarget ) ) + nRet = rEvt.mnAction; + } + else if( DND_ACTION_MOVE == rEvt.mnAction ) + { + if ( MoveSelection( aDDInfo.pSource, pTarget ) ) + nRet = rEvt.mnAction; + } + else if( DND_ACTION_COPYMOVE == rEvt.mnAction ) + { + if ( MoveSelectionCopyFallbackPossible( aDDInfo.pSource, pTarget, sal_True ) ) + nRet = rEvt.mnAction; + } + } + return nRet; +} + +sal_Int8 SvLBox::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + DBG_CHKTHIS(SvLBox,0); + return ExecuteDrop( rEvt, GetSourceView() ); +} + +void SvLBox::StartDrag( sal_Int8, const Point& rPosPixel ) +{ + DBG_CHKTHIS(SvLBox,0); + + Point aEventPos( rPosPixel ); + MouseEvent aMouseEvt( aEventPos, 1, MOUSE_SELECT, MOUSE_LEFT ); + MouseButtonUp( aMouseEvt ); + + nOldDragMode = GetDragDropMode(); + if ( !nOldDragMode ) + return; + + ReleaseMouse(); + + SvLBoxEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos ); + if( !pEntry ) + { + DragFinished( DND_ACTION_NONE ); + return; + } + + TransferDataContainer* pContainer = new TransferDataContainer; + ::com::sun::star::uno::Reference< + ::com::sun::star::datatransfer::XTransferable > xRef( pContainer ); + + nDragDropMode = NotifyStartDrag( *pContainer, pEntry ); + if( !nDragDropMode || 0 == GetSelectionCount() ) + { + nDragDropMode = nOldDragMode; + DragFinished( DND_ACTION_NONE ); + return; + } + + SvLBoxDDInfo aDDInfo; + memset(&aDDInfo,0,sizeof(SvLBoxDDInfo)); + aDDInfo.pApp = GetpApp(); + aDDInfo.pSource = this; + aDDInfo.pDDStartEntry = pEntry; + // abgeleitete Views zum Zuge kommen lassen + WriteDragServerInfo( rPosPixel, &aDDInfo ); + + pContainer->CopyAnyData( SOT_FORMATSTR_ID_TREELISTBOX, + (sal_Char*)&aDDInfo, sizeof(SvLBoxDDInfo) ); + pDDSource = this; + pDDTarget = 0; + + sal_Bool bOldUpdateMode = Control::IsUpdateMode(); + Control::SetUpdateMode( sal_True ); + Update(); + Control::SetUpdateMode( bOldUpdateMode ); + + // Selektion & deren Childs im Model als DropTargets sperren + // Wichtig: Wenn im DropHandler die Selektion der + // SourceListBox veraendert wird, muessen vorher die Eintraege + // als DropTargets wieder freigeschaltet werden: + // (GetSourceListBox()->EnableSelectionAsDropTarget( sal_True, sal_True );) + EnableSelectionAsDropTarget( sal_False, sal_True /* with Childs */ ); + + pContainer->StartDrag( this, nDragOptions, GetDragFinishedHdl() ); +} + +void SvLBox::DragFinished( sal_Int8 +#ifndef UNX +nAction +#endif +) +{ + EnableSelectionAsDropTarget( sal_True, sal_True ); + +#ifndef UNX + if( (nAction == DND_ACTION_MOVE) && ( (pDDTarget && + ((sal_uLong)(pDDTarget->GetModel())!=(sal_uLong)(this->GetModel()))) || + !pDDTarget )) + { + RemoveSelection(); + } +#endif + + ImplShowTargetEmphasis( pTargetEntry, sal_False ); + pDDSource = 0; + pDDTarget = 0; + pTargetEntry = 0; + nDragDropMode = nOldDragMode; +} + +DragDropMode SvLBox::NotifyStartDrag( TransferDataContainer&, SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return (DragDropMode)0xffff; +} + +sal_Bool SvLBox::NotifyAcceptDrop( SvLBoxEntry* ) +{ + DBG_CHKTHIS(SvLBox,0); + return sal_True; +} + +// handler and methods for Drag - finished handler. +// The with get GetDragFinishedHdl() get link can set on the +// TransferDataContainer. This link is a callback for the DragFinished +// call. AddBox method is called from the GetDragFinishedHdl() and the +// remove is called in link callback and in the destructor. So it can't +// called to a deleted object. + +namespace +{ + struct SortLBoxes : public rtl::Static<SvULongsSort, SortLBoxes> {}; +} + +void SvLBox::AddBoxToDDList_Impl( const SvLBox& rB ) +{ + sal_uLong nVal = (sal_uLong)&rB; + SortLBoxes::get().Insert( nVal ); +} + +void SvLBox::RemoveBoxFromDDList_Impl( const SvLBox& rB ) +{ + sal_uLong nVal = (sal_uLong)&rB; + SortLBoxes::get().Remove( nVal ); +} + +IMPL_STATIC_LINK( SvLBox, DragFinishHdl_Impl, sal_Int8*, pAction ) +{ + sal_uLong nVal = (sal_uLong)pThis; + sal_uInt16 nFnd; + SvULongsSort &rSortLBoxes = SortLBoxes::get(); + if( rSortLBoxes.Seek_Entry( nVal, &nFnd ) ) + { + pThis->DragFinished( *pAction ); + rSortLBoxes.Remove( nFnd, 1 ); + } + return 0; +} + +Link SvLBox::GetDragFinishedHdl() const +{ + AddBoxToDDList_Impl( *this ); + return STATIC_LINK( this, SvLBox, DragFinishHdl_Impl ); +} + +void SvLBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& ) const +{ +} + +::com::sun::star::uno::Reference< XAccessible > SvLBox::CreateAccessible() +{ + return ::com::sun::star::uno::Reference< XAccessible >(); +} + +Rectangle SvLBox::GetBoundingRect( SvLBoxEntry* ) +{ + return Rectangle(); +} + diff --git a/svtools/source/contnr/svtabbx.cxx b/svtools/source/contnr/svtabbx.cxx new file mode 100644 index 000000000000..ed48f9fc6352 --- /dev/null +++ b/svtools/source/contnr/svtabbx.cxx @@ -0,0 +1,1304 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" +#include <svtools/svtabbx.hxx> +#include <svtools/headbar.hxx> +#include <svtools/svtdata.hxx> +#ifndef _SVTOOLS_HRC +#include <svtools/svtools.hrc> +#endif +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#ifndef SVTOOLS_ACCESSIBLE_FACTORY_HXX +#include "svtaccessiblefactory.hxx" +#endif + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::accessibility; + +#define MYTABMASK \ + ( SV_LBOXTAB_ADJUST_RIGHT | SV_LBOXTAB_ADJUST_LEFT | SV_LBOXTAB_ADJUST_CENTER | SV_LBOXTAB_ADJUST_NUMERIC ) + +// SvTreeListBox-Callback + +void SvTabListBox::SetTabs() +{ + SvTreeListBox::SetTabs(); + if( nTabCount ) + { + DBG_ASSERT(pTabList,"TabList ?"); + + // die TreeListBox hat jetzt ihre Tabulatoren in die Liste eingefuegt. + // jetzt plustern wir die Liste mit zusaetzlichen Tabulatoren auf, + // und passen den ganz rechten Tab der Treelistbox an. + + // den ganz rechten Tab nehmen + // HACK fuer den Explorer! Wenn der ViewParent != 0 ist, dann wird + // der erste Tab der TreeListBox von der TreelistBox berechnet! + // Dies wird fuer ButtonsOnRoot benoetigt, da der Explorer nicht + // weiss, welchen zusaetzlichen Offset er in diesem Modus auf + // den Tabulator addieren muss. Die TreeListBox weiss es! + /* + if( !pViewParent ) + { + SvLBoxTab* pFirstTab = (SvLBoxTab*)aTabs.GetObject( aTabs.Count()-1 ); + pFirstTab->SetPos( pTabList[0].GetPos() ); + pFirstTab->nFlags &= ~MYTABMASK; + pFirstTab->nFlags |= pTabList[0].nFlags; + } + */ + + // alle anderen Tabs an Liste haengen + for( sal_uInt16 nCurTab = 1; nCurTab < nTabCount; nCurTab++ ) + { + SvLBoxTab* pTab = pTabList+nCurTab; + AddTab( pTab->GetPos(), pTab->nFlags ); + } + } +} + +void SvTabListBox::InitEntry( SvLBoxEntry* pEntry, const XubString& rStr, + const Image& rColl, const Image& rExp, SvLBoxButtonKind eButtonKind ) +{ + SvTreeListBox::InitEntry( pEntry, rStr, rColl, rExp, eButtonKind ); + XubString aToken; + + const xub_Unicode* pCurToken = aCurEntry.GetBuffer(); + sal_uInt16 nCurTokenLen; + const xub_Unicode* pNextToken = GetToken( pCurToken, nCurTokenLen ); + sal_uInt16 nCount = nTabCount; nCount--; + for( sal_uInt16 nToken = 0; nToken < nCount; nToken++ ) + { + if( pCurToken && nCurTokenLen ) + // aToken.Assign( pCurToken, nCurTokenLen ); + aToken = XubString( pCurToken, nCurTokenLen ); + else + aToken.Erase(); + SvLBoxString* pStr = new SvLBoxString( pEntry, 0, aToken ); + pEntry->AddItem( pStr ); + pCurToken = pNextToken; + if( pCurToken ) + pNextToken = GetToken( pCurToken, nCurTokenLen ); + else + nCurTokenLen = 0; + } +} + + +SvTabListBox::SvTabListBox( Window* pParent, WinBits nBits ) + : SvTreeListBox( pParent, nBits ) +{ + pTabList = 0; + nTabCount = 0; + pViewParent = 0; + SetHighlightRange(); // ueber volle Breite selektieren +} + +SvTabListBox::SvTabListBox( Window* pParent, const ResId& rResId ) + : SvTreeListBox( pParent, rResId ) +{ + pTabList = 0; + nTabCount = 0; + pViewParent = 0; + SvTabListBox::Resize(); + SetHighlightRange(); +} + +SvTabListBox::~SvTabListBox() +{ + // array-delete + delete [] pTabList; +#ifdef DBG_UTIL + pTabList = 0; + nTabCount = 0; +#endif +} + +void SvTabListBox::SetTabs( long* pTabs, MapUnit eMapUnit ) +{ + DBG_ASSERT(pTabs,"SetTabs:NULL-Ptr"); + if( !pTabs ) + return; + + delete [] pTabList; + sal_uInt16 nCount = (sal_uInt16)(*pTabs); + pTabList = new SvLBoxTab[ nCount ]; + nTabCount = nCount; + + MapMode aMMSource( eMapUnit ); + MapMode aMMDest( MAP_PIXEL ); + + pTabs++; + for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++, pTabs++ ) + { + Size aSize( *pTabs, 0 ); + aSize = LogicToLogic( aSize, &aMMSource, &aMMDest ); + long nNewTab = aSize.Width(); + pTabList[nIdx].SetPos( nNewTab ); + pTabList[nIdx].nFlags=(SV_LBOXTAB_ADJUST_LEFT| SV_LBOXTAB_INV_ALWAYS); + } + SvTreeListBox::nTreeFlags |= TREEFLAG_RECALCTABS; + if( IsUpdateMode() ) + Invalidate(); +} + +void SvTabListBox::SetTab( sal_uInt16 nTab,long nValue,MapUnit eMapUnit ) +{ + DBG_ASSERT(nTab<nTabCount,"Invalid Tab-Pos"); + if( nTab < nTabCount ) + { + DBG_ASSERT(pTabList,"TabList?"); + MapMode aMMSource( eMapUnit ); + MapMode aMMDest( MAP_PIXEL ); + Size aSize( nValue, 0 ); + aSize = LogicToLogic( aSize, &aMMSource, &aMMDest ); + nValue = aSize.Width(); + pTabList[ nTab ].SetPos( nValue ); + SvTreeListBox::nTreeFlags |= TREEFLAG_RECALCTABS; + if( IsUpdateMode() ) + Invalidate(); + } +} + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rText, SvLBoxEntry* pParent, + sal_Bool /*bChildsOnDemand*/, + sal_uLong nPos, void* pUserData, + SvLBoxButtonKind ) +{ + return InsertEntryToColumn( rText, pParent, nPos, 0xffff, pUserData ); +} + +SvLBoxEntry* SvTabListBox::InsertEntry( const XubString& rText, + const Image& rExpandedEntryBmp, + const Image& rCollapsedEntryBmp, + SvLBoxEntry* pParent, + sal_Bool /*bChildsOnDemand*/, + sal_uLong nPos, void* pUserData, + SvLBoxButtonKind ) +{ + return InsertEntryToColumn( rText, rExpandedEntryBmp, rCollapsedEntryBmp, + pParent, nPos, 0xffff, pUserData ); +} + +SvLBoxEntry* SvTabListBox::InsertEntryToColumn(const XubString& rStr,SvLBoxEntry* pParent,sal_uLong nPos,sal_uInt16 nCol, + void* pUser ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + sal_uInt16 nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Erase( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + return SvTreeListBox::InsertEntry( aFirstStr, pParent, sal_False, nPos, pUser ); +} + +SvLBoxEntry* SvTabListBox::InsertEntryToColumn( const XubString& rStr, + const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp, + SvLBoxEntry* pParent,sal_uLong nPos,sal_uInt16 nCol, void* pUser ) +{ + XubString aStr; + if( nCol != 0xffff ) + { + while( nCol ) + { + aStr += '\t'; + nCol--; + } + } + aStr += rStr; + XubString aFirstStr( aStr ); + sal_uInt16 nEnd = aFirstStr.Search( '\t' ); + if( nEnd != STRING_NOTFOUND ) + { + aFirstStr.Erase( nEnd ); + aCurEntry = aStr; + aCurEntry.Erase( 0, ++nEnd ); + } + else + aCurEntry.Erase(); + + return SvTreeListBox::InsertEntry( + aFirstStr, + rExpandedEntryBmp, rCollapsedEntryBmp, + pParent, sal_False, nPos, pUser ); +} + +SvLBoxEntry* SvTabListBox::InsertEntryToColumn( const XubString& rStr, sal_uLong nPos, + sal_uInt16 nCol, void* pUser ) +{ + return InsertEntryToColumn( rStr,0,nPos, nCol, pUser ); +} + +String SvTabListBox::GetEntryText( SvLBoxEntry* pEntry ) const +{ + return GetEntryText( pEntry, 0xffff ); +} + +String SvTabListBox::GetEntryText( SvLBoxEntry* pEntry, sal_uInt16 nCol ) const +{ + DBG_ASSERT(pEntry,"GetEntryText:Invalid Entry"); + XubString aResult; + if( pEntry ) + { + sal_uInt16 nCount = pEntry->ItemCount(); + sal_uInt16 nCur = 0; + while( nCur < nCount ) + { + SvLBoxItem* pStr = pEntry->GetItem( nCur ); + if( pStr->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + if( nCol == 0xffff ) + { + if( aResult.Len() ) + aResult += '\t'; + aResult += static_cast<SvLBoxString*>( pStr )->GetText(); + } + else + { + if( nCol == 0 ) + return static_cast<SvLBoxString*>( pStr )->GetText(); + nCol--; + } + } + nCur++; + } + } + return aResult; +} + +String SvTabListBox::GetEntryText( sal_uLong nPos, sal_uInt16 nCol ) const +{ + SvLBoxEntry* pEntry = GetEntryOnPos( nPos ); + return GetEntryText( pEntry, nCol ); +} + +void SvTabListBox::SetEntryText( const XubString& rStr, sal_uLong nPos, sal_uInt16 nCol ) +{ + SvLBoxEntry* pEntry = SvTreeListBox::GetEntry( nPos ); + SetEntryText( rStr, pEntry, nCol ); +} + +void SvTabListBox::SetEntryText( const XubString& rStr, SvLBoxEntry* pEntry, sal_uInt16 nCol ) +{ + DBG_ASSERT(pEntry,"SetEntryText:Invalid Entry"); + if( !pEntry ) + return; + + String sOldText = GetEntryText( pEntry, nCol ); + if ( sOldText == rStr ) + return; + + sal_uInt16 nTextColumn = nCol; + const xub_Unicode* pCurToken = rStr.GetBuffer(); + sal_uInt16 nCurTokenLen; + const xub_Unicode* pNextToken = GetToken( pCurToken, nCurTokenLen ); + + XubString aTemp; + sal_uInt16 nCount = pEntry->ItemCount(); + sal_uInt16 nCur = 0; + while( nCur < nCount ) + { + SvLBoxItem* pStr = pEntry->GetItem( nCur ); + if( pStr && pStr->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + if( nCol == 0xffff ) + { + if( pCurToken ) + aTemp = XubString( pCurToken, nCurTokenLen ); + else + aTemp.Erase(); // alle Spalten ohne Token loeschen + ((SvLBoxString*)pStr)->SetText( pEntry, aTemp ); + pCurToken = pNextToken; + pNextToken = GetToken( pCurToken, nCurTokenLen ); + } + else + { + if( !nCol ) + { + aTemp = XubString( pCurToken, nCurTokenLen ); + ((SvLBoxString*)pStr)->SetText( pEntry, aTemp ); + if( !pNextToken ) + break; + pCurToken = pNextToken; + pNextToken = GetToken( pCurToken, nCurTokenLen ); + } + else + nCol--; + } + } + nCur++; + } + GetModel()->InvalidateEntry( pEntry ); + + TabListBoxEventData* pData = new TabListBoxEventData( pEntry, nTextColumn, sOldText ); + ImplCallEventListeners( VCLEVENT_TABLECELL_NAMECHANGED, pData ); + delete pData; +} + +String SvTabListBox::GetCellText( sal_uLong nPos, sal_uInt16 nCol ) const +{ + SvLBoxEntry* pEntry = GetEntryOnPos( nPos ); + DBG_ASSERT( pEntry, "SvTabListBox::GetCellText(): Invalid Entry" ); + XubString aResult; + if ( pEntry && pEntry->ItemCount() > ( nCol + 1 ) ) + { + SvLBoxItem* pStr = pEntry->GetItem( nCol + 1 ); + if ( pStr && pStr->IsA() == SV_ITEM_ID_LBOXSTRING ) + aResult = static_cast< SvLBoxString* >( pStr )->GetText(); + } + return aResult; +} + +sal_uLong SvTabListBox::GetEntryPos( const XubString& rStr, sal_uInt16 nCol ) +{ + sal_uLong nPos = 0; + SvLBoxEntry* pEntry = First(); + while( pEntry ) + { + XubString aStr( GetEntryText( pEntry, nCol )); + if( aStr == rStr ) + return nPos; + pEntry = Next( pEntry ); + nPos++; + } + return 0xffffffff; +} + +sal_uLong SvTabListBox::GetEntryPos( const SvLBoxEntry* pEntry ) const +{ + sal_uLong nPos = 0; + SvLBoxEntry* pTmpEntry = First(); + while( pTmpEntry ) + { + if ( pTmpEntry == pEntry ) + return nPos; + pTmpEntry = Next( pTmpEntry ); + ++nPos; + } + return 0xffffffff; +} + +void __EXPORT SvTabListBox::Resize() +{ + SvTreeListBox::Resize(); +} + +// static +const xub_Unicode* SvTabListBox::GetToken( const xub_Unicode* pPtr, sal_uInt16& rLen ) +{ + if( !pPtr || *pPtr == 0 ) + { + rLen = 0; + return 0; + } + xub_Unicode c = *pPtr; + sal_uInt16 nLen = 0; + while( c != '\t' && c != 0 ) + { + pPtr++; + nLen++; + c = *pPtr; + } + if( c ) + pPtr++; // Tab ueberspringen + else + pPtr = 0; + rLen = nLen; + return pPtr; +} + +String SvTabListBox::GetTabEntryText( sal_uLong nPos, sal_uInt16 nCol ) const +{ + SvLBoxEntry* pEntry = SvTreeListBox::GetEntry( nPos ); + DBG_ASSERT( pEntry, "GetTabEntryText(): Invalid entry " ); + XubString aResult; + if ( pEntry ) + { + sal_uInt16 nCount = pEntry->ItemCount(); + sal_uInt16 nCur = ( 0 == nCol && IsCellFocusEnabled() ) ? GetCurrentTabPos() : 0; + while( nCur < nCount ) + { + SvLBoxItem* pStr = pEntry->GetItem( nCur ); + if ( pStr->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + if ( nCol == 0xffff ) + { + if ( aResult.Len() ) + aResult += '\t'; + aResult += static_cast<SvLBoxString*>( pStr )->GetText(); + } + else + { + if ( nCol == 0 ) + { + String sRet = static_cast<SvLBoxString*>( pStr )->GetText(); + if ( sRet.Len() == 0 ) + sRet = String( SvtResId( STR_SVT_ACC_EMPTY_FIELD ) ); + return sRet; + } + --nCol; + } + } + ++nCur; + } + } + return aResult; +} + +SvLBoxEntry* SvTabListBox::GetEntryOnPos( sal_uLong _nEntryPos ) const +{ + SvLBoxEntry* pEntry = NULL; + sal_uLong i, nPos = 0, nCount = GetLevelChildCount( NULL ); + for ( i = 0; i < nCount; ++i ) + { + SvLBoxEntry* pParent = GetEntry(i); + if ( nPos == _nEntryPos ) + { + pEntry = pParent; + break; + } + else + { + nPos++; + pEntry = GetChildOnPos( pParent, _nEntryPos, nPos ); + if ( pEntry ) + break; + } + } + + return pEntry; +} + +SvLBoxEntry* SvTabListBox::GetChildOnPos( SvLBoxEntry* _pParent, sal_uLong _nEntryPos, sal_uLong& _rPos ) const +{ + sal_uLong i, nCount = GetLevelChildCount( _pParent ); + for ( i = 0; i < nCount; ++i ) + { + SvLBoxEntry* pParent = GetEntry( _pParent, i ); + if ( _rPos == _nEntryPos ) + return pParent; + else + { + _rPos++; + SvLBoxEntry* pEntry = GetChildOnPos( pParent, _nEntryPos, _rPos ); + if ( pEntry ) + return pEntry; + } + } + + return NULL; +} + +void SvTabListBox::SetTabJustify( sal_uInt16 nTab, SvTabJustify eJustify) +{ + if( nTab >= nTabCount ) + return; + SvLBoxTab* pTab = &(pTabList[ nTab ]); + sal_uInt16 nFlags = pTab->nFlags; + nFlags &= (~MYTABMASK); + nFlags |= (sal_uInt16)eJustify; + pTab->nFlags = nFlags; + SvTreeListBox::nTreeFlags |= TREEFLAG_RECALCTABS; + if( IsUpdateMode() ) + Invalidate(); +} + +SvTabJustify SvTabListBox::GetTabJustify( sal_uInt16 nTab ) const +{ + SvTabJustify eResult = AdjustLeft; + if( nTab >= nTabCount ) + return eResult; + SvLBoxTab* pTab = &(pTabList[ nTab ]); + sal_uInt16 nFlags = pTab->nFlags; + nFlags &= MYTABMASK; + eResult = (SvTabJustify)nFlags; + return eResult; +} + +long SvTabListBox::GetLogicTab( sal_uInt16 nTab ) +{ + if( SvTreeListBox::nTreeFlags & TREEFLAG_RECALCTABS ) + ((SvTabListBox*)this)->SetTabs(); + + DBG_ASSERT(nTab<nTabCount,"GetTabPos:Invalid Tab"); + return ((SvLBoxTab*)aTabs.GetObject( nTab ))->GetPos(); +} + +// class SvHeaderTabListBoxImpl ------------------------------------------ + +namespace svt +{ + struct SvHeaderTabListBoxImpl + { + HeaderBar* m_pHeaderBar; + AccessibleFactoryAccess m_aFactoryAccess; + + SvHeaderTabListBoxImpl() : m_pHeaderBar( NULL ) { } + }; +} + +// class SvHeaderTabListBox ---------------------------------------------- + +SvHeaderTabListBox::SvHeaderTabListBox( Window* pParent, WinBits nWinStyle ) : + + SvTabListBox( pParent, nWinStyle ), + + m_bFirstPaint ( sal_True ), + m_pImpl ( new ::svt::SvHeaderTabListBoxImpl ), + m_pAccessible ( NULL ) +{ +} + +// ----------------------------------------------------------------------- + +SvHeaderTabListBox::SvHeaderTabListBox( Window* pParent, const ResId& rResId ) : + + SvTabListBox( pParent, rResId ), + + m_bFirstPaint ( sal_True ), + m_pImpl ( new ::svt::SvHeaderTabListBoxImpl ), + m_pAccessible ( NULL ) +{ +} + +// ----------------------------------------------------------------------- + +SvHeaderTabListBox::~SvHeaderTabListBox() +{ + delete m_pImpl; +} + +// ----------------------------------------------------------------------- + +void SvHeaderTabListBox::Paint( const Rectangle& rRect ) +{ + if ( m_bFirstPaint ) + { + m_bFirstPaint = sal_False; + RepaintScrollBars(); + } + SvTabListBox::Paint( rRect ); +} + +// ----------------------------------------------------------------------- + +void SvHeaderTabListBox::InitHeaderBar( HeaderBar* pHeaderBar ) +{ + DBG_ASSERT( !m_pImpl->m_pHeaderBar, "header bar already initialized" ); + DBG_ASSERT( pHeaderBar, "invalid header bar initialization" ); + m_pImpl->m_pHeaderBar = pHeaderBar; + SetScrolledHdl( LINK( this, SvHeaderTabListBox, ScrollHdl_Impl ) ); + m_pImpl->m_pHeaderBar->SetCreateAccessibleHdl( LINK( this, SvHeaderTabListBox, CreateAccessibleHdl_Impl ) ); +} + +// ----------------------------------------------------------------------- + +sal_Bool SvHeaderTabListBox::IsItemChecked( SvLBoxEntry* pEntry, sal_uInt16 nCol ) const +{ + SvButtonState eState = SV_BUTTON_UNCHECKED; + SvLBoxButton* pItem = (SvLBoxButton*)( pEntry->GetItem( nCol + 1 ) ); + + if ( pItem && ( (SvLBoxItem*)pItem )->IsA() == SV_ITEM_ID_LBOXBUTTON ) + { + sal_uInt16 nButtonFlags = pItem->GetButtonFlags(); + eState = pCheckButtonData->ConvertToButtonState( nButtonFlags ); + } + + return ( eState == SV_BUTTON_CHECKED ); +} + +// ----------------------------------------------------------------------- + +SvLBoxEntry* SvHeaderTabListBox::InsertEntryToColumn( + const XubString& rStr, sal_uLong nPos, sal_uInt16 nCol, void* pUserData ) +{ + SvLBoxEntry* pEntry = SvTabListBox::InsertEntryToColumn( rStr, nPos, nCol, pUserData ); + RecalculateAccessibleChildren(); + return pEntry; +} + +// ----------------------------------------------------------------------- + +SvLBoxEntry* SvHeaderTabListBox::InsertEntryToColumn( + const XubString& rStr, SvLBoxEntry* pParent, sal_uLong nPos, sal_uInt16 nCol, void* pUserData ) +{ + SvLBoxEntry* pEntry = SvTabListBox::InsertEntryToColumn( rStr, pParent, nPos, nCol, pUserData ); + RecalculateAccessibleChildren(); + return pEntry; +} + +// ----------------------------------------------------------------------- + +SvLBoxEntry* SvHeaderTabListBox::InsertEntryToColumn( + const XubString& rStr, const Image& rExpandedEntryBmp, const Image& rCollapsedEntryBmp, + SvLBoxEntry* pParent, sal_uLong nPos, sal_uInt16 nCol, void* pUserData ) +{ + SvLBoxEntry* pEntry = SvTabListBox::InsertEntryToColumn( + rStr, rExpandedEntryBmp, rCollapsedEntryBmp, pParent, nPos, nCol, pUserData ); + RecalculateAccessibleChildren(); + return pEntry; +} + +// ----------------------------------------------------------------------- + +sal_uLong SvHeaderTabListBox::Insert( + SvLBoxEntry* pEnt, SvLBoxEntry* pPar, sal_uLong nPos ) +{ + sal_uLong n = SvTabListBox::Insert( pEnt, pPar, nPos ); + RecalculateAccessibleChildren(); + return n; +} + +// ----------------------------------------------------------------------- + +sal_uLong SvHeaderTabListBox::Insert( SvLBoxEntry* pEntry, sal_uLong nRootPos ) +{ + sal_uLong nPos = SvTabListBox::Insert( pEntry, nRootPos ); + RecalculateAccessibleChildren(); + return nPos; +} + +// ----------------------------------------------------------------------- + +void SvHeaderTabListBox::RemoveEntry( SvLBoxEntry* _pEntry ) +{ + GetModel()->Remove( _pEntry ); + m_aAccessibleChildren.clear(); +} + +// ----------------------------------------------------------------------- + +void SvHeaderTabListBox::Clear() +{ + SvTabListBox::Clear(); + m_aAccessibleChildren.clear(); +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( SvHeaderTabListBox, ScrollHdl_Impl, SvTabListBox*, EMPTYARG ) +{ + m_pImpl->m_pHeaderBar->SetOffset( -GetXOffset() ); + return 0; +} + +// ----------------------------------------------------------------------- + +IMPL_LINK( SvHeaderTabListBox, CreateAccessibleHdl_Impl, HeaderBar*, EMPTYARG ) +{ + Window* pParent = m_pImpl->m_pHeaderBar->GetAccessibleParentWindow(); + DBG_ASSERT( pParent, "SvHeaderTabListBox..CreateAccessibleHdl_Impl - accessible parent not found" ); + if ( pParent ) + { + ::com::sun::star::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible(); + if ( xAccParent.is() ) + { + Reference< XAccessible > xAccessible = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxHeaderBar( + xAccParent, *this, ::svt::BBTYPE_COLUMNHEADERBAR ); + m_pImpl->m_pHeaderBar->SetAccessible( xAccessible ); + } + } + return 0; +} + +// ----------------------------------------------------------------------- + +void SvHeaderTabListBox::RecalculateAccessibleChildren() +{ + if ( !m_aAccessibleChildren.empty() ) + { + sal_uInt32 nCount = ( GetRowCount() + 1 ) * GetColumnCount(); + if ( m_aAccessibleChildren.size() < nCount ) + m_aAccessibleChildren.resize( nCount ); + else + { + DBG_ASSERT( m_aAccessibleChildren.size() == nCount, "wrong children count" ); + } + } +} + +// ----------------------------------------------------------------------- + +sal_Bool SvHeaderTabListBox::IsCellCheckBox( long _nRow, sal_uInt16 _nColumn, TriState& _rState ) +{ + sal_Bool bRet = sal_False; + SvLBoxEntry* pEntry = GetEntry( _nRow ); + if ( pEntry ) + { + sal_uInt16 nItemCount = pEntry->ItemCount(); + if ( nItemCount > ( _nColumn + 1 ) ) + { + SvLBoxButton* pItem = (SvLBoxButton*)( pEntry->GetItem( _nColumn + 1 ) ); + if ( pItem && ( (SvLBoxItem*)pItem )->IsA() == SV_ITEM_ID_LBOXBUTTON ) + { + bRet = sal_True; + _rState = ( ( pItem->GetButtonFlags() & SV_ITEMSTATE_UNCHECKED ) == 0 ) + ? STATE_CHECK : STATE_NOCHECK; + } + } + else + { + DBG_ERRORFILE( "SvHeaderTabListBox::IsCellCheckBox(): column out of range" ); + } + } + return bRet; +} + +// ----------------------------------------------------------------------- +long SvHeaderTabListBox::GetRowCount() const +{ + return GetEntryCount(); +} +// ----------------------------------------------------------------------- +sal_uInt16 SvHeaderTabListBox::GetColumnCount() const +{ + return m_pImpl->m_pHeaderBar->GetItemCount(); +} +// ----------------------------------------------------------------------- +sal_Int32 SvHeaderTabListBox::GetCurrRow() const +{ + sal_Int32 nRet = -1; + SvLBoxEntry* pEntry = GetCurEntry(); + if ( pEntry ) + { + sal_uLong nCount = GetEntryCount(); + for ( sal_uLong i = 0; i < nCount; ++i ) + { + if ( pEntry == GetEntry(i) ) + { + nRet = i; + break; + } + } + } + + return nRet; +} +// ----------------------------------------------------------------------- +sal_uInt16 SvHeaderTabListBox::GetCurrColumn() const +{ + sal_uInt16 nPos = GetCurrentTabPos() - 1; + return nPos; +} +// ----------------------------------------------------------------------- +::rtl::OUString SvHeaderTabListBox::GetRowDescription( sal_Int32 _nRow ) const +{ + return ::rtl::OUString( GetEntryText( _nRow ) ); +} +// ----------------------------------------------------------------------- +::rtl::OUString SvHeaderTabListBox::GetColumnDescription( sal_uInt16 _nColumn ) const +{ + return ::rtl::OUString( m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( _nColumn ) ) ); +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::HasRowHeader() const +{ + return sal_False; +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::IsCellFocusable() const +{ + return IsCellFocusEnabled(); +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::GoToCell( sal_Int32 _nRow, sal_uInt16 _nColumn ) +{ + sal_Bool bRet = ( IsCellFocusEnabled() == sal_True ); + if ( bRet ) + { + // first set cursor to _nRow + SetCursor( GetEntry( _nRow ), sal_True ); + // then set the focus into _nColumn + bRet = ( SetCurrentTabPos( _nColumn ) == true ); + } + return bRet; +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::SetNoSelection() +{ + SvLBox::SelectAll( sal_False ); +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::SelectAll() +{ + SvLBox::SelectAll( sal_True ); +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::SelectAll( sal_Bool bSelect, sal_Bool bPaint ) +{ + // overwritten just to disambiguate the SelectAll() from the base' class SelectAll( BOOl, sal_Bool ) + SvTabListBox::SelectAll( bSelect, bPaint ); +} + +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::SelectRow( long _nRow, sal_Bool _bSelect, sal_Bool ) +{ + Select( GetEntry( _nRow ), _bSelect ); +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::SelectColumn( sal_uInt16, sal_Bool ) +{ +} +// ----------------------------------------------------------------------- +sal_Int32 SvHeaderTabListBox::GetSelectedRowCount() const +{ + return GetSelectionCount(); +} +// ----------------------------------------------------------------------- +sal_Int32 SvHeaderTabListBox::GetSelectedColumnCount() const +{ + return 0; +} +// ----------------------------------------------------------------------- +bool SvHeaderTabListBox::IsRowSelected( long _nRow ) const +{ + SvLBoxEntry* pEntry = GetEntry( _nRow ); + return ( pEntry && IsSelected( pEntry ) ); +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::IsColumnSelected( long ) const +{ + return sal_False; +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::GetAllSelectedRows( ::com::sun::star::uno::Sequence< sal_Int32 >& ) const +{ +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::GetAllSelectedColumns( ::com::sun::star::uno::Sequence< sal_Int32 >& ) const +{ +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::IsCellVisible( sal_Int32, sal_uInt16 ) const +{ + return sal_True; +} +// ----------------------------------------------------------------------- +String SvHeaderTabListBox::GetAccessibleCellText( long _nRow, sal_uInt16 _nColumnPos ) const +{ + return ::rtl::OUString( GetTabEntryText( _nRow, _nColumnPos ) ); +} +// ----------------------------------------------------------------------- +Rectangle SvHeaderTabListBox::calcHeaderRect( sal_Bool _bIsColumnBar, sal_Bool _bOnScreen ) +{ + Rectangle aRect; + if ( _bIsColumnBar ) + { + Window* pParent = NULL; + if ( !_bOnScreen ) + pParent = m_pImpl->m_pHeaderBar->GetAccessibleParentWindow(); + + aRect = m_pImpl->m_pHeaderBar->GetWindowExtentsRelative( pParent ); + } + return aRect; +} +// ----------------------------------------------------------------------- +Rectangle SvHeaderTabListBox::calcTableRect( sal_Bool _bOnScreen ) +{ + Window* pParent = NULL; + if ( !_bOnScreen ) + pParent = GetAccessibleParentWindow(); + + Rectangle aRect( GetWindowExtentsRelative( pParent ) ); + return aRect; +} +// ----------------------------------------------------------------------- +Rectangle SvHeaderTabListBox::GetFieldRectPixelAbs( sal_Int32 _nRow, sal_uInt16 _nColumn, sal_Bool _bIsHeader, sal_Bool _bOnScreen ) +{ + DBG_ASSERT( !_bIsHeader || 0 == _nRow, "invalid parameters" ); + Rectangle aRect; + SvLBoxEntry* pEntry = GetEntry( _nRow ); + if ( pEntry ) + { + aRect = _bIsHeader ? calcHeaderRect( sal_True, sal_False ) : GetBoundingRect( pEntry ); + Point aTopLeft = aRect.TopLeft(); + DBG_ASSERT( m_pImpl->m_pHeaderBar->GetItemCount() > _nColumn, "invalid column" ); + Rectangle aItemRect = m_pImpl->m_pHeaderBar->GetItemRect( m_pImpl->m_pHeaderBar->GetItemId( _nColumn ) ); + aTopLeft.X() = aItemRect.Left(); + Size aSize = aItemRect.GetSize(); + aRect = Rectangle( aTopLeft, aSize ); + Window* pParent = NULL; + if ( !_bOnScreen ) + pParent = GetAccessibleParentWindow(); + aTopLeft = aRect.TopLeft(); + aTopLeft += GetWindowExtentsRelative( pParent ).TopLeft(); + aRect = Rectangle( aTopLeft, aRect.GetSize() ); + } + + return aRect; +} +// ----------------------------------------------------------------------- +Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleCell( sal_Int32 _nRow, sal_uInt16 _nColumnPos ) +{ + OSL_ENSURE( m_pAccessible, "Invalid call: Accessible is null" ); + + Reference< XAccessible > xChild; + sal_Int32 nIndex = -1; + + if ( !AreChildrenTransient() ) + { + const sal_uInt16 nColumnCount = GetColumnCount(); + + // first call? -> initial list + if ( m_aAccessibleChildren.empty() ) + { + sal_Int32 nCount = ( GetRowCount() + 1 ) * nColumnCount; + m_aAccessibleChildren.assign( nCount, Reference< XAccessible >() ); + } + + nIndex = ( _nRow * nColumnCount ) + _nColumnPos + nColumnCount; + xChild = m_aAccessibleChildren[ nIndex ]; + } + + if ( !xChild.is() ) + { + TriState eState = STATE_DONTKNOW; + sal_Bool bIsCheckBox = IsCellCheckBox( _nRow, _nColumnPos, eState ); + if ( bIsCheckBox ) + xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleCheckBoxCell( + m_pAccessible->getAccessibleChild( 0 ), *this, NULL, _nRow, _nColumnPos, eState, sal_True, sal_False ); + else + xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxTableCell( + m_pAccessible->getAccessibleChild( 0 ), *this, NULL, _nRow, _nColumnPos, OFFSET_NONE ); + + // insert into list + if ( !AreChildrenTransient() ) + m_aAccessibleChildren[ nIndex ] = xChild; + } + + return xChild; +} +// ----------------------------------------------------------------------- +Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleRowHeader( sal_Int32 ) +{ + Reference< XAccessible > xHeader; + return xHeader; +} +// ----------------------------------------------------------------------- +Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleColumnHeader( sal_uInt16 _nColumn ) +{ + // first call? -> initial list + if ( m_aAccessibleChildren.empty() ) + { + const sal_uInt16 nColumnCount = GetColumnCount(); + sal_Int32 nCount = AreChildrenTransient() ? + nColumnCount : ( GetRowCount() + 1 ) * nColumnCount; + m_aAccessibleChildren.assign( nCount, Reference< XAccessible >() ); + } + + // get header + Reference< XAccessible > xChild = m_aAccessibleChildren[ _nColumn ]; + // already exists? + if ( !xChild.is() && m_pAccessible ) + { + // no -> create new header cell + xChild = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleBrowseBoxHeaderCell( + _nColumn, m_pAccessible->getHeaderBar( ::svt::BBTYPE_COLUMNHEADERBAR ), + *this, NULL, ::svt::BBTYPE_COLUMNHEADERCELL + ); + + // insert into list + m_aAccessibleChildren[ _nColumn ] = xChild; + } + + return xChild; +} +// ----------------------------------------------------------------------- +sal_Int32 SvHeaderTabListBox::GetAccessibleControlCount() const +{ + return -1; +} +// ----------------------------------------------------------------------- +Reference< XAccessible > SvHeaderTabListBox::CreateAccessibleControl( sal_Int32 ) +{ + Reference< XAccessible > xControl; + return xControl; +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::ConvertPointToControlIndex( sal_Int32&, const Point& ) +{ + return sal_False; +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::ConvertPointToCellAddress( sal_Int32&, sal_uInt16&, const Point& ) +{ + return sal_False; +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::ConvertPointToRowHeader( sal_Int32&, const Point& ) +{ + return sal_False; +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::ConvertPointToColumnHeader( sal_uInt16&, const Point& ) +{ + return sal_False; +} +// ----------------------------------------------------------------------- +::rtl::OUString SvHeaderTabListBox::GetAccessibleObjectName( ::svt::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const +{ + ::rtl::OUString aRetText; + switch( _eType ) + { + case ::svt::BBTYPE_BROWSEBOX: + case ::svt::BBTYPE_TABLE: + case ::svt::BBTYPE_COLUMNHEADERBAR: + // should be empty now (see #i63983) + aRetText = ::rtl::OUString(); + break; + + case ::svt::BBTYPE_TABLECELL: + { + // here we need a valid pos, we can not handle -1 + if ( _nPos >= 0 ) + { + sal_uInt16 nColumnCount = GetColumnCount(); + if (nColumnCount > 0) + { + sal_Int32 nRow = _nPos / nColumnCount; + sal_uInt16 nColumn = static_cast< sal_uInt16 >( _nPos % nColumnCount ); + aRetText = GetCellText( nRow, nColumn ); + } + } + break; + } + case ::svt::BBTYPE_CHECKBOXCELL: + { + break; // checkbox cells have no name + } + case ::svt::BBTYPE_COLUMNHEADERCELL: + { + aRetText = m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( (sal_uInt16)_nPos ) ); + break; + } + + case ::svt::BBTYPE_ROWHEADERBAR: + case ::svt::BBTYPE_ROWHEADERCELL: + aRetText = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "error" ) ); + break; + + default: + OSL_ENSURE(0,"BrowseBox::GetAccessibleName: invalid enum!"); + } + return aRetText; +} +// ----------------------------------------------------------------------- +::rtl::OUString SvHeaderTabListBox::GetAccessibleObjectDescription( ::svt::AccessibleBrowseBoxObjType _eType, sal_Int32 _nPos ) const +{ + ::rtl::OUString aRetText; + + if( _eType == ::svt::BBTYPE_TABLECELL && _nPos != -1 ) + { + static const String sVar1( RTL_CONSTASCII_USTRINGPARAM( "%1" ) ); + static const String sVar2( RTL_CONSTASCII_USTRINGPARAM( "%2" ) ); + + sal_uInt16 nColumnCount = GetColumnCount(); + if (nColumnCount > 0) + { + sal_Int32 nRow = _nPos / nColumnCount; + sal_uInt16 nColumn = static_cast< sal_uInt16 >( _nPos % nColumnCount ); + + String aText( SvtResId( STR_SVT_ACC_DESC_TABLISTBOX ) ); + aText.SearchAndReplace( sVar1, String::CreateFromInt32( nRow ) ); + String sColHeader = m_pImpl->m_pHeaderBar->GetItemText( m_pImpl->m_pHeaderBar->GetItemId( nColumn ) ); + if ( sColHeader.Len() == 0 ) + sColHeader = String::CreateFromInt32( nColumn ); + aText.SearchAndReplace( sVar2, sColHeader ); + aRetText = aText; + } + } + + return aRetText; +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& _rStateSet, ::svt::AccessibleBrowseBoxObjType _eType ) const +{ + switch( _eType ) + { + case ::svt::BBTYPE_BROWSEBOX: + case ::svt::BBTYPE_TABLE: + { + _rStateSet.AddState( AccessibleStateType::FOCUSABLE ); + if ( HasFocus() ) + _rStateSet.AddState( AccessibleStateType::FOCUSED ); + if ( IsActive() ) + _rStateSet.AddState( AccessibleStateType::ACTIVE ); + if ( IsEnabled() ) + { + _rStateSet.AddState( AccessibleStateType::ENABLED ); + _rStateSet.AddState( AccessibleStateType::SENSITIVE ); + } + if ( IsReallyVisible() ) + _rStateSet.AddState( AccessibleStateType::VISIBLE ); + if ( _eType == ::svt::BBTYPE_TABLE ) + { + + if ( AreChildrenTransient() ) + _rStateSet.AddState( AccessibleStateType::MANAGES_DESCENDANTS ); + _rStateSet.AddState( AccessibleStateType::MULTI_SELECTABLE ); + } + break; + } + + case ::svt::BBTYPE_COLUMNHEADERBAR: + { + sal_Int32 nCurRow = GetCurrRow(); + sal_uInt16 nCurColumn = GetCurrColumn(); + if ( IsCellVisible( nCurRow, nCurColumn ) ) + _rStateSet.AddState( AccessibleStateType::VISIBLE ); + _rStateSet.AddState( AccessibleStateType::TRANSIENT ); + break; + } + + case ::svt::BBTYPE_ROWHEADERCELL: + case ::svt::BBTYPE_COLUMNHEADERCELL: + { + _rStateSet.AddState( AccessibleStateType::VISIBLE ); + _rStateSet.AddState( AccessibleStateType::FOCUSABLE ); + _rStateSet.AddState( AccessibleStateType::TRANSIENT ); + break; + } + default: + break; + } +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::FillAccessibleStateSetForCell( ::utl::AccessibleStateSetHelper& _rStateSet, sal_Int32 _nRow, sal_uInt16 _nColumn ) const +{ + _rStateSet.AddState( AccessibleStateType::SELECTABLE ); + if ( AreChildrenTransient() ) + _rStateSet.AddState( AccessibleStateType::TRANSIENT ); + + if ( IsCellVisible( _nRow, _nColumn ) ) + { + _rStateSet.AddState( AccessibleStateType::VISIBLE ); + _rStateSet.AddState( AccessibleStateType::ENABLED ); + } + + if ( IsRowSelected( _nRow ) ) + { + _rStateSet.AddState( AccessibleStateType::ACTIVE ); + _rStateSet.AddState( AccessibleStateType::SELECTED ); + } +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::GrabTableFocus() +{ + GrabFocus(); +} +// ----------------------------------------------------------------------- +sal_Bool SvHeaderTabListBox::GetGlyphBoundRects( const Point& rOrigin, const String& rStr, int nIndex, int nLen, int nBase, MetricVector& rVector ) +{ + return Control::GetGlyphBoundRects( rOrigin, rStr, nIndex, nLen, nBase, rVector ); +} +// ----------------------------------------------------------------------- +Rectangle SvHeaderTabListBox::GetWindowExtentsRelative( Window *pRelativeWindow ) const +{ + return Control::GetWindowExtentsRelative( pRelativeWindow ); +} +// ----------------------------------------------------------------------- +void SvHeaderTabListBox::GrabFocus() +{ + Control::GrabFocus(); +} +// ----------------------------------------------------------------------- +Reference< XAccessible > SvHeaderTabListBox::GetAccessible( sal_Bool bCreate ) +{ + return Control::GetAccessible( bCreate ); +} +// ----------------------------------------------------------------------- +Window* SvHeaderTabListBox::GetAccessibleParentWindow() const +{ + return Control::GetAccessibleParentWindow(); +} +// ----------------------------------------------------------------------- +Window* SvHeaderTabListBox::GetWindowInstance() +{ + return this; +} +// ----------------------------------------------------------------------- +Reference< XAccessible > SvHeaderTabListBox::CreateAccessible() +{ + Window* pParent = GetAccessibleParentWindow(); + DBG_ASSERT( pParent, "SvHeaderTabListBox::::CreateAccessible - accessible parent not found" ); + + Reference< XAccessible > xAccessible; + if ( m_pAccessible ) xAccessible = m_pAccessible->getMyself(); + + if( pParent && !m_pAccessible ) + { + Reference< XAccessible > xAccParent = pParent->GetAccessible(); + if ( xAccParent.is() ) + { + m_pAccessible = m_pImpl->m_aFactoryAccess.getFactory().createAccessibleTabListBox( xAccParent, *this ); + if ( m_pAccessible ) + xAccessible = m_pAccessible->getMyself(); + } + } + return xAccessible; +} +// ----------------------------------------------------------------------------- +Rectangle SvHeaderTabListBox::GetFieldCharacterBounds(sal_Int32,sal_Int32,sal_Int32) +{ + Rectangle aRect; + return aRect; +} +// ----------------------------------------------------------------------------- +sal_Int32 SvHeaderTabListBox::GetFieldIndexAtPoint(sal_Int32 _nRow,sal_Int32 _nColumnPos,const Point& _rPoint) +{ + String sText = GetAccessibleCellText( _nRow, static_cast< sal_uInt16 >( _nColumnPos ) ); + MetricVector aRects; + if ( GetGlyphBoundRects(Point(0,0),sText,0,STRING_LEN,0,aRects) ) + { + for (MetricVector::iterator aIter = aRects.begin(); aIter != aRects.end(); ++aIter) + { + if( aIter->IsInside(_rPoint) ) + return aIter - aRects.begin(); + } + } + + return -1; +} +// ----------------------------------------------------------------------------- + + diff --git a/svtools/source/contnr/svtreebx.cxx b/svtools/source/contnr/svtreebx.cxx new file mode 100644 index 000000000000..b48bcb0910ee --- /dev/null +++ b/svtools/source/contnr/svtreebx.cxx @@ -0,0 +1,2684 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#define _SVTREEBX_CXX +#include <vcl/svapp.hxx> +#ifndef GCC +#endif + +class TabBar; + +// #102891# ----------------------- + +#include <svtools/svlbox.hxx> +#include <svtools/svlbitm.hxx> +#include <svtools/svtreebx.hxx> +#include <tools/diagnose_ex.h> +#include <svimpbox.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/awt/XWindowPeer.hpp> + + +using namespace ::com::sun::star::accessibility; + +/* + Bugs/ToDo + + - Berechnung Rectangle beim Inplace-Editing (Bug bei manchen Fonts) + - SetSpaceBetweenEntries: Offset wird in SetEntryHeight nicht + beruecksichtigt +*/ + +#define TREEFLAG_FIXEDHEIGHT 0x0010 + + +DBG_NAME(SvTreeListBox) + +#define SV_LBOX_DEFAULT_INDENT_PIXEL 20 + +SvTreeListBox::SvTreeListBox( Window* pParent, WinBits nWinStyle ) + : SvLBox( pParent, nWinStyle ) +{ + DBG_CTOR(SvTreeListBox,0); + InitTreeView(); + + SetSublistOpenWithLeftRight(); +} + +SvTreeListBox::SvTreeListBox( Window* pParent , const ResId& rResId ) + : SvLBox( pParent,rResId ) +{ + DBG_CTOR(SvTreeListBox,0); + + InitTreeView(); + Resize(); + + SetSublistOpenWithLeftRight(); +} + +void SvTreeListBox::InitTreeView() +{ + DBG_CHKTHIS(SvTreeListBox,0); + pCheckButtonData = NULL; + pEdEntry = NULL; + pEdItem = NULL; + nEntryHeight = 0; + pEdCtrl = NULL; + nFirstSelTab = 0; + nLastSelTab = 0; + nFocusWidth = -1; + + Link* pLink = new Link( LINK(this,SvTreeListBox, DefaultCompare) ); + pLBoxImpl->m_pLink = pLink; + + nTreeFlags = TREEFLAG_RECALCTABS; + nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL; + nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL; + pImp = new SvImpLBox( this, GetModel(), GetStyle() ); + + aContextBmpMode = SVLISTENTRYFLAG_EXPANDED; + nContextBmpWidthMax = 0; + SetFont( GetFont() ); + SetSpaceBetweenEntries( 0 ); + SetLineColor(); + InitSettings( sal_True, sal_True, sal_True ); + ImplInitStyle(); + SetTabs(); +} + + +SvTreeListBox::~SvTreeListBox() +{ + DBG_DTOR(SvTreeListBox,0); + pImp->CallEventListeners( VCLEVENT_OBJECT_DYING ); + delete pImp; + delete pLBoxImpl->m_pLink; + ClearTabList(); +} + +void SvTreeListBox::SetExtendedWinBits( ExtendedWinBits _nBits ) +{ + pImp->SetExtendedWindowBits( _nBits ); +} + +ExtendedWinBits SvTreeListBox::GetExtendedWinBits() const +{ + return pImp->GetExtendedWindowBits(); +} + +void SvTreeListBox::SetModel( SvLBoxTreeList* pNewModel ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetModel( pNewModel ); + SvLBox::SetModel( pNewModel ); +} + +void SvTreeListBox::DisconnectFromModel() +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::DisconnectFromModel(); + pImp->SetModel( GetModel() ); +} + + +sal_uInt16 SvTreeListBox::IsA() +{ + DBG_CHKTHIS(SvTreeListBox,0); + return SV_LISTBOX_ID_TREEBOX; +} + +void SvTreeListBox::SetSublistOpenWithReturn( sal_Bool b ) +{ + pImp->bSubLstOpRet = b; +} + +sal_Bool SvTreeListBox::IsSublistOpenWithReturn() const +{ + return pImp->bSubLstOpRet; +} + +void SvTreeListBox::SetSublistOpenWithLeftRight( sal_Bool b ) +{ + pImp->bSubLstOpLR = b; +} + +sal_Bool SvTreeListBox::IsSublistOpenWithLeftRight() const +{ + return pImp->bSubLstOpLR; +} + +void SvTreeListBox::Resize() +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing( sal_True ); + SvLBox::Resize(); + pImp->Resize(); + nFocusWidth = -1; + pImp->ShowCursor( sal_False ); + pImp->ShowCursor( sal_True ); +} + +/* Faelle: + + A) Entries haben Bitmaps + 0. Keine Buttons + 1. Node-Buttons (optional auch an Root-Items) + 2. Node-Buttons (optional auch an Root-Items) + CheckButton + 3. CheckButton + B) Entries haben keine Bitmaps (->ueber WindowBits wg. D&D !!!!!!) + 0. Keine Buttons + 1. Node-Buttons (optional auch an Root-Items) + 2. Node-Buttons (optional auch an Root-Items) + CheckButton + 3. CheckButton +*/ + +#define NO_BUTTONS 0 +#define NODE_BUTTONS 1 +#define NODE_AND_CHECK_BUTTONS 2 +#define CHECK_BUTTONS 3 + +#define TABFLAGS_TEXT (SV_LBOXTAB_DYNAMIC | \ + SV_LBOXTAB_ADJUST_LEFT | \ + SV_LBOXTAB_EDITABLE | \ + SV_LBOXTAB_SHOW_SELECTION) + +#define TABFLAGS_CONTEXTBMP (SV_LBOXTAB_DYNAMIC | SV_LBOXTAB_ADJUST_CENTER) + +#define TABFLAGS_CHECKBTN (SV_LBOXTAB_DYNAMIC | \ + SV_LBOXTAB_ADJUST_CENTER | \ + SV_LBOXTAB_PUSHABLE) + +#define TAB_STARTPOS 2 + +// bei Aenderungen GetTextOffset beruecksichtigen +void SvTreeListBox::SetTabs() +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing( sal_True ); + nTreeFlags &= (~TREEFLAG_RECALCTABS); + nFocusWidth = -1; + const WinBits nStyle( GetStyle() ); + sal_Bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0; + sal_Bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT | + WB_HASBUTTONSATROOT))!=0; + long nStartPos = TAB_STARTPOS; + long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width(); + + long nCheckWidth = 0; + if( nTreeFlags & TREEFLAG_CHKBTN ) + nCheckWidth = pCheckButtonData->aBmps[0].GetSizePixel().Width(); + long nCheckWidthDIV2 = nCheckWidth / 2; + + long nContextWidth = nContextBmpWidthMax; + long nContextWidthDIV2 = nContextWidth / 2; + + ClearTabList(); + + int nCase = NO_BUTTONS; + if( !(nTreeFlags & TREEFLAG_CHKBTN) ) + { + if( bHasButtons ) + nCase = NODE_BUTTONS; + } + else + { + if( bHasButtons ) + nCase = NODE_AND_CHECK_BUTTONS; + else + nCase = CHECK_BUTTONS; + } + + switch( nCase ) + { + case NO_BUTTONS : + nStartPos += nContextWidthDIV2; // wg. Zentrierung + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + + case NODE_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + (nNodeWidthPixel/2) ); + else + nStartPos += nContextWidthDIV2; + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + + case NODE_AND_CHECK_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + nNodeWidthPixel ); + else + nStartPos += nCheckWidthDIV2; + AddTab( nStartPos, TABFLAGS_CHECKBTN ); + nStartPos += nCheckWidthDIV2; // rechter Rand des CheckButtons + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + + case CHECK_BUTTONS : + nStartPos += nCheckWidthDIV2; + AddTab( nStartPos, TABFLAGS_CHECKBTN ); + nStartPos += nCheckWidthDIV2; // rechter Rand CheckButton + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + AddTab( nStartPos, TABFLAGS_CONTEXTBMP ); + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + AddTab( nStartPos, TABFLAGS_TEXT ); + break; + } + pImp->NotifyTabsChanged(); +} + +void SvTreeListBox::InitEntry( SvLBoxEntry* pEntry, + const XubString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp, + SvLBoxButtonKind eButtonKind) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxButton* pButton; + SvLBoxString* pString; + SvLBoxContextBmp* pContextBmp; + + if( nTreeFlags & TREEFLAG_CHKBTN ) + { + pButton= new SvLBoxButton( pEntry,eButtonKind,0,pCheckButtonData ); + pEntry->AddItem( pButton ); + } + + pContextBmp= new SvLBoxContextBmp( pEntry,0, aCollEntryBmp,aExpEntryBmp, + aContextBmpMode ); + pEntry->AddItem( pContextBmp ); + + pString = new SvLBoxString( pEntry, 0, aStr ); + pEntry->AddItem( pString ); +} + +String SvTreeListBox::GetEntryText(SvLBoxEntry* pEntry) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): no entry" ); + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): item not found" ); + return pItem->GetText(); +} + +String SvTreeListBox::SearchEntryText( SvLBoxEntry* pEntry ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT( pEntry, "SvTreeListBox::SearchEntryText(): no entry" ); + String sRet; + sal_uInt16 nCount = pEntry->ItemCount(); + sal_uInt16 nCur = 0; + SvLBoxItem* pItem; + while( nCur < nCount ) + { + pItem = pEntry->GetItem( nCur ); + if ( pItem->IsA() == SV_ITEM_ID_LBOXSTRING && + static_cast<SvLBoxString*>( pItem )->GetText().Len() > 0 ) + { + sRet = static_cast<SvLBoxString*>( pItem )->GetText(); + break; + } + nCur++; + } + return sRet; +} + +const Image& SvTreeListBox::GetExpandedEntryBmp(SvLBoxEntry* pEntry, BmpColorMode _eMode) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"Entry?"); + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + DBG_ASSERT(pItem,"GetContextBmp:Item not found"); + return pItem->GetBitmap2( _eMode ); +} + +const Image& SvTreeListBox::GetCollapsedEntryBmp( SvLBoxEntry* pEntry, BmpColorMode _eMode ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"Entry?"); + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + DBG_ASSERT(pItem,"GetContextBmp:Item not found"); + return pItem->GetBitmap1( _eMode ); +} + +IMPL_LINK_INLINE_START( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pHdlEntry = pData->GetActEntry(); + CheckButtonHdl(); + return 0; +} +IMPL_LINK_INLINE_END( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData ) + +SvLBoxEntry* SvTreeListBox::InsertEntry( const XubString& aText,SvLBoxEntry* pParent, + sal_Bool bChildsOnDemand, sal_uLong nPos, void* pUser, + SvLBoxButtonKind eButtonKind ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nTreeFlags |= TREEFLAG_MANINS; + + const Image& rDefExpBmp = pImp->GetDefaultEntryExpBmp( ); + const Image& rDefColBmp = pImp->GetDefaultEntryColBmp( ); + + aCurInsertedExpBmp = rDefExpBmp; + aCurInsertedColBmp = rDefColBmp; + + SvLBoxEntry* pEntry = CreateEntry(); + pEntry->SetUserData( pUser ); + InitEntry( pEntry, aText, rDefColBmp, rDefExpBmp, eButtonKind ); + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + + // Add the HC versions of the default images + SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) ); + if( pBmpItem ) + { + pBmpItem->SetBitmap1( pImp->GetDefaultEntryColBmp( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST ); + pBmpItem->SetBitmap2( pImp->GetDefaultEntryExpBmp( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST ); + } + + if( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + + aPrevInsertedExpBmp = rDefExpBmp; + aPrevInsertedColBmp = rDefColBmp; + + nTreeFlags &= (~TREEFLAG_MANINS); + + return pEntry; +} + +SvLBoxEntry* SvTreeListBox::InsertEntry( const XubString& aText, + const Image& aExpEntryBmp, const Image& aCollEntryBmp, + SvLBoxEntry* pParent, sal_Bool bChildsOnDemand, sal_uLong nPos, void* pUser, + SvLBoxButtonKind eButtonKind ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nTreeFlags |= TREEFLAG_MANINS; + + aCurInsertedExpBmp = aExpEntryBmp; + aCurInsertedColBmp = aCollEntryBmp; + + SvLBoxEntry* pEntry = CreateEntry(); + pEntry->SetUserData( pUser ); + InitEntry( pEntry, aText, aCollEntryBmp, aExpEntryBmp, eButtonKind ); + + pEntry->EnableChildsOnDemand( bChildsOnDemand ); + + if( !pParent ) + SvLBox::Insert( pEntry, nPos ); + else + SvLBox::Insert( pEntry, pParent, nPos ); + + aPrevInsertedExpBmp = aExpEntryBmp; + aPrevInsertedColBmp = aCollEntryBmp; + + nTreeFlags &= (~TREEFLAG_MANINS); + + return pEntry; +} + +void SvTreeListBox::SetEntryText( SvLBoxEntry* pEntry, const XubString& aStr) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + DBG_ASSERT(pItem,"SetText:Item not found"); + pItem->SetText( pEntry, aStr ); + pItem->InitViewData( this, pEntry, 0 ); + GetModel()->InvalidateEntry( pEntry ); +} + +void SvTreeListBox::SetExpandedEntryBmp( SvLBoxEntry* pEntry, const Image& aBmp, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + + DBG_ASSERT(pItem,"SetExpBmp:Item not found"); + pItem->SetBitmap2( aBmp, _eMode ); + + GetModel()->InvalidateEntry( pEntry ); + SetEntryHeight( pEntry ); + Size aSize = aBmp.GetSizePixel(); + // #97680# --------------- + short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() ); + if( nWidth > nContextBmpWidthMax ) + { + nContextBmpWidthMax = nWidth; + SetTabs(); + } +} + +void SvTreeListBox::SetCollapsedEntryBmp(SvLBoxEntry* pEntry,const Image& aBmp, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + + DBG_ASSERT(pItem,"SetExpBmp:Item not found"); + pItem->SetBitmap1( aBmp, _eMode ); + + GetModel()->InvalidateEntry( pEntry ); + SetEntryHeight( pEntry ); + Size aSize = aBmp.GetSizePixel(); + // #97680# ----------- + short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() ); + if( nWidth > nContextBmpWidthMax ) + { + nContextBmpWidthMax = nWidth; + SetTabs(); + } +} + +void SvTreeListBox::ImpEntryInserted( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + SvLBoxEntry* pParent = (SvLBoxEntry*)pModel->GetParent( pEntry ); + if( pParent ) + { + sal_uInt16 nFlags = pParent->GetFlags(); + nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP; + pParent->SetFlags( nFlags ); + } + + if(!((nTreeFlags & TREEFLAG_MANINS) && + (aPrevInsertedExpBmp == aCurInsertedExpBmp) && + (aPrevInsertedColBmp == aCurInsertedColBmp) )) + { + Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + { + nContextBmpWidthMax = (short)aSize.Width(); + nTreeFlags |= TREEFLAG_RECALCTABS; + } + aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + { + nContextBmpWidthMax = (short)aSize.Width(); + nTreeFlags |= TREEFLAG_RECALCTABS; + } + } + SetEntryHeight( (SvLBoxEntry*)pEntry ); +} + + + +void SvTreeListBox::SetCheckButtonState( SvLBoxEntry* pEntry, SvButtonState eState) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nTreeFlags & TREEFLAG_CHKBTN ) + { + SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON)); + if(!(pItem && pItem->CheckModification())) + return ; + switch( eState ) + { + case SV_BUTTON_CHECKED: + pItem->SetStateChecked(); + break; + + case SV_BUTTON_UNCHECKED: + pItem->SetStateUnchecked(); + break; + + case SV_BUTTON_TRISTATE: + pItem->SetStateTristate(); + break; + } + InvalidateEntry( pEntry ); + } +} + +SvButtonState SvTreeListBox::GetCheckButtonState( SvLBoxEntry* pEntry ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvButtonState eState = SV_BUTTON_UNCHECKED; + if( nTreeFlags & TREEFLAG_CHKBTN ) + { + SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON)); + if(!pItem) + return SV_BUTTON_TRISTATE; + sal_uInt16 nButtonFlags = pItem->GetButtonFlags(); + eState = pCheckButtonData->ConvertToButtonState( nButtonFlags ); + } + return eState; +} + +void SvTreeListBox::CheckButtonHdl() +{ + DBG_CHKTHIS(SvTreeListBox,0); + aCheckButtonHdl.Call( this ); + if ( pCheckButtonData ) + pImp->CallEventListeners( VCLEVENT_CHECKBOX_TOGGLE, (void*)pCheckButtonData->GetActEntry() ); +} + +// ********************************************************************* +// ********************************************************************* + +// +// TODO: Momentan werden die Daten so geklont, dass sie dem +// Standard-TreeView-Format entsprechen. Hier sollte eigentlich +// das Model als Referenz dienen. Dies fuehrt dazu, dass +// SvLBoxEntry::Clone _nicht_ gerufen wird, sondern nur dessen +// Basisklasse SvListEntry +// + +SvLBoxEntry* SvTreeListBox::CloneEntry( SvLBoxEntry* pSource ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + XubString aStr; + Image aCollEntryBmp; + Image aExpEntryBmp; + SvLBoxButtonKind eButtonKind = SvLBoxButtonKind_enabledCheckbox; + + SvLBoxString* pStringItem = (SvLBoxString*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXSTRING)); + if( pStringItem ) + aStr = pStringItem->GetText(); + SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP)); + if( pBmpItem ) + { + aCollEntryBmp = pBmpItem->GetBitmap1( BMP_COLOR_NORMAL ); + aExpEntryBmp = pBmpItem->GetBitmap2( BMP_COLOR_NORMAL ); + } + SvLBoxButton* pButtonItem = (SvLBoxButton*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXBUTTON)); + if( pButtonItem ) + eButtonKind = pButtonItem->GetKind(); + SvLBoxEntry* pClone = CreateEntry(); + InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp, eButtonKind ); + pClone->SvListEntry::Clone( pSource ); + pClone->EnableChildsOnDemand( pSource->HasChildsOnDemand() ); + pClone->SetUserData( pSource->GetUserData() ); + + if ( pBmpItem ) + { + SvLBoxContextBmp* pCloneBitmap = static_cast< SvLBoxContextBmp* >( pClone->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) ); + if ( pCloneBitmap ) + { + pCloneBitmap->SetBitmap1( pBmpItem->GetBitmap1( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST ); + pCloneBitmap->SetBitmap2( pBmpItem->GetBitmap2( BMP_COLOR_HIGHCONTRAST ), BMP_COLOR_HIGHCONTRAST ); + } + } + + return pClone; +} + +// ********************************************************************* +// ********************************************************************* + + +void SvTreeListBox::ShowExpandBitmapOnCursor( sal_Bool bYes ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( bYes ) + aContextBmpMode = SVLISTENTRYFLAG_FOCUSED; + else + aContextBmpMode = SVLISTENTRYFLAG_EXPANDED; +} + +void SvTreeListBox::SetIndent( short nNewIndent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nIndent = nNewIndent; + SetTabs(); + if( IsUpdateMode() ) + Invalidate(); +} + +const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( BmpColorMode _eMode ) const +{ + return pImp->GetDefaultEntryExpBmp( _eMode ); +} + +const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( BmpColorMode _eMode ) const +{ + return pImp->GetDefaultEntryColBmp( _eMode ); +} + +void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize = aBmp.GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + nContextBmpWidthMax = (short)aSize.Width(); + SetTabs(); + + pImp->SetDefaultEntryExpBmp( aBmp, _eMode ); +} + +void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize = aBmp.GetSizePixel(); + if( aSize.Width() > nContextBmpWidthMax ) + nContextBmpWidthMax = (short)aSize.Width(); + SetTabs(); + + pImp->SetDefaultEntryColBmp( aBmp, _eMode ); +} + +void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(!GetEntryCount(),"EnableCheckButton: Entry count != 0"); + if( !pData ) + nTreeFlags &= (~TREEFLAG_CHKBTN); + else + { + SetCheckButtonData( pData ); + nTreeFlags |= TREEFLAG_CHKBTN; + pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick)); + } + + SetTabs(); + if( IsUpdateMode() ) + Invalidate(); +} + +void SvTreeListBox::SetCheckButtonData( SvLBoxButtonData* pData ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if ( pData ) + pCheckButtonData = pData; +} + +const Image& SvTreeListBox::GetDefaultExpandedNodeImage( BmpColorMode _eMode ) +{ + return SvImpLBox::GetDefaultExpandedNodeImage( _eMode ); +} + +const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( BmpColorMode _eMode ) +{ + return SvImpLBox::GetDefaultCollapsedNodeImage( _eMode ); +} + +void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, const Image& rExpandedNodeBmp, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SetExpandedNodeBmp( rExpandedNodeBmp, _eMode ); + SetCollapsedNodeBmp( rCollapsedNodeBmp, _eMode ); + SetTabs(); +} + +void SvTreeListBox::SetDontKnowNodeBitmap( const Image& rDontKnowBmp, BmpColorMode _eMode ) +{ + pImp->SetDontKnowNodeBmp( rDontKnowBmp, _eMode ); +} + +sal_Bool SvTreeListBox::EditingEntry( SvLBoxEntry*, Selection& ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + return sal_True; +} + +sal_Bool SvTreeListBox::EditedEntry( SvLBoxEntry* /*pEntry*/,const XubString& /*rNewText*/) +{ + DBG_CHKTHIS(SvTreeListBox,0); + return sal_True; +} + +void SvTreeListBox::EnableInplaceEditing( sal_Bool bOn ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::EnableInplaceEditing( bOn ); +} + +void SvTreeListBox::KeyInput( const KeyEvent& rKEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + // unter OS/2 bekommen wir auch beim Editieren Key-Up/Down + if( IsEditingActive() ) + return; + + nImpFlags |= SVLBOX_IS_TRAVELSELECT; + +#ifdef OVDEBUG + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + switch ( nCode ) + { + case KEY_F1: + { + SvLBoxEntry* pEntry = First(); + pEntry = NextVisible( pEntry ); + SetEntryText( pEntry, "SetEntryText" ); + Sound::Beep(); + } + break; + } +#endif + + if( !pImp->KeyInput( rKEvt ) ) + SvLBox::KeyInput( rKEvt ); + + nImpFlags &= ~SVLBOX_IS_TRAVELSELECT; +} + +void SvTreeListBox::RequestingChilds( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( !pParent->HasChilds() ) + InsertEntry( String::CreateFromAscii("<dummy>"), pParent, sal_False, LIST_APPEND ); +} + +void SvTreeListBox::GetFocus() +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->GetFocus(); + SvLBox::GetFocus(); + + SvLBoxEntry* pEntry = FirstSelected(); + if ( pEntry ) + pImp->CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry ); + +} + +void SvTreeListBox::LoseFocus() +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->LoseFocus(); + SvLBox::LoseFocus(); +} + +void SvTreeListBox::ModelHasCleared() +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->pCursor = 0; //sonst Absturz beim Inplace-Editieren im GetFocus + delete pEdCtrl; + pEdCtrl = NULL; + pImp->Clear(); + nFocusWidth = -1; + + nContextBmpWidthMax = 0; + SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() ); + SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() ); + + if( !(nTreeFlags & TREEFLAG_FIXEDHEIGHT )) + nEntryHeight = 0; + AdjustEntryHeight( GetFont() ); + AdjustEntryHeight( GetDefaultExpandedEntryBmp() ); + AdjustEntryHeight( GetDefaultCollapsedEntryBmp() ); + + SvLBox::ModelHasCleared(); +// if( IsUpdateMode() ) +// Invalidate(); +} + +void SvTreeListBox::ShowTargetEmphasis( SvLBoxEntry* pEntry, sal_Bool /* bShow */ ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->PaintDDCursor( pEntry ); +} + +void SvTreeListBox::ScrollOutputArea( short nDeltaEntries ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( !nDeltaEntries || !pImp->aVerSBar.IsVisible() ) + return; + + long nThumb = pImp->aVerSBar.GetThumbPos(); + long nMax = pImp->aVerSBar.GetRange().Max(); + + NotifyBeginScroll(); + if( nDeltaEntries < 0 ) + { + // das Fenster nach oben verschieben + nDeltaEntries *= -1; + long nVis = pImp->aVerSBar.GetVisibleSize(); + long nTemp = nThumb + nVis; + if( nDeltaEntries > (nMax - nTemp) ) + nDeltaEntries = (short)(nMax - nTemp); + pImp->PageDown( (sal_uInt16)nDeltaEntries ); + } + else + { + if( nDeltaEntries > nThumb ) + nDeltaEntries = (short)nThumb; + pImp->PageUp( (sal_uInt16)nDeltaEntries ); + } + pImp->SyncVerThumb(); + NotifyEndScroll(); +} + +void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::SetSelectionMode( eSelectMode ); + pImp->SetSelectionMode( eSelectMode ); +} + +void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::SetDragDropMode( nDDMode ); + pImp->SetDragDropMode( nDDMode ); +} + +short SvTreeListBox::GetHeightOffset(const Image& rBmp, Size& aSizeLogic ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + short nOffset = 0; + aSizeLogic = rBmp.GetSizePixel(); + if( GetEntryHeight() > aSizeLogic.Height() ) + nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2; + return nOffset; +} + +short SvTreeListBox::GetHeightOffset(const Font& /* rFont */, Size& aSizeLogic ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + short nOffset = 0; + aSizeLogic = Size(GetTextWidth('X'), GetTextHeight()); + if( GetEntryHeight() > aSizeLogic.Height() ) + nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2; + return nOffset; +} + +void SvTreeListBox::SetEntryHeight( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + short nHeight, nHeightMax=0; + sal_uInt16 nCount = pEntry->ItemCount(); + sal_uInt16 nCur = 0; + SvViewDataEntry* pViewData = GetViewDataEntry( pEntry ); + while( nCur < nCount ) + { + SvLBoxItem* pItem = pEntry->GetItem( nCur ); + nHeight = (short)(pItem->GetSize( pViewData, nCur ).Height()); + if( nHeight > nHeightMax ) + nHeightMax = nHeight; + nCur++; + } + + if( nHeightMax > nEntryHeight ) + { + nEntryHeight = nHeightMax; + SvLBox::SetFont( GetFont() ); + pImp->SetEntryHeight( nHeightMax ); + } +} + +void SvTreeListBox::SetEntryHeight( short nHeight, sal_Bool bAlways ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + if( bAlways || nHeight > nEntryHeight ) + { + nEntryHeight = nHeight; + if( nEntryHeight ) + nTreeFlags |= TREEFLAG_FIXEDHEIGHT; + else + nTreeFlags &= ~TREEFLAG_FIXEDHEIGHT; + SvLBox::SetFont( GetFont() ); + pImp->SetEntryHeight( nHeight ); + } +} + + +void SvTreeListBox::AdjustEntryHeight( const Image& rBmp ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize; + GetHeightOffset( rBmp, aSize ); + if( aSize.Height() > nEntryHeight ) + { + nEntryHeight = (short)aSize.Height() + nEntryHeightOffs; + pImp->SetEntryHeight( nEntryHeight ); + } +} + +void SvTreeListBox::AdjustEntryHeight( const Font& rFont ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize; + GetHeightOffset( rFont, aSize ); + if( aSize.Height() > nEntryHeight ) + { + nEntryHeight = (short)aSize.Height() + nEntryHeightOffs; + pImp->SetEntryHeight( nEntryHeight ); + } +} + +sal_Bool SvTreeListBox::Expand( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pHdlEntry = pParent; + sal_Bool bExpanded = sal_False; + sal_uInt16 nFlags; + + if( pParent->HasChildsOnDemand() ) + RequestingChilds( pParent ); + if( pParent->HasChilds() ) + { + nImpFlags |= SVLBOX_IS_EXPANDING; + if( ExpandingHdl() ) + { + bExpanded = sal_True; + SvListView::Expand( pParent ); + pImp->EntryExpanded( pParent ); + pHdlEntry = pParent; + ExpandedHdl(); + } + nFlags = pParent->GetFlags(); + nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP; + nFlags |= SV_ENTRYFLAG_HAD_CHILDREN; + pParent->SetFlags( nFlags ); + } + else + { + nFlags = pParent->GetFlags(); + nFlags |= SV_ENTRYFLAG_NO_NODEBMP; + pParent->SetFlags( nFlags ); + GetModel()->InvalidateEntry( pParent ); // neu zeichnen + } + + // --> OD 2009-04-01 #i92103# + if ( bExpanded ) + { + pImp->CallEventListeners( VCLEVENT_ITEM_EXPANDED, pParent ); + } + // <-- + + return bExpanded; +} + +sal_Bool SvTreeListBox::Collapse( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nImpFlags &= ~SVLBOX_IS_EXPANDING; + pHdlEntry = pParent; + sal_Bool bCollapsed = sal_False; + + if( ExpandingHdl() ) + { + bCollapsed = sal_True; + pImp->CollapsingEntry( pParent ); + SvListView::Collapse( pParent ); + pImp->EntryCollapsed( pParent ); + pHdlEntry = pParent; + ExpandedHdl(); + } + + // --> OD 2009-04-01 #i92103# + if ( bCollapsed ) + { + pImp->CallEventListeners( VCLEVENT_ITEM_COLLAPSED, pParent ); + } + // <-- + + return bCollapsed; +} + +sal_Bool SvTreeListBox::Select( SvLBoxEntry* pEntry, sal_Bool bSelect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"Select: Null-Ptr"); + sal_Bool bRetVal = SvListView::Select( pEntry, bSelect ); + DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed"); + if( bRetVal ) + { + pImp->EntrySelected( pEntry, bSelect ); + pHdlEntry = pEntry; + if( bSelect ) + { + SelectHdl(); + pImp->CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry ); + } + else + DeselectHdl(); + } + return bRetVal; +} + +sal_uLong SvTreeListBox::SelectChilds( SvLBoxEntry* pParent, sal_Bool bSelect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->DestroyAnchor(); + sal_uLong nRet = 0; + if( !pParent->HasChilds() ) + return 0; + sal_uInt16 nRefDepth = pModel->GetDepth( pParent ); + SvLBoxEntry* pChild = FirstChild( pParent ); + do { + nRet++; + Select( pChild, bSelect ); + pChild = Next( pChild ); + } while( pChild && pModel->GetDepth( pChild ) > nRefDepth ); + return nRet; +} + +void SvTreeListBox::SelectAll( sal_Bool bSelect, sal_Bool ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SelAllDestrAnch( + bSelect, + sal_True, // Anker loeschen, + sal_True ); // auch bei SINGLE_SELECTION den Cursor deselektieren +} + +void SvTreeListBox::ModelHasInsertedTree( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + sal_uInt16 nRefDepth = pModel->GetDepth( (SvLBoxEntry*)pEntry ); + SvLBoxEntry* pTmp = (SvLBoxEntry*)pEntry; + do + { + ImpEntryInserted( pTmp ); + pTmp = Next( pTmp ); + } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) ); + pImp->TreeInserted( (SvLBoxEntry*)pEntry ); +} + +void SvTreeListBox::ModelHasInserted( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + ImpEntryInserted( (SvLBoxEntry*)pEntry ); + pImp->EntryInserted( (SvLBoxEntry*)pEntry ); +} + +void SvTreeListBox::ModelIsMoving(SvListEntry* pSource, + SvListEntry* /* pTargetParent */, + sal_uLong /* nChildPos */ ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MovingEntry( (SvLBoxEntry*)pSource ); +} + +void SvTreeListBox::ModelHasMoved( SvListEntry* pSource ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->EntryMoved( (SvLBoxEntry*)pSource ); +} + +void SvTreeListBox::ModelIsRemoving( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if(pEdEntry == pEntry) + pEdEntry = NULL; + + pImp->RemovingEntry( (SvLBoxEntry*)pEntry ); + NotifyRemoving( (SvLBoxEntry*)pEntry ); +} + +void SvTreeListBox::ModelHasRemoved( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if ( pEntry == pHdlEntry) + pHdlEntry = NULL; + pImp->EntryRemoved(); +} + +void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + AdjustEntryHeight( rBmp ); + pImp->SetCollapsedNodeBmp( rBmp, _eMode ); +} + +void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp, BmpColorMode _eMode ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + AdjustEntryHeight( rBmp ); + pImp->SetExpandedNodeBmp( rBmp, _eMode ); +} + + +void SvTreeListBox::SetFont( const Font& rFont ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Font aTempFont( rFont ); + aTempFont.SetTransparent( sal_True ); + Control::SetFont( aTempFont ); + AdjustEntryHeight( aTempFont ); + // immer Invalidieren, sonst fallen wir + // bei SetEntryHeight auf die Nase + RecalcViewData(); +} + + +void SvTreeListBox::Paint( const Rectangle& rRect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::Paint( rRect ); + if( nTreeFlags & TREEFLAG_RECALCTABS ) + SetTabs(); + pImp->Paint( rRect ); +} + +void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MouseButtonDown( rMEvt ); +} + +void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MouseButtonUp( rMEvt ); +} + +void SvTreeListBox::MouseMove( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->MouseMove( rMEvt ); +} + + +void SvTreeListBox::SetUpdateMode( sal_Bool bUpdate ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetUpdateMode( bUpdate ); +} + +void SvTreeListBox::SetUpdateModeFast( sal_Bool bUpdate ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetUpdateModeFast( bUpdate ); +} + +void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nOffsLogic != nEntryHeightOffs ) + { + nEntryHeight = nEntryHeight - nEntryHeightOffs; + nEntryHeightOffs = (short)nOffsLogic; + nEntryHeight = nEntryHeight + nOffsLogic; + AdjustEntryHeight( GetFont() ); + RecalcViewData(); + pImp->SetEntryHeight( nEntryHeight ); + } +} + +void SvTreeListBox::SetCursor( SvLBoxEntry* pEntry, sal_Bool bForceNoSelect ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetCursor(pEntry, bForceNoSelect); +} + +void SvTreeListBox::SetCurEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + pImp->SetCurEntry( pEntry ); +} + +Image SvTreeListBox::GetCollapsedNodeBmp( BmpColorMode _eMode ) const +{ + return pImp->GetCollapsedNodeBmp( _eMode ); +} + +Image SvTreeListBox::GetExpandedNodeBmp( BmpColorMode _eMode ) const +{ + return pImp->GetExpandedNodeBmp( _eMode ); +} + +Point SvTreeListBox::GetEntryPosition( SvLBoxEntry* pEntry ) const +{ + return pImp->GetEntryPosition( pEntry ); +} + +void SvTreeListBox::ShowEntry( SvLBoxEntry* pEntry ) +{ + MakeVisible( pEntry ); +} + +void SvTreeListBox::MakeVisible( SvLBoxEntry* pEntry ) +{ + pImp->MakeVisible(pEntry); +} + +void SvTreeListBox::MakeVisible( SvLBoxEntry* pEntry, sal_Bool bMoveToTop ) +{ + pImp->MakeVisible( pEntry, bMoveToTop ); +} + +void SvTreeListBox::ModelHasEntryInvalidated( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + // die einzelnen Items des Entries reinitialisieren + SvLBox::ModelHasEntryInvalidated( pEntry ); + // repainten + pImp->InvalidateEntry( (SvLBoxEntry*)pEntry ); +} + +void SvTreeListBox::EditItemText( SvLBoxEntry* pEntry, SvLBoxString* pItem, + const Selection& rSelection ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry&&pItem,"EditItemText: Bad params"); + if( IsSelected( pEntry )) + { + pImp->ShowCursor( sal_False ); + SvListView::Select( pEntry, sal_False ); + PaintEntry( pEntry ); + SvListView::Select( pEntry, sal_True ); + pImp->ShowCursor( sal_True ); + } + pEdEntry = pEntry; + pEdItem = pItem; + SvLBoxTab* pTab = GetTab( pEntry, pItem ); + DBG_ASSERT(pTab,"EditItemText:Tab not found"); + + Size aItemSize( pItem->GetSize(this, pEntry) ); + Point aPos = GetEntryPosition( pEntry ); + aPos.Y() += ( nEntryHeight - aItemSize.Height() ) / 2; + aPos.X() = GetTabPos( pEntry, pTab ); + long nOutputWidth = pImp->GetOutputSize().Width(); + Size aSize( nOutputWidth - aPos.X(), aItemSize.Height() ); + sal_uInt16 nPos = aTabs.GetPos( pTab ); + if( nPos+1 < aTabs.Count() ) + { + SvLBoxTab* pRightTab = (SvLBoxTab*)aTabs.GetObject( nPos + 1 ); + long nRight = GetTabPos( pEntry, pRightTab ); + if( nRight <= nOutputWidth ) + aSize.Width() = nRight - aPos.X(); + } + Point aOrigin( GetMapMode().GetOrigin() ); + aPos += aOrigin; // in Win-Koord umrechnen + aSize.Width() -= aOrigin.X(); + Rectangle aRect( aPos, aSize ); +#ifdef OS2 + // Platz lassen fuer WB_BORDER + aRect.Left() -= 2; + aRect.Top() -= 3; + aRect.Bottom() += 3; +#endif + EditText( pItem->GetText(), aRect, rSelection ); +} + +void SvTreeListBox::CancelEditing() +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBox::CancelTextEditing(); +} + +void SvTreeListBox::EditEntry( SvLBoxEntry* pEntry ) +{ + pImp->aEditClickPos = Point( -1, -1 ); + ImplEditEntry( pEntry ); +} + +void SvTreeListBox::ImplEditEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing(); + if( !pEntry ) + pEntry = GetCurEntry(); + if( pEntry ) + { + long nClickX = pImp->aEditClickPos.X(); + bool bIsMouseTriggered = nClickX >= 0; + + SvLBoxString* pItem = NULL; + sal_uInt16 nCount = pEntry->ItemCount(); + for( sal_uInt16 i = 0 ; i < nCount ; i++ ) + { + SvLBoxItem* pTmpItem = pEntry->GetItem( i ); + if( pTmpItem->IsA() != SV_ITEM_ID_LBOXSTRING ) + continue; + + SvLBoxTab* pTab = GetTab( pEntry, pTmpItem ); + long nTabPos = pTab->GetPos(); + long nNextTabPos = -1; + if( i < nCount - 1 ) + { + SvLBoxItem* pNextItem = pEntry->GetItem( i + 1 ); + SvLBoxTab* pNextTab = GetTab( pEntry, pNextItem ); + nNextTabPos = pNextTab->GetPos(); + } + + if( pTab && pTab->IsEditable() ) + { + if( !bIsMouseTriggered || (nClickX > nTabPos && (nNextTabPos == -1 || nClickX < nNextTabPos ) ) ) + { + pItem = static_cast<SvLBoxString*>( pTmpItem ); + break; + } + } + } + + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if( pItem && EditingEntry( pEntry, aSel ) ) + { + SelectAll( sal_False ); + MakeVisible( pEntry ); + EditItemText( pEntry, pItem, aSel ); + } + } +} + +sal_Bool SvTreeListBox::AreChildrenTransient() const +{ + return pImp->AreChildrenTransient(); +} + +void SvTreeListBox::SetChildrenNotTransient() +{ + pImp->SetChildrenNotTransient(); +} + +void SvTreeListBox::EditedText( const XubString& rStr ) + +{ + DBG_CHKTHIS(SvTreeListBox,0); + if(pEdEntry) // we have to check if this entry is null that means that it is removed while editing + { + Point aPos = GetEntryPosition( pEdEntry ); + if( EditedEntry( pEdEntry, rStr ) ) + { + ((SvLBoxString*)pEdItem)->SetText( pEdEntry, rStr ); + pModel->InvalidateEntry( pEdEntry ); + } + //if( GetSelectionMode() == SINGLE_SELECTION ) + //{ + if( GetSelectionCount() == 0 ) + Select( pEdEntry ); + if( GetSelectionMode() == MULTIPLE_SELECTION && !GetCurEntry() ) + SetCurEntry( pEdEntry ); + //} + } +} + +void SvTreeListBox::EditingRequest( SvLBoxEntry* pEntry, SvLBoxItem* pItem, + const Point& ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( IsEditingActive() ) + EndEditing(); + if( pItem->IsA() == SV_ITEM_ID_LBOXSTRING ) + { + Selection aSel( SELECTION_MIN, SELECTION_MAX ); + if( EditingEntry( pEntry, aSel ) ) + { + SelectAll( sal_False ); + EditItemText( pEntry, (SvLBoxString*)pItem, aSel ); + } + } +} + + + +SvLBoxEntry* SvTreeListBox::GetDropTarget( const Point& rPos ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + // Scrollen + if( rPos.Y() < 12 ) + { + SvLBox::ImplShowTargetEmphasis( SvLBox::pTargetEntry, sal_False ); + ScrollOutputArea( +1 ); + } + else + { + Size aSize( pImp->GetOutputSize() ); + if( rPos.Y() > aSize.Height() - 12 ) + { + SvLBox::ImplShowTargetEmphasis( SvLBox::pTargetEntry, sal_False ); + ScrollOutputArea( -1 ); + } + } + + SvLBoxEntry* pTarget = pImp->GetEntry( rPos ); + // bei Droppen in leere Flaeche -> den letzten Eintrag nehmen + if( !pTarget ) + return (SvLBoxEntry*)LastVisible(); + else if( (GetDragDropMode() & SV_DRAGDROP_ENABLE_TOP) && + pTarget == First() && rPos.Y() < 6 ) + return 0; + + return pTarget; +} + + +SvLBoxEntry* SvTreeListBox::GetEntry( const Point& rPos, sal_Bool bHit ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxEntry* pEntry = pImp->GetEntry( rPos ); + if( pEntry && bHit ) + { + long nLine = pImp->GetEntryLine( pEntry ); + if( !(pImp->EntryReallyHit( pEntry, rPos, nLine)) ) + return 0; + } + return pEntry; +} + +SvLBoxEntry* SvTreeListBox::GetCurEntry() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + return pImp->GetCurEntry(); +} + +void SvTreeListBox::ImplInitStyle() +{ + DBG_CHKTHIS(SvTreeListBox,0); + + const WinBits nWindowStyle = GetStyle(); + + nTreeFlags |= TREEFLAG_RECALCTABS; + if( nWindowStyle & WB_SORT ) + { + GetModel()->SetSortMode( SortAscending ); + GetModel()->SetCompareHdl( LINK(this,SvTreeListBox,DefaultCompare)); + } + else + { + GetModel()->SetSortMode( SortNone ); + GetModel()->SetCompareHdl( Link() ); + } +#ifdef OS2 + nWindowStyle |= WB_VSCROLL; +#endif + pImp->SetStyle( nWindowStyle ); + pImp->Resize(); + Invalidate(); +} + +void SvTreeListBox::PaintEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"PaintEntry:No Entry"); + if( pEntry ) + pImp->PaintEntry( pEntry ); +} + +void SvTreeListBox::InvalidateEntry( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pEntry,"InvalidateEntry:No Entry"); + if( pEntry ) + { + GetModel()->InvalidateEntry( pEntry ); + // pImp->InvalidateEntry( pEntry ); + } +} + + +long SvTreeListBox::PaintEntry(SvLBoxEntry* pEntry,long nLine,sal_uInt16 nTabFlags) +{ + return PaintEntry1(pEntry,nLine,nTabFlags); +} + +#define SV_TAB_BORDER 8 + +long SvTreeListBox::PaintEntry1(SvLBoxEntry* pEntry,long nLine,sal_uInt16 nTabFlags, + sal_Bool bHasClipRegion ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + Rectangle aRect; // multi purpose + + sal_Bool bHorSBar = pImp->HasHorScrollBar(); + PreparePaint( pEntry ); + + // #97680# ------------------ + pImp->UpdateContextBmpWidthMax( pEntry ); + + if( nTreeFlags & TREEFLAG_RECALCTABS ) + SetTabs(); + + short nTempEntryHeight = GetEntryHeight(); + long nWidth = pImp->GetOutputSize().Width(); + + // wurde innerhalb des PreparePaints die horizontale ScrollBar + // angeschaltet? Wenn ja, muss die ClipRegion neu gesetzt werden + if( !bHorSBar && pImp->HasHorScrollBar() ) + SetClipRegion( Region(pImp->GetClipRegionRect()) ); + + Point aEntryPos( GetMapMode().GetOrigin() ); + aEntryPos.X() *= -1; // Umrechnung Dokumentkoord. + long nMaxRight = nWidth + aEntryPos.X() - 1; + + Color aBackupTextColor( GetTextColor() ); + Font aBackupFont( GetFont() ); + Color aBackupColor = GetFillColor(); + + bool bCurFontIsSel = false; + sal_Bool bInUse = pEntry->HasInUseEmphasis(); + // wenn eine ClipRegion von aussen gesetzt wird, dann + // diese nicht zuruecksetzen + const WinBits nWindowStyle = GetStyle(); + const sal_Bool bResetClipRegion = !bHasClipRegion; + const sal_Bool bHideSelection = ((nWindowStyle & WB_HIDESELECTION) && !HasFocus())!=0; + const StyleSettings& rSettings = GetSettings().GetStyleSettings(); + + Font aHighlightFont( GetFont() ); + const Color aHighlightTextColor( rSettings.GetHighlightTextColor() ); + aHighlightFont.SetColor( aHighlightTextColor ); + + Size aRectSize( 0, nTempEntryHeight ); + + if( !bHasClipRegion && nWindowStyle & WB_HSCROLL ) + { + SetClipRegion( Region(pImp->GetClipRegionRect()) ); + bHasClipRegion = sal_True; + } + + SvViewDataEntry* pViewDataEntry = GetViewDataEntry( pEntry ); + + sal_uInt16 nTabCount = aTabs.Count(); + sal_uInt16 nItemCount = pEntry->ItemCount(); + sal_uInt16 nCurTab = 0; + sal_uInt16 nCurItem = 0; + + while( nCurTab < nTabCount && nCurItem < nItemCount ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject( nCurTab ); + sal_uInt16 nNextTab = nCurTab + 1; + SvLBoxTab* pNextTab = nNextTab < nTabCount ? (SvLBoxTab*)aTabs.GetObject(nNextTab) : 0; + SvLBoxItem* pItem = nCurItem < nItemCount ? pEntry->GetItem(nCurItem) : 0; + + sal_uInt16 nFlags = pTab->nFlags; + Size aSize( pItem->GetSize( pViewDataEntry, nCurItem )); + long nTabPos = GetTabPos( pEntry, pTab ); + + long nNextTabPos; + if( pNextTab ) + nNextTabPos = GetTabPos( pEntry, pNextTab ); + else + { + nNextTabPos = nMaxRight; + if( nTabPos > nMaxRight ) + nNextTabPos += 50; + } + + long nX; + if( pTab->nFlags & SV_LBOXTAB_ADJUST_RIGHT ) + //verhindern, das rechter Rand von der Tabtrennung abgeschnitten wird + nX = nTabPos + pTab->CalcOffset(aSize.Width(), (nNextTabPos-SV_TAB_BORDER-1) -nTabPos); + else + nX = nTabPos + pTab->CalcOffset(aSize.Width(), nNextTabPos-nTabPos); + + if( nFlags & nTabFlags ) + { + if( !bHasClipRegion && nX + aSize.Width() >= nMaxRight ) + { + SetClipRegion( Region(pImp->GetClipRegionRect()) ); + bHasClipRegion = sal_True; + } + aEntryPos.X() = nX; + aEntryPos.Y() = nLine; + + // Hintergrund-Muster & Farbe bestimmen + + Wallpaper aWallpaper = GetBackground(); + + int bSelTab = nFlags & SV_LBOXTAB_SHOW_SELECTION; + sal_uInt16 nItemType = pItem->IsA(); + + if ( pViewDataEntry->IsSelected() && bSelTab && !pViewDataEntry->IsCursored() ) + { + Color aNewWallColor = rSettings.GetHighlightColor(); + if ( !bInUse || nItemType != SV_ITEM_ID_LBOXCONTEXTBMP ) + { + // if the face color is bright then the deactive color is also bright + // -> so you can't see any deactive selection + if ( bHideSelection && !rSettings.GetFaceColor().IsBright() && + aWallpaper.GetColor().IsBright() != rSettings.GetDeactiveColor().IsBright() ) + aNewWallColor = rSettings.GetDeactiveColor(); + // set font color to highlight + if ( !bCurFontIsSel ) + { + SetTextColor( aHighlightTextColor ); + SetFont( aHighlightFont ); + bCurFontIsSel = true; + } + } + aWallpaper.SetColor( aNewWallColor ); + } + else // keine Selektion + { + if( bInUse && nItemType == SV_ITEM_ID_LBOXCONTEXTBMP ) + aWallpaper.SetColor( rSettings.GetFieldColor() ); + else if( bCurFontIsSel ) + { + bCurFontIsSel = false; + SetTextColor( aBackupTextColor ); + SetFont( aBackupFont ); + } + } + + // Hintergrund zeichnen + if( !(nTreeFlags & TREEFLAG_USESEL)) + { + // nur den Bereich zeichnen, den das Item einnimmt + aRectSize.Width() = aSize.Width(); + aRect.SetPos( aEntryPos ); + aRect.SetSize( aRectSize ); + } + else + { + // vom aktuellen bis zum naechsten Tab zeichnen + if( nCurTab != 0 ) + aRect.Left() = nTabPos; + else + // beim nullten Tab immer ab Spalte 0 zeichnen + // (sonst Probleme bei Tabs mit Zentrierung) + aRect.Left() = 0; + aRect.Top() = nLine; + aRect.Bottom() = nLine + nTempEntryHeight - 1; + if( pNextTab ) + { + long nRight; + nRight = GetTabPos(pEntry,pNextTab)-1; + if( nRight > nMaxRight ) + nRight = nMaxRight; + aRect.Right() = nRight; + } + else + aRect.Right() = nMaxRight; + } + // bei anwenderdefinierter Selektion, die bei einer Tabposition + // groesser 0 beginnt den Hintergrund des 0.ten Items nicht + // fuellen, da sonst z.B. TablistBoxen mit Linien nicht + // realisiert werden koennen. + if( !(nCurTab==0 && (nTreeFlags & TREEFLAG_USESEL) && nFirstSelTab) ) + { + SetFillColor( aWallpaper.GetColor() ); + // Bei kleinen hor. Resizes tritt dieser Fall auf + if( aRect.Left() < aRect.Right() ) + DrawRect( aRect ); + } + // Item zeichnen + // vertikal zentrieren + aEntryPos.Y() += ( nTempEntryHeight - aSize.Height() ) / 2; + pItem->Paint( aEntryPos, *this, pViewDataEntry->GetFlags(), pEntry ); + + // Trennungslinie zwischen Tabs + if( pNextTab && pItem->IsA() == SV_ITEM_ID_LBOXSTRING && + // nicht am rechten Fensterrand! + aRect.Right() < nMaxRight ) + { + aRect.Left() = aRect.Right() - SV_TAB_BORDER; + DrawRect( aRect ); + } + + SetFillColor( aBackupColor ); + } + nCurItem++; + nCurTab++; + } + if( pViewDataEntry->IsCursored() && !HasFocus() ) + { + // Cursor-Emphasis + SetFillColor(); + Color aOldLineColor = GetLineColor(); + SetLineColor( Color( COL_BLACK ) ); + aRect = GetFocusRect( pEntry, nLine ); + aRect.Top()++; + aRect.Bottom()--; + DrawRect( aRect ); + SetLineColor( aOldLineColor ); + SetFillColor( aBackupColor ); + } + + if( bCurFontIsSel ) + { + SetTextColor( aBackupTextColor ); + SetFont( aBackupFont ); + } + + sal_uInt16 nFirstDynTabPos; + SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab( nFirstDynTabPos ); + long nDynTabPos = GetTabPos( pEntry, pFirstDynamicTab ); + nDynTabPos += pImp->nNodeBmpTabDistance; + nDynTabPos += pImp->nNodeBmpWidth / 2; + nDynTabPos += 4; // 4 Pixel Reserve, damit die Node-Bitmap + // nicht zu nah am naechsten Tab steht + + if( (!(pEntry->GetFlags() & SV_ENTRYFLAG_NO_NODEBMP)) && + (nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab && + ( pEntry->HasChilds() || pEntry->HasChildsOnDemand() ) ) + { + // ersten festen Tab suchen, und pruefen ob die Node-Bitmap + // in ihn hineinragt + sal_uInt16 nNextTab = nFirstDynTabPos; + SvLBoxTab* pNextTab; + do + { + nNextTab++; + pNextTab = nNextTab < nTabCount ? (SvLBoxTab*)aTabs.GetObject(nNextTab) : 0; + } while( pNextTab && pNextTab->IsDynamic() ); + + if( !pNextTab || (GetTabPos( pEntry, pNextTab ) > nDynTabPos) ) + { + if((nWindowStyle & WB_HASBUTTONSATROOT) || pModel->GetDepth(pEntry) > 0) + { + Point aPos( GetTabPos(pEntry,pFirstDynamicTab), nLine ); + aPos.X() += pImp->nNodeBmpTabDistance; + + const Image* pImg = 0; + BmpColorMode eBitmapMode = BMP_COLOR_NORMAL; + if ( GetSettings().GetStyleSettings().GetHighContrastMode() ) + eBitmapMode = BMP_COLOR_HIGHCONTRAST; + + if( IsExpanded(pEntry) ) + pImg = &pImp->GetExpandedNodeBmp( eBitmapMode ); + else + { + if( (!pEntry->HasChilds()) && pEntry->HasChildsOnDemand() && + (!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) && + pImp->GetDontKnowNodeBmp().GetSizePixel().Width() ) + pImg = &pImp->GetDontKnowNodeBmp( eBitmapMode ); + else + pImg = &pImp->GetCollapsedNodeBmp( eBitmapMode ); + } + aPos.Y() += (nTempEntryHeight - pImg->GetSizePixel().Height()) / 2; + + sal_uInt16 nStyle = 0; + if ( !IsEnabled() ) + nStyle |= IMAGE_DRAW_DISABLE; + + //native + sal_Bool bNativeOK = sal_False; + if ( IsNativeControlSupported( CTRL_LISTNODE, PART_ENTIRE_CONTROL) ) + { + ImplControlValue aControlValue; + Rectangle aCtrlRegion( aPos, pImg->GetSizePixel() ); + ControlState nState = 0; + + if ( IsEnabled() ) nState |= CTRL_STATE_ENABLED; + + if ( IsExpanded(pEntry) ) + aControlValue.setTristateVal( BUTTONVALUE_ON );//expanded node + else + { + if( (!pEntry->HasChilds()) && pEntry->HasChildsOnDemand() && + (!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) && + pImp->GetDontKnowNodeBmp().GetSizePixel().Width() ) + aControlValue.setTristateVal( BUTTONVALUE_DONTKNOW );//dont know + else + aControlValue.setTristateVal( BUTTONVALUE_OFF );//collapsed node + } + + bNativeOK = DrawNativeControl( CTRL_LISTNODE, PART_ENTIRE_CONTROL, + aCtrlRegion, nState, aControlValue, rtl::OUString() ); + } + + if( !bNativeOK) { + //non native + DrawImage( aPos, *pImg ,nStyle); + } + } + } + } + + + if( bHasClipRegion && bResetClipRegion ) + SetClipRegion(); + return 0; // nRowLen; +} + +void SvTreeListBox::PreparePaint( SvLBoxEntry* ) +{ +} + +Rectangle SvTreeListBox::GetFocusRect( SvLBoxEntry* pEntry, long nLine ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize; + Rectangle aRect; + aRect.Top() = nLine; + aSize.Height() = GetEntryHeight(); + + long nRealWidth = pImp->GetOutputSize().Width(); + nRealWidth -= GetMapMode().GetOrigin().X(); + + sal_uInt16 nCurTab; + SvLBoxTab* pTab = GetFirstTab( SV_LBOXTAB_SHOW_SELECTION, nCurTab ); + long nTabPos = 0; + if( pTab ) + nTabPos = GetTabPos( pEntry, pTab ); + long nNextTabPos; + if( pTab && nCurTab < aTabs.Count() - 1 ) + { + SvLBoxTab* pNextTab = (SvLBoxTab*)aTabs.GetObject( nCurTab + 1 ); + nNextTabPos = GetTabPos( pEntry, pNextTab ); + } + else + { + nNextTabPos = nRealWidth; + if( nTabPos > nRealWidth ) + nNextTabPos += 50; + } + + sal_Bool bUserSelection = (sal_Bool)( nTreeFlags & TREEFLAG_USESEL ) != 0; + if( !bUserSelection ) + { + if( pTab && nCurTab < pEntry->ItemCount() ) + { + SvLBoxItem* pItem = pEntry->GetItem( nCurTab ); + aSize.Width() = pItem->GetSize( this, pEntry ).Width(); + if( !aSize.Width() ) + aSize.Width() = 15; + long nX = nTabPos; //GetTabPos( pEntry, pTab ); + // Ausrichtung + nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos ); + aRect.Left() = nX; + // damit erster & letzter Buchstabe nicht angeknabbert werden + aRect.SetSize( aSize ); + if( aRect.Left() > 0 ) + aRect.Left()--; + aRect.Right()++; + } + } + else + { + // wenn erster SelTab != 0, dann muessen wir auch rechnen + if( nFocusWidth == -1 || nFirstSelTab ) + { + sal_uInt16 nLastTab; + SvLBoxTab* pLastTab = GetLastTab(SV_LBOXTAB_SHOW_SELECTION,nLastTab); + nLastTab++; + if( nLastTab < aTabs.Count() ) // gibts noch einen ? + pLastTab = (SvLBoxTab*)aTabs.GetObject( nLastTab ); + else + pLastTab = 0; // ueber gesamte Breite selektieren + aSize.Width() = pLastTab ? pLastTab->GetPos() : 0x0fffffff; + nFocusWidth = (short)aSize.Width(); + if( pTab ) + nFocusWidth = nFocusWidth - (short)nTabPos; //pTab->GetPos(); + } + else + { + aSize.Width() = nFocusWidth; + if( pTab ) + { + if( nCurTab ) + aSize.Width() += nTabPos; + else + aSize.Width() += pTab->GetPos(); // Tab0 immer ab ganz links + } + } + // wenn Sel. beim nullten Tab anfaengt, dann ab Spalte 0 sel. zeichnen + if( nCurTab != 0 ) + { + aRect.Left() = nTabPos; + aSize.Width() -= nTabPos; + } + aRect.SetSize( aSize ); + } + // rechten Rand anpassen wg. Clipping + if( aRect.Right() >= nRealWidth ) + { + aRect.Right() = nRealWidth-1; + nFocusWidth = (short)aRect.GetWidth(); + } + return aRect; +} + + +long SvTreeListBox::GetTabPos( SvLBoxEntry* pEntry, SvLBoxTab* pTab) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pTab,"No Tab"); + long nPos = pTab->GetPos(); + if( pTab->IsDynamic() ) + { + sal_uInt16 nDepth = pModel->GetDepth( pEntry ); + nDepth = nDepth * (sal_uInt16)nIndent; + nPos += (long)nDepth; + } + return nPos; +} + +SvLBoxItem* SvTreeListBox::GetItem_Impl( SvLBoxEntry* pEntry, long nX, + SvLBoxTab** ppTab, sal_uInt16 nEmptyWidth ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxItem* pItemClicked = 0; + sal_uInt16 nTabCount = aTabs.Count(); + sal_uInt16 nItemCount = pEntry->ItemCount(); + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject(0); + SvLBoxItem* pItem = pEntry->GetItem(0); + sal_uInt16 nNextItem = 1; + nX -= GetMapMode().GetOrigin().X(); + long nRealWidth = pImp->GetOutputSize().Width(); + nRealWidth -= GetMapMode().GetOrigin().X(); + + while( 1 ) + { + SvLBoxTab* pNextTab=nNextItem<nTabCount ? (SvLBoxTab*)aTabs.GetObject(nNextItem) : 0; + long nStart = GetTabPos( pEntry, pTab ); + + long nNextTabPos; + if( pNextTab ) + nNextTabPos = GetTabPos( pEntry, pNextTab ); + else + { + nNextTabPos = nRealWidth; + if( nStart > nRealWidth ) + nNextTabPos += 50; + } + + Size aItemSize( pItem->GetSize(this, pEntry)); + nStart += pTab->CalcOffset( aItemSize.Width(), nNextTabPos - nStart ); + long nLen = aItemSize.Width(); + if( pNextTab ) + { + long nTabWidth = GetTabPos( pEntry, pNextTab ) - nStart; + if( nTabWidth < nLen ) + nLen = nTabWidth; + } + + if( !nLen ) + nLen = nEmptyWidth; + + if( nX >= nStart && nX < (nStart+nLen ) ) + { + pItemClicked = pItem; + if( ppTab ) + { + *ppTab = pTab; + break; + } + } + if( nNextItem >= nItemCount || nNextItem >= nTabCount) + break; + pTab = (SvLBoxTab*)aTabs.GetObject( nNextItem ); + pItem = pEntry->GetItem( nNextItem ); + nNextItem++; + } + return pItemClicked; +} + +SvLBoxItem* SvTreeListBox::GetItem(SvLBoxEntry* pEntry,long nX,SvLBoxTab** ppTab) +{ + return GetItem_Impl( pEntry, nX, ppTab, 0 ); +} + +SvLBoxItem* SvTreeListBox::GetItem(SvLBoxEntry* pEntry,long nX ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + SvLBoxTab* pDummyTab; + return GetItem_Impl( pEntry, nX, &pDummyTab, 0 ); +} + +SvLBoxItem* SvTreeListBox::GetFirstDynamicItem( SvLBoxEntry* pEntry ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject(0); + SvLBoxItem* pItem = pEntry->GetItem(0); + sal_uInt16 nTabCount = aTabs.Count(); + + sal_uInt16 nNext = 1; + while ( !pTab->IsDynamic() && nNext < nTabCount ) + { + pItem = pEntry->GetItem( nNext ); + pTab = (SvLBoxTab*)aTabs.GetObject( nNext ); + nNext++; + } + return pItem; +} + +void SvTreeListBox::AddTab(long nTabPos,sal_uInt16 nFlags,void* pUserData ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + nFocusWidth = -1; + SvLBoxTab* pTab = new SvLBoxTab( nTabPos, nFlags ); + pTab->SetUserData( pUserData ); + aTabs.Insert( pTab, aTabs.Count() ); + if( nTreeFlags & TREEFLAG_USESEL ) + { + sal_uInt16 nPos = aTabs.Count() - 1; + if( nPos >= nFirstSelTab && nPos <= nLastSelTab ) + pTab->nFlags |= SV_LBOXTAB_SHOW_SELECTION; + else + // String-Items werden normalerweise immer selektiert + // deshalb explizit ausschalten + pTab->nFlags &= ~SV_LBOXTAB_SHOW_SELECTION; + } +} + + + +SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( sal_uInt16& rPos ) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + sal_uInt16 nCurTab = 0; + sal_uInt16 nTabCount = aTabs.Count(); + while( nCurTab < nTabCount ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject(nCurTab); + if( pTab->nFlags & SV_LBOXTAB_DYNAMIC ) + { + rPos = nCurTab; + return pTab; + } + nCurTab++; + } + return 0; +} + +SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const +{ + sal_uInt16 nDummy; + return GetFirstDynamicTab( nDummy ); +} + +SvLBoxTab* SvTreeListBox::GetTab( SvLBoxEntry* pEntry, SvLBoxItem* pItem) const +{ + DBG_CHKTHIS(SvTreeListBox,0); + sal_uInt16 nPos = pEntry->GetPos( pItem ); + return (SvLBoxTab*)aTabs.GetObject( nPos ); +} + +void SvTreeListBox::ClearTabList() +{ + DBG_CHKTHIS(SvTreeListBox,0); + sal_uInt16 nTabCount = aTabs.Count(); + while( nTabCount ) + { + nTabCount--; + SvLBoxTab* pDelTab = (SvLBoxTab*)aTabs.GetObject( nTabCount ); + delete pDelTab; + } + aTabs.Remove(0,aTabs.Count()); +} + + +Size SvTreeListBox::GetOutputSizePixel() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + Size aSize = pImp->GetOutputSize(); + return aSize; +} + +void SvTreeListBox::NotifyBeginScroll() +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::NotifyEndScroll() +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::NotifyScrolling( long ) +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::NotifyScrolled() +{ + DBG_CHKTHIS(SvTreeListBox,0); + aScrolledHdl.Call( this ); +} + +void SvTreeListBox::NotifyInvalidating() +{ + DBG_CHKTHIS(SvTreeListBox,0); +} + +void SvTreeListBox::Invalidate( sal_uInt16 nInvalidateFlags ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nFocusWidth == -1 ) + // damit Control nicht nach dem Paint ein falsches FocusRect anzeigt + pImp->RecalcFocusRect(); + NotifyInvalidating(); + SvLBox::Invalidate( nInvalidateFlags ); + pImp->Invalidate(); +} + +void SvTreeListBox::Invalidate( const Rectangle& rRect, sal_uInt16 nInvalidateFlags ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + if( nFocusWidth == -1 ) + // damit Control nicht nach dem Paint ein falsches FocusRect anzeigt + pImp->RecalcFocusRect(); + NotifyInvalidating(); + SvLBox::Invalidate( rRect, nInvalidateFlags ); +} + + +void SvTreeListBox::SetHighlightRange( sal_uInt16 nStart, sal_uInt16 nEnd) +{ + DBG_CHKTHIS(SvTreeListBox,0); + + sal_uInt16 nTemp; + nTreeFlags |= TREEFLAG_USESEL; + if( nStart > nEnd ) + { + nTemp = nStart; + nStart = nEnd; + nEnd = nTemp; + } + // alle Tabs markieren, die im Bereich liegen + nTreeFlags |= TREEFLAG_RECALCTABS; + nFirstSelTab = nStart; + nLastSelTab = nEnd; + pImp->RecalcFocusRect(); +} + +void SvTreeListBox::RemoveHighlightRange() +{ + DBG_CHKTHIS(SvTreeListBox,0); + nTreeFlags &= (~TREEFLAG_USESEL); + if( IsUpdateMode() ) + Invalidate(); +} + +sal_uLong SvTreeListBox::GetAscInsertionPos(SvLBoxEntry*,SvLBoxEntry*) +{ + return LIST_APPEND; +} + +sal_uLong SvTreeListBox::GetDescInsertionPos(SvLBoxEntry*,SvLBoxEntry*) +{ + DBG_CHKTHIS(SvTreeListBox,0); + return LIST_APPEND; +} + +Region SvTreeListBox::GetDragRegion() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + Rectangle aRect; + SvLBoxEntry* pEntry = GetCurEntry(); + if( pEntry ) + { + Point aPos = GetEntryPosition( pEntry ); + aRect = ((SvTreeListBox*)this)->GetFocusRect( pEntry, aPos.Y() ); + } + Region aRegion( aRect ); + return aRegion; +} + + +void SvTreeListBox::Command( const CommandEvent& rCEvt ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + // FIXME gnumake2 resync to DEV300_m84 + pImp->Command( rCEvt ); +} + + +void SvTreeListBox::RemoveParentKeepChilds( SvLBoxEntry* pParent ) +{ + DBG_CHKTHIS(SvTreeListBox,0); + DBG_ASSERT(pParent,"RemoveParentKeepChilds:No Parent"); + SvLBoxEntry* pNewParent = GetParent( pParent ); + if( pParent->HasChilds()) + { + SvLBoxEntry* pChild = FirstChild( pParent ); + while( pChild ) + { + pModel->Move( pChild, pNewParent, LIST_APPEND ); + pChild = FirstChild( pParent ); + } + } + pModel->Remove( pParent ); +} + +SvLBoxTab* SvTreeListBox::GetFirstTab( sal_uInt16 nFlagMask, sal_uInt16& rPos ) +{ + sal_uInt16 nTabCount = aTabs.Count(); + for( sal_uInt16 nPos = 0; nPos < nTabCount; nPos++ ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject( nPos ); + if( (pTab->nFlags & nFlagMask) ) + { + rPos = nPos; + return pTab; + } + } + rPos = 0xffff; + return 0; +} + +SvLBoxTab* SvTreeListBox::GetLastTab( sal_uInt16 nFlagMask, sal_uInt16& rTabPos ) +{ + short nTabCount = (short)aTabs.Count(); + if( nTabCount ) + { + for( short nPos = nTabCount-1; nPos >= 0; nPos-- ) + { + SvLBoxTab* pTab = (SvLBoxTab*)aTabs.GetObject( (sal_uInt16)nPos ); + if( (pTab->nFlags & nFlagMask) ) + { + rTabPos = (sal_uInt16)nPos; + return pTab; + } + } + } + rTabPos = 0xffff; + return 0; +} + +void SvTreeListBox::SetAddMode( sal_Bool bAdd ) +{ + pImp->SetAddMode( bAdd ); +} + +sal_Bool SvTreeListBox::IsAddMode() const +{ + return pImp->IsAddMode(); +} + +void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if( !pImp->RequestHelp( rHEvt ) ) + SvLBox::RequestHelp( rHEvt ); +} + +void SvTreeListBox::CursorMoved( SvLBoxEntry* ) +{ +} + +IMPL_LINK( SvTreeListBox, DefaultCompare, SvSortData*, pData ) +{ + SvLBoxEntry* pLeft = (SvLBoxEntry*)(pData->pLeft ); + SvLBoxEntry* pRight = (SvLBoxEntry*)(pData->pRight ); + String aLeft( ((SvLBoxString*)(pLeft->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText()); + String aRight( ((SvLBoxString*)(pRight->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText()); + // #102891# ---------------- + pImp->UpdateIntlWrapper(); + return pImp->pIntlWrapper->getCaseCollator()->compareString( aLeft, aRight ); +} + +void SvTreeListBox::ModelNotification( sal_uInt16 nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, sal_uLong nPos ) +{ + if( nActionId == LISTACTION_CLEARING ) + CancelTextEditing(); + + SvLBox::ModelNotification( nActionId, pEntry1, pEntry2, nPos ); + switch( nActionId ) + { + case LISTACTION_INSERTED: + { + SvLBoxEntry* pEntry( dynamic_cast< SvLBoxEntry* >( pEntry1 ) ); + ENSURE_OR_BREAK( pEntry, "SvTreeListBox::ModelNotification: invalid entry!" ); + SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) ); + if ( !pBmpItem ) + break; + const Image& rBitmap1( pBmpItem->GetBitmap1() ); + const Image& rBitmap2( pBmpItem->GetBitmap2() ); + short nMaxWidth = short( Max( rBitmap1.GetSizePixel().Width(), rBitmap2.GetSizePixel().Width() ) ); + nMaxWidth = pImp->UpdateContextBmpWidthVector( pEntry, nMaxWidth ); + if( nMaxWidth > nContextBmpWidthMax ) + { + nContextBmpWidthMax = nMaxWidth; + SetTabs(); + } + } + break; + + case LISTACTION_RESORTING: + SetUpdateMode( sal_False ); + break; + + case LISTACTION_RESORTED: + // nach Sortierung den ersten Eintrag anzeigen, dabei die + // Selektion erhalten. + MakeVisible( (SvLBoxEntry*)pModel->First(), sal_True ); + SetUpdateMode( sal_True ); + break; + + case LISTACTION_CLEARED: + if( IsUpdateMode() ) + Update(); + break; + } +} + +// bei Aenderungen SetTabs beruecksichtigen +long SvTreeListBox::GetTextOffset() const +{ + DBG_CHKTHIS(SvTreeListBox,0); + const WinBits nWindowStyle = GetStyle(); + sal_Bool bHasButtons = (nWindowStyle & WB_HASBUTTONS)!=0; + sal_Bool bHasButtonsAtRoot = (nWindowStyle & (WB_HASLINESATROOT | + WB_HASBUTTONSATROOT))!=0; + long nStartPos = TAB_STARTPOS; + long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width(); + + long nCheckWidth = 0; + if( nTreeFlags & TREEFLAG_CHKBTN ) + nCheckWidth = pCheckButtonData->aBmps[0].GetSizePixel().Width(); + long nCheckWidthDIV2 = nCheckWidth / 2; + + long nContextWidth = nContextBmpWidthMax; + long nContextWidthDIV2 = nContextWidth / 2; + + int nCase = NO_BUTTONS; + if( !(nTreeFlags & TREEFLAG_CHKBTN) ) + { + if( bHasButtons ) + nCase = NODE_BUTTONS; + } + else + { + if( bHasButtons ) + nCase = NODE_AND_CHECK_BUTTONS; + else + nCase = CHECK_BUTTONS; + } + + switch( nCase ) + { + case NO_BUTTONS : + nStartPos += nContextWidthDIV2; // wg. Zentrierung + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + + case NODE_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + (nNodeWidthPixel/2) ); + else + nStartPos += nContextWidthDIV2; + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + + case NODE_AND_CHECK_BUTTONS : + if( bHasButtonsAtRoot ) + nStartPos += ( nIndent + nNodeWidthPixel ); + else + nStartPos += nCheckWidthDIV2; + nStartPos += nCheckWidthDIV2; // rechter Rand des CheckButtons + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + // Abstand setzen nur wenn Bitmaps da + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + + case CHECK_BUTTONS : + nStartPos += nCheckWidthDIV2; + nStartPos += nCheckWidthDIV2; // rechter Rand CheckButton + nStartPos += 3; // Abstand CheckButton Context-Bmp + nStartPos += nContextWidthDIV2; // Mitte der Context-Bmp + nStartPos += nContextWidthDIV2; // rechter Rand der Context-Bmp + if( nContextBmpWidthMax ) + nStartPos += 5; // Abstand Context-Bmp - Text + break; + } + return nStartPos; +} + +void SvTreeListBox::EndSelection() +{ + pImp->EndSelection(); +} + +sal_Bool SvTreeListBox::IsNodeButton( const Point& rPos ) const +{ + SvLBoxEntry* pEntry = GetEntry( rPos ); + if( pEntry ) + return pImp->IsNodeButton( rPos, pEntry ); + return sal_False; +} + +void SvTreeListBox::RepaintScrollBars() const +{ + ((SvTreeListBox*)this)->pImp->RepaintScrollBars(); +} + +ScrollBar *SvTreeListBox::GetVScroll() +{ + return &((SvTreeListBox*)this)->pImp->aVerSBar; +} + +ScrollBar *SvTreeListBox::GetHScroll() +{ + return &((SvTreeListBox*)this)->pImp->aHorSBar; +} + +void SvTreeListBox::EnableAsyncDrag( sal_Bool b ) +{ + pImp->EnableAsyncDrag( b ); +} + +SvLBoxEntry* SvTreeListBox::GetFirstEntryInView() const +{ + Point aPos; + return GetEntry( aPos ); +} + +SvLBoxEntry* SvTreeListBox::GetNextEntryInView(SvLBoxEntry* pEntry ) const +{ + SvLBoxEntry* pNext = (SvLBoxEntry*)NextVisible( pEntry ); + if( pNext ) + { + Point aPos( GetEntryPosition(pNext) ); + const Size& rSize = pImp->GetOutputSize(); + if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() ) + return 0; + } + return pNext; +} + +void SvTreeListBox::ShowFocusRect( const SvLBoxEntry* pEntry ) +{ + pImp->ShowFocusRect( pEntry ); +} + +void SvTreeListBox::SetTabBar( TabBar* pTabBar ) +{ + pImp->SetTabBar( pTabBar ); +} + +void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if( (rDCEvt.GetType()==DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) ) + { + nEntryHeight = 0; // _together_ with sal_True of 1. par (bFont) of InitSettings() a zero-height + // forces complete recalc of heights! + InitSettings( sal_True, sal_True, sal_True ); + Invalidate(); + } + else + Control::DataChanged( rDCEvt ); +} + +void SvTreeListBox::StateChanged( StateChangedType i_nStateChange ) +{ + SvLBox::StateChanged( i_nStateChange ); + if ( i_nStateChange == STATE_CHANGE_STYLE ) + ImplInitStyle(); +} + +void SvTreeListBox::InitSettings(sal_Bool bFont,sal_Bool bForeground,sal_Bool bBackground) +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + if( bFont ) + { + Font aFont; + aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont( aFont ); + AdjustEntryHeight( aFont ); + RecalcViewData(); + } + + if( bForeground || bFont ) + { + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + } + + if( bBackground ) + SetBackground( rStyleSettings.GetFieldColor() ); + + // always try to re-create default-SvLBoxButtonData + if( pCheckButtonData && pCheckButtonData->HasDefaultImages() ) + pCheckButtonData->SetDefaultImages( this ); +} + +sal_Bool SvTreeListBox::IsCellFocusEnabled() const +{ + return pImp->IsCellFocusEnabled(); +} + +bool SvTreeListBox::SetCurrentTabPos( sal_uInt16 _nNewPos ) +{ + return pImp->SetCurrentTabPos( _nNewPos ); +} + +sal_uInt16 SvTreeListBox::GetCurrentTabPos() const +{ + return pImp->GetCurrentTabPos(); +} + +void SvTreeListBox::InitStartEntry() +{ + if( !pImp->pStartEntry ) + pImp->pStartEntry = GetModel()->First(); +} + +void SvTreeListBox::CancelPendingEdit() +{ + if( pImp ) + pImp->CancelPendingEdit(); +} + +PopupMenu* SvTreeListBox::CreateContextMenu( void ) +{ + return NULL; +} + +void SvTreeListBox::ExcecuteContextMenuAction( sal_uInt16 ) +{ + DBG_WARNING( "SvTreeListBox::ExcecuteContextMenuAction(): now there's happening nothing!" ); +} + +void SvTreeListBox::EnableContextMenuHandling( void ) +{ + DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" ); + + pImp->bContextMenuHandling = sal_True; +} + +void SvTreeListBox::EnableContextMenuHandling( sal_Bool b ) +{ + DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" ); + + pImp->bContextMenuHandling = b; +} + +sal_Bool SvTreeListBox::IsContextMenuHandlingEnabled( void ) const +{ + DBG_ASSERT( pImp, "-SvTreeListBox::IsContextMenuHandlingEnabled(): No implementation!" ); + + return pImp->bContextMenuHandling; +} + +void SvTreeListBox::EnableList( bool _bEnable ) +{ + // call base class method + Window::Enable( _bEnable != false ); + // then paint immediately + Paint( Rectangle( Point(), GetSizePixel() ) ); +} + +::com::sun::star::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible() +{ + Window* pParent = GetAccessibleParentWindow(); + DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" ); + + ::com::sun::star::uno::Reference< XAccessible > xAccessible; + if ( pParent ) + { + ::com::sun::star::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible(); + if ( xAccParent.is() ) + { + // need to be done here to get the vclxwindow later on in the accessbile + ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xTemp(GetComponentInterface()); + xAccessible = pImp->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent ); + } + } + return xAccessible; +} + +void SvTreeListBox::FillAccessibleEntryStateSet( SvLBoxEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const +{ + DBG_ASSERT( pEntry, "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry" ); + + if ( pEntry->HasChildsOnDemand() || pEntry->HasChilds() ) + { + rStateSet.AddState( AccessibleStateType::EXPANDABLE ); + if ( IsExpanded( pEntry ) ) + rStateSet.AddState( (sal_Int16)AccessibleStateType::EXPANDED ); + } + + if ( GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED ) + rStateSet.AddState( AccessibleStateType::CHECKED ); + if ( IsEntryVisible( pEntry ) ) + rStateSet.AddState( AccessibleStateType::VISIBLE ); + if ( IsSelected( pEntry ) ) + rStateSet.AddState( AccessibleStateType::SELECTED ); +} + +Rectangle SvTreeListBox::GetBoundingRect( SvLBoxEntry* pEntry ) +{ + Point aPos = GetEntryPosition( pEntry ); + Rectangle aRect = GetFocusRect( pEntry, aPos.Y() ); + return aRect; +} + +void SvTreeListBox::EnableCellFocus() +{ + pImp->EnableCellFocus(); +} + +void SvTreeListBox::CallImplEventListeners(sal_uLong nEvent, void* pData) +{ + CallEventListeners(nEvent, pData); +} + +void SvTreeListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& rStateSet ) const +{ + SvLBox::FillAccessibleStateSet( rStateSet ); +} diff --git a/svtools/source/contnr/templwin.cxx b/svtools/source/contnr/templwin.cxx new file mode 100644 index 000000000000..2959d8e0460f --- /dev/null +++ b/svtools/source/contnr/templwin.cxx @@ -0,0 +1,2018 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" +#include "templwin.hxx" +#include <svtools/templdlg.hxx> +#include <svtools/svtdata.hxx> +#include <unotools/pathoptions.hxx> +#include <unotools/dynamicmenuoptions.hxx> +#include <unotools/extendedsecurityoptions.hxx> +#include <svtools/xtextedt.hxx> +#include <svl/inettype.hxx> +#include <svtools/imagemgr.hxx> +#include <svtools/miscopt.hxx> +#include <svtools/templatefoldercache.hxx> +#include <svtools/imgdef.hxx> +#include <svtools/txtattr.hxx> +#include <svtools/svtools.hrc> +#include "templwin.hrc" +#include <svtools/helpid.hrc> +#include <unotools/pathoptions.hxx> +#include <unotools/viewoptions.hxx> +#include <unotools/ucbhelper.hxx> +#include "unotools/configmgr.hxx" +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <com/sun/star/util/URL.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> +#include <com/sun/star/util/XOfficeInstallationDirectories.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XDocumentTemplates.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/ucb/XContent.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/view/XPrintable.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/system/XSystemShellExecute.hpp> +#include <com/sun/star/system/SystemShellExecuteFlags.hpp> +#include <unotools/localedatawrapper.hxx> +#include <com/sun/star/container/XNameContainer.hpp> +#include <vcl/waitobj.hxx> +#include <comphelper/processfactory.hxx> +#include <tools/urlobj.hxx> +#include <tools/datetime.hxx> +#include <vcl/svapp.hxx> +#include <vcl/split.hxx> +#include <vcl/msgbox.hxx> +#include <svtools/DocumentInfoPreview.hxx> +#include <vcl/mnemonic.hxx> + +#include <ucbhelper/content.hxx> +#include <comphelper/string.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::view; +using namespace svtools; + +extern ::rtl::OUString CreateExactSizeText_Impl( sal_Int64 nSize ); // fileview.cxx + +#define SPLITSET_ID 0 +#define COLSET_ID 1 +#define ICONWIN_ID 2 +#define FILEWIN_ID 3 +#define FRAMEWIN_ID 4 + +#define ICON_POS_NEWDOC 0 +#define ICON_POS_TEMPLATES 1 +#define ICON_POS_MYDOCS 2 +#define ICON_POS_SAMPLES 3 + +#define ASCII_STR(s) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(s) ) +#define VIEWSETTING_NEWFROMTEMPLATE ASCII_STR("NewFromTemplate") +#define VIEWSETTING_SELECTEDGROUP ASCII_STR("SelectedGroup") +#define VIEWSETTING_SELECTEDVIEW ASCII_STR("SelectedView") +#define VIEWSETTING_SPLITRATIO ASCII_STR("SplitRatio") +#define VIEWSETTING_LASTFOLDER ASCII_STR("LastFolder") + +struct FolderHistory +{ + String m_sURL; + sal_uLong m_nGroup; + + FolderHistory( const String& _rURL, sal_Int32 _nGroup ) : + m_sURL( _rURL ), m_nGroup( _nGroup ) {} +}; + +DECLARE_LIST( HistoryList_Impl, FolderHistory* ) +DECLARE_LIST( NewDocList_Impl, ::rtl::OUString* ) + +ODocumentInfoPreview::ODocumentInfoPreview( Window* pParent ,WinBits _nBits) : Window(pParent,WB_DIALOGCONTROL) +{ + m_pEditWin = new SvtExtendedMultiLineEdit_Impl(this,_nBits); + m_pEditWin->Show(); + m_pEditWin->EnableCursor( sal_False ); + m_pInfoTable = new SvtDocInfoTable_Impl(); + // detect application language + m_aLocale = SvtPathOptions().GetLocale(); +} +// ----------------------------------------------------------------------------- +ODocumentInfoPreview::~ODocumentInfoPreview() +{ + delete m_pEditWin; + delete m_pInfoTable; +} +// ----------------------------------------------------------------------------- +void ODocumentInfoPreview::Resize() +{ + Size aOutputSize( GetOutputSize() ); + m_pEditWin->SetPosSizePixel( Point(0,0),aOutputSize); +} +// ----------------------------------------------------------------------------- +void ODocumentInfoPreview::Clear() +{ + m_pEditWin->Clear(); +} +// ----------------------------------------------------------------------------- + +void lcl_insertDateTimeEntry(SvtExtendedMultiLineEdit_Impl* i_pEditWin, + const ::rtl::OUString & i_rName, const util::DateTime & i_rUDT) +{ + DateTime aToolsDT = + DateTime( Date( i_rUDT.Day, i_rUDT.Month, i_rUDT.Year ), + Time( i_rUDT.Hours, i_rUDT.Minutes, + i_rUDT.Seconds, i_rUDT.HundredthSeconds ) ); + if ( aToolsDT.IsValid() ) + { + LocaleDataWrapper aLocaleWrapper( + ::comphelper::getProcessServiceFactory(), + Application::GetSettings().GetLocale() ); + String aDateStr = aLocaleWrapper.getDate( aToolsDT ); + aDateStr += String( RTL_CONSTASCII_STRINGPARAM(", ") ); + aDateStr += aLocaleWrapper.getTime( aToolsDT ); + i_pEditWin->InsertEntry( i_rName, aDateStr ); + } +} + +void ODocumentInfoPreview::fill( + const Reference< XDocumentProperties >& i_xDocProps, const String& i_rURL) +{ + if (!i_xDocProps.is()) throw RuntimeException(); + + ::rtl::OUString aStr; + m_pEditWin->SetAutoScroll( sal_False ); + + aStr = i_xDocProps->getTitle(); + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString( DI_TITLE ), aStr ); + } + + aStr = i_xDocProps->getAuthor(); + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString( DI_FROM ), aStr ); + } + + lcl_insertDateTimeEntry(m_pEditWin, + m_pInfoTable->GetString( DI_DATE ), + i_xDocProps->getCreationDate()); + + aStr = i_xDocProps->getModifiedBy(); + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString(DI_MODIFIEDBY), aStr ); + } + + lcl_insertDateTimeEntry(m_pEditWin, + m_pInfoTable->GetString( DI_MODIFIEDDATE ), + i_xDocProps->getModificationDate()); + + aStr = i_xDocProps->getPrintedBy(); + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString( DI_PRINTBY ), aStr ); + } + + lcl_insertDateTimeEntry(m_pEditWin, + m_pInfoTable->GetString( DI_PRINTDATE ), + i_xDocProps->getPrintDate()); + + aStr = i_xDocProps->getSubject(); + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString( DI_THEME ), aStr ); + } + + aStr = + ::comphelper::string::convertCommaSeparated(i_xDocProps->getKeywords()); + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString( DI_KEYWORDS ), aStr ); + } + + aStr = i_xDocProps->getDescription(); + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString( DI_DESCRIPTION ), + aStr ); + } + + // size + if ( i_rURL.Len() > 0 ) + { + sal_uLong nDocSize = ::utl::UCBContentHelper::GetSize( i_rURL ); + m_pEditWin->InsertEntry( + m_pInfoTable->GetString( DI_SIZE ), + CreateExactSizeText_Impl( nDocSize ) ); + } + + // MIMEType + if ( i_rURL.Len() > 0 ) + { + INetContentType eTypeID = + INetContentTypes::GetContentTypeFromURL( i_rURL ); + if ( eTypeID != CONTENT_TYPE_APP_OCTSTREAM ) { + aStr = INetContentTypes::GetPresentation( eTypeID, m_aLocale ); + } else { + aStr = SvFileInformationManager::GetDescription( + INetURLObject(i_rURL) ); + } + if (aStr.getLength()) { + m_pEditWin->InsertEntry( m_pInfoTable->GetString( DI_MIMETYPE ), + aStr ); + } + } + + // user-defined (custom) properties + Reference< XPropertySet > xUserDefined( + i_xDocProps->getUserDefinedProperties(), UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xUDInfo = xUserDefined->getPropertySetInfo(); + Sequence< Property > props = xUDInfo->getProperties(); + for (sal_Int32 i = 0; i < props.getLength(); ++i) { + const ::rtl::OUString name = props[i].Name; + uno::Any aAny; + try { + aAny = xUserDefined->getPropertyValue(name); + uno::Reference < script::XTypeConverter > xConverter( + comphelper::getProcessServiceFactory()->createInstance( + ASCII_STR("com.sun.star.script.Converter")), + UNO_QUERY ); + uno::Any aNew; + aNew = xConverter->convertToSimpleType( aAny, TypeClass_STRING ); + if ((aNew >>= aStr) && aStr.getLength()) { + m_pEditWin->InsertEntry( name, aStr); + } + } catch (uno::Exception &) { + // ignore + } + } + + m_pEditWin->SetSelection( Selection( 0, 0 ) ); + m_pEditWin->SetAutoScroll( sal_True ); +} + +// ----------------------------------------------------------------------------- +void ODocumentInfoPreview::InsertEntry( const String& rTitle, const String& rValue ) +{ + m_pEditWin->InsertEntry( rTitle, rValue); +} +// ----------------------------------------------------------------------------- + +// class SvtDummyHeaderBar_Impl ------------------------------------------ + +void SvtDummyHeaderBar_Impl::UpdateBackgroundColor() +{ + SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetWindowColor() ) ); +} + +SvtDummyHeaderBar_Impl::SvtDummyHeaderBar_Impl( Window* pPar ) : Window( pPar ) +{ + SetSizePixel( HeaderBar( this, 0 ).CalcWindowSizePixel() ); // HeaderBar used only to calculate size + + UpdateBackgroundColor(); +} + +SvtDummyHeaderBar_Impl::~SvtDummyHeaderBar_Impl() +{ +} + +void SvtDummyHeaderBar_Impl::DataChanged( const DataChangedEvent& r ) +{ + Window::DataChanged( r ); + if( r.GetType() == DATACHANGED_SETTINGS ) + UpdateBackgroundColor(); +} + +// class SvtIconWindow_Impl ---------------------------------------------- + +SvtIconWindow_Impl::SvtIconWindow_Impl( Window* pParent ) : + + Window( pParent, WB_DIALOGCONTROL | WB_BORDER | WB_3DLOOK ), + + aDummyHeaderBar( this ), + aIconCtrl( this, WB_ICON | WB_NOCOLUMNHEADER | WB_HIGHLIGHTFRAME | /*!WB_NOSELECTION |*/ + WB_NODRAGSELECTION | WB_TABSTOP | WB_CLIPCHILDREN ), + aNewDocumentRootURL( ASCII_STR("private:newdoc") ), + aMyDocumentsRootURL( SvtPathOptions().GetWorkPath() ), + aSamplesFolderRootURL( SvtPathOptions(). + SubstituteVariable( String( ASCII_STR("$(insturl)/share/samples/$(vlang)") ) ) ), + nMaxTextLength( 0 ) + +{ + aDummyHeaderBar.Show(); + + aIconCtrl.SetAccessibleName( String( RTL_CONSTASCII_USTRINGPARAM("Groups") ) ); + aIconCtrl.SetHelpId( HID_TEMPLATEDLG_ICONCTRL ); + aIconCtrl.SetChoiceWithCursor( sal_True ); + aIconCtrl.SetSelectionMode( SINGLE_SELECTION ); + aIconCtrl.Show(); + + // detect the root URL of templates + Reference< XDocumentTemplates > xTemplates( ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.frame.DocumentTemplates") ), UNO_QUERY ); + + if ( xTemplates.is() ) + { + Reference < XContent > aRootContent = xTemplates->getContent(); + Reference < XCommandEnvironment > aCmdEnv; + + if ( aRootContent.is() ) + aTemplateRootURL = aRootContent->getIdentifier()->getContentIdentifier(); + } + + // insert the categories + // "New Document" + sal_Bool bHiContrast = GetSettings().GetStyleSettings().GetHighContrastMode(); + Image aImage( SvtResId( bHiContrast ? IMG_SVT_NEWDOC_HC : IMG_SVT_NEWDOC ) ); + nMaxTextLength = aImage.GetSizePixel().Width(); + String aEntryStr = String( SvtResId( STR_SVT_NEWDOC ) ); + SvxIconChoiceCtrlEntry* pEntry = + aIconCtrl.InsertEntry( aEntryStr, aImage, ICON_POS_NEWDOC ); + pEntry->SetUserData( new String( aNewDocumentRootURL ) ); + pEntry->SetQuickHelpText( String( SvtResId( STR_SVT_NEWDOC_HELP ) ) ); + DBG_ASSERT( !pEntry->GetBoundRect().IsEmpty(), "empty rectangle" ); + long nTemp = pEntry->GetBoundRect().GetSize().Width(); + if (nTemp > nMaxTextLength) + nMaxTextLength = nTemp; + + // "Templates" + if( aTemplateRootURL.Len() > 0 ) + { + aEntryStr = String( SvtResId( STR_SVT_TEMPLATES ) ); + pEntry = aIconCtrl.InsertEntry( + aEntryStr, Image( SvtResId( bHiContrast ? IMG_SVT_TEMPLATES_HC : IMG_SVT_TEMPLATES ) ), ICON_POS_TEMPLATES ); + pEntry->SetUserData( new String( aTemplateRootURL ) ); + pEntry->SetQuickHelpText( String( SvtResId( STR_SVT_TEMPLATES_HELP ) ) ); + DBG_ASSERT( !pEntry->GetBoundRect().IsEmpty(), "empty rectangle" ); + nTemp = pEntry->GetBoundRect().GetSize().Width(); + if (nTemp > nMaxTextLength) + nMaxTextLength = nTemp; + } + + // "My Documents" + aEntryStr = String( SvtResId( STR_SVT_MYDOCS ) ); + pEntry = aIconCtrl.InsertEntry( + aEntryStr, Image( SvtResId( bHiContrast ? IMG_SVT_MYDOCS_HC : IMG_SVT_MYDOCS ) ), ICON_POS_MYDOCS ); + pEntry->SetUserData( new String( aMyDocumentsRootURL ) ); + pEntry->SetQuickHelpText( String( SvtResId( STR_SVT_MYDOCS_HELP ) ) ); + DBG_ASSERT( !pEntry->GetBoundRect().IsEmpty(), "empty rectangle" ); + nTemp = pEntry->GetBoundRect().GetSize().Width(); + if( nTemp > nMaxTextLength ) + nMaxTextLength = nTemp; + + // "Samples" + aEntryStr = String( SvtResId( STR_SVT_SAMPLES ) ); + pEntry = aIconCtrl.InsertEntry( + aEntryStr, Image( SvtResId( bHiContrast ? IMG_SVT_SAMPLES_HC : IMG_SVT_SAMPLES ) ), ICON_POS_SAMPLES ); + pEntry->SetUserData( new String( aSamplesFolderRootURL ) ); + pEntry->SetQuickHelpText( String( SvtResId( STR_SVT_SAMPLES_HELP ) ) ); + DBG_ASSERT( !pEntry->GetBoundRect().IsEmpty(), "empty rectangle" ); + nTemp = pEntry->GetBoundRect().GetSize().Width(); + if (nTemp > nMaxTextLength) + nMaxTextLength = nTemp; + + aIconCtrl.CreateAutoMnemonics(); +} + +SvtIconWindow_Impl::~SvtIconWindow_Impl() +{ + for ( sal_uLong i = 0; i < aIconCtrl.GetEntryCount(); ++i ) + { + SvxIconChoiceCtrlEntry* pEntry = aIconCtrl.GetEntry( i ); + delete (String*)pEntry->GetUserData(); + } +} + +SvxIconChoiceCtrlEntry* SvtIconWindow_Impl::GetEntry( const String& rURL ) const +{ + SvxIconChoiceCtrlEntry* pEntry = NULL; + for ( sal_uLong i = 0; i < aIconCtrl.GetEntryCount(); ++i ) + { + SvxIconChoiceCtrlEntry* pTemp = aIconCtrl.GetEntry( i ); + String aURL( *( (String*)pTemp->GetUserData() ) ); + if ( aURL == rURL ) + { + pEntry = pTemp; + break; + } + } + + return pEntry; +} + +void SvtIconWindow_Impl::Resize() +{ + Size aWinSize = GetOutputSizePixel(); + Size aHeaderSize = aDummyHeaderBar.GetSizePixel(); + aHeaderSize.Width() = aWinSize.Width(); + aDummyHeaderBar.SetSizePixel( aHeaderSize ); + long nHeaderHeight = aHeaderSize.Height(); + aWinSize.Height() -= nHeaderHeight; + aIconCtrl.SetPosSizePixel( Point( 0, nHeaderHeight ), aWinSize ); + aIconCtrl.ArrangeIcons(); +} + +String SvtIconWindow_Impl::GetCursorPosIconURL() const +{ + String aURL; + SvxIconChoiceCtrlEntry* pEntry = aIconCtrl.GetCursor( ); + if ( pEntry ) + aURL = *static_cast<String*>(pEntry->GetUserData()); + return aURL; + +} + +String SvtIconWindow_Impl::GetSelectedIconURL() const +{ + sal_uLong nPos; + SvxIconChoiceCtrlEntry* pEntry = aIconCtrl.GetSelectedEntry( nPos ); + String aURL; + if ( pEntry ) + aURL = *static_cast<String*>(pEntry->GetUserData()); + return aURL; +} + +String SvtIconWindow_Impl::GetSelectedIconText() const +{ + sal_uLong nPos; + return MnemonicGenerator::EraseAllMnemonicChars( aIconCtrl.GetSelectedEntry( nPos )->GetText() ); +} + +String SvtIconWindow_Impl::GetIconText( const String& rURL ) const +{ + String aText; + SvxIconChoiceCtrlEntry* pEntry = GetEntry( rURL ); + if ( pEntry ) + aText = MnemonicGenerator::EraseAllMnemonicChars( pEntry->GetText() ); + return aText; +} + +void SvtIconWindow_Impl::InvalidateIconControl() +{ + aIconCtrl.Invalidate(); +} + +sal_uLong SvtIconWindow_Impl::GetCursorPos() const +{ + sal_uLong nPos = ~sal_uLong(0); + + SvxIconChoiceCtrlEntry* pCursorEntry = aIconCtrl.GetCursor( ); + if ( pCursorEntry ) + nPos = aIconCtrl.GetEntryListPos( pCursorEntry ); + + return nPos; +} + +sal_uLong SvtIconWindow_Impl::GetSelectEntryPos() const +{ + sal_uLong nPos; + if ( !aIconCtrl.GetSelectedEntry( nPos ) ) + nPos = ~sal_uLong(0); + return nPos; +} + +void SvtIconWindow_Impl::SetCursorPos( sal_uLong nPos ) +{ + SvxIconChoiceCtrlEntry* pEntry = aIconCtrl.GetEntry( nPos ); + aIconCtrl.SetCursor( pEntry ); + aIconCtrl.Invalidate(); + aIconCtrl.Update(); +} + +void SvtIconWindow_Impl::SetFocus() +{ + aIconCtrl.GrabFocus(); +} + +long SvtIconWindow_Impl::CalcHeight() const +{ + // calculate the required height of the IconControl + long nHeight = 0; + sal_uLong nCount = aIconCtrl.GetEntryCount(); + if ( nCount > 0 ) + // bottom of the last icon + nHeight = aIconCtrl.GetEntry(nCount-1)->GetBoundRect().Bottom(); + + // + headerbar height + nHeight += aDummyHeaderBar.GetSizePixel().Height(); + + return nHeight; +} + +sal_Bool SvtIconWindow_Impl::IsRootURL( const String& rURL ) const +{ + return rURL == aNewDocumentRootURL || + rURL == aTemplateRootURL || + rURL == aMyDocumentsRootURL || + rURL == aSamplesFolderRootURL; +} + +sal_uLong SvtIconWindow_Impl::GetRootPos( const String& rURL ) const +{ + sal_uLong nPos = ~sal_uLong(0); + if ( aNewDocumentRootURL.Match( rURL ) == STRING_MATCH ) + nPos = 0; + else if ( aTemplateRootURL.Match( rURL ) == STRING_MATCH ) + nPos = 1; + else if ( aMyDocumentsRootURL.Match( rURL ) == STRING_MATCH ) + nPos = 2; + else if ( aSamplesFolderRootURL.Match( rURL ) == STRING_MATCH ) + nPos = 3; + else if ( rURL.Match( aMyDocumentsRootURL ) == STRING_MATCH ) + nPos = 2; + else + { + DBG_WARNING( "SvtIconWindow_Impl::GetRootPos(): invalid position" ); + nPos = 2; + } + + return nPos; +} + +void SvtIconWindow_Impl::UpdateIcons( sal_Bool _bHiContrast ) +{ + aIconCtrl.GetEntry( ICON_POS_NEWDOC )->SetImage( + Image( SvtResId( _bHiContrast ? IMG_SVT_NEWDOC_HC : IMG_SVT_NEWDOC ) ) ); + aIconCtrl.GetEntry( ICON_POS_TEMPLATES )->SetImage( + Image( SvtResId( _bHiContrast ? IMG_SVT_TEMPLATES_HC : IMG_SVT_TEMPLATES ) ) ); + aIconCtrl.GetEntry( ICON_POS_MYDOCS )->SetImage( + Image( SvtResId( _bHiContrast ? IMG_SVT_MYDOCS_HC : IMG_SVT_MYDOCS ) ) ); + aIconCtrl.GetEntry( ICON_POS_SAMPLES )->SetImage( + Image( SvtResId( _bHiContrast ? IMG_SVT_SAMPLES_HC : IMG_SVT_SAMPLES ) ) ); +} +/* -----------------27.11.2002 16:58----------------- + * + * --------------------------------------------------*/ +void SvtIconWindow_Impl::SelectFolder(sal_Int32 nFolderPosition) +{ + SvxIconChoiceCtrlEntry* pEntry = aIconCtrl.GetEntry( nFolderPosition ); + if(pEntry) + { + aIconCtrl.SetCursor( pEntry ); + aIconCtrl.GetClickHdl().Call(&aIconCtrl); + } +} + +// class SvtFileViewWindow_Impl -----------------------------------------_ + +SvtFileViewWindow_Impl::SvtFileViewWindow_Impl( SvtTemplateWindow* pParent ) : + + Window( pParent, WB_DIALOGCONTROL | WB_TABSTOP | WB_BORDER | WB_3DLOOK ), + + rParent ( *pParent ), + aFileView ( this, SvtResId( CTRL_FILEVIEW ), FILEVIEW_SHOW_TITLE ), + bIsTemplateFolder ( sal_False ) + +{ + aFileView.SetStyle( aFileView.GetStyle() | WB_DIALOGCONTROL | WB_TABSTOP ); + aFileView.SetHelpId( HID_TEMPLATEDLG_FILEVIEW ); + aFileView.Show(); + aFileView.SetPosPixel( Point( 0, 0 ) ); + aFileView.EnableAutoResize(); + aFileView.EnableContextMenu( sal_False ); + aFileView.EnableDelete( sal_False ); +} + +SvtFileViewWindow_Impl::~SvtFileViewWindow_Impl() +{ +} + +void GetMenuEntry_Impl +( + Sequence< PropertyValue >& aDynamicMenuEntry, + ::rtl::OUString& rTitle, + ::rtl::OUString& rURL, + ::rtl::OUString& rFrame, + ::rtl::OUString& rImageId +) +{ + for ( int i = 0; i < aDynamicMenuEntry.getLength(); i++ ) + { + if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_URL ) + aDynamicMenuEntry[i].Value >>= rURL; + else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_TITLE ) + aDynamicMenuEntry[i].Value >>= rTitle; + else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_IMAGEIDENTIFIER ) + aDynamicMenuEntry[i].Value >>= rImageId; + else if ( aDynamicMenuEntry[i].Name == DYNAMICMENU_PROPERTYNAME_TARGETNAME ) + aDynamicMenuEntry[i].Value >>= rFrame; + } +} +Sequence< ::rtl::OUString > SvtFileViewWindow_Impl::GetNewDocContents() const +{ + NewDocList_Impl aNewDocs; + Sequence< Sequence< PropertyValue > > aDynamicMenuEntries; + aDynamicMenuEntries = SvtDynamicMenuOptions().GetMenu( E_NEWMENU ); + + ::rtl::OUString aTitle; + ::rtl::OUString aURL; + ::rtl::OUString aImageURL; + ::rtl::OUString aTargetFrame; + + sal_uInt32 i, nCount = aDynamicMenuEntries.getLength(); + ::rtl::OUString sSeparator( ASCII_STR("private:separator") ); + ::rtl::OUString sSlotURL( ASCII_STR("slot:5500") ); + + for ( i = 0; i < nCount; ++i ) + { + GetMenuEntry_Impl( aDynamicMenuEntries[i], aTitle, aURL, aTargetFrame, aImageURL ); + + if ( aURL == sSeparator || aURL == sSlotURL ) + continue; + else + { + // title + String aRow = MnemonicGenerator::EraseAllMnemonicChars( String( aTitle ) ); + aRow += '\t'; + // no type + aRow += '\t'; + // no size + aRow += '\t'; + // no date + aRow += '\t'; + // url + aRow += String( aURL ); + aRow += '\t'; + // folder == false + aRow += '0'; + // image url? + if ( aImageURL.getLength() > 0 ) + { + aRow += '\t'; + aRow += String( aImageURL ); + } + + ::rtl::OUString* pRow = new ::rtl::OUString( aRow ); + aNewDocs.Insert( pRow, LIST_APPEND ); + } + } + + nCount = aNewDocs.Count(); + Sequence < ::rtl::OUString > aRet( nCount ); + ::rtl::OUString* pRet = aRet.getArray(); + for ( i = 0; i < nCount; ++i ) + { + ::rtl::OUString* pNewDoc = aNewDocs.GetObject(i); + pRet[i] = *( pNewDoc ); + delete pNewDoc; + } + + return aRet; +} + +void SvtFileViewWindow_Impl::Resize() +{ + Size aWinSize = GetOutputSizePixel(); + + static int x = 0; + static int y = 0; + + aWinSize.nA += x; + aWinSize.nB += y; + aFileView.SetSizePixel( aWinSize ); +} + +String SvtFileViewWindow_Impl::GetSelectedFile() const +{ + return aFileView.GetCurrentURL(); +} + +void SvtFileViewWindow_Impl::OpenFolder( const String& rURL ) +{ + aFolderURL = rURL; + + rParent.SetPrevLevelButtonState( rURL ); + + aFileView.SetUrlFilter( &aURLFilter ); + + INetProtocol eProt = INetURLObject( rURL ).GetProtocol(); + bIsTemplateFolder = ( eProt == INET_PROT_VND_SUN_STAR_HIER ); + bool isNewDocumentFolder = ( eProt == INET_PROT_PRIVATE ); + + aURLFilter.enableFilter( !bIsTemplateFolder && !isNewDocumentFolder ); + + if ( isNewDocumentFolder ) + { + aFileView.EnableNameReplacing( sal_False ); + aFileView.Initialize( GetNewDocContents() ); + } + else + { + xub_StrLen nSampFoldLen = aSamplesFolderURL.Len(); + aFileView.EnableNameReplacing( + nSampFoldLen && rURL.CompareTo( aSamplesFolderURL, nSampFoldLen ) == COMPARE_EQUAL ); + aFileView.Initialize( rURL, String(), NULL ); + } + aNewFolderLink.Call( this ); +} + +sal_Bool SvtFileViewWindow_Impl::HasPreviousLevel( String& rURL ) const +{ + INetURLObject aViewObj( aFileView.GetViewURL() ); + INetURLObject aRootObj( aCurrentRootURL ); + INetURLObject aMyDocObj( aMyDocumentsURL ); + + return ( ( aViewObj != aRootObj || aRootObj == aMyDocObj ) && aFileView.GetParentURL( rURL ) ); +} + +String SvtFileViewWindow_Impl::GetFolderTitle() const +{ + String aTitle; + ::utl::UCBContentHelper::GetTitle( aFolderURL, aTitle ); + return aTitle; +} + +void SvtFileViewWindow_Impl::SetFocus() +{ + aFileView.SetFocus(); +} + +// class SvtDocInfoTable_Impl -------------------------------------------- + +SvtDocInfoTable_Impl::SvtDocInfoTable_Impl() : + + ResStringArray( SvtResId( STRARY_SVT_DOCINFO ) ) + +{ +} +// ----------------------------------------------------------------------------- +// class SvtExtendedMultiLineEdit_Impl -------------------------------------------- +SvtExtendedMultiLineEdit_Impl::SvtExtendedMultiLineEdit_Impl( Window* pParent,WinBits _nBits ) : + + ExtMultiLineEdit( pParent, _nBits ) + +{ + SetLeftMargin( 10 ); +} +// ----------------------------------------------------------------------------- +void SvtExtendedMultiLineEdit_Impl::InsertEntry( const String& rTitle, const String& rValue ) +{ + String aText( '\n' ); + aText += rTitle; + aText += ':'; + InsertText( aText ); + sal_uLong nPara = GetParagraphCount() - 1; + SetAttrib( TextAttribFontWeight( WEIGHT_BOLD ), nPara, 0, aText.Len() ); + + aText = '\n'; + aText += rValue; + InsertText( aText ); + nPara = GetParagraphCount() - 1; + SetAttrib( TextAttribFontWeight( WEIGHT_NORMAL ), nPara, 0, aText.Len() ); + + InsertText( String( '\n' ) ); +} +// ----------------------------------------------------------------------------- + +// ----------------------------------------------------------------------- + +const String& SvtDocInfoTable_Impl::GetString( long nId ) const +{ + sal_uInt32 nPos( FindIndex( nId ) ); + + if ( RESARRAY_INDEX_NOTFOUND != nPos ) + return ResStringArray::GetString( nPos ); + else + return aEmptyString; +} + +// class SvtFrameWindow_Impl --------------------------------------------- + +SvtFrameWindow_Impl::SvtFrameWindow_Impl( Window* pParent ) : + + Window( pParent ) + +{ + // detect application language + aLocale= SvtPathOptions().GetLocale(); + + // create windows and frame + pEditWin = new ODocumentInfoPreview( this ,WB_LEFT | WB_VSCROLL | WB_READONLY | WB_BORDER | WB_3DLOOK); + pTextWin = new Window( this ); + xFrame = Reference < XFrame > ( ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.frame.Frame") ), UNO_QUERY ); + xWindow = VCLUnoHelper::GetInterface( pTextWin ); + xFrame->initialize( xWindow ); + + // create docinfo instance + m_xDocProps.set( ::comphelper::getProcessServiceFactory()->createInstance( + ASCII_STR("com.sun.star.document.DocumentProperties") ), + UNO_QUERY ); + + pEmptyWin = new Window( this, WB_BORDER | WB_3DLOOK ); +} + +SvtFrameWindow_Impl::~SvtFrameWindow_Impl() +{ + delete pEditWin; + delete pEmptyWin; + xFrame->dispose(); +} + +void SvtFrameWindow_Impl::ViewEditWin() +{ + pEmptyWin->Hide(); + xWindow->setVisible( sal_False ); + pTextWin->Hide(); + pEditWin->Show(); +} + +void SvtFrameWindow_Impl::ViewTextWin() +{ + pEmptyWin->Hide(); + pEditWin->Hide(); + xWindow->setVisible( sal_True ); + pTextWin->Show(); +} + +void SvtFrameWindow_Impl::ViewEmptyWin() +{ + xWindow->setVisible( sal_False ); + pTextWin->Hide(); + pEditWin->Hide(); + pEmptyWin->Show(); +} + +void SvtFrameWindow_Impl::ViewNonEmptyWin() +{ + if( bDocInfo ) + ViewEditWin(); + else + ViewTextWin(); +} + +IMPL_STATIC_LINK_NOINSTANCE( SvtFrameWindow_Impl, ExecuteHdl_Impl, SvtExecuteInfo*, pExecuteInfo ) +{ + try + { + pExecuteInfo->xDispatch->dispatch( pExecuteInfo->aTargetURL, Sequence < PropertyValue >() ); + } + catch ( Exception& ) + { + } + + delete pExecuteInfo; + return 0; +} + +void SvtFrameWindow_Impl::ShowDocInfo( const String& rURL ) +{ + try + { + uno::Reference < task::XInteractionHandler > xInteractionHandler( ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.task.InteractionHandler") ), uno::UNO_QUERY ); + uno::Sequence < beans::PropertyValue> aProps(1); + aProps[0].Name = ::rtl::OUString::createFromAscii("InteractionHandler"); + aProps[0].Value <<= xInteractionHandler; + m_xDocProps->loadFromMedium( rURL, aProps ); + pEditWin->fill( m_xDocProps, rURL ); + } + catch ( UnknownPropertyException& ) {} + catch ( Exception& ) {} +} + +void SvtFrameWindow_Impl::Resize() +{ + Size aWinSize = GetOutputSizePixel(); + pEditWin->SetSizePixel( aWinSize ); + pTextWin->SetSizePixel( aWinSize ); + pEmptyWin->SetSizePixel( aWinSize ); +} + +void SvtFrameWindow_Impl::OpenFile( const String& rURL, sal_Bool bPreview, sal_Bool bIsTemplate, sal_Bool bAsTemplate ) +{ + if ( bPreview ) + aCurrentURL = rURL; + + ViewNonEmptyWin(); + pEditWin->Clear(); + + if ( rURL.Len() > 0 && bPreview && m_xDocProps.is() ) + ShowDocInfo( rURL ); + + if ( rURL.Len() == 0 ) + { + xFrame->setComponent( Reference < com::sun::star::awt::XWindow >(), Reference < XController >() ); + ViewEmptyWin(); + } + else if ( !::utl::UCBContentHelper::IsFolder( rURL ) ) + { + com::sun::star::util::URL aURL; + aURL.Complete = rURL; + Reference < com::sun::star::util::XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.util.URLTransformer" ) ), UNO_QUERY ); + xTrans->parseStrict( aURL ); + + String aTarget; + Reference < XDispatchProvider > xProv( xFrame, UNO_QUERY ); + if ( bPreview ) + aTarget = ASCII_STR("_self"); + else + { + // can be removed if the database application change its URL + String sServiceScheme( RTL_CONSTASCII_STRINGPARAM( "service:" ) ); + if ( rURL.Match( sServiceScheme ) != sServiceScheme.Len() ) + // service URL has no default target + aTarget = ASCII_STR("_default"); + xProv = Reference < XDispatchProvider >( ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.frame.Desktop") ), UNO_QUERY ); + } + + Reference < XDispatch > xDisp = xProv.is() ? + xProv->queryDispatch( aURL, aTarget, 0 ) : Reference < XDispatch >(); + + if ( xDisp.is() ) + { + if ( bPreview ) + { + if ( m_aOpenURL != aURL.Complete ) + { + WaitObject aWaitCursor( GetParent() ); + // disabling must be done here, does not work in ctor because + // execute of the dialog will overwrite it + // ( own execute method would help ) + pTextWin->EnableInput( sal_False, sal_True ); + if ( pTextWin->IsReallyVisible() ) + { + sal_Bool b = sal_True; + Sequence < PropertyValue > aArgs( 4 ); + aArgs[0].Name = ASCII_STR("Preview"); + aArgs[0].Value.setValue( &b, ::getBooleanCppuType() ); + aArgs[1].Name = ASCII_STR("ReadOnly"); + aArgs[1].Value.setValue( &b, ::getBooleanCppuType() ); + aArgs[2].Name = ASCII_STR("AsTemplate"); // prevents getting an empty URL with getURL()! + + uno::Reference < task::XInteractionHandler > xInteractionHandler( ::comphelper::getProcessServiceFactory()->createInstance( + ::rtl::OUString::createFromAscii("com.sun.star.task.InteractionHandler") ), uno::UNO_QUERY ); + aArgs[3].Name = ::rtl::OUString::createFromAscii("InteractionHandler"); + aArgs[3].Value <<= xInteractionHandler; + + b = sal_False; + aArgs[2].Value.setValue( &b, ::getBooleanCppuType() ); + xDisp->dispatch( aURL, aArgs ); + + ::rtl::OUString aDispURL; + Reference< ::com::sun::star::frame::XController > xCtrl = xFrame->getController(); + if( xCtrl.is() ) + { + Reference< ::com::sun::star::frame::XModel > xMdl = xCtrl->getModel(); + if( xMdl.is() ) + aDispURL = xMdl->getURL(); + } + + if( aDispURL != aURL.Complete ) + { + xFrame->setComponent( Reference < com::sun::star::awt::XWindow >(), Reference < XController >() ); + ViewEmptyWin(); + m_aOpenURL = rtl::OUString(); + } + else + m_aOpenURL = aDispURL; + } + } + } + else if ( bIsTemplate ) + { + Sequence < PropertyValue > aArgs( 1 ); + aArgs[0].Name = ASCII_STR("AsTemplate"); + aArgs[0].Value <<= bAsTemplate; + xDisp->dispatch( aURL, aArgs ); + m_aOpenURL = rtl::OUString(); + } + else + { + /* + SvtExecuteInfo* pExecuteInfo = new SvtExecuteInfo; + pExecuteInfo->xDispatch = xDisp; + pExecuteInfo->aTargetURL = aURL; + Application::PostUserEvent( + STATIC_LINK(0, SvtFrameWindow_Impl, ExecuteHdl_Impl), pExecuteInfo ); + */ + Sequence < PropertyValue > aArgs; + xDisp->dispatch( aURL, aArgs ); + m_aOpenURL = rtl::OUString(); + } + } + } +} + +void SvtFrameWindow_Impl::ToggleView( sal_Bool bDI ) +{ + bDocInfo = bDI; + + // view is set properly in OpenFile() + + OpenFile( aCurrentURL, sal_True, sal_False, sal_False ); +} + +// class SvtTemplateWindow ----------------------------------------------- + +SvtTemplateWindow::SvtTemplateWindow( Window* pParent ) : + + Window( pParent, WB_DIALOGCONTROL ), + + aFileViewTB ( this, SvtResId( TB_SVT_FILEVIEW ) ), + aFrameWinTB ( this, SvtResId( TB_SVT_FRAMEWIN ) ), + aSplitWin ( this, WB_DIALOGCONTROL | WB_NOSPLITDRAW ), + pHistoryList ( NULL ) + +{ + // create windows + pIconWin = new SvtIconWindow_Impl( this ); + pFileWin = new SvtFileViewWindow_Impl( this ); + pFileWin->SetMyDocumentsURL( pIconWin->GetMyDocumentsRootURL() ); + pFileWin->SetSamplesFolderURL( pIconWin->GetSamplesFolderURL() ); + pFrameWin = new SvtFrameWindow_Impl( this ); + + // set handlers + pIconWin->SetClickHdl( LINK( this, SvtTemplateWindow, IconClickHdl_Impl ) ); + pFileWin->SetSelectHdl( LINK( this, SvtTemplateWindow, FileSelectHdl_Impl ) ); + pFileWin->SetDoubleClickHdl( LINK( this, SvtTemplateWindow, FileDblClickHdl_Impl ) ); + pFileWin->SetNewFolderHdl( LINK( this, SvtTemplateWindow, NewFolderHdl_Impl ) ); + + // create the split items + aSplitWin.SetAlign( WINDOWALIGN_LEFT ); + long nWidth = pIconWin->GetMaxTextLength() * 8 / 7 + 1; // extra space for border + aSplitWin.InsertItem( ICONWIN_ID, pIconWin, nWidth, SPLITWINDOW_APPEND, 0, SWIB_FIXED ); + aSplitWin.InsertItem( FILEWIN_ID, pFileWin, 50, SPLITWINDOW_APPEND, 0, SWIB_PERCENTSIZE ); + aSplitWin.InsertItem( FRAMEWIN_ID, pFrameWin, 50, SPLITWINDOW_APPEND, 0, SWIB_PERCENTSIZE ); + aSplitWin.SetSplitHdl( LINK( this, SvtTemplateWindow, ResizeHdl_Impl ) ); + + // show the windows + pIconWin->Show(); + pFileWin->Show(); + pFrameWin->Show(); + aSplitWin.Show(); + + // initialize the timers + aSelectTimer.SetTimeout( 200 ); + aSelectTimer.SetTimeoutHdl( LINK( this, SvtTemplateWindow, TimeoutHdl_Impl ) ); + + // initialize the toolboxes and then show them + InitToolBoxes(); + aFileViewTB.Show(); + aFrameWinTB.Show(); + + ReadViewSettings( ); + + Application::PostUserEvent( LINK( this, SvtTemplateWindow, ResizeHdl_Impl ) ); +} + +// ------------------------------------------------------------------------ + +SvtTemplateWindow::~SvtTemplateWindow() +{ + WriteViewSettings( ); + + delete pIconWin; + delete pFileWin; + delete pFrameWin; + if ( pHistoryList ) + { + for ( sal_uInt32 i = 0; i < pHistoryList->Count(); ++i ) + delete pHistoryList->GetObject(i); + delete pHistoryList; + } +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtTemplateWindow , IconClickHdl_Impl, SvtIconChoiceCtrl *, EMPTYARG ) +{ + String aURL = pIconWin->GetSelectedIconURL(); + if ( !aURL.Len() ) + aURL = pIconWin->GetCursorPosIconURL(); + if ( pFileWin->GetRootURL() != aURL ) + { + pFileWin->OpenRoot( aURL ); + pIconWin->InvalidateIconControl(); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_PRINT, sal_False ); + } + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtTemplateWindow , FileSelectHdl_Impl, SvtFileView *, EMPTYARG ) +{ + aSelectTimer.Start(); + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtTemplateWindow , FileDblClickHdl_Impl, SvtFileView *, EMPTYARG ) +{ + if ( aSelectTimer.IsActive() ) + aSelectTimer.Stop(); + + String aURL = pFileWin->GetSelectedFile(); + if ( aURL.Len() > 0 ) + { + if ( ::utl::UCBContentHelper::IsFolder( aURL ) ) + pFileWin->OpenFolder( aURL ); + else + aDoubleClickHdl.Call( this ); + } + + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtTemplateWindow , NewFolderHdl_Impl, SvtFileView *, EMPTYARG ) +{ + pFrameWin->OpenFile( String(), sal_True, sal_False, sal_False ); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_PRINT, sal_False ); + + String sURL = pFileWin->GetFolderURL(); + sal_uLong nPos = pIconWin->GetRootPos( sURL ); + AppendHistoryURL( sURL, nPos ); + + aNewFolderHdl.Call( this ); + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtTemplateWindow , TimeoutHdl_Impl, Timer *, EMPTYARG ) +{ + aSelectHdl.Call( this ); + String sURL = pFileWin->GetSelectedFile(); + sal_Bool bIsNewDoc = ( pIconWin->GetSelectEntryPos() == ICON_POS_NEWDOC ); + sal_Bool bIsFile = ( sURL.Len() != 0 && !::utl::UCBContentHelper::IsFolder( sURL ) && + INetURLObject( sURL ).GetProtocol() != INET_PROT_PRIVATE && !bIsNewDoc ); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_PRINT, bIsFile ); + aFrameWinTB.EnableItem( TI_DOCTEMPLATE_PREVIEW, !bIsNewDoc ); + + if ( bIsFile ) + pFrameWin->OpenFile( sURL, sal_True, sal_False, sal_False ); + else if ( bIsNewDoc && aFrameWinTB.IsItemChecked( TI_DOCTEMPLATE_PREVIEW ) ) + { + aFrameWinTB.CheckItem( TI_DOCTEMPLATE_DOCINFO ); + DoAction( TI_DOCTEMPLATE_DOCINFO ); + } + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtTemplateWindow , ClickHdl_Impl, ToolBox *, pToolBox ) +{ + DoAction( pToolBox->GetCurItemId() ); + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtTemplateWindow , ResizeHdl_Impl, SplitWindow *, EMPTYARG ) +{ + Resize(); + return 0; +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::PrintFile( const String& rURL ) +{ + // open the file readonly and hidden + Sequence < PropertyValue > aArgs( 2 ); + aArgs[0].Name = ASCII_STR("ReadOnly"); + aArgs[0].Value <<= sal_True; + aArgs[1].Name = ASCII_STR("Hidden"); + aArgs[1].Value <<= sal_True; + + Reference < XComponentLoader > xDesktop( ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.frame.Desktop") ), UNO_QUERY ); + Reference < XModel > xModel( xDesktop->loadComponentFromURL( + rURL, ASCII_STR("_blank"), 0, aArgs ), UNO_QUERY ); + if ( xModel.is() ) + { + // print + Reference < XPrintable > xPrintable( xModel, UNO_QUERY ); + if ( xPrintable.is() ) + xPrintable->print( Sequence < PropertyValue >() ); + } +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::AppendHistoryURL( const String& rURL, sal_uLong nGroup ) +{ + sal_Bool bInsert = sal_True; + if ( !pHistoryList ) + pHistoryList = new HistoryList_Impl; + else if ( pHistoryList->Count() > 0 ) + { + FolderHistory* pLastEntry = pHistoryList->GetObject( pHistoryList->Count() - 1 ); + bInsert = ( rURL != pLastEntry->m_sURL); + } + + if ( bInsert ) + { + FolderHistory* pEntry = new FolderHistory( rURL, nGroup ); + pHistoryList->Insert( pEntry, LIST_APPEND ); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_BACK, pHistoryList->Count() > 1 ); + } +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::OpenHistory() +{ + FolderHistory* pEntry = pHistoryList->Remove( pHistoryList->Count() - 1 ); + pEntry = pHistoryList->Remove( pHistoryList->Count() - 1 ); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_BACK, pHistoryList->Count() > 1 ); + pFileWin->OpenFolder( pEntry->m_sURL ); + pIconWin->SetCursorPos( pEntry->m_nGroup ); + delete pEntry; +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::DoAction( sal_uInt16 nAction ) +{ + switch( nAction ) + { + case TI_DOCTEMPLATE_BACK : + { + if ( pHistoryList && pHistoryList->Count() > 1 ) + OpenHistory(); + break; + } + + case TI_DOCTEMPLATE_PREV : + { + String aURL; + if ( pFileWin->HasPreviousLevel( aURL ) ) + pFileWin->OpenFolder( aURL ); + break; + } + + case TI_DOCTEMPLATE_PRINT : + { + String sPrintFile( pFileWin->GetSelectedFile() ); + if ( sPrintFile.Len() > 0 ) + PrintFile( sPrintFile ); + break; + } + + case TI_DOCTEMPLATE_DOCINFO : + case TI_DOCTEMPLATE_PREVIEW : + { + pFrameWin->ToggleView( TI_DOCTEMPLATE_DOCINFO == nAction ); + break; + } + } +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::InitToolBoxes() +{ + InitToolBoxImages(); + + Size aSize = aFileViewTB.CalcWindowSizePixel(); + aSize.Height() += 4; + aFileViewTB.SetPosSizePixel( Point( 0, 2 ), aSize ); + aSize = aFrameWinTB.CalcWindowSizePixel(); + aSize.Height() += 4; + aFrameWinTB.SetPosSizePixel( Point( pFrameWin->GetPosPixel().X() + 2, 2 ), aSize ); + + sal_Bool bFlat = ( SvtMiscOptions().GetToolboxStyle() == TOOLBOX_STYLE_FLAT ); + if ( bFlat ) + { + aFileViewTB.SetOutStyle( TOOLBOX_STYLE_FLAT ); + aFrameWinTB.SetOutStyle( TOOLBOX_STYLE_FLAT ); + } + + aFileViewTB.EnableItem( TI_DOCTEMPLATE_BACK, sal_False ); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_PREV, sal_False ); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_PRINT, sal_False ); + + Link aLink = LINK( this, SvtTemplateWindow, ClickHdl_Impl ); + aFileViewTB.SetClickHdl( aLink ); + aFrameWinTB.SetClickHdl( aLink ); +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::InitToolBoxImages() +{ + SvtMiscOptions aMiscOpt; + sal_Bool bLarge = aMiscOpt.AreCurrentSymbolsLarge(); + sal_Bool bHiContrast = aFileViewTB.GetSettings().GetStyleSettings().GetHighContrastMode(); + + aFileViewTB.SetItemImage( TI_DOCTEMPLATE_BACK, Image( SvtResId( + bLarge ? bHiContrast ? IMG_SVT_DOCTEMPL_HC_BACK_LARGE : IMG_SVT_DOCTEMPLATE_BACK_LARGE + : bHiContrast ? IMG_SVT_DOCTEMPL_HC_BACK_SMALL : IMG_SVT_DOCTEMPLATE_BACK_SMALL ) ) ); + aFileViewTB.SetItemImage( TI_DOCTEMPLATE_PREV, Image( SvtResId( + bLarge ? bHiContrast ? IMG_SVT_DOCTEMPL_HC_PREV_LARGE : IMG_SVT_DOCTEMPLATE_PREV_LARGE + : bHiContrast ? IMG_SVT_DOCTEMPL_HC_PREV_SMALL : IMG_SVT_DOCTEMPLATE_PREV_SMALL ) ) ); + aFileViewTB.SetItemImage( TI_DOCTEMPLATE_PRINT, Image( SvtResId( + bLarge ? bHiContrast ? IMG_SVT_DOCTEMPL_HC_PRINT_LARGE : IMG_SVT_DOCTEMPLATE_PRINT_LARGE + : bHiContrast ? IMG_SVT_DOCTEMPL_HC_PRINT_SMALL : IMG_SVT_DOCTEMPLATE_PRINT_SMALL ) ) ); + + aFrameWinTB.SetItemImage( TI_DOCTEMPLATE_DOCINFO, Image( SvtResId( + bLarge ? bHiContrast ? IMG_SVT_DOCTEMPL_HC_DOCINFO_LARGE : IMG_SVT_DOCTEMPLATE_DOCINFO_LARGE + : bHiContrast ? IMG_SVT_DOCTEMPL_HC_DOCINFO_SMALL : IMG_SVT_DOCTEMPLATE_DOCINFO_SMALL ) ) ); + aFrameWinTB.SetItemImage( TI_DOCTEMPLATE_PREVIEW, Image( SvtResId( + bLarge ? bHiContrast ? IMG_SVT_DOCTEMPL_HC_PREVIEW_LARGE : IMG_SVT_DOCTEMPLATE_PREVIEW_LARGE + : bHiContrast ? IMG_SVT_DOCTEMPL_HC_PREVIEW_SMALL : IMG_SVT_DOCTEMPLATE_PREVIEW_SMALL ) ) ); +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::UpdateIcons() +{ + pIconWin->UpdateIcons( aFileViewTB.GetSettings().GetStyleSettings().GetHighContrastMode() ); +} + +// ------------------------------------------------------------------------ + +long SvtTemplateWindow::PreNotify( NotifyEvent& rNEvt ) +{ + sal_uInt16 nType = rNEvt.GetType(); + long nRet = 0; + + if ( EVENT_KEYINPUT == nType && rNEvt.GetKeyEvent() ) + { + const KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode(); + sal_uInt16 nCode = rKeyCode.GetCode(); + + if ( KEY_BACKSPACE == nCode && !rKeyCode.GetModifier() && pFileWin->HasChildPathFocus() ) + { + DoAction( TI_DOCTEMPLATE_BACK ); + nRet = 1; + } + else if ( pIconWin->ProcessKeyEvent( *rNEvt.GetKeyEvent() ) ) + { + nRet = 1; + } + } + + return nRet ? nRet : Window::PreNotify( rNEvt ); +} + +// ----------------------------------------------------------------------------- + +void SvtTemplateWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( ( ( rDCEvt.GetType() == DATACHANGED_SETTINGS ) || + ( rDCEvt.GetType() == DATACHANGED_DISPLAY ) ) && + ( rDCEvt.GetFlags() & SETTINGS_STYLE ) ) + { + // update of the background for the area left of the FileView toolbox + SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetFaceColor() ) ); + // update of the images of the IconChoiceControl + UpdateIcons(); + // update of the toolbox images + InitToolBoxImages(); + } +} +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::Resize() +{ + long nItemSize = aSplitWin.GetItemSize( ICONWIN_ID ); + long nSplitterWidth = Splitter( this, 0 ).GetSizePixel().Width(); + + Point aPos = aFileViewTB.GetPosPixel(); + aPos.X() = nItemSize + nSplitterWidth / 2; + aFileViewTB.SetPosPixel( aPos ); + + Size aWinSize = GetOutputSizePixel(); + long nWidth = aWinSize.Width() - aPos.X(); + + nItemSize = nWidth * aSplitWin.GetItemSize( FILEWIN_ID ) / 100; + aPos.X() = pFrameWin->GetPosPixel().X() + 2; + aFrameWinTB.SetPosPixel( aPos ); + + Size aSize = aFileViewTB.GetSizePixel(); + aSize.Width() = nItemSize; + aFileViewTB.SetSizePixel( aSize ); + + aSize = aFrameWinTB.GetSizePixel(); + aSize.Width() = nWidth - nItemSize; + aFrameWinTB.SetSizePixel( aSize ); + + long nToolBoxHeight = aSize.Height() + aFrameWinTB.GetPosPixel().Y(); + aSize = aWinSize; + aSize.Height() -= nToolBoxHeight; + aSplitWin.SetPosSizePixel( Point( 0, nToolBoxHeight ), aSize ); +} + +// ------------------------------------------------------------------------ + +String SvtTemplateWindow::GetSelectedFile() const +{ + return pFileWin->GetSelectedFile(); +} + +// ------------------------------------------------------------------------ + +sal_Bool SvtTemplateWindow::IsFileSelected() const +{ + String aURL = pFileWin->GetSelectedFile(); + sal_Bool bRet = ( aURL.Len() > 0 && !::utl::UCBContentHelper::IsFolder( aURL ) ); + return bRet; +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::OpenFile( sal_Bool bNotAsTemplate ) +{ + String aURL = pFileWin->GetSelectedFile(); + if ( aURL.Len() > 0 && !::utl::UCBContentHelper::IsFolder( aURL ) ) + pFrameWin->OpenFile( aURL, sal_False, pFileWin->IsTemplateFolder(), !bNotAsTemplate ); +} + +// ------------------------------------------------------------------------ + +String SvtTemplateWindow::GetFolderTitle() const +{ + String sTitle; + String sFolderURL = pFileWin->GetFolderURL(); + if ( pIconWin->IsRootURL( sFolderURL ) ) + sTitle = pIconWin->GetIconText( sFolderURL ); + else + sTitle = pFileWin->GetFolderTitle(); + return sTitle; +} + +// ------------------------------------------------------------------------ + +String SvtTemplateWindow::GetFolderURL() const +{ + return pFileWin->GetFolderURL(); +} + + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::SetFocus( sal_Bool bIconWin ) +{ + if ( bIconWin ) + pIconWin->SetFocus(); + else + pFileWin->SetFocus(); +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::OpenTemplateRoot() +{ + pFileWin->OpenFolder( pIconWin->GetTemplateRootURL() ); +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::SetPrevLevelButtonState( const String& rURL ) +{ + // disable the prev level button on root folder of the icon pane (except My Documents) + // and on the root of all (file:/// -> count == 0) + INetURLObject aObj( rURL ); + sal_Int32 nCount = aObj.getSegmentCount(); + sal_Bool bEnable = + ( nCount > 0 && + ( !pIconWin->IsRootURL( rURL ) || rURL == pIconWin->GetMyDocumentsRootURL() ) ); + aFileViewTB.EnableItem( TI_DOCTEMPLATE_PREV, bEnable ); +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::ClearHistory() +{ + if( pHistoryList ) + pHistoryList->Clear(); +} + +// ------------------------------------------------------------------------ + +long SvtTemplateWindow::CalcHeight() const +{ + // toolbox height + long nHeight = aFileViewTB.GetSizePixel().Height(); + // + iconwin height + nHeight += pIconWin->CalcHeight(); + // + little offset + nHeight += 8; + return nHeight; +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::ReadViewSettings() +{ + // defaults + sal_Int32 nSelectedGroup = ICON_POS_TEMPLATES; + sal_Int32 nSelectedView = TI_DOCTEMPLATE_DOCINFO; + double nSplitRatio = 0.5; + ::rtl::OUString sLastFolder; + + SvtViewOptions aViewSettings( E_DIALOG, VIEWSETTING_NEWFROMTEMPLATE ); + if ( aViewSettings.Exists() ) + { + // read the settings + Sequence< NamedValue > aSettings = aViewSettings.GetUserData( ); + + aViewSettings.GetUserItem( VIEWSETTING_SELECTEDGROUP ) >>= nSelectedGroup; + aViewSettings.GetUserItem( VIEWSETTING_SELECTEDVIEW ) >>= nSelectedView; + aViewSettings.GetUserItem( VIEWSETTING_SPLITRATIO ) >>= nSplitRatio; + aViewSettings.GetUserItem( VIEWSETTING_LASTFOLDER ) >>= sLastFolder; + } + // normalize + if ( nSelectedGroup < ICON_POS_NEWDOC ) nSelectedGroup = ICON_POS_NEWDOC; + if ( nSelectedGroup > ICON_POS_SAMPLES ) nSelectedGroup = ICON_POS_SAMPLES; + + if ( ( TI_DOCTEMPLATE_DOCINFO != nSelectedView ) && ( TI_DOCTEMPLATE_PREVIEW != nSelectedView ) ) + nSelectedView = TI_DOCTEMPLATE_DOCINFO; + + if ( nSplitRatio < 0.2 ) nSplitRatio = 0.2; + if ( nSplitRatio > 0.8 ) nSplitRatio = 0.8; + + // change our view according to the settings + + // the selected view (details or preview) + pFrameWin->ToggleView( TI_DOCTEMPLATE_DOCINFO == nSelectedView ); + aFrameWinTB.CheckItem( (sal_uInt16)nSelectedView, sal_True ); + + // the split ratio + sal_Int32 nSplitFileAndFrameSize = aSplitWin.GetItemSize( FILEWIN_ID ) + aSplitWin.GetItemSize( FRAMEWIN_ID ); + sal_Int32 nSplitFileSize = (sal_Int32)(nSplitFileAndFrameSize * nSplitRatio); + sal_Int32 nSplitFrameSize = nSplitFileAndFrameSize - nSplitFileSize; + aSplitWin.SetItemSize( FILEWIN_ID, nSplitFileSize ); + aSplitWin.SetItemSize( FRAMEWIN_ID, nSplitFrameSize ); + Resize(); + + // the selected folder + pIconWin->SetCursorPos( nSelectedGroup ); + + // open the last folder or the selected group + if ( sLastFolder.getLength() > 0 ) + pFileWin->OpenFolder( sLastFolder ); + else + IconClickHdl_Impl( NULL ); +} + +// ------------------------------------------------------------------------ + +void SvtTemplateWindow::WriteViewSettings() +{ + // collect + Sequence< NamedValue > aSettings(4); + + // the selected group + aSettings[0].Name = VIEWSETTING_SELECTEDGROUP; + pIconWin->SetFocus(); + aSettings[0].Value <<= (sal_Int32)pIconWin->GetCursorPos( ); + + // the selected view mode + aSettings[1].Name = VIEWSETTING_SELECTEDVIEW; + aSettings[1].Value <<= sal_Int32( aFrameWinTB.IsItemChecked( TI_DOCTEMPLATE_DOCINFO ) ? TI_DOCTEMPLATE_DOCINFO : TI_DOCTEMPLATE_PREVIEW ); + + // the split ratio + aSettings[2].Name = VIEWSETTING_SPLITRATIO; + sal_Int32 nSplitFileSize = aSplitWin.GetItemSize( FILEWIN_ID ); + sal_Int32 nSplitFileAndFrameSize = nSplitFileSize + aSplitWin.GetItemSize( FRAMEWIN_ID ); + aSettings[2].Value <<= double( 1.0 * nSplitFileSize / nSplitFileAndFrameSize ); + + // last folder + aSettings[3].Name = VIEWSETTING_LASTFOLDER; + aSettings[3].Value <<= ::rtl::OUString( pFileWin->GetFolderURL() ); + + // write + SvtViewOptions aViewSettings( E_DIALOG, VIEWSETTING_NEWFROMTEMPLATE ); + aViewSettings.SetUserData( aSettings ); +} +/* -----------------27.11.2002 17:20----------------- + * + * --------------------------------------------------*/ + +void SvtTemplateWindow::SelectFolder(sal_Int32 nFolderPosition) +{ + pIconWin->SelectFolder(nFolderPosition); +} +// struct SvtTmplDlg_Impl ------------------------------------------------ + +struct SvtTmplDlg_Impl +{ + SvtTemplateWindow* pWin; + String aTitle; + Timer aUpdateTimer; + sal_Bool bSelectNoOpen; + + uno::Reference< util::XOfficeInstallationDirectories > m_xOfficeInstDirs; + + + SvtTmplDlg_Impl( Window* pParent ) : pWin( new SvtTemplateWindow( pParent ) ) ,bSelectNoOpen( sal_False ) {} + + ~SvtTmplDlg_Impl() { delete pWin; } + + uno::Reference< util::XOfficeInstallationDirectories > getOfficeInstDirs(); +}; + +uno::Reference< util::XOfficeInstallationDirectories > SvtTmplDlg_Impl::getOfficeInstDirs() +{ + if ( !m_xOfficeInstDirs.is() ) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xSMgr = comphelper::getProcessServiceFactory(); + + uno::Reference< beans::XPropertySet > xPropSet( xSMgr, uno::UNO_QUERY ); + if ( xPropSet.is() ) + { + uno::Reference< uno::XComponentContext > xCtx; + xPropSet->getPropertyValue( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ) ) ) + >>= xCtx; + + if ( xCtx.is() ) + { + xCtx->getValueByName( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "/singletons/com.sun.star.util.theOfficeInstallationDirectories" ) ) ) + >>= m_xOfficeInstDirs; + } + } + } + catch( uno::Exception& ) + {} + } + + return m_xOfficeInstDirs; +} + +// class SvtDocumentTemplateDialog --------------------------------------- + +SvtDocumentTemplateDialog::SvtDocumentTemplateDialog( Window* _pParent, SelectOnly ) : + ModalDialog( _pParent, SvtResId( DLG_DOCTEMPLATE ) ), + + aMoreTemplatesLink ( this, SvtResId( FT_DOCTEMPLATE_LINK ) ), + aLine ( this, SvtResId( FL_DOCTEMPLATE ) ), + aManageBtn ( this, SvtResId( BTN_DOCTEMPLATE_MANAGE ) ), + aEditBtn ( this, SvtResId( BTN_DOCTEMPLATE_EDIT ) ), + aOKBtn ( this, SvtResId( BTN_DOCTEMPLATE_OPEN ) ), + aCancelBtn ( this, SvtResId( BTN_DOCTEMPLATE_CANCEL ) ), + aHelpBtn ( this, SvtResId( BTN_DOCTEMPLATE_HELP ) ), + pImpl ( NULL ) +{ + FreeResource(); + InitImpl( ); + + // no editing of templates + aEditBtn.Hide(); + + pImpl->bSelectNoOpen = sal_True; +} + +// ------------------------------------------------------------------------ + +SvtDocumentTemplateDialog::SvtDocumentTemplateDialog( Window* pParent ) : + + ModalDialog( pParent, SvtResId( DLG_DOCTEMPLATE ) ), + + aMoreTemplatesLink ( this, SvtResId( FT_DOCTEMPLATE_LINK ) ), + aLine ( this, SvtResId( FL_DOCTEMPLATE ) ), + aManageBtn ( this, SvtResId( BTN_DOCTEMPLATE_MANAGE ) ), + aEditBtn ( this, SvtResId( BTN_DOCTEMPLATE_EDIT ) ), + aOKBtn ( this, SvtResId( BTN_DOCTEMPLATE_OPEN ) ), + aCancelBtn ( this, SvtResId( BTN_DOCTEMPLATE_CANCEL ) ), + aHelpBtn ( this, SvtResId( BTN_DOCTEMPLATE_HELP ) ), + pImpl ( NULL ) +{ + FreeResource(); + InitImpl( ); +} + +// ------------------------------------------------------------------------ + +void SvtDocumentTemplateDialog::InitImpl( ) +{ + pImpl = new SvtTmplDlg_Impl( this ); + pImpl->aTitle = GetText(); + + bool bHideLink = ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode() + == SvtExtendedSecurityOptions::OPEN_NEVER ); + if ( !bHideLink ) + { + aMoreTemplatesLink.SetURL( String( + RTL_CONSTASCII_STRINGPARAM( "http://templates.services.openoffice.org/?cid=923508" ) ) ); + aMoreTemplatesLink.SetClickHdl( LINK( this, SvtDocumentTemplateDialog, OpenLinkHdl_Impl ) ); + } + else + aMoreTemplatesLink.Hide(); + + aManageBtn.SetClickHdl( LINK( this, SvtDocumentTemplateDialog, OrganizerHdl_Impl ) ); + Link aLink = LINK( this, SvtDocumentTemplateDialog, OKHdl_Impl ); + aEditBtn.SetClickHdl( aLink ); + aOKBtn.SetClickHdl( aLink ); + + pImpl->pWin->SetSelectHdl( LINK( this, SvtDocumentTemplateDialog, SelectHdl_Impl ) ); + pImpl->pWin->SetDoubleClickHdl( LINK( this, SvtDocumentTemplateDialog, DoubleClickHdl_Impl ) ); + pImpl->pWin->SetNewFolderHdl( LINK( this, SvtDocumentTemplateDialog, NewFolderHdl_Impl ) ); + pImpl->pWin->SetSendFocusHdl( LINK( this, SvtDocumentTemplateDialog, SendFocusHdl_Impl ) ); + + // dynamic height adjustment + long nHeight = pImpl->pWin->CalcHeight(); + + Size aSize = GetOutputSizePixel(); + Point aPos = aMoreTemplatesLink.GetPosPixel(); + Size a6Size = LogicToPixel( Size( 6, 6 ), MAP_APPFONT ); + if ( bHideLink ) + aPos.Y() += aMoreTemplatesLink.GetSizePixel().Height(); + else + aPos.Y() -= a6Size.Height(); + long nDelta = aPos.Y() - nHeight; + aSize.Height() -= nDelta; + SetOutputSizePixel( aSize ); + + aSize.Height() = nHeight; + aSize.Width() -= ( a6Size.Width() * 2 ); + pImpl->pWin->SetPosSizePixel( Point( a6Size.Width(), 0 ), aSize ); + + aPos = aMoreTemplatesLink.GetPosPixel(); + aPos.Y() -= nDelta; + aMoreTemplatesLink.SetPosPixel( aPos ); + aPos = aLine.GetPosPixel(); + aPos.Y() -= nDelta; + aLine.SetPosPixel( aPos ); + aPos = aManageBtn.GetPosPixel(); + aPos.Y() -= nDelta; + aManageBtn.SetPosPixel( aPos ); + aPos = aEditBtn.GetPosPixel(); + aPos.Y() -= nDelta; + aEditBtn.SetPosPixel( aPos ); + aPos = aOKBtn.GetPosPixel(); + aPos.Y() -= nDelta; + aOKBtn.SetPosPixel( aPos ); + aPos = aCancelBtn.GetPosPixel(); + aPos.Y() -= nDelta; + aCancelBtn.SetPosPixel( aPos ); + aPos = aHelpBtn.GetPosPixel(); + aPos.Y() -= nDelta; + aHelpBtn.SetPosPixel( aPos ); + + pImpl->pWin->Show(); + + SelectHdl_Impl( NULL ); + NewFolderHdl_Impl( NULL ); + + UpdateHdl_Impl( NULL ); +} + +// ------------------------------------------------------------------------ + +SvtDocumentTemplateDialog::~SvtDocumentTemplateDialog() +{ + delete pImpl; +} + +// ------------------------------------------------------------------------ + +sal_Bool SvtDocumentTemplateDialog::IsFileSelected( ) const +{ + return pImpl->pWin->IsFileSelected(); +} + +// ------------------------------------------------------------------------ + +String SvtDocumentTemplateDialog::GetSelectedFileURL( ) const +{ + return pImpl->pWin->GetSelectedFile(); +} + +// ------------------------------------------------------------------------ + +sal_Bool SvtDocumentTemplateDialog::CanEnableEditBtn() const +{ + sal_Bool bEnable = sal_False; + + ::rtl::OUString aFolderURL = pImpl->pWin->GetFolderURL(); + if ( pImpl->pWin->IsFileSelected() && aFolderURL.getLength() ) + { + ::rtl::OUString aFileTargetURL = pImpl->pWin->GetSelectedFile(); + bEnable = aFileTargetURL.getLength() > 0; + } + + return bEnable; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog , SelectHdl_Impl, SvtTemplateWindow *, EMPTYARG ) +{ + aEditBtn.Enable( pImpl->pWin->IsTemplateFolderOpen() && CanEnableEditBtn() ); + aOKBtn.Enable( pImpl->pWin->IsFileSelected() ); + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog , DoubleClickHdl_Impl, SvtTemplateWindow *, EMPTYARG ) +{ + EndDialog( RET_OK ); + + if ( !pImpl->bSelectNoOpen ) + pImpl->pWin->OpenFile( !pImpl->pWin->IsTemplateFolderOpen() ); + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog , NewFolderHdl_Impl, SvtTemplateWindow *, EMPTYARG ) +{ + String aNewTitle( pImpl->aTitle ); + aNewTitle += String( ASCII_STR(" - ") ); + aNewTitle += pImpl->pWin->GetFolderTitle(); + SetText( aNewTitle ); + + SelectHdl_Impl( NULL ); + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog , SendFocusHdl_Impl, SvtTemplateWindow *, EMPTYARG ) +{ + if ( pImpl->pWin->HasIconWinFocus() ) + aHelpBtn.GrabFocus(); + else + { + if ( aEditBtn.IsEnabled() ) + aEditBtn.GrabFocus(); + else if ( aOKBtn.IsEnabled() ) + aOKBtn.GrabFocus(); + else + aCancelBtn.GrabFocus(); + } + + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog , OKHdl_Impl, PushButton *, pBtn ) +{ + if ( pImpl->pWin->IsFileSelected() ) + { + EndDialog( RET_OK ); + + if ( !pImpl->bSelectNoOpen ) + pImpl->pWin->OpenFile( &aEditBtn == pBtn ); + } + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog , OrganizerHdl_Impl, PushButton *, EMPTYARG ) +{ + Window* pOldDefWin = Application::GetDefDialogParent(); + Application::SetDefDialogParent( this ); + Reference < XFramesSupplier > xDesktop = Reference < XFramesSupplier >( + ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.frame.Desktop") ), UNO_QUERY ); + Reference < XFrame > xFrame( xDesktop->getActiveFrame() ); + if ( !xFrame.is() ) + xFrame = Reference < XFrame >( xDesktop, UNO_QUERY ); + + com::sun::star::util::URL aTargetURL; + aTargetURL.Complete = ASCII_STR("slot:5540"); + Reference < com::sun::star::util::XURLTransformer > xTrans( ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.util.URLTransformer") ), UNO_QUERY ); + xTrans->parseStrict( aTargetURL ); + + Reference < XDispatchProvider > xProv( xFrame, UNO_QUERY ); + Reference < XDispatch > xDisp; + xDisp = xProv->queryDispatch( aTargetURL, ::rtl::OUString(), 0 ); + + if ( xDisp.is() ) + { + Sequence<PropertyValue> aArgs(1); + PropertyValue* pArg = aArgs.getArray(); + pArg[0].Name = ASCII_STR("Referer"); + pArg[0].Value <<= ASCII_STR("private:user"); + xDisp->dispatch( aTargetURL, aArgs ); + } + + Application::SetDefDialogParent( pOldDefWin ); + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog, UpdateHdl_Impl, Timer*, _pEventSource ) +{ + pImpl->pWin->SetFocus( sal_False ); + Reference< XDocumentTemplates > xTemplates( ::comphelper::getProcessServiceFactory()-> + createInstance( ASCII_STR("com.sun.star.frame.DocumentTemplates") ), UNO_QUERY ); + if ( xTemplates.is() ) + { + if ( _pEventSource ) + { // it was no direct call, which means it was triggered by the timer, which means we alread checked the necessity + WaitObject aWaitCursor( this ); + xTemplates->update(); + if ( pImpl->pWin->IsTemplateFolderOpen() ) + { + pImpl->pWin->ClearHistory(); + pImpl->pWin->OpenTemplateRoot(); + } + } + else + { + // check if we really need to do the update + ::svt::TemplateFolderCache aCache; + if ( aCache.needsUpdate() ) + { // yes -> do it asynchronous (it will take a noticeable time) + + // (but first store the current state) + aCache.storeState(); + + // start the timer for the async update + pImpl->aUpdateTimer.SetTimeout( 300 ); + pImpl->aUpdateTimer.SetTimeoutHdl( LINK( this, SvtDocumentTemplateDialog, UpdateHdl_Impl ) ); + pImpl->aUpdateTimer.Start(); + } + } + } + return 0; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK ( SvtDocumentTemplateDialog, OpenLinkHdl_Impl, svt::FixedHyperlink*, EMPTYARG ) +{ + ::rtl::OUString sURL( aMoreTemplatesLink.GetURL() ); + if ( sURL.getLength() > 0 ) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xSMGR = + ::comphelper::getProcessServiceFactory(); + uno::Reference< com::sun::star::system::XSystemShellExecute > xSystemShell( + xSMGR->createInstance( ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SystemShellExecute" ) ) ), + uno::UNO_QUERY_THROW ); + if ( xSystemShell.is() ) + xSystemShell->execute( sURL, ::rtl::OUString(), com::sun::star::system::SystemShellExecuteFlags::DEFAULTS ); + EndDialog( RET_CANCEL ); + } + catch( const uno::Exception& e ) + { + OSL_TRACE( "Caught exception: %s\n thread terminated.\n", + rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); + } + } + return 0; +} + +/* -----------------27.11.2002 16:54----------------- + * + * --------------------------------------------------*/ +void SvtDocumentTemplateDialog::SelectTemplateFolder() +{ + pImpl->pWin->SelectFolder(ICON_POS_TEMPLATES); +} + diff --git a/svtools/source/contnr/templwin.hrc b/svtools/source/contnr/templwin.hrc new file mode 100644 index 000000000000..5a0d84f1d377 --- /dev/null +++ b/svtools/source/contnr/templwin.hrc @@ -0,0 +1,59 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SVTOOLS_TEMPLWIN_HRC +#define _SVTOOLS_TEMPLWIN_HRC + +#define FL_DOCTEMPLATE 10 +#define BTN_DOCTEMPLATE_MANAGE 11 +#define BTN_DOCTEMPLATE_EDIT 12 +#define BTN_DOCTEMPLATE_OPEN 13 +#define BTN_DOCTEMPLATE_CANCEL 14 +#define BTN_DOCTEMPLATE_HELP 15 +#define FT_DOCTEMPLATE_LINK 16 + +#define TI_DOCTEMPLATE_BACK 1 +#define TI_DOCTEMPLATE_PREV 2 +#define TI_DOCTEMPLATE_PRINT 3 +#define TI_DOCTEMPLATE_DOCINFO 4 +#define TI_DOCTEMPLATE_PREVIEW 5 + +#define HBI_CATEGORY 1 + +#define DI_TITLE 1 +#define DI_FROM 2 +#define DI_DATE 3 +#define DI_KEYWORDS 4 +#define DI_DESCRIPTION 5 +#define DI_MIMETYPE 6 +#define DI_MODIFIEDDATE 7 +#define DI_MODIFIEDBY 8 +#define DI_PRINTDATE 9 +#define DI_PRINTBY 10 +#define DI_THEME 11 +#define DI_SIZE 12 + +#endif // _SVTOOLS_TEMPLWIN_HRC diff --git a/svtools/source/contnr/templwin.hxx b/svtools/source/contnr/templwin.hxx new file mode 100644 index 000000000000..c6100ba5bc20 --- /dev/null +++ b/svtools/source/contnr/templwin.hxx @@ -0,0 +1,309 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SVTOOLS_TEMPLWIN_HXX +#define _SVTOOLS_TEMPLWIN_HXX + +#include <tools/resary.hxx> +#include <vcl/splitwin.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/window.hxx> +#include <svtools/headbar.hxx> +#include <svtools/fileview.hxx> +#include <svtools/ivctrl.hxx> +#include <svtools/svmedit2.hxx> +#include <svl/restrictedpaths.hxx> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/lang/Locale.hpp> + +namespace com{ namespace sun { namespace star { namespace awt { class XWindow; } } } } +namespace com{ namespace sun { namespace star { namespace frame { class XFrame; } } } } +namespace com{ namespace sun { namespace star { namespace document { + class XDocumentProperties; +} } } } +namespace svtools +{ + class ODocumentInfoPreview; +} + +// class SvtDummyHeaderBar_Impl ------------------------------------------ + +class SvtDummyHeaderBar_Impl : public Window +{ +private: + void UpdateBackgroundColor(); + +public: + SvtDummyHeaderBar_Impl( Window* pParent ); + ~SvtDummyHeaderBar_Impl(); + + virtual void DataChanged( const DataChangedEvent& rDCEvt ); +}; + +// class SvtIconWindow_Impl ---------------------------------------------- + +class SvtIconWindow_Impl : public Window +{ +private: + SvtDummyHeaderBar_Impl aDummyHeaderBar; // spaceholder instead of HeaderBar + SvtIconChoiceCtrl aIconCtrl; + + String aNewDocumentRootURL; + String aTemplateRootURL; + String aMyDocumentsRootURL; + String aSamplesFolderRootURL; + + long nMaxTextLength; + + SvxIconChoiceCtrlEntry* GetEntry( const String& rURL ) const; + +public: + SvtIconWindow_Impl( Window* pParent ); + ~SvtIconWindow_Impl(); + + virtual void Resize(); + + inline long GetMaxTextLength() const { return nMaxTextLength; } + inline void SetClickHdl( const Link& rLink ) { aIconCtrl.SetClickHdl( rLink ); } + + String GetSelectedIconURL() const; + String GetSelectedIconText() const; + String GetCursorPosIconURL() const; + String GetIconText( const String& rURL ) const; + void InvalidateIconControl(); + void SetCursorPos( sal_uLong nPos ); + sal_uLong GetCursorPos() const; + sal_uLong GetSelectEntryPos() const; + void SetFocus(); + long CalcHeight() const; + sal_Bool IsRootURL( const String& rURL ) const; + sal_uLong GetRootPos( const String& rURL ) const; + void UpdateIcons( sal_Bool _bHiContrast ); + + inline sal_Bool ProcessKeyEvent( const KeyEvent& rKEvt ); + + inline const String& GetTemplateRootURL() const { return aTemplateRootURL; } + inline const String& GetMyDocumentsRootURL() const { return aMyDocumentsRootURL; } + inline const String& GetSamplesFolderURL() const { return aSamplesFolderRootURL; } + + void SelectFolder(sal_Int32 nFolderPos); +}; + +inline sal_Bool SvtIconWindow_Impl::ProcessKeyEvent( const KeyEvent& rKEvt ) +{ + return ( rKEvt.GetKeyCode().IsMod2() ? aIconCtrl.DoKeyInput( rKEvt ) : sal_False ); +} + +// class SvtFileViewWindow_Impl ------------------------------------------ + +class SvtTemplateWindow; + +class SvtFileViewWindow_Impl : public Window +{ +private: + SvtTemplateWindow& rParent; + SvtFileView aFileView; + Link aNewFolderLink; + String aCurrentRootURL; + String aFolderURL; + String aMyDocumentsURL; + String aSamplesFolderURL; + ::svt::RestrictedPaths + aURLFilter; + + sal_Bool bIsTemplateFolder; + + ::com::sun::star::uno::Sequence< ::rtl::OUString > + GetNewDocContents() const; + +public: + SvtFileViewWindow_Impl( SvtTemplateWindow* pParent ); + ~SvtFileViewWindow_Impl(); + + virtual void Resize(); + + inline void SetSelectHdl( const Link& rLink ) { aFileView.SetSelectHdl( rLink ); } + inline void SetDoubleClickHdl( const Link& rLink ) { aFileView.SetDoubleClickHdl( rLink ); } + inline void SetNewFolderHdl( const Link& rLink ) { aNewFolderLink = rLink; } + inline void ResetCursor() { aFileView.ResetCursor(); } + inline sal_Bool IsTemplateFolder() const { return bIsTemplateFolder; } + inline String GetFolderURL() const { return aFolderURL; } + inline String GetRootURL() const { return aCurrentRootURL; } + inline void OpenRoot( const String& rRootURL ) + { aCurrentRootURL = rRootURL; OpenFolder( rRootURL ); } + inline void SetMyDocumentsURL( const String& _rNewURL ) { aMyDocumentsURL = _rNewURL; } + inline void SetSamplesFolderURL( const String& _rNewURL ) { aSamplesFolderURL = _rNewURL; } + + String GetSelectedFile() const; + void OpenFolder( const String& rURL ); + sal_Bool HasPreviousLevel( String& rURL ) const; + String GetFolderTitle() const; + void SetFocus(); +}; + +// class SvtFrameWindow_Impl --------------------------------------------- + +class SvtDocInfoTable_Impl : public ResStringArray +{ +private: + String aEmptyString; + +public: + SvtDocInfoTable_Impl(); + + const String& GetString( long nId ) const; +}; + +class SvtExtendedMultiLineEdit_Impl : public ExtMultiLineEdit +{ +public: + SvtExtendedMultiLineEdit_Impl( Window* pParent,WinBits _nBits ); + inline ~SvtExtendedMultiLineEdit_Impl() {} + + inline void Clear() { SetText( String() ); } + void InsertEntry( const String& rTitle, const String& rValue ); +}; + +class SvtFrameWindow_Impl : public Window +{ +private: + ::com::sun::star::uno::Reference < ::com::sun::star::frame::XFrame > + xFrame; + ::com::sun::star::uno::Reference < ::com::sun::star::document::XDocumentProperties> + m_xDocProps; + ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindow > + xWindow; + + ::svtools::ODocumentInfoPreview* + pEditWin; + Window* pTextWin; + Window* pEmptyWin; + ::com::sun::star::lang::Locale aLocale; + SvtDocInfoTable_Impl aInfoTable; + String aCurrentURL; + ::rtl::OUString m_aOpenURL; + sal_Bool bDocInfo; + + void ShowDocInfo( const String& rURL ); + void ViewEditWin(); + void ViewTextWin(); + void ViewEmptyWin(); + void ViewNonEmptyWin(); // views depending on bDocInfo + + struct SvtExecuteInfo + { + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XDispatch > xDispatch; + ::com::sun::star::util::URL aTargetURL; + }; + + DECL_STATIC_LINK( SvtFrameWindow_Impl, ExecuteHdl_Impl, SvtExecuteInfo* ); + +public: + SvtFrameWindow_Impl( Window* pParent ); + ~SvtFrameWindow_Impl(); + + virtual void Resize(); + + void OpenFile( const String& rURL, sal_Bool bPreview, sal_Bool bIsTemplate, sal_Bool bAsTemplate ); + void ToggleView( sal_Bool bDocInfo ); +}; + +// class SvtTemplateWindow ----------------------------------------------- + +class HistoryList_Impl; + +class SvtTemplateWindow : public Window +{ +private: + ToolBox aFileViewTB; + ToolBox aFrameWinTB; + SplitWindow aSplitWin; + + SvtIconWindow_Impl* pIconWin; + SvtFileViewWindow_Impl* pFileWin; + SvtFrameWindow_Impl* pFrameWin; + HistoryList_Impl* pHistoryList; + + Link aSelectHdl; + Link aDoubleClickHdl; + Link aNewFolderHdl; + Link aSendFocusHdl; + + Timer aSelectTimer; + + String aFolderTitle; + + virtual void Resize(); + + DECL_LINK( IconClickHdl_Impl, SvtIconChoiceCtrl* ); + DECL_LINK( FileSelectHdl_Impl, SvtFileView* ); + DECL_LINK( FileDblClickHdl_Impl, SvtFileView* ); + DECL_LINK( NewFolderHdl_Impl, SvtFileView* ); + DECL_LINK( TimeoutHdl_Impl, Timer* ); + DECL_LINK( ClickHdl_Impl, ToolBox* ); + DECL_LINK( ResizeHdl_Impl, SplitWindow* ); // used for split and initial setting of toolbar pos + + void PrintFile( const String& rURL ); + void AppendHistoryURL( const String& rURL, sal_uLong nGroup ); + void OpenHistory(); + void DoAction( sal_uInt16 nAction ); + void InitToolBoxes(); + void InitToolBoxImages(); + void UpdateIcons(); + +protected: + virtual long PreNotify( NotifyEvent& rNEvt ); + virtual void DataChanged( const DataChangedEvent& rDCEvt ); + +public: + SvtTemplateWindow( Window* pParent ); + ~SvtTemplateWindow(); + + inline void SetSelectHdl( const Link& rLink ) { aSelectHdl = rLink; } + inline void SetDoubleClickHdl( const Link& rLink ) { aDoubleClickHdl = rLink; } + inline void SetNewFolderHdl( const Link& rLink ) { aNewFolderHdl = rLink; } + inline void SetSendFocusHdl( const Link& rLink ) { aSendFocusHdl = rLink; } + inline sal_Bool IsTemplateFolderOpen() const { return pFileWin->IsTemplateFolder(); } + inline sal_Bool HasIconWinFocus() const { return pIconWin->HasChildPathFocus(); } + + void ReadViewSettings( ); + void WriteViewSettings( ); + sal_Bool IsFileSelected() const; + String GetSelectedFile() const; + void OpenFile( sal_Bool bNotAsTemplate ); + String GetFolderTitle() const; + String GetFolderURL() const; + void SetFocus( sal_Bool bIconWin ); + void OpenTemplateRoot(); + void SetPrevLevelButtonState( const String& rURL ); // sets state (enable/disable) for previous level button + void ClearHistory(); + long CalcHeight() const; + + void SelectFolder(sal_Int32 nFolderPosition); +}; + +#endif // _SVTOOLS_TEMPLWIN_HXX + diff --git a/svtools/source/contnr/templwin.src b/svtools/source/contnr/templwin.src new file mode 100644 index 000000000000..113e20c34f28 --- /dev/null +++ b/svtools/source/contnr/templwin.src @@ -0,0 +1,378 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + // includes ------------------------------------------------------------------ + +#include "templwin.hrc" +#include <svtools/controldims.hrc> +#include <svtools/helpid.hrc> +#include <svtools/svtools.hrc> + +// Magenta and Grey as mask colors +#define MASK_COL_MAGENTA Color { Red = 0xFFFF ; Green = 0x0000 ; Blue = 0xFFFF ; }; + +Control CTRL_FILEVIEW +{ + Pos = MAP_APPFONT ( 0 , 0 ) ; + Size = MAP_APPFONT ( 200 , 180 ) ; +}; + +String STR_SVT_NEWDOC +{ + Text [ en-US ] = "New Document"; +}; + +Image IMG_SVT_NEWDOC +{ + ImageBitmap = Bitmap { File = "new_doc.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +Image IMG_SVT_NEWDOC_HC +{ + ImageBitmap = Bitmap { File = "new_doc_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +String STR_SVT_MYDOCS +{ + Text [ en-US ] = "My Documents"; +}; + +Image IMG_SVT_MYDOCS +{ + ImageBitmap = Bitmap { File = "my_docs.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +Image IMG_SVT_MYDOCS_HC +{ + ImageBitmap = Bitmap { File = "my_docs_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +String STR_SVT_TEMPLATES +{ + Text [ en-US ] = "Templates"; +}; + +Image IMG_SVT_TEMPLATES +{ + ImageBitmap = Bitmap { File = "template.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +Image IMG_SVT_TEMPLATES_HC +{ + ImageBitmap = Bitmap { File = "template_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +String STR_SVT_SAMPLES +{ + Text [ en-US ] = "Samples"; +}; + +Image IMG_SVT_SAMPLES +{ + ImageBitmap = Bitmap { File = "samples.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +Image IMG_SVT_SAMPLES_HC +{ + ImageBitmap = Bitmap { File = "samples_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +ToolBox TB_SVT_FILEVIEW +{ + Pos = MAP_APPFONT ( 0 , 0 ) ; + Size = MAP_APPFONT ( 100 , 12 ) ; + ItemList = + { + ToolBoxItem + { + Identifier = TI_DOCTEMPLATE_BACK; + HelpId = HID_TEMPLATEDLG_TB_BACK; + Text [ en-US ] = "Back" ; + }; + ToolBoxItem + { + Identifier = TI_DOCTEMPLATE_PREV; + HelpId = HID_TEMPLATEDLG_TB_PREV; + Text [ en-US ] = "Up One Level" ; + }; + ToolBoxItem + { + Type = TOOLBOXITEM_SEPARATOR ; + }; + ToolBoxItem + { + Identifier = TI_DOCTEMPLATE_PRINT; + HelpId = HID_TEMPLATEDLG_TB_PRINT; + Text [ en-US ] = "Print" ; + }; + }; +}; + +Image IMG_SVT_DOCTEMPLATE_BACK_SMALL +{ + ImageBitmap = Bitmap { File = "back_small.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_BACK_LARGE +{ + ImageBitmap = Bitmap { File = "back_large.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_PREV_SMALL +{ + ImageBitmap = Bitmap { File = "up_small.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_PREV_LARGE +{ + ImageBitmap = Bitmap { File = "up_large.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_PRINT_SMALL +{ + ImageBitmap = Bitmap { File = "sc05509.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_PRINT_LARGE +{ + ImageBitmap = Bitmap { File = "lc05509.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_BACK_SMALL +{ + ImageBitmap = Bitmap { File = "back_small_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_BACK_LARGE +{ + ImageBitmap = Bitmap { File = "back_large_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_PREV_SMALL +{ + ImageBitmap = Bitmap { File = "up_small_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_PREV_LARGE +{ + ImageBitmap = Bitmap { File = "up_large_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_PRINT_SMALL +{ + ImageBitmap = Bitmap { File = "sch05509.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_PRINT_LARGE +{ + ImageBitmap = Bitmap { File = "lch05509.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +ToolBox TB_SVT_FRAMEWIN +{ + Pos = MAP_APPFONT ( 0 , 0 ) ; + Size = MAP_APPFONT ( 100 , 12 ) ; + ItemList = + { + ToolBoxItem + { + RadioCheck = TRUE; + AutoCheck = TRUE; + Identifier = TI_DOCTEMPLATE_DOCINFO; + HelpId = HID_TEMPLATEDLG_TB_DOCINFO; + Text [ en-US ] = "Document Properties" ; + }; + ToolBoxItem + { + RadioCheck = TRUE; + AutoCheck = TRUE; + Identifier = TI_DOCTEMPLATE_PREVIEW; + HelpId = HID_TEMPLATEDLG_TB_PREVIEW; + Text [ en-US ] = "Preview" ; + }; + }; +}; + +Image IMG_SVT_DOCTEMPLATE_DOCINFO_SMALL +{ + ImageBitmap = Bitmap { File = "info_small.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_DOCINFO_LARGE +{ + ImageBitmap = Bitmap { File = "info_large.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_PREVIEW_SMALL +{ + ImageBitmap = Bitmap { File = "preview_small.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPLATE_PREVIEW_LARGE +{ + ImageBitmap = Bitmap { File = "preview_large.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_DOCINFO_SMALL +{ + ImageBitmap = Bitmap { File = "info_small_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_DOCINFO_LARGE +{ + ImageBitmap = Bitmap { File = "info_large_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_PREVIEW_SMALL +{ + ImageBitmap = Bitmap { File = "preview_small_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; +Image IMG_SVT_DOCTEMPL_HC_PREVIEW_LARGE +{ + ImageBitmap = Bitmap { File = "preview_large_h.bmp" ; }; + MaskColor = MASK_COL_MAGENTA +}; + +ModalDialog DLG_DOCTEMPLATE +{ + HelpId = HID_TEMPLATEDLG_DIALOG ; + OutputSize = TRUE ; + SVLook = TRUE ; + Size = MAP_APPFONT( 320, 250 ); + Text [ en-US ] = "Templates and Documents" ; + Moveable = TRUE ; + FixedText FT_DOCTEMPLATE_LINK + { + Left = TRUE ; + Pos = MAP_APPFONT ( 6 , 208 ) ; + Size = MAP_APPFONT ( 311 , RSC_CD_FIXEDTEXT_HEIGHT ) ; + Text [ en-US ] = "~Get more templates online..."; + }; + FixedLine FL_DOCTEMPLATE + { + Pos = MAP_APPFONT( 0, 219 ); + Size = MAP_APPFONT( 320, 8 ); + }; + PushButton BTN_DOCTEMPLATE_MANAGE + { + HelpID = "svtools:PushButton:DLG_DOCTEMPLATE:BTN_DOCTEMPLATE_MANAGE"; + Pos = MAP_APPFONT( 6, 230 ); + Size = MAP_APPFONT( 50, 14 ); + Text [ en-US ] = "Organi~ze..."; + }; + PushButton BTN_DOCTEMPLATE_EDIT + { + HelpID = "svtools:PushButton:DLG_DOCTEMPLATE:BTN_DOCTEMPLATE_EDIT"; + Pos = MAP_APPFONT( 59, 230 ); + Size = MAP_APPFONT( 50, 14 ); + Text [ en-US ] = "~Edit"; + }; + OKButton BTN_DOCTEMPLATE_OPEN + { + Pos = MAP_APPFONT( 155, 230 ); + Size = MAP_APPFONT( 50, 14 ); + DefButton = TRUE; + Text [ en-US ] = "~Open"; + }; + CancelButton BTN_DOCTEMPLATE_CANCEL + { + Pos = MAP_APPFONT( 208, 230 ); + Size = MAP_APPFONT( 50, 14 ); + }; + HelpButton BTN_DOCTEMPLATE_HELP + { + Pos = MAP_APPFONT( 264, 230 ); + Size = MAP_APPFONT( 50, 14 ); + }; +}; + +StringArray STRARY_SVT_DOCINFO +{ + ItemList [ en-US ] = + { + < "Title" ; DI_TITLE ; > ; + < "By" ; DI_FROM ; > ; + < "Date" ; DI_DATE ; > ; + < "Keywords" ; DI_KEYWORDS ; > ; + < "Description" ; DI_DESCRIPTION ; > ; + < "Type" ; DI_MIMETYPE ; > ; + < "Modified on" ; DI_MODIFIEDDATE ; > ; + < "Modified by" ; DI_MODIFIEDBY ; > ; + < "Printed on" ; DI_PRINTDATE ; > ; + < "Printed by" ; DI_PRINTBY ; > ; + < "Subject" ; DI_THEME ; > ; + < "Size" ; DI_SIZE ; > ; + }; + }; + +String STR_SVT_NEWDOC_HELP +{ + Text [ en-US ] = "Click here to create new documents."; +}; +String STR_SVT_MYDOCS_HELP +{ + Text [ en-US ] = "Contains your letters, reports and other documents"; +}; +String STR_SVT_TEMPLATES_HELP +{ + Text [ en-US ] = "Contains templates for creating new documents"; +}; +String STR_SVT_SAMPLES_HELP +{ + Text [ en-US ] = "Contains a selection of sample letters, reports and other documents"; +}; + + + + + + + + + + + + + + + + + + + + + diff --git a/svtools/source/contnr/tooltiplbox.cxx b/svtools/source/contnr/tooltiplbox.cxx new file mode 100644 index 000000000000..69073a0793c5 --- /dev/null +++ b/svtools/source/contnr/tooltiplbox.cxx @@ -0,0 +1,120 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" +#include <svtools/tooltiplbox.hxx> +#include <vcl/help.hxx> + +// ============================================================================ + +namespace svtools { + +// ---------------------------------------------------------------------------- + +void lcl_ToolTipLBox_ShowToolTip( ListBox& rListBox, const HelpEvent& rHEvt ) +{ + // only show tooltip if helpmode is BALLOON or QUICK + if ( !( rHEvt.GetMode() & HELPMODE_BALLOON ) && !( rHEvt.GetMode() & HELPMODE_QUICK ) ) + { + // else call base class method + rListBox.ListBox::RequestHelp( rHEvt ); + return ; + } + + // find the list box entry the mouse points to + Point aMousePos( rListBox.ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); + + sal_uInt16 nTop = rListBox.GetTopEntry(); + sal_uInt16 nBottom = nTop + rListBox.GetDisplayLineCount(); + + sal_uInt16 nPos; + for( nPos = nTop; nPos < nBottom; ++nPos ) + { + Rectangle aItemRect( rListBox.GetBoundingRectangle( nPos ) ); + if( (aItemRect.Top() <= aMousePos.Y()) && (aMousePos.Y() <= aItemRect.Bottom()) ) + break; + } + + // show text content of the entry, if it does not fit + if( nPos < nBottom ) + { + String aHelpText( rListBox.GetEntry( nPos ) ); + if( rListBox.GetTextWidth( aHelpText ) > rListBox.GetOutputSizePixel().Width() ) + { + Point aLBoxPos( rListBox.OutputToScreenPixel( Point( 0, 0 ) ) ); + Size aLBoxSize( rListBox.GetSizePixel() ); + Rectangle aLBoxRect( aLBoxPos, aLBoxSize ); + + if( rHEvt.GetMode() == HELPMODE_BALLOON ) + Help::ShowBalloon( &rListBox, aLBoxRect.Center(), aLBoxRect, aHelpText ); + else + Help::ShowQuickHelp( &rListBox, aLBoxRect, aHelpText ); + } + } +} + +// ---------------------------------------------------------------------------- + +ToolTipListBox::ToolTipListBox( Window* pParent, WinBits nStyle ) : + ListBox( pParent, nStyle ) +{ +} + +ToolTipListBox::ToolTipListBox( Window* pParent, const ResId& rResId ) : + ListBox( pParent, rResId ) +{ +} + +void ToolTipListBox::RequestHelp( const HelpEvent& rHEvt ) +{ + lcl_ToolTipLBox_ShowToolTip( *this, rHEvt ); +} + +// ---------------------------------------------------------------------------- + +ToolTipMultiListBox::ToolTipMultiListBox( Window* pParent, WinBits nStyle ) : + MultiListBox( pParent, nStyle ) +{ +} + +ToolTipMultiListBox::ToolTipMultiListBox( Window* pParent, const ResId& rResId ) : + MultiListBox( pParent, rResId ) +{ +} + +void ToolTipMultiListBox::RequestHelp( const HelpEvent& rHEvt ) +{ + lcl_ToolTipLBox_ShowToolTip( *this, rHEvt ); +} + +// ---------------------------------------------------------------------------- + +} // namespace svtools + +// ============================================================================ + diff --git a/svtools/source/contnr/treelist.cxx b/svtools/source/contnr/treelist.cxx new file mode 100644 index 000000000000..c4ec516a735b --- /dev/null +++ b/svtools/source/contnr/treelist.cxx @@ -0,0 +1,2116 @@ +/************************************************************************* + * + * 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 + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svtools.hxx" + +#define _TREELIST_CXX + +#ifndef GCC +#endif + +#include <svtools/treelist.hxx> + +#ifdef DBG_UTIL +// Prueft Integritaet der Liste nach jeder Operation +//#define CHECK_INTEGRITY +#endif + + +DBG_NAME(SvListEntry); + +SvListEntry::SvListEntry() +{ + DBG_CTOR(SvListEntry,0); + pChilds = 0; + pParent = 0; + nListPos = 0; + nAbsPos = 0; +} + +SvListEntry::SvListEntry( const SvListEntry& rEntry ) +{ + DBG_CTOR(SvListEntry,0); + pChilds = 0; + pParent = 0; + nListPos &= 0x80000000; + nListPos |= ( rEntry.nListPos & 0x7fffffff); + nAbsPos = rEntry.nAbsPos; +} + +SvListEntry::~SvListEntry() +{ + DBG_DTOR(SvListEntry,0); + if ( pChilds ) + { + pChilds->DestroyAll(); + delete pChilds; + } +#ifdef DBG_UTIL + pChilds = 0; + pParent = 0; +#endif +} + +void SvListEntry::Clone( SvListEntry* pSource) +{ + DBG_CHKTHIS(SvListEntry,0); + nListPos &= 0x80000000; + nListPos |= ( pSource->nListPos & 0x7fffffff); + nAbsPos = pSource->nAbsPos; +} + +void SvListEntry::SetListPositions() +{ + if( pChilds ) + { + SvListEntry *pEntry = (SvListEntry*)pChilds->First(); + sal_uLong nCur = 0; + while ( pEntry ) + { + pEntry->nListPos &= 0x80000000; + pEntry->nListPos |= nCur; + nCur++; + pEntry = (SvListEntry*)pChilds->Next(); + } + } + nListPos &= (~0x80000000); +} + + +DBG_NAME(SvViewData); + +SvViewData::SvViewData() +{ + DBG_CTOR(SvViewData,0); + nFlags = 0; + nVisPos = 0; +} + +SvViewData::SvViewData( const SvViewData& rData ) +{ + DBG_CTOR(SvViewData,0); + nFlags = rData.nFlags; + nFlags &= ~( SVLISTENTRYFLAG_SELECTED | SVLISTENTRYFLAG_FOCUSED ); + nVisPos = rData.nVisPos; +} + +SvViewData::~SvViewData() +{ + DBG_DTOR(SvViewData,0); +#ifdef DBG_UTIL + nVisPos = 0x12345678; + nFlags = 0x1234; +#endif +} + +void SvTreeEntryList::DestroyAll() +{ + SvListEntry* pPtr = (SvListEntry*)First(); + while( pPtr ) + { + delete pPtr; + pPtr = (SvListEntry*)Next(); + } +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeList::SvTreeList() +{ + nEntryCount = 0; + bAbsPositionsValid = sal_False; + nRefCount = 1; + pRootItem = new SvListEntry; + eSortMode = SortNone; +} + + +/************************************************************************* +|* +|* SvTreeList::~SvTreeList +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeList::~SvTreeList() +{ + Clear(); + delete pRootItem; +#ifdef DBG_UTIL + pRootItem = 0; +#endif +} + +/************************************************************************* +|* +|* SvTreeList::Broadcast +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Broadcast( sal_uInt16 nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, sal_uLong nPos ) +{ + sal_uLong nViewCount = aViewList.Count(); + for( sal_uLong nCurView = 0; nCurView < nViewCount; nCurView++ ) + { + SvListView* pView = (SvListView*)aViewList.GetObject( nCurView ); + if( pView ) + pView->ModelNotification( nActionId, pEntry1, pEntry2, nPos ); + } +} + +void SvTreeList::InsertView( SvListView* pView) +{ + sal_uLong nPos = aViewList.GetPos( pView ); + if ( nPos == LIST_ENTRY_NOTFOUND ) + { + aViewList.Insert( pView, LIST_APPEND ); + nRefCount++; + } +} + +void SvTreeList::RemoveView( SvListView* pView ) +{ + sal_uLong nPos = aViewList.GetPos( pView ); + if ( nPos != LIST_ENTRY_NOTFOUND ) + { + aViewList.Remove( pView ); + nRefCount--; + } +} + + +// Ein Entry ist sichtbar, wenn alle Parents expandiert sind +sal_Bool SvTreeList::IsEntryVisible( const SvListView* pView, SvListEntry* pEntry ) const +{ + DBG_ASSERT(pView&&pEntry,"IsVisible:Invalid Params"); + sal_Bool bRetVal=sal_False; + do + { + if ( pEntry == pRootItem ) + { + bRetVal=sal_True; + break; + } + pEntry = pEntry->pParent; + } while( pView->IsExpanded( pEntry ) ); + return bRetVal; +} + +sal_uInt16 SvTreeList::GetDepth( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry&&pEntry!=pRootItem,"GetDepth:Bad Entry"); + sal_uInt16 nDepth = 0; + while( pEntry->pParent != pRootItem ) + { + nDepth++; + pEntry = pEntry->pParent; + } + return nDepth; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Clear() +{ + Broadcast( LISTACTION_CLEARING ); + SvTreeEntryList* pRootList = pRootItem->pChilds; + if ( pRootList ) + { + SvListEntry* pEntry = (SvListEntry*)(pRootList->First()); + while( pEntry ) + { + delete pEntry; + pEntry = (SvListEntry*)(pRootList->Next()); + } + delete pRootItem->pChilds; + pRootItem->pChilds = 0; + } + nEntryCount = 0; + Broadcast( LISTACTION_CLEARED ); +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_Bool SvTreeList::IsChild( SvListEntry* pParent, SvListEntry* pChild ) const +{ + if ( !pParent ) + pParent = pRootItem; + + sal_Bool bIsChild = sal_False; + SvTreeEntryList* pList = pParent->pChilds; + if ( !pList ) + return sal_False; + SvListEntry* pActualChild = (SvListEntry*)(pList->First()); + while( !bIsChild && pActualChild ) + { + if ( pActualChild == pChild ) + bIsChild = sal_True; + else + { + if ( pActualChild->pChilds ) + bIsChild = IsChild( pActualChild, pChild ); + pActualChild = (SvListEntry*)(pList->Next()); + } + } + return bIsChild; +} + +sal_uLong SvTreeList::Move(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,sal_uLong nListPos) +{ + // pDest darf Null sein! + DBG_ASSERT(pSrcEntry,"Entry?"); + if ( !pTargetParent ) + pTargetParent = pRootItem; + DBG_ASSERT(pSrcEntry!=pTargetParent,"Move:Source=Target"); + + Broadcast( LISTACTION_MOVING, pSrcEntry, pTargetParent, nListPos ); + + if ( !pTargetParent->pChilds ) + pTargetParent->pChilds = new SvTreeEntryList; + if ( pSrcEntry == pTargetParent ) + return pSrcEntry->GetChildListPos(); + + bAbsPositionsValid = sal_False; + + SvTreeEntryList* pDstList = pTargetParent->pChilds; + SvTreeEntryList* pSrcList = pSrcEntry->pParent->pChilds; + + // Dummy-Ptr einfuegen, weil nListPos durch das + // folgende Remove ungueltig werden koennte + SvListEntry* pDummy = 0; pDstList->Insert( pDummy, nListPos ); + + // loeschen + pSrcList->Remove( pSrcEntry ); + // Hat Parent noch Childs ? + if ( pSrcList->Count() == 0 ) + { + // Keine Childs, deshalb Child-List loeschen + SvListEntry* pParent = pSrcEntry->pParent; + pParent->pChilds = 0; + delete pSrcList; + pSrcList = 0; + } + + // Parent umsetzen (erst hier, weil wir zum Loeschen + // der ChildList den alten Parent noch benoetigen!) + pSrcEntry->pParent = pTargetParent; + + pDstList->Replace( pSrcEntry, pDummy ); + + // Listenpositionen in Zielliste korrigieren + SetListPositions( pDstList ); + if ( pSrcList && (sal_uLong)pSrcList != (sal_uLong)pDstList ) + SetListPositions( pSrcList ); + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + + sal_uLong nRetVal = pDstList->GetPos( pSrcEntry ); + DBG_ASSERT(nRetVal==pSrcEntry->GetChildListPos(),"ListPos not valid"); + Broadcast( LISTACTION_MOVED,pSrcEntry,pTargetParent,nRetVal); + return nRetVal; +} + +sal_uLong SvTreeList::Copy(SvListEntry* pSrcEntry,SvListEntry* pTargetParent,sal_uLong nListPos) +{ + // pDest darf Null sein! + DBG_ASSERT(pSrcEntry,"Entry?"); + if ( !pTargetParent ) + pTargetParent = pRootItem; + if ( !pTargetParent->pChilds ) + pTargetParent->pChilds = new SvTreeEntryList; + + bAbsPositionsValid = sal_False; + + sal_uLong nCloneCount = 0; + SvListEntry* pClonedEntry = Clone( pSrcEntry, nCloneCount ); + nEntryCount += nCloneCount; + + SvTreeEntryList* pDstList = pTargetParent->pChilds; + pClonedEntry->pParent = pTargetParent; // Parent umsetzen + pDstList->Insert( pClonedEntry, nListPos ); // Einfuegen + SetListPositions( pDstList ); // Listenpositionen in Zielliste korrigieren + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast( LISTACTION_INSERTED_TREE, pClonedEntry ); + sal_uLong nRetVal = pDstList->GetPos( pClonedEntry ); + return nRetVal; +} + + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Move( SvListEntry* pSrcEntry, SvListEntry* pDstEntry ) +{ + SvListEntry* pParent; + sal_uLong nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos(); + nPos++; // UNTER (Bildschirm) pDstEntry einfuegen + } + Move( pSrcEntry, pParent, nPos ); +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Copy( SvListEntry* pSrcEntry, SvListEntry* pDstEntry ) +{ + SvListEntry* pParent; + sal_uLong nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos()+1; + } + Copy( pSrcEntry, pParent, nPos ); +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +void SvTreeList::InsertTree( SvListEntry* pSrcEntry, SvListEntry* pDstEntry) +{ + SvListEntry* pParent; + sal_uLong nPos; + + if ( !pDstEntry ) + { + pParent = pRootItem; + nPos = 0UL; + } + else + { + pParent = pDstEntry->pParent; + nPos = pDstEntry->GetChildListPos()+1; + } + InsertTree( pSrcEntry, pParent, nPos ); +} + + +void SvTreeList::InsertTree(SvListEntry* pSrcEntry, + SvListEntry* pTargetParent,sal_uLong nListPos) +{ + DBG_ASSERT(pSrcEntry,"InsertTree:Entry?"); + if ( !pSrcEntry ) + return; + + if ( !pTargetParent ) + pTargetParent = pRootItem; + if ( !pTargetParent->pChilds ) + pTargetParent->pChilds = new SvTreeEntryList; + + // Sortierung beruecksichtigen + GetInsertionPos( pSrcEntry, pTargetParent, nListPos ); + + bAbsPositionsValid = sal_False; + + pSrcEntry->pParent = pTargetParent; // Parent umsetzen + SvTreeEntryList* pDstList = pTargetParent->pChilds; + pDstList->Insert( pSrcEntry, nListPos ); // einfuegen + SetListPositions(pDstList); // Listenpositionen in Zielliste korrigieren + nEntryCount += GetChildCount( pSrcEntry ); + nEntryCount++; // der Parent ist ja auch neu + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast(LISTACTION_INSERTED_TREE, pSrcEntry ); +} + +SvListEntry* SvTreeList::CloneEntry( SvListEntry* pSource ) const +{ + if( aCloneLink.IsSet() ) + return (SvListEntry*)aCloneLink.Call( pSource ); + SvListEntry* pEntry = CreateEntry(); + pSource->Clone( pEntry ); + return pSource; +} + +SvListEntry* SvTreeList::CreateEntry() const +{ + return new SvListEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::Clone( SvListEntry* pEntry, sal_uLong& nCloneCount ) const +{ + SvListEntry* pClonedEntry = CloneEntry( pEntry ); + nCloneCount = 1; + SvTreeEntryList* pChilds = pEntry->pChilds; + if ( pChilds ) + pClonedEntry->pChilds=CloneChilds(pChilds,pClonedEntry,nCloneCount); + return pClonedEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvTreeEntryList* SvTreeList::CloneChilds( SvTreeEntryList* pChilds, + SvListEntry* pNewParent, + sal_uLong& nCloneCount ) const +{ + DBG_ASSERT(pChilds->Count(),"Childs?"); + SvTreeEntryList* pClonedChilds = new SvTreeEntryList; + SvListEntry* pChild = (SvListEntry*)pChilds->First(); + while ( pChild ) + { + SvListEntry* pNewChild = CloneEntry( pChild ); + nCloneCount++; + pNewChild->pParent = pNewParent; + SvTreeEntryList* pSubChilds = pChild->pChilds; + if ( pSubChilds ) + { + pSubChilds = CloneChilds( pSubChilds, pNewChild, nCloneCount ); + pNewChild->pChilds = pSubChilds; + } + + pClonedChilds->Insert( pNewChild, LIST_APPEND ); + pChild = (SvListEntry*)pChilds->Next(); + } + return pClonedChilds; +} + + +/************************************************************************* +|* +|* SvTreeList::GetChildCount +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_uLong SvTreeList::GetChildCount( SvListEntry* pParent ) const +{ + if ( !pParent ) + return GetEntryCount(); + + if ( !pParent || !pParent->pChilds) + return 0; + sal_uLong nCount = 0; + sal_uInt16 nRefDepth = GetDepth( pParent ); + sal_uInt16 nActDepth = nRefDepth; + do + { + pParent = Next( pParent, &nActDepth ); + nCount++; + } while( pParent && nRefDepth < nActDepth ); + nCount--; + return nCount; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_uLong SvTreeList::GetVisibleChildCount(const SvListView* pView, SvListEntry* pParent) const +{ + DBG_ASSERT(pView,"GetVisChildCount:No View"); + if ( !pParent ) + pParent = pRootItem; + if ( !pParent || !pView->IsExpanded(pParent) || !pParent->pChilds ) + return 0; + sal_uLong nCount = 0; + sal_uInt16 nRefDepth = GetDepth( pParent ); + sal_uInt16 nActDepth = nRefDepth; + do + { + pParent = NextVisible( pView, pParent, &nActDepth ); + nCount++; + } while( pParent && nRefDepth < nActDepth ); + nCount--; + return nCount; +} + +sal_uLong SvTreeList::GetChildSelectionCount(const SvListView* pView,SvListEntry* pParent) const +{ + DBG_ASSERT(pView,"GetChildSelCount:No View"); + if ( !pParent ) + pParent = pRootItem; + if ( !pParent || !pParent->pChilds) + return 0; + sal_uLong nCount = 0; + sal_uInt16 nRefDepth = GetDepth( pParent ); + sal_uInt16 nActDepth = nRefDepth; + do + { + pParent = Next( pParent, &nActDepth ); + if( pParent && pView->IsSelected( pParent ) && nRefDepth < nActDepth) + nCount++; + } while( pParent && nRefDepth < nActDepth ); +// nCount--; + return nCount; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::First() const +{ + if ( nEntryCount ) + return (SvListEntry*)(pRootItem->pChilds->GetObject(0)); + else + return 0; +} + +/************************************************************************* +|* +|* SvTreeList::Next +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +SvListEntry* SvTreeList::Next( SvListEntry* pActEntry, sal_uInt16* pDepth ) const +{ + DBG_ASSERT( pActEntry && pActEntry->pParent, "SvTreeList::Next: invalid entry/parent!" ); + if ( !pActEntry || !pActEntry->pParent ) + return NULL; + + sal_uInt16 nDepth = 0; + int bWithDepth = sal_False; + if ( pDepth ) + { + nDepth = *pDepth; + bWithDepth = sal_True; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + sal_uLong nActualPos = pActEntry->GetChildListPos(); + + if ( pActEntry->pChilds /* && pActEntry->pChilds->Count() */ ) + { + nDepth++; + pActEntry = (SvListEntry*)(pActEntry->pChilds->GetObject(0)); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + + if ( pActualList->Count() > ( nActualPos + 1 ) ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos + 1 )); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + + SvListEntry* pParent = pActEntry->pParent; + nDepth--; + while( pParent != pRootItem && pParent != 0 ) + { + DBG_ASSERT(pParent!=0,"TreeData corrupt!"); + pActualList = pParent->pParent->pChilds; + DBG_ASSERT(pActualList,"TreeData corrupt!"); + nActualPos = pParent->GetChildListPos(); + if ( pActualList->Count() > ( nActualPos + 1 ) ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos + 1 )); + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + pParent = pParent->pParent; + nDepth--; + } + return 0; +} + +/************************************************************************* +|* +|* SvTreeList::Prev +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +SvListEntry* SvTreeList::Prev( SvListEntry* pActEntry, sal_uInt16* pDepth ) const +{ + DBG_ASSERT(pActEntry!=0,"Entry?"); + + sal_uInt16 nDepth = 0; + int bWithDepth = sal_False; + if ( pDepth ) + { + nDepth = *pDepth; + bWithDepth = sal_True; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + sal_uLong nActualPos = pActEntry->GetChildListPos(); + + if ( nActualPos > 0 ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos - 1 )); + while( pActEntry->pChilds /* && pActEntry->pChilds->Count() */ ) + { + pActualList = pActEntry->pChilds; + nDepth++; + pActEntry = (SvListEntry*)(pActualList->Last()); + } + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + if ( pActEntry->pParent == pRootItem ) + return 0; + + pActEntry = pActEntry->pParent; + + if ( pActEntry ) + { + nDepth--; + if ( bWithDepth ) + *pDepth = nDepth; + return pActEntry; + } + return 0; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::Last( sal_uInt16* /* nDepth */ ) const +{ + SvTreeEntryList* pActList = pRootItem->pChilds; +// if ( pActList->Count() == 0 ) +// return 0; + SvListEntry* pEntry = 0; + while( pActList ) + { + pEntry = (SvListEntry*)(pActList->Last()); + pActList = pEntry->pChilds; +// if ( pActList->Count() == 0 ) +// pActList = 0; + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_uLong SvTreeList::GetVisiblePos( const SvListView* pView, SvListEntry* pEntry ) const +{ + DBG_ASSERT(pView&&pEntry,"View/Entry?"); + + if ( !pView->bVisPositionsValid ) + { + // damit GetVisibleCount die Positionen aktualisiert + ((SvListView*)pView)->nVisibleCount = 0; + GetVisibleCount( pView ); + } + SvViewData* pViewData = pView->GetViewData( pEntry ); + return pViewData->nVisPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_uLong SvTreeList::GetVisibleCount( const SvListView* pView ) const +{ + DBG_ASSERT(pView,"GetVisCount:No View"); + if( !pView->HasViewData() ) + return 0; + if ( pView->nVisibleCount ) + return pView->nVisibleCount; + + sal_uLong nPos = 0; + SvListEntry* pEntry = First(); // erster Eintrag immer sichtbar + while ( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + pViewData->nVisPos = nPos; + nPos++; + pEntry = NextVisible( pView, pEntry ); + } +#ifdef DBG_UTIL + if( nPos > 10000000 ) + { + DBG_ERROR("nVisibleCount bad"); + } +#endif + ((SvListView*)pView)->nVisibleCount = nPos; + ((SvListView*)pView)->bVisPositionsValid = sal_True; + return nPos; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +// Funktion geht aus Geschwindigkeitsgruenden davon aus, +// das der uebergebene Eintrag bereits sichtbar ist + +SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pActEntry,sal_uInt16* pActDepth) const +{ + DBG_ASSERT(pView,"NextVisible:No View"); + if ( !pActEntry ) + return 0; + + sal_uInt16 nDepth = 0; + int bWithDepth = sal_False; + if ( pActDepth ) + { + nDepth = *pActDepth; + bWithDepth = sal_True; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + sal_uLong nActualPos = pActEntry->GetChildListPos(); + + if ( pView->IsExpanded(pActEntry) ) + { + DBG_ASSERT(pActEntry->pChilds,"Childs?"); + nDepth++; + pActEntry = (SvListEntry*)(pActEntry->pChilds->GetObject(0)); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + + nActualPos++; + if ( pActualList->Count() > nActualPos ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos )); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + + SvListEntry* pParent = pActEntry->pParent; + nDepth--; + while( pParent != pRootItem ) + { + pActualList = pParent->pParent->pChilds; + nActualPos = pParent->GetChildListPos(); + nActualPos++; + if ( pActualList->Count() > nActualPos ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos )); + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + pParent = pParent->pParent; + nDepth--; + } + return 0; +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +// Funktion geht aus Geschwindigkeitsgruenden davon aus, +// das der uebergebene Eintrag bereits sichtbar ist + +SvListEntry* SvTreeList::PrevVisible(const SvListView* pView, SvListEntry* pActEntry, sal_uInt16* pActDepth) const +{ + DBG_ASSERT(pView&&pActEntry,"PrevVis:View/Entry?"); + + sal_uInt16 nDepth = 0; + int bWithDepth = sal_False; + if ( pActDepth ) + { + nDepth = *pActDepth; + bWithDepth = sal_True; + } + + SvTreeEntryList* pActualList = pActEntry->pParent->pChilds; + sal_uLong nActualPos = pActEntry->GetChildListPos(); + + if ( nActualPos > 0 ) + { + pActEntry = (SvListEntry*)(pActualList->GetObject( nActualPos - 1 )); + while( pView->IsExpanded(pActEntry) ) + { + pActualList = pActEntry->pChilds; + nDepth++; + pActEntry = (SvListEntry*)(pActualList->Last()); + } + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + + if ( pActEntry->pParent == pRootItem ) + return 0; + + pActEntry = pActEntry->pParent; + if ( pActEntry ) + { + nDepth--; + if ( bWithDepth ) + *pActDepth = nDepth; + return pActEntry; + } + return 0; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::LastVisible( const SvListView* pView, sal_uInt16* pDepth) const +{ + DBG_ASSERT(pView,"LastVis:No View"); + SvListEntry* pEntry = Last(); + while( pEntry && !IsEntryVisible( pView, pEntry ) ) + pEntry = PrevVisible( pView, pEntry ); + if ( pEntry && pDepth ) + *pDepth = GetDepth( pEntry ); + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::NextVisible(const SvListView* pView,SvListEntry* pEntry,sal_uInt16& nDelta) const +{ + DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"NextVis:Wrong Prms/!Vis"); + + sal_uLong nVisPos = GetVisiblePos( pView, pEntry ); + // nDelta Eintraege vorhanden ? + // Beispiel: 0,1,2,3,4,5,6,7,8,9 nVisPos=5 nDelta=7 + // nNewDelta = 10-nVisPos-1 == 4 + if ( nVisPos+nDelta >= pView->nVisibleCount ) + { + nDelta = (sal_uInt16)(pView->nVisibleCount-nVisPos); + nDelta--; + } + sal_uInt16 nDeltaTmp = nDelta; + while( nDeltaTmp ) + { + pEntry = NextVisible( pView, pEntry ); + nDeltaTmp--; + DBG_ASSERT(pEntry,"Entry?"); + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::PrevVisible( const SvListView* pView, SvListEntry* pEntry, sal_uInt16& nDelta ) const +{ + DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"PrevVis:Parms/!Vis"); + + sal_uLong nVisPos = GetVisiblePos( pView, pEntry ); + // nDelta Eintraege vorhanden ? + // Beispiel: 0,1,2,3,4,5,6,7,8,9 nVisPos=8 nDelta=20 + // nNewDelta = nNewVisPos + if ( nDelta > nVisPos ) + nDelta = (sal_uInt16)nVisPos; + sal_uInt16 nDeltaTmp = nDelta; + while( nDeltaTmp ) + { + pEntry = PrevVisible( pView, pEntry ); + nDeltaTmp--; + DBG_ASSERT(pEntry,"Entry?"); + } + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::FirstSelected( const SvListView* pView) const +{ + DBG_ASSERT(pView,"FirstSel:No View"); + if( !pView ) + return 0; + SvListEntry* pActSelEntry = First(); + while( pActSelEntry && !pView->IsSelected(pActSelEntry) ) + pActSelEntry = NextVisible( pView, pActSelEntry ); + return pActSelEntry; +} + + +SvListEntry* SvTreeList::FirstChild( SvListEntry* pParent ) const +{ + if ( !pParent ) + pParent = pRootItem; + SvListEntry* pResult; + if ( pParent->pChilds ) + pResult = (SvListEntry*)(pParent->pChilds->GetObject( 0 )); + else + pResult = 0; + return pResult; +} + +SvListEntry* SvTreeList::NextSibling( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"Entry?"); + if( !pEntry ) + return 0; + SvTreeEntryList* pList = pEntry->pParent->pChilds; +// sal_uLong nPos = pList->GetPos( pEntry ); + sal_uLong nPos = pEntry->GetChildListPos(); + nPos++; + pEntry = (SvListEntry*)(pList->GetObject( nPos )); + return pEntry; +} + +SvListEntry* SvTreeList::PrevSibling( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"Entry?"); + if( !pEntry ) + return 0; + + SvTreeEntryList* pList = pEntry->pParent->pChilds; + // sal_uLong nPos = pList->GetPos( pEntry ); + sal_uLong nPos = pEntry->GetChildListPos(); + if ( nPos == 0 ) + return 0; + nPos--; + pEntry = (SvListEntry*)(pList->GetObject( nPos )); + return pEntry; +} + + +SvListEntry* SvTreeList::LastSibling( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"LastSibling:Entry?"); + if( !pEntry ) + return 0; + SvListEntry* pSib = 0; + SvTreeEntryList* pSibs = pEntry->pParent->pChilds; + if ( pSibs ) + pSib = (SvListEntry*)(pSibs->Last()); + return pSib; +} + + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::NextSelected( const SvListView* pView, SvListEntry* pEntry ) const +{ + DBG_ASSERT(pView&&pEntry,"NextSel:View/Entry?"); + pEntry = Next( pEntry ); + while( pEntry && !pView->IsSelected(pEntry) ) + pEntry = Next( pEntry ); + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::PrevSelected( const SvListView* pView, SvListEntry* pEntry) const +{ + DBG_ASSERT(pView&&pEntry,"PrevSel:View/Entry?"); + pEntry = Prev( pEntry ); + while( pEntry && !pView->IsSelected(pEntry) ) + pEntry = Prev( pEntry ); + + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +SvListEntry* SvTreeList::LastSelected( const SvListView* pView ) const +{ + DBG_ASSERT(pView,"LastSel:No View"); + SvListEntry* pEntry = Last(); + while( pEntry && !pView->IsSelected(pEntry) ) + pEntry = Prev( pEntry ); + return pEntry; +} + +/************************************************************************* +|* +|* SvTreeList::Insert +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ +sal_uLong SvTreeList::Insert( SvListEntry* pEntry,SvListEntry* pParent,sal_uLong nPos ) +{ + DBG_ASSERT( pEntry,"Entry?"); + + if ( !pParent ) + pParent = pRootItem; + + + SvTreeEntryList* pList = pParent->pChilds; + if ( !pList ) + { + // Parent bekommt zum erstenmal ein Kind + pList = new SvTreeEntryList; + pParent->pChilds = pList; + } + + // Sortierung beruecksichtigen + GetInsertionPos( pEntry, pParent, nPos ); + + bAbsPositionsValid = sal_False; + pEntry->pParent = pParent; + + pList->Insert( pEntry, nPos ); + nEntryCount++; + if( nPos != LIST_APPEND && (nPos != (pList->Count()-1)) ) + SetListPositions( pList ); + else + pEntry->nListPos = pList->Count()-1; + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast( LISTACTION_INSERTED, pEntry ); + return nPos; // pEntry->nListPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_uLong SvTreeList::GetAbsPos( SvListEntry* pEntry) const +{ + if ( !bAbsPositionsValid ) + ((SvTreeList*)this)->SetAbsolutePositions(); + return pEntry->nAbsPos; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::SetAbsolutePositions() +{ + sal_uLong nPos = 0; + SvListEntry* pEntry = First(); + while ( pEntry ) + { + pEntry->nAbsPos = nPos; + nPos++; + pEntry = Next( pEntry ); + } + bAbsPositionsValid = sal_True; +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +/************************************************************************* +|* +|* SvTreeList::Expand +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Expand( SvListView* pView, SvListEntry* pEntry ) +{ + DBG_ASSERT(pEntry&&pView,"Expand:View/Entry?"); + if ( pView->IsExpanded(pEntry) ) + return; + + DBG_ASSERT(pEntry->pChilds,"Expand:No Childs!"); + + SvViewData* pViewData = pView->GetViewData(pEntry); + pViewData->nFlags |= SVLISTENTRYFLAG_EXPANDED; + SvListEntry* pParent = pEntry->pParent; + // wenn Parent sichtbar dann Statusdaten invalidieren + if ( pView->IsExpanded( pParent ) ) + { + pView->bVisPositionsValid = sal_False; + pView->nVisibleCount = 0; + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + +/************************************************************************* +|* +|* SvTreeList::Collapse +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +void SvTreeList::Collapse( SvListView* pView, SvListEntry* pEntry ) +{ + DBG_ASSERT(pView&&pEntry,"Collapse:View/Entry?"); + if ( !pView->IsExpanded(pEntry) ) + return; + + DBG_ASSERT(pEntry->pChilds,"Collapse:No Childs!"); + + SvViewData* pViewData = pView->GetViewData( pEntry ); + pViewData->nFlags &=(~SVLISTENTRYFLAG_EXPANDED); + + SvListEntry* pParent = pEntry->pParent; + if ( pView->IsExpanded(pParent) ) + { + pView->nVisibleCount = 0; + pView->bVisPositionsValid = sal_False; + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_Bool SvTreeList::Select( SvListView* pView, SvListEntry* pEntry, sal_Bool bSelect ) +{ + DBG_ASSERT(pView&&pEntry,"Select:View/Entry?"); + SvViewData* pViewData = pView->GetViewData( pEntry ); + if ( bSelect ) + { + if ( pViewData->IsSelected() || !pViewData->IsSelectable() ) + return sal_False; + else + { + pViewData->nFlags |= SVLISTENTRYFLAG_SELECTED; + pView->nSelectionCount++; + } + } + else + { + if ( !pViewData->IsSelected() ) + return sal_False; + else + { + pViewData->nFlags &= ~( SVLISTENTRYFLAG_SELECTED ); + pView->nSelectionCount--; + } + } +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + return sal_True; +} + +/************************************************************************* +|* +|* SvTreeList::Remove +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 05.04.01 +|* +*************************************************************************/ +sal_Bool SvTreeList::Remove( SvListEntry* pEntry ) +{ + DBG_ASSERT(pEntry,"Cannot remove root, use clear"); + + if( !pEntry->pParent ) + { + DBG_ERROR("Removing entry not in model!"); + // unter gewissen Umstaenden (welche?) loescht der + // Explorer aus der View Eintraege, die er nicht in die View + // eingefuegt hat. Da sich der Kunde fuer ein platzendes + // Office nichts kaufen kann, fange ich diesen Fall ab. + return sal_False; + } + + Broadcast( LISTACTION_REMOVING, pEntry ); + sal_uLong nRemoved = 1 + GetChildCount(pEntry); + bAbsPositionsValid = sal_False; + + SvListEntry* pParent = pEntry->pParent; + SvTreeEntryList* pList = pParent->pChilds; + DBG_ASSERT(pList,"Remove:No Childlist"); + sal_Bool bLastEntry = sal_False; + + if ( pEntry->HasChildListPos() ) + { + sal_uLong nListPos = pEntry->GetChildListPos(); + bLastEntry = (nListPos == (pList->Count()-1) ) ? sal_True : sal_False; + pList->Remove( nListPos ); + } + else + { + pList->Remove( (void*) pEntry ); + } + + + // moved to end of method because it is used later with Broadcast + // delete pEntry; // loescht auch alle Childs + + if ( pList->Count() == 0 ) + { + pParent->pChilds = 0; + delete pList; + } + else + { + if( !bLastEntry ) + SetListPositions( pList ); + } + nEntryCount -= nRemoved; + +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + Broadcast( LISTACTION_REMOVED, pEntry ); + + delete pEntry; // loescht auch alle Childs + return sal_True; +} + +/************************************************************************* +|* +|* SvTreeList:: +|* +|* Beschreibung +|* Ersterstellung 17.08.94 +|* Letzte Aenderung 17.08.94 +|* +*************************************************************************/ + +sal_uLong SvTreeList::SelectChilds(SvListView* pView, SvListEntry* pParent,sal_Bool bSelect ) +{ + DBG_ASSERT(pView&&pParent,"SelChilds:View/Parent?"); + if ( !pParent->pChilds ) + return 0; + if ( pParent->pChilds->Count() == 0 ) + return 0; + + sal_uInt16 nRefDepth = GetDepth( pParent ); + sal_uInt16 nDepth = nRefDepth; + sal_uLong nCount = 0; + pParent = Next( pParent ); + do + { + if ( Select( pView, pParent, bSelect ) ) + nCount++; // nur die tatsaechlichen Selektierungen zaehlen + pParent = Next( pParent, &nDepth ); + } + while( pParent && nDepth > nRefDepth ); +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif + return nCount; +} + +void SvTreeList::SelectAll( SvListView* pView, sal_Bool bSelect ) +{ + DBG_ASSERT(pView,"SelectAll:NoView"); + SvListEntry* pEntry = First(); + while ( pEntry ) + { + SvViewData* pViewData = pView->GetViewData( pEntry ); + if ( bSelect ) + pViewData->nFlags |= SVLISTENTRYFLAG_SELECTED; + else + pViewData->nFlags &= (~SVLISTENTRYFLAG_SELECTED); + + pEntry = Next( pEntry ); + } + if ( bSelect ) + pView->nSelectionCount = nEntryCount; + else + pView->nSelectionCount = 0; +#ifdef CHECK_INTEGRITY +CheckIntegrity(); +#endif +} + + +SvListEntry* SvTreeList::GetEntryAtAbsPos( sal_uLong nAbsPos ) const +{ + SvListEntry* pEntry = First(); + while ( nAbsPos && pEntry ) + { + pEntry = Next( pEntry ); + nAbsPos--; + } + return pEntry; +} + +SvListEntry* SvTreeList::GetEntryAtVisPos( const SvListView* pView, sal_uLong nVisPos ) const +{ + DBG_ASSERT(pView,"GetEntryAtVisPos:No View"); + SvListEntry* pEntry = First(); + while ( nVisPos && pEntry ) + { + pEntry = NextVisible( pView, pEntry ); + nVisPos--; + } + return pEntry; +} + +void SvTreeList::SetListPositions( SvTreeEntryList* pList ) +{ + if( pList->Count() ) + { + SvListEntry* pEntry = (SvListEntry*)(pList->GetObject(0)); + if( pEntry->pParent ) + pEntry->pParent->InvalidateChildrensListPositions(); + } + /* + sal_uLong nListPos = 0; + SvListEntry* pEntry = (SvListEntry*)(pList->First()); + while( pEntry ) + { + pEntry->nListPos = nListPos; + nListPos++; + pEntry = (SvListEntry*)(pList->Next()); + } + */ +} + + +void SvTreeList::InvalidateEntry( SvListEntry* pEntry ) +{ + Broadcast( LISTACTION_INVALIDATE_ENTRY, pEntry ); +} + +sal_Bool SvTreeList::IsInChildList( SvListEntry* pParent, SvListEntry* pChild) const +{ + if ( !pParent ) + pParent = pRootItem; + sal_Bool bIsChild = sal_False; + if ( pParent->pChilds ) + bIsChild = (sal_Bool)(pParent->pChilds->GetPos(pChild) != LIST_ENTRY_NOTFOUND); + return bIsChild; +} + + +void lcl_CheckList( SvTreeEntryList* pList ) +{ + SvListEntry* pEntry = (SvListEntry*)(pList->First()); + sal_uLong nPos = 0; + while ( pEntry ) + { + DBG_ASSERT(pEntry->GetChildListPos()==nPos,"Wrong ListPos"); + pEntry = (SvListEntry*)(pList->Next()); + nPos++; + } +} + +void SvTreeList::CheckIntegrity() const +{ + sal_uLong nMyEntryCount = 0; + if ( pRootItem->pChilds ) + { + lcl_CheckList( pRootItem->pChilds ); + SvListEntry* pEntry = First(); + while( pEntry ) + { + nMyEntryCount++; + if ( pEntry->pChilds ) + lcl_CheckList( pEntry->pChilds ); + pEntry = Next( pEntry ); + } + } + DBG_ASSERT(nMyEntryCount==GetEntryCount(),"Entry count invalid"); +} + +SvListEntry* SvTreeList::GetRootLevelParent( SvListEntry* pEntry ) const +{ + DBG_ASSERT(pEntry,"GetRootLevelParent:No Entry"); + SvListEntry* pCurParent = 0; + if ( pEntry ) + { + pCurParent = pEntry->pParent; + if ( pCurParent == pRootItem ) + return pEntry; // ist sein eigener Parent + while( pCurParent && pCurParent->pParent != pRootItem ) + pCurParent = pCurParent->pParent; + } + return pCurParent; +} + + + + +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* +//************************************************************************* + +DBG_NAME(SvListView); + +SvListView::SvListView( SvTreeList* pModell ) +{ + DBG_CTOR(SvListView,0); + pModel = 0; + nSelectionCount = 0; + nVisibleCount = 0; + bVisPositionsValid = sal_False; + SetModel( pModell ); +} + +SvListView::SvListView() +{ + DBG_CTOR(SvListView,0); + pModel = 0; + nSelectionCount = 0; + nVisibleCount = 0; + bVisPositionsValid = sal_False; +} + + +SvListView::~SvListView() +{ + DBG_DTOR(SvListView,0); + ClearTable(); +} + +void SvListView::InitTable() +{ + DBG_CHKTHIS(SvListView,0); + DBG_ASSERT(pModel,"InitTable:No Model"); + DBG_ASSERT(!nSelectionCount&&!nVisibleCount&&!bVisPositionsValid,"InitTable: Not cleared!"); + + if( aDataTable.Count() ) + { + DBG_ASSERT(aDataTable.Count()==1,"InitTable: TableCount != 1"); + // die im Clear fuer die Root allozierten View-Daten loeschen + // Achtung: Das zu dem RootEntry (und damit auch der Entry) + // gehoerende Model kann bereits geloescht sein! + SvViewData* pViewData = (SvViewData*)aDataTable.GetObject( 0 ); + delete pViewData; + aDataTable.Clear(); + } + + SvListEntry* pEntry; + SvViewData* pViewData; + + // RootEntry einfuegen + pEntry = pModel->pRootItem; + pViewData = new SvViewData; + pViewData->nFlags = SVLISTENTRYFLAG_EXPANDED; + aDataTable.Insert( (sal_uLong)pEntry, pViewData ); + // Jetzt alle anderen Entries + pEntry = pModel->First(); + while( pEntry ) + { + pViewData = CreateViewData( pEntry ); + DBG_ASSERT(pViewData,"InitTable:No ViewData"); + InitViewData( pViewData, pEntry ); + aDataTable.Insert( (sal_uLong)pEntry, pViewData ); + pEntry = pModel->Next( pEntry ); + } +} + +SvViewData* SvListView::CreateViewData( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); + return new SvViewData; +} + +void SvListView::ClearTable() +{ + DBG_CHKTHIS(SvListView,0); + SvViewData* pViewData = (SvViewData*)aDataTable.First(); + while( pViewData ) + { + delete pViewData; + pViewData = (SvViewData*)aDataTable.Next(); + } + aDataTable.Clear(); +} + +void SvListView::Clear() +{ + ClearTable(); + nSelectionCount = 0; + nVisibleCount = 0; + bVisPositionsValid = sal_False; + if( pModel ) + { + // RootEntry einfuegen + SvListEntry* pEntry = pModel->pRootItem; + SvViewData* pViewData = new SvViewData; + pViewData->nFlags = SVLISTENTRYFLAG_EXPANDED; + aDataTable.Insert( (sal_uLong)pEntry, pViewData ); + } +} + +void SvListView::SetModel( SvTreeList* pNewModel ) +{ + DBG_CHKTHIS(SvListView,0); + sal_Bool bBroadcastCleared = sal_False; + if ( pModel ) + { + pModel->RemoveView( this ); + bBroadcastCleared = sal_True; + ModelNotification( LISTACTION_CLEARING,0,0,0 ); + if ( pModel->GetRefCount() == 0 ) + delete pModel; + } + pModel = pNewModel; + InitTable(); + pNewModel->InsertView( this ); + if( bBroadcastCleared ) + ModelNotification( LISTACTION_CLEARED,0,0,0 ); +} + + +void SvListView::ModelHasCleared() +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasInserted( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasInsertedTree( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelIsMoving( SvListEntry* /* pSource */ , + SvListEntry* /* pTargetParent */ , sal_uLong /* nPos */ ) +{ + DBG_CHKTHIS(SvListView,0); +} + + +void SvListView::ModelHasMoved( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelIsRemoving( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasRemoved( SvListEntry* ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ModelHasEntryInvalidated( SvListEntry*) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ActionMoving( SvListEntry* pEntry,SvListEntry*,sal_uLong) +{ + DBG_CHKTHIS(SvListView,0); + SvListEntry* pParent = pEntry->pParent; + DBG_ASSERT(pParent,"Model not consistent"); + if( pParent != pModel->pRootItem && pParent->pChilds->Count() == 1 ) + { + SvViewData* pViewData = (SvViewData*)aDataTable.Get( (sal_uLong)pParent ); + pViewData->nFlags &= (~SVLISTENTRYFLAG_EXPANDED); + } + // vorlaeufig + nVisibleCount = 0; + bVisPositionsValid = sal_False; +} + +void SvListView::ActionMoved( SvListEntry* /* pEntry */ , + SvListEntry* /* pTargetPrnt */ , + sal_uLong /* nChildPos */ ) +{ + DBG_CHKTHIS(SvListView,0); + nVisibleCount = 0; + bVisPositionsValid = sal_False; +} + +void SvListView::ActionInserted( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvListView,0); + DBG_ASSERT(pEntry,"Insert:No Entry"); + SvViewData* pData = CreateViewData( pEntry ); + InitViewData( pData, pEntry ); + #ifdef DBG_UTIL + sal_Bool bSuccess = + #endif + aDataTable.Insert( (sal_uLong)pEntry, pData ); + DBG_ASSERT(bSuccess,"Entry already in View"); + if ( nVisibleCount && pModel->IsEntryVisible( this, pEntry )) + { + nVisibleCount = 0; + bVisPositionsValid = sal_False; + } +} + +void SvListView::ActionInsertedTree( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvListView,0); + if ( pModel->IsEntryVisible( this, pEntry )) + { + nVisibleCount = 0; + bVisPositionsValid = sal_False; + } + // ueber Entry und seine Childs iterieren + SvListEntry* pCurEntry = pEntry; + sal_uInt16 nRefDepth = pModel->GetDepth( pCurEntry ); + while( pCurEntry ) + { + DBG_ASSERT(aDataTable.Get((sal_uLong)pCurEntry)==0,"Entry already in Table"); + SvViewData* pViewData = CreateViewData( pCurEntry ); + DBG_ASSERT(pViewData,"No ViewData"); + InitViewData( pViewData, pEntry ); + aDataTable.Insert( (sal_uLong)pCurEntry, pViewData ); + pCurEntry = pModel->Next( pCurEntry ); + if ( pCurEntry && pModel->GetDepth(pCurEntry) <= nRefDepth) + pCurEntry = 0; + } +} + +void SvListView::RemoveViewData( SvListEntry* pParent ) +{ + SvTreeEntryList* pChilds = pParent->pChilds; + if( pChilds ) + { + SvListEntry* pCur = (SvListEntry*)pChilds->First(); + while( pCur ) + { + SvViewData* pViewData = (SvViewData*)aDataTable.Get((sal_uLong)pCur); + delete pViewData; + aDataTable.Remove( (sal_uLong)pCur ); + if( pCur->HasChilds()) + RemoveViewData( pCur ); + pCur = (SvListEntry*)pChilds->Next(); + } + } +} + + + +void SvListView::ActionRemoving( SvListEntry* pEntry ) +{ + DBG_CHKTHIS(SvListView,0); + DBG_ASSERT(pEntry,"Remove:No Entry"); + + SvViewData* pViewData = (SvViewData*)aDataTable.Get( (sal_uLong)pEntry ); + sal_uLong nSelRemoved = 0; + if ( pViewData->IsSelected() ) + nSelRemoved = 1 + pModel->GetChildSelectionCount( this, pEntry ); + nSelectionCount -= nSelRemoved; + sal_uLong nVisibleRemoved = 0; + if ( pModel->IsEntryVisible( this, pEntry ) ) + nVisibleRemoved = 1 + pModel->GetVisibleChildCount( this, pEntry ); + if( nVisibleCount ) + { +#ifdef DBG_UTIL + if( nVisibleCount < nVisibleRemoved ) + { + DBG_ERROR("nVisibleRemoved bad"); + } +#endif + nVisibleCount -= nVisibleRemoved; + } + bVisPositionsValid = sal_False; + + pViewData = (SvViewData*)aDataTable.Get((sal_uLong)pEntry); + delete pViewData; + aDataTable.Remove( (sal_uLong)pEntry ); + RemoveViewData( pEntry ); + + SvListEntry* pCurEntry = pEntry->pParent; + if ( pCurEntry && pCurEntry != pModel->pRootItem && + pCurEntry->pChilds->Count() == 1 ) + { + pViewData = (SvViewData*)aDataTable.Get((sal_uLong)pCurEntry); + pViewData->nFlags &= (~SVLISTENTRYFLAG_EXPANDED); + } +} + +void SvListView::ActionRemoved( SvListEntry* /* pEntry */ ) +{ + DBG_CHKTHIS(SvListView,0); +} + +void SvListView::ActionClear() +{ + DBG_CHKTHIS(SvListView,0); + Clear(); +} + +void SvListView::ModelNotification( sal_uInt16 nActionId, SvListEntry* pEntry1, + SvListEntry* pEntry2, sal_uLong nPos ) +{ + DBG_CHKTHIS(SvListView,0); + switch( nActionId ) + { + case LISTACTION_INSERTED: + ActionInserted( pEntry1 ); + ModelHasInserted( pEntry1 ); + break; + case LISTACTION_INSERTED_TREE: + ActionInsertedTree( pEntry1 ); + ModelHasInsertedTree( pEntry1 ); + break; + case LISTACTION_REMOVING: + ModelIsRemoving( pEntry1 ); + ActionRemoving( pEntry1 ); + break; + case LISTACTION_REMOVED: + ActionRemoved( pEntry1 ); + ModelHasRemoved( pEntry1 ); + break; + case LISTACTION_MOVING: + ModelIsMoving( pEntry1, pEntry2, nPos ); + ActionMoving( pEntry1, pEntry2, nPos ); + break; + case LISTACTION_MOVED: + ActionMoved( pEntry1, pEntry2, nPos ); + ModelHasMoved( pEntry1 ); + break; + case LISTACTION_CLEARING: + ActionClear(); + ModelHasCleared(); //sic! wg. Kompatibilitaet! + break; + case LISTACTION_CLEARED: + break; + case LISTACTION_INVALIDATE_ENTRY: + // keine Action fuer die Basisklasse + ModelHasEntryInvalidated( pEntry1 ); + break; + case LISTACTION_RESORTED: + bVisPositionsValid = sal_False; + break; + case LISTACTION_RESORTING: + break; + default: + DBG_ERROR("unknown ActionId"); + } +} + +void SvListView::InitViewData( SvViewData*, SvListEntry* ) +{ +} + +StringCompare SvTreeList::Compare( SvListEntry* pLeft, SvListEntry* pRight) const +{ + if( aCompareLink.IsSet()) + { + SvSortData aSortData; + aSortData.pLeft = pLeft; + aSortData.pRight = pRight; + return (StringCompare)aCompareLink.Call( &aSortData ); + } + return COMPARE_EQUAL; +} + +void SvTreeList::Resort() +{ + Broadcast( LISTACTION_RESORTING ); + bAbsPositionsValid = sal_False; + ResortChilds( pRootItem ); + Broadcast( LISTACTION_RESORTED ); +} + +void SvTreeList::ResortChilds( SvListEntry* pParent ) +{ + DBG_ASSERT(pParent,"Parent not set"); + List* pChildList = pParent->pChilds; + if( !pChildList ) + return; + List aList( *pChildList ); + pChildList->Clear(); + + sal_uLong nCount = aList.Count(); + for( sal_uLong nCur = 0; nCur < nCount; nCur++ ) + { + SvListEntry* pCurEntry = (SvListEntry*)aList.GetObject( nCur ); + sal_uLong nListPos = LIST_APPEND; + GetInsertionPos( pCurEntry, pParent, nListPos ); + pChildList->Insert( pCurEntry, nListPos ); + if( pCurEntry->pChilds ) + ResortChilds( pCurEntry ); + } + SetListPositions( (SvTreeEntryList*)pChildList ); +} + +void SvTreeList::GetInsertionPos( SvListEntry* pEntry, SvListEntry* pParent, + sal_uLong& rPos ) +{ + DBG_ASSERT(pEntry,"No Entry"); + + if( eSortMode == SortNone ) + return; + + rPos = LIST_APPEND; + SvTreeEntryList* pChildList = GetChildList( pParent ); + + if( pChildList && pChildList->Count() ) + { + long i = 0; + long j = pChildList->Count()-1; + long k; + StringCompare eCompare = COMPARE_GREATER; + + do + { + k = (i+j)/2; + SvListEntry* pTempEntry = (SvListEntry*)(pChildList->GetObject(k)); + eCompare = Compare( pEntry, pTempEntry ); + if( eSortMode == SortDescending && eCompare != COMPARE_EQUAL ) + { + if( eCompare == COMPARE_LESS ) + eCompare = COMPARE_GREATER; + else + eCompare = COMPARE_LESS; + } + if( eCompare == COMPARE_GREATER ) + i = k + 1; + else + j = k - 1; + } while( (eCompare != COMPARE_EQUAL) && (i <= j) ); + + if( eCompare != COMPARE_EQUAL ) + { + if(i > ((long)pChildList->Count() - 1)) // nicht gefunden, Ende der Liste + rPos = LIST_APPEND; + else + rPos = i; // nicht gefunden, Mitte + } + else + rPos = k; + } +} + + |