diff options
Diffstat (limited to 'sd/source/ui/slidesorter')
100 files changed, 26924 insertions, 0 deletions
diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx new file mode 100644 index 000000000000..8a65d0ea092b --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx @@ -0,0 +1,671 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsBitmapCache.cxx,v $ + * $Revision: 1.10 $ + * + * 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_sd.hxx" + +#include "SlsBitmapCache.hxx" +#include "SlsCacheCompactor.hxx" +#include "SlsBitmapCompressor.hxx" +#include "SlsCacheConfiguration.hxx" + +#include "taskpane/SlideSorterCacheDisplay.hxx" +#include "sdpage.hxx" +#include "drawdoc.hxx" + +// Uncomment the following define for some more OSL_TRACE messages. +#ifdef DEBUG +//#define VERBOSE +#endif + +// Define the default value for the maximal cache size that is used for +// previews that are currently not visible. The visible previews are all +// held in memory at all times. This default is used only when the +// configuration does not have a value. +static const sal_Int32 MAXIMAL_CACHE_SIZE = 4L*1024L*1024L; + +using namespace ::com::sun::star::uno; + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache::CacheEntry +{ +public: + CacheEntry(const ::boost::shared_ptr<BitmapEx>& rpBitmap, + sal_Int32 nLastAccessTime, bool bIsPrecious); + CacheEntry(sal_Int32 nLastAccessTime, bool bIsPrecious); + ~CacheEntry (void) {}; + inline void Recycle (const CacheEntry& rEntry); + inline sal_Int32 GetMemorySize (void) const; + void Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor); + inline void Decompress (void); + + bool IsUpToDate (void) const { return mbIsUpToDate; } + void SetUpToDate (bool bIsUpToDate) { mbIsUpToDate = bIsUpToDate; } + sal_Int32 GetAccessTime (void) const { return mnLastAccessTime; } + void SetAccessTime (sal_Int32 nAccessTime) { mnLastAccessTime = nAccessTime; } + ::boost::shared_ptr<BitmapEx> GetPreview (void) const { return mpPreview; } + inline void SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview); + bool HasPreview (void) const; + bool HasReplacement (void) const { return (mpReplacement.get() != NULL); } + inline bool HasLosslessReplacement (void) const; + void Clear (void) { mpPreview.reset(); mpReplacement.reset(); mpCompressor.reset(); } + void Invalidate (void) { mpReplacement.reset(); mpCompressor.reset(); mbIsUpToDate = false; } + bool IsPrecious (void) const { return mbIsPrecious; } + void SetPrecious (bool bIsPrecious) { mbIsPrecious = bIsPrecious; } + +private: + ::boost::shared_ptr<BitmapEx> mpPreview; + ::boost::shared_ptr<BitmapReplacement> mpReplacement; + ::boost::shared_ptr<BitmapCompressor> mpCompressor; + Size maBitmapSize; + bool mbIsUpToDate; + sal_Int32 mnLastAccessTime; + // When this flag is set then the bitmap is not modified by a cache + // compactor. + bool mbIsPrecious; +}; +class CacheEntry; + +class CacheHash { +public: + size_t operator()(const BitmapCache::CacheKey& p) const + { return (size_t)p; } +}; + +class BitmapCache::CacheBitmapContainer + : public ::std::hash_map<CacheKey, CacheEntry, CacheHash> +{ +public: + CacheBitmapContainer (void) {} +}; + +namespace { + +typedef ::std::vector< + ::std::pair< ::sd::slidesorter::cache::BitmapCache::CacheKey, + ::sd::slidesorter::cache::BitmapCache::CacheEntry> + > SortableBitmapContainer; + + /** Compare elements of the bitmap cache according to their last access + time. + */ + class AccessTimeComparator + { + public: + bool operator () ( + const SortableBitmapContainer::value_type& e1, + const SortableBitmapContainer::value_type& e2) + { + return e1.second.GetAccessTime() < e2.second.GetAccessTime(); + } + }; + + +} // end of anonymous namespace + + +//===== BitmapCache ========================================================= + +BitmapCache::BitmapCache (const sal_Int32 nMaximalNormalCacheSize) + : maMutex(), + mpBitmapContainer(new CacheBitmapContainer()), + mnNormalCacheSize(0), + mnPreciousCacheSize(0), + mnCurrentAccessTime(0), + mnMaximalNormalCacheSize(MAXIMAL_CACHE_SIZE), + mpCacheCompactor(), + mbIsFull(false) +{ + if (nMaximalNormalCacheSize > 0) + mnMaximalNormalCacheSize = nMaximalNormalCacheSize; + else + { + Any aCacheSize (CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CacheSize")))); + if (aCacheSize.has<sal_Int32>()) + aCacheSize >>= mnMaximalNormalCacheSize; + } + + mpCacheCompactor = CacheCompactor::Create(*this,mnMaximalNormalCacheSize); +} + + + + +BitmapCache::~BitmapCache (void) +{ + Clear(); +} + + + + +void BitmapCache::Clear (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + mpBitmapContainer->clear(); + mnNormalCacheSize = 0; + mnPreciousCacheSize = 0; + mnCurrentAccessTime = 0; +} + + + + +bool BitmapCache::IsEmpty (void) const +{ + return mpBitmapContainer->empty(); +} + + + + +bool BitmapCache::IsFull (void) const +{ + return mbIsFull; +} + + + + +sal_Int32 BitmapCache::GetSize (void) +{ + return mnNormalCacheSize; +} + + + + +bool BitmapCache::HasBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + return (iEntry != mpBitmapContainer->end() + && (iEntry->second.HasPreview() || iEntry->second.HasReplacement())); +} + + + + +bool BitmapCache::BitmapIsUpToDate (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + bool bIsUpToDate = false; + CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey)); + if (aIterator != mpBitmapContainer->end()) + bIsUpToDate = aIterator->second.IsUpToDate(); + + return bIsUpToDate; +} + + + + +::boost::shared_ptr<BitmapEx> BitmapCache::GetBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry == mpBitmapContainer->end()) + { + // Create an empty bitmap for the given key that acts as placeholder + // until we are given the real one. Mark it as not being up to date. + SetBitmap (rKey, ::boost::shared_ptr<BitmapEx>(new BitmapEx()), false); + iEntry = mpBitmapContainer->find(rKey); + iEntry->second.SetUpToDate(false); + SSCD_SET_UPTODATE(iEntry->first,false); + } + else + { + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + + // Maybe we have to decompress the preview. + if ( ! iEntry->second.HasPreview() && iEntry->second.HasReplacement()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Decompress(); + UpdateCacheSize(iEntry->second, ADD); + } + } + return iEntry->second.GetPreview(); +} + + + + +void BitmapCache::ReleaseBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey)); + if (aIterator != mpBitmapContainer->end()) + { + UpdateCacheSize(aIterator->second, REMOVE); + mpBitmapContainer->erase(aIterator); + } +} + + + + +void BitmapCache::InvalidateBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + iEntry->second.SetUpToDate(false); + SSCD_SET_UPTODATE(iEntry->first,false); + + // When there is a preview then we release the replacement. The + // preview itself is kept until a new one is created. + if (iEntry->second.HasPreview()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Invalidate(); + SSCD_SET_UPTODATE(iEntry->first,false); + UpdateCacheSize(iEntry->second, ADD); + } + } +} + + + + +void BitmapCache::InvalidateCache (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry; + for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) + { + iEntry->second.Invalidate(); + SSCD_SET_UPTODATE(iEntry->first,false); + } + ReCalculateTotalCacheSize(); +} + + + + +void BitmapCache::SetBitmap ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapEx>& rpPreview, + bool bIsPrecious) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.SetPreview(rpPreview); + iEntry->second.SetUpToDate(true); + SSCD_SET_UPTODATE(iEntry->first,true); + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + } + else + { + iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( + rKey, + CacheEntry (rpPreview, mnCurrentAccessTime++, bIsPrecious)) + ).first; + } + + if (iEntry != mpBitmapContainer->end()) + UpdateCacheSize(iEntry->second, ADD); +} + + + + +bool BitmapCache::IsPrecious (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator aIterator (mpBitmapContainer->find(rKey)); + if (aIterator != mpBitmapContainer->end()) + return aIterator->second.IsPrecious(); + else + return false; +} + + + + +void BitmapCache::SetPrecious (const CacheKey& rKey, bool bIsPrecious) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + if (iEntry->second.IsPrecious() != bIsPrecious) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.SetPrecious(bIsPrecious); + UpdateCacheSize(iEntry->second, ADD); + } + } + else if (bIsPrecious) + { + iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( + rKey, + CacheEntry ( + ::boost::shared_ptr<BitmapEx>(), + mnCurrentAccessTime++, bIsPrecious)) + ).first; + UpdateCacheSize(iEntry->second, ADD); + } +} + + + + +void BitmapCache::ReCalculateTotalCacheSize (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + mnNormalCacheSize = 0; + mnPreciousCacheSize = 0; + CacheBitmapContainer::iterator iEntry; + for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) + { + if (iEntry->second.IsPrecious()) + mnPreciousCacheSize += iEntry->second.GetMemorySize(); + else + mnNormalCacheSize += iEntry->second.GetMemorySize(); + } + mbIsFull = (mnNormalCacheSize >= mnMaximalNormalCacheSize); + +#ifdef VERBOSE + OSL_TRACE("cache size is %d/%d", mnNormalCacheSize, mnPreciousCacheSize); +#endif +} + + + + +void BitmapCache::Recycle (const BitmapCache& rCache) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::const_iterator iOtherEntry; + for (iOtherEntry=rCache.mpBitmapContainer->begin(); + iOtherEntry!=rCache.mpBitmapContainer->end(); + ++iOtherEntry) + { + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(iOtherEntry->first)); + if (iEntry == mpBitmapContainer->end()) + { + iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( + iOtherEntry->first, + CacheEntry(mnCurrentAccessTime++, true)) + ).first; + UpdateCacheSize(iEntry->second, ADD); + } + if (iEntry != mpBitmapContainer->end()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Recycle(iOtherEntry->second); + UpdateCacheSize(iEntry->second, ADD); + } + } +} + + + + +::std::auto_ptr<BitmapCache::CacheIndex> BitmapCache::GetCacheIndex ( + bool bIncludePrecious, + bool bIncludeNoPreview) const +{ + ::osl::MutexGuard aGuard (maMutex); + + // Create a copy of the bitmap container. + SortableBitmapContainer aSortedContainer; + aSortedContainer.reserve(mpBitmapContainer->size()); + + // Copy the relevant entries. + CacheBitmapContainer::iterator iEntry; + for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) + { + if ( ! bIncludePrecious && iEntry->second.IsPrecious()) + continue; + + if ( ! bIncludeNoPreview && ! iEntry->second.HasPreview()) + continue; + + aSortedContainer.push_back(SortableBitmapContainer::value_type( + iEntry->first,iEntry->second)); + } + + // Sort the remaining entries. + ::std::sort(aSortedContainer.begin(), aSortedContainer.end(), AccessTimeComparator()); + + // Return a list with the keys of the sorted entries. + ::std::auto_ptr<CacheIndex> pIndex(new CacheIndex()); + SortableBitmapContainer::iterator iIndexEntry; + pIndex->reserve(aSortedContainer.size()); + for (iIndexEntry=aSortedContainer.begin(); iIndexEntry!=aSortedContainer.end(); ++iIndexEntry) + pIndex->push_back(iIndexEntry->first); + return pIndex; +} + + + + +void BitmapCache::Compress ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapCompressor>& rpCompressor) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end() && iEntry->second.HasPreview()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.Compress(rpCompressor); + UpdateCacheSize(iEntry->second, ADD); + } +} + + + + +void BitmapCache::UpdateCacheSize (const CacheEntry& rEntry, CacheOperation eOperation) +{ + sal_Int32 nEntrySize (rEntry.GetMemorySize()); + sal_Int32& rCacheSize (rEntry.IsPrecious() ? mnPreciousCacheSize : mnNormalCacheSize); + switch (eOperation) + { + case ADD: + rCacheSize += nEntrySize; + if ( ! rEntry.IsPrecious() && mnNormalCacheSize>mnMaximalNormalCacheSize) + { + mbIsFull = true; +#ifdef VERBOSE + OSL_TRACE("cache size is %d > %d", mnNormalCacheSize,mnMaximalNormalCacheSize); +#endif + mpCacheCompactor->RequestCompaction(); + } + break; + + case REMOVE: + rCacheSize -= nEntrySize; + if (mnNormalCacheSize < mnMaximalNormalCacheSize) + mbIsFull = false; + break; + + default: + OSL_ASSERT(false); + break; + } +} + + + + +//===== CacheEntry ============================================================ + +BitmapCache::CacheEntry::CacheEntry( + sal_Int32 nLastAccessTime, + bool bIsPrecious) + : mpPreview(), + mbIsUpToDate(true), + mnLastAccessTime(nLastAccessTime), + mbIsPrecious(bIsPrecious) +{ +} + + + + +BitmapCache::CacheEntry::CacheEntry( + const ::boost::shared_ptr<BitmapEx>& rpPreview, + sal_Int32 nLastAccessTime, + bool bIsPrecious) + : mpPreview(rpPreview), + mbIsUpToDate(true), + mnLastAccessTime(nLastAccessTime), + mbIsPrecious(bIsPrecious) +{ +} + + + + +inline void BitmapCache::CacheEntry::Recycle (const CacheEntry& rEntry) +{ + if ((rEntry.HasPreview() || rEntry.HasLosslessReplacement()) + && ! (HasPreview() || HasLosslessReplacement())) + { + mpPreview = rEntry.mpPreview; + mpReplacement = rEntry.mpReplacement; + mpCompressor = rEntry.mpCompressor; + mnLastAccessTime = rEntry.mnLastAccessTime; + mbIsUpToDate = rEntry.mbIsUpToDate; + } +} + + + + +inline sal_Int32 BitmapCache::CacheEntry::GetMemorySize (void) const +{ + sal_Int32 nSize (0); + if (mpPreview.get() != NULL) + nSize += mpPreview->GetSizeBytes(); + if (mpReplacement.get() != NULL) + nSize += mpReplacement->GetMemorySize(); + return nSize; +} + + + + +void BitmapCache::CacheEntry::Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor) +{ + if (mpPreview.get() != NULL) + { + if (mpReplacement.get() == NULL) + { + mpReplacement = rpCompressor->Compress(mpPreview); + +#ifdef VERBOSE + sal_uInt32 nOldSize (mpPreview->GetSizeBytes()); + sal_uInt32 nNewSize (mpReplacement.get()!=NULL ? mpReplacement->GetMemorySize() : 0); + if (nOldSize == 0) + nOldSize = 1; + sal_Int32 nRatio (100L * nNewSize / nOldSize); + OSL_TRACE("compressing bitmap for %x from %d to %d bytes (%d%%)", + this, + nOldSize, + nNewSize, + nRatio); +#endif + + mpCompressor = rpCompressor; + } + + mpPreview.reset(); + } +} + + + + +inline void BitmapCache::CacheEntry::Decompress (void) +{ + if (mpReplacement.get()!=NULL && mpCompressor.get()!=NULL && mpPreview.get()==NULL) + { + mpPreview = mpCompressor->Decompress(*mpReplacement); + if ( ! mpCompressor->IsLossless()) + mbIsUpToDate = false; + } +} + + + +inline void BitmapCache::CacheEntry::SetPreview (const ::boost::shared_ptr<BitmapEx>& rpPreview) +{ + mpPreview = rpPreview; + mpReplacement.reset(); + mpCompressor.reset(); +} + + + + +bool BitmapCache::CacheEntry::HasPreview (void) const +{ + if (mpPreview.get() != NULL) + return mpPreview->GetSizePixel().Width()>0 && mpPreview->GetSizePixel().Height()>0; + else + return false; +} + + + + +inline bool BitmapCache::CacheEntry::HasLosslessReplacement (void) const +{ + return mpReplacement.get()!=NULL + && mpCompressor.get()!=NULL + && mpCompressor->IsLossless(); +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx new file mode 100644 index 000000000000..283c0e08cf62 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx @@ -0,0 +1,228 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsBitmapCache.hxx,v $ + * $Revision: 1.6 $ + * + * 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 SD_SLIDESORTER_BITMAP_CACHE_HXX +#define SD_SLIDESORTER_BITMAP_CACHE_HXX + +class SdrPage; + +#include <vcl/bitmapex.hxx> +#include <osl/mutex.hxx> +#include <memory> +#include <boost/shared_ptr.hpp> +#include <hash_map> + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapReplacement; +class CacheCompactor; +class BitmapCompressor; + +/** This low level cache is the actual bitmap container. It supports a + precious flag for every preview bitmap and keeps track of total sizes + for all previews with as well as those without the flag. The precious + flag is used by compaction algorithms to determine which previews may be + compressed or even discarded and which have to remain in their original + form. The precious flag is usually set for the visible previews. +*/ +class BitmapCache +{ +public: + /** The key for looking up preview bitmaps is a pointer to an SdrPage + object. The prior use of PageObjectViewObjectContact objects (which + ultimatly use them) turned out to be less suitable because their + life time is shorter then that of the page objects. Frequent + destruction and re-creation of the preview bitmaps was the result. + */ + typedef const SdrPage* CacheKey; + class CacheEntry; + class CacheBitmapContainer; + typedef ::std::vector<CacheKey> CacheIndex; + + /** Create a new cache for bitmap objects. + @param nMaximalNormalCacheSize + When a size larger then zero is given then that size is used. + Otherwise the default value from the configuration is used. + When that does not exist either then a internal default value is + used. + */ + BitmapCache (const sal_Int32 nMaximalNormalCacheSize = 0); + + /** The destructor clears the cache and relases all bitmaps still in it. + */ + ~BitmapCache (void); + + /** Remove all preview bitmaps from the cache. After this call the + cache is empty. + */ + void Clear (void); + + /** Returns <TRUE/> when there is no preview bitmap in the cache. + */ + bool IsEmpty (void) const; + + /** Return <TRUE/> when the cache is full, i.e. the cache compactor had + to be run. + */ + bool IsFull (void) const; + + /** Return the memory size that is occupied by all non-precious bitmaps + in the cache. + */ + sal_Int32 GetSize (void); + + /** Return <TRUE/> when a preview bitmap exists for the given key. + */ + bool HasBitmap (const CacheKey& rKey); + + /** Return <TRUE/> when a preview bitmap exists for the given key and + when it is up-to-date. + */ + bool BitmapIsUpToDate (const CacheKey& rKey); + + /** Return the preview bitmap for the given contact object. + */ + ::boost::shared_ptr<BitmapEx> GetBitmap (const CacheKey& rKey); + + /** Release the reference to the preview bitmap that is associated with + the given key. + */ + void ReleaseBitmap (const CacheKey& rKey); + + /** Mark the specified preview bitmap as not being up-to-date anymore. + */ + void InvalidateBitmap (const CacheKey& rKey); + + /** Mark all preview bitmaps as not being up-to-date anymore. + */ + void InvalidateCache (void); + + /** Add or replace a bitmap for the given key. + */ + void SetBitmap ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapEx>& rpPreview, + bool bIsPrecious); + + /** Return whether the specified preview bitmap has been marked as + precious. + */ + bool IsPrecious (const CacheKey& rKey); + + /** Mark the specified preview bitmap as precious, i.e. that it must not + be compressed or otherwise removed from the cache. + */ + void SetPrecious (const CacheKey& rKey, bool bIsPrecious); + + /** Calculate the cache size. This should rarely be necessary because + the cache size is tracked with each modification of preview + bitmaps. + */ + void ReCalculateTotalCacheSize (void); + + /** Use the previews in the given cache to initialize missing previews. + */ + void Recycle (const BitmapCache& rCache); + + /** Return a list of sorted cache keys that represent an index into (a + part of) the cache. The entries of the index are sorted according + to last access times with the least recently access time first. + @param bIncludePrecious + When this flag is <TRUE/> entries with the precious flag set are + included in the index. When the flag is <FALSE/> these entries + are ommited. + @param bIncludeNoPreview + When this flag is <TRUE/> entries with that have no preview + bitmaps are included in the index. When the flag is <FALSE/> these entries + are ommited. + */ + ::std::auto_ptr<CacheIndex> GetCacheIndex ( + bool bIncludePrecious, + bool bIncludeNoPreview) const; + + /** Compress the specified preview bitmap with the given bitmap + compressor. A reference to the compressor is stored for later + decompression. + */ + void Compress ( + const CacheKey& rKey, + const ::boost::shared_ptr<BitmapCompressor>& rpCompressor); + +private: + mutable ::osl::Mutex maMutex; + + ::std::auto_ptr<CacheBitmapContainer> mpBitmapContainer; + + /** Total size of bytes that are occupied by bitmaps in the cache for + whom the slides are currently not inside the visible area. + */ + sal_Int32 mnNormalCacheSize; + + /** Total size of bytes that are occupied by bitmaps in the cache for + whom the slides are currently visible. + */ + sal_Int32 mnPreciousCacheSize; + + /** At the moment the access time is not an actual time or date value + but a counter that is increased with every access. It thus defines + the same ordering as a true time. + */ + sal_Int32 mnCurrentAccessTime; + + /** The maximal cache size for the off-screen preview bitmaps. When + mnNormalCacheSize grows larger than this value then the + mpCacheCompactor member is used to reduce the cache size. + */ + sal_Int32 mnMaximalNormalCacheSize; + + /** The cache compactor is used to reduce the number of bytes used by + off-screen preview bitmaps. + */ + ::std::auto_ptr<CacheCompactor> mpCacheCompactor; + + /** This flag stores if the cache is or recently was full, i.e. the + cache compactor has or had to be run in order to reduce the cache + size to the allowed value. + */ + bool mbIsFull; + + /** Update mnNormalCacheSize or mnPreciousCacheSize according to the + precious flag of the specified preview bitmap and the specified + operation. + */ + enum CacheOperation { ADD, REMOVE }; + void UpdateCacheSize (const CacheEntry& rKey, CacheOperation eOperation); +}; + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx new file mode 100644 index 000000000000..67f031ffb0ae --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx @@ -0,0 +1,276 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsBitmapCompressor.cxx,v $ + * $Revision: 1.6 $ + * + * 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_sd.hxx" + +#include "SlsBitmapCompressor.hxx" + +#include <tools/stream.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/pngread.hxx> +#include <vcl/pngwrite.hxx> + +namespace sd { namespace slidesorter { namespace cache { + + +//===== NoBitmapCompression =================================================== + +/** This dummy replacement simply stores a shared pointer to the original + preview bitmap. +*/ +class NoBitmapCompression::DummyReplacement + : public BitmapReplacement +{ +public: + ::boost::shared_ptr<BitmapEx> mpPreview; + Size maOriginalSize; + + DummyReplacement (const ::boost::shared_ptr<BitmapEx>& rpPreview) : mpPreview(rpPreview) + { + } + + virtual ~DummyReplacement(); + + virtual sal_Int32 GetMemorySize (void) const; +}; + +NoBitmapCompression::DummyReplacement::~DummyReplacement() +{ +} + +sal_Int32 NoBitmapCompression::DummyReplacement::GetMemorySize (void) const +{ + return mpPreview->GetSizeBytes(); +} + +::boost::shared_ptr<BitmapReplacement> NoBitmapCompression::Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +{ + return ::boost::shared_ptr<BitmapReplacement>(new DummyReplacement(rpBitmap)); +} + +::boost::shared_ptr<BitmapEx> NoBitmapCompression::Decompress ( + const BitmapReplacement& rBitmapData) const +{ + return dynamic_cast<const DummyReplacement&>(rBitmapData).mpPreview; +} + + + + +bool NoBitmapCompression::IsLossless (void) const +{ + return true; +} + + + + +//===== CompressionByDeletion ================================================= + +::boost::shared_ptr<BitmapReplacement> CompressionByDeletion::Compress ( + const ::boost::shared_ptr<BitmapEx>& ) const +{ + return ::boost::shared_ptr<BitmapReplacement>(); +} + + + + +::boost::shared_ptr<BitmapEx> CompressionByDeletion::Decompress ( + const BitmapReplacement& ) const +{ + // Return a NULL pointer. This will eventually lead to a request for + // the creation of a new one. + return ::boost::shared_ptr<BitmapEx>(); +} + + + + +bool CompressionByDeletion::IsLossless (void) const +{ + return false; +} + + + + +//===== ResolutionReduction =================================================== + +/** Store a scaled down bitmap together with the original size. +*/ +class ResolutionReduction::ResolutionReducedReplacement : public BitmapReplacement +{ +public: + ::boost::shared_ptr<BitmapEx> mpPreview; + Size maOriginalSize; + + virtual ~ResolutionReducedReplacement(); + + virtual sal_Int32 GetMemorySize (void) const; +}; + +ResolutionReduction::ResolutionReducedReplacement::~ResolutionReducedReplacement() +{ +} + +sal_Int32 ResolutionReduction::ResolutionReducedReplacement::GetMemorySize (void) const +{ + if (mpPreview.get() != NULL) + return mpPreview->GetSizeBytes(); + else + return 0; +} + +::boost::shared_ptr<BitmapReplacement> ResolutionReduction::Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +{ + ResolutionReducedReplacement* pResult = new ResolutionReducedReplacement(); + pResult->mpPreview.reset(new BitmapEx(*rpBitmap)); + Size aSize (rpBitmap->GetSizePixel()); + pResult->maOriginalSize = aSize; + if (aSize.Width()>0 && aSize.Width()<mnWidth) + { + int nHeight = aSize.Height() * mnWidth / aSize.Width() ; + pResult->mpPreview->Scale(Size(mnWidth,nHeight)); + } + + return ::boost::shared_ptr<BitmapReplacement>(pResult); +} + + + + +::boost::shared_ptr<BitmapEx> ResolutionReduction::Decompress ( + const BitmapReplacement& rBitmapData) const +{ + ::boost::shared_ptr<BitmapEx> pResult; + + const ResolutionReducedReplacement* pData ( + dynamic_cast<const ResolutionReducedReplacement*>(&rBitmapData)); + + if (pData->mpPreview.get() != NULL) + { + pResult.reset(new BitmapEx(*pData->mpPreview)); + if (pData->maOriginalSize.Width() > mnWidth) + pResult->Scale(pData->maOriginalSize); + } + + return pResult; +} + + + + +bool ResolutionReduction::IsLossless (void) const +{ + return false; +} + + + + +//===== PNGCompression ======================================================== + + +class PngCompression::PngReplacement : public BitmapReplacement +{ +public: + void* mpData; + sal_Int32 mnDataSize; + Size maImageSize; + PngReplacement (void) + : mpData(NULL), + mnDataSize(0), + maImageSize(0,0) + {} + virtual ~PngReplacement (void) + { + delete [] (char*)mpData; + } + virtual sal_Int32 GetMemorySize (void) const + { + return mnDataSize; + } +}; + + + + +::boost::shared_ptr<BitmapReplacement> PngCompression::Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const +{ + ::vcl::PNGWriter aWriter (*rpBitmap); + SvMemoryStream aStream (32768, 32768); + aWriter.Write(aStream); + + PngReplacement* pResult = new PngReplacement(); + pResult->maImageSize = rpBitmap->GetSizePixel(); + pResult->mnDataSize = aStream.Tell(); + pResult->mpData = new char[pResult->mnDataSize]; + memcpy(pResult->mpData, aStream.GetData(), pResult->mnDataSize); + + return ::boost::shared_ptr<BitmapReplacement>(pResult); +} + + + + +::boost::shared_ptr<BitmapEx> PngCompression::Decompress ( + const BitmapReplacement& rBitmapData) const +{ + BitmapEx* pResult = NULL; + const PngReplacement* pData (dynamic_cast<const PngReplacement*>(&rBitmapData)); + if (pData != NULL) + { + SvMemoryStream aStream (pData->mpData, pData->mnDataSize, STREAM_READ); + ::vcl::PNGReader aReader (aStream); + pResult = new BitmapEx(aReader.Read()); + } + +// sal_Int32 nRatio ((100L * (ULONG)pResult->GetSizeBytes()) / (ULONG)pData->mnDataSize); + + return ::boost::shared_ptr<BitmapEx>(pResult); +} + + + + +bool PngCompression::IsLossless (void) const +{ + return true; +} + + + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx new file mode 100644 index 000000000000..d9f51e0c9dc7 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx @@ -0,0 +1,163 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsBitmapCompressor.hxx,v $ + * $Revision: 1.4 $ + * + * 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 SD_SLIDESORTER_BITMAP_COMPRESSOR_HXX +#define SD_SLIDESORTER_BITMAP_COMPRESSOR_HXX + +#include <sal/types.h> +#include <tools/gen.hxx> +#include <boost/shared_ptr.hpp> + +class BitmapEx; + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapReplacement; + + +/** This interface class provides the minimal method set for classes that + implement the compression and decompression of preview bitmaps. +*/ +class BitmapCompressor +{ +public: + /** Compress the given bitmap into a replacement format that is specific + to the compressor class. + */ + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const = 0; + + /** Decompress the given replacement data into a preview bitmap. + Depending on the compression technique the returned bitmap may + differ from the original bitmap given to the Compress() method. It + may even of the wrong size or empty or the NULL pointer. It is the + task of the caller to create a new preview bitmap if the returned + one is not as desired. + */ + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData)const=0; + + /** Return whether the compression and decompression is lossless. This + value is used by the caller of Decompress() to decide whether to use + the returned bitmap as is or if a new preview has to be created. + */ + virtual bool IsLossless (void) const = 0; +}; + + + +/** Interface for preview bitmap replacements. Each bitmap + compressor/decompressor has to provide an implementation that is + suitable to store the compressed bitmaps. +*/ +class BitmapReplacement +{ +public: + virtual sal_Int32 GetMemorySize (void) const { return 0; } +}; + + + + +/** This is one trivial bitmap compressor. It stores bitmaps unmodified + instead of compressing them. + This compressor is lossless. +*/ +class NoBitmapCompression + : public BitmapCompressor +{ + class DummyReplacement; +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + + + +/** This is another trivial bitmap compressor. Instead of compressing a + bitmap, it throws the bitmap away. Its Decompress() method returns a + NULL pointer. The caller has to create a new preview bitmap instead. + This compressor clearly is not lossless. +*/ +class CompressionByDeletion + : public BitmapCompressor +{ +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + + + +/** Compress a preview bitmap by reducing its resolution. While the aspect + ratio is maintained the horizontal resolution is scaled down to 100 + pixels. + This compressor is not lossless. +*/ +class ResolutionReduction + : public BitmapCompressor +{ + class ResolutionReducedReplacement; + static const sal_Int32 mnWidth = 100; +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + /** Scale the replacement bitmap up to the original size. + */ + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + + + +/** Compress preview bitmaps using the PNG format. + This compressor is lossless. +*/ +class PngCompression + : public BitmapCompressor +{ + class PngReplacement; +public: + virtual ::boost::shared_ptr<BitmapReplacement> Compress ( + const ::boost::shared_ptr<BitmapEx>& rpBitmap) const; + virtual ::boost::shared_ptr<BitmapEx> Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx new file mode 100644 index 000000000000..915daccecd50 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsBitmapFactory.cxx,v $ + * + * $Revision: 1.5 $ + * + * 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_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsBitmapFactory.hxx" + +#include "PreviewRenderer.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "sdpage.hxx" +#include "Window.hxx" +#include <svx/svdtypes.hxx> +#include <svx/svdpage.hxx> +#include <vcl/bitmapex.hxx> + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +class PageObjectViewObjectContact; +} } } + +namespace sd { namespace slidesorter { namespace cache { + +BitmapFactory::BitmapFactory (void) + : maRenderer(NULL,false) +{ +} + + + + +BitmapFactory::~BitmapFactory (void) +{ +} + + + + +::boost::shared_ptr<BitmapEx> BitmapFactory::CreateBitmap ( + const SdPage& rPage, + const Size& rPixelSize) +{ + Image aPreview (maRenderer.RenderPage ( + &rPage, + rPixelSize, + String())); + + return ::boost::shared_ptr<BitmapEx>(new BitmapEx(aPreview.GetBitmapEx())); +} + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx new file mode 100644 index 000000000000..5eca09bbaa8c --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsBitmapFactory.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_PREVIEW_BITMAP_FACTORY_HXX +#define SD_SLIDESORTER_PREVIEW_BITMAP_FACTORY_HXX + +#include "PreviewRenderer.hxx" +#include <boost/shared_ptr.hpp> + +class BitmapEx; +class SdPage; +class Size; + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + +namespace sd { namespace slidesorter { namespace cache { + +/** This factory class creates preview bitmaps for page objects. It is + merely an adapter for the PreviewRenderer. +*/ +class BitmapFactory +{ +public: + BitmapFactory (void); + ~BitmapFactory (void); + + ::boost::shared_ptr<BitmapEx> CreateBitmap ( + const SdPage& rPage, + const Size& rPixelSize); + +private: + PreviewRenderer maRenderer; +}; + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx new file mode 100644 index 000000000000..4ad85a01db93 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx @@ -0,0 +1,239 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCacheCompactor.cxx,v $ + * $Revision: 1.7 $ + * + * 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_sd.hxx" + +#include "SlsCacheCompactor.hxx" + +#include "SlsBitmapCompressor.hxx" +#include "SlsBitmapCache.hxx" +#include "SlsCacheCompactor.hxx" +#include "SlsCacheConfiguration.hxx" + +#include <rtl/ustring.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <set> + +using namespace ::com::sun::star::uno; + +// Uncomment the definition of VERBOSE to get some more OSL_TRACE messages. +#ifdef DEBUG +//#define VERBOSE +#endif + +namespace { + +/** This is a trivial implementation of the CacheCompactor interface class. + It ignores calls to RequestCompaction() and thus will never decrease the + total size of off-screen preview bitmaps. +*/ +class NoCacheCompaction + : public ::sd::slidesorter::cache::CacheCompactor +{ +public: + NoCacheCompaction ( + ::sd::slidesorter::cache::BitmapCache& rCache, + sal_Int32 nMaximalCacheSize) + : CacheCompactor(rCache, nMaximalCacheSize) + {} + + virtual void RequestCompaction (void) { /* Ignored */ }; + +protected: + virtual void Run (void) { /* Do nothing */ }; +}; + + + + +/** This implementation of the CacheCompactor interface class uses one of + several bitmap compression algorithms to reduce the number of the bytes + of the off-screen previews in the bitmap cache. See the documentation + of CacheCompactor::Create() for more details on configuration properties + that control the choice of compression algorithm. +*/ +class CacheCompactionByCompression + : public ::sd::slidesorter::cache::CacheCompactor +{ +public: + CacheCompactionByCompression ( + ::sd::slidesorter::cache::BitmapCache& rCache, + sal_Int32 nMaximalCacheSize, + const ::boost::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor>& rpCompressor); + +protected: + virtual void Run (void); + +private: + ::boost::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor> mpCompressor; +}; + + +} // end of anonymous namespace + +namespace sd { namespace slidesorter { namespace cache { + + +::std::auto_ptr<CacheCompactor> CacheCompactor::Create ( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize) +{ + static const ::rtl::OUString sNone (RTL_CONSTASCII_USTRINGPARAM("None")); + static const ::rtl::OUString sCompress (RTL_CONSTASCII_USTRINGPARAM("Compress")); + static const ::rtl::OUString sErase (RTL_CONSTASCII_USTRINGPARAM("Erase")); + static const ::rtl::OUString sResolution (RTL_CONSTASCII_USTRINGPARAM("ResolutionReduction")); + static const ::rtl::OUString sPNGCompression (RTL_CONSTASCII_USTRINGPARAM("PNGCompression")); + + ::boost::shared_ptr<BitmapCompressor> pCompressor; + ::rtl::OUString sCompressionPolicy(sPNGCompression); + Any aCompressionPolicy (CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CompressionPolicy")))); + if (aCompressionPolicy.has<rtl::OUString>()) + aCompressionPolicy >>= sCompressionPolicy; + if (sCompressionPolicy == sNone) + pCompressor.reset(new NoBitmapCompression()); + else if (sCompressionPolicy == sErase) + pCompressor.reset(new CompressionByDeletion()); + else if (sCompressionPolicy == sResolution) + pCompressor.reset(new ResolutionReduction()); + else + pCompressor.reset(new PngCompression()); + + ::std::auto_ptr<CacheCompactor> pCompactor (NULL); + ::rtl::OUString sCompactionPolicy(sCompress); + Any aCompactionPolicy (CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CompactionPolicy")))); + if (aCompactionPolicy.has<rtl::OUString>()) + aCompactionPolicy >>= sCompactionPolicy; + if (sCompactionPolicy == sNone) + pCompactor.reset(new NoCacheCompaction(rCache,nMaximalCacheSize)); + else + pCompactor.reset(new CacheCompactionByCompression(rCache,nMaximalCacheSize,pCompressor)); + + return pCompactor; +} + + + + +void CacheCompactor::RequestCompaction (void) +{ + if ( ! mbIsCompactionRunning && ! maCompactionTimer.IsActive()) + maCompactionTimer.Start(); +} + + + + +CacheCompactor::CacheCompactor( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize) + : mrCache(rCache), + mnMaximalCacheSize(nMaximalCacheSize), + mbIsCompactionRunning(false) +{ + maCompactionTimer.SetTimeout(100 /*ms*/); + maCompactionTimer.SetTimeoutHdl(LINK(this,CacheCompactor,CompactionCallback)); + +} + + + + +IMPL_LINK(CacheCompactor, CompactionCallback, Timer*, EMPTYARG) +{ + mbIsCompactionRunning = true; + + try + { + Run(); + } + catch(::com::sun::star::uno::RuntimeException e) { } + catch(::com::sun::star::uno::Exception e) { } + + mbIsCompactionRunning = false; + return 1; +} + + + + +} } } // end of namespace ::sd::slidesorter::cache + + + + +namespace { + +//===== CacheCompactionByCompression ========================================== + +CacheCompactionByCompression::CacheCompactionByCompression ( + ::sd::slidesorter::cache::BitmapCache& rCache, + sal_Int32 nMaximalCacheSize, + const ::boost::shared_ptr< ::sd::slidesorter::cache::BitmapCompressor>& rpCompressor) + : CacheCompactor(rCache,nMaximalCacheSize), + mpCompressor(rpCompressor) +{ +} + + + + +void CacheCompactionByCompression::Run (void) +{ + if (mrCache.GetSize() > mnMaximalCacheSize) + { +#ifdef VERBOSE + OSL_TRACE ("bitmap cache uses to much space: %d > %d", + mrCache.GetSize(), mnMaximalCacheSize); +#endif + + ::std::auto_ptr< ::sd::slidesorter::cache::BitmapCache::CacheIndex> pIndex ( + mrCache.GetCacheIndex(false,false)); + ::sd::slidesorter::cache::BitmapCache::CacheIndex::iterator iIndex; + for (iIndex=pIndex->begin(); iIndex!=pIndex->end(); ++iIndex) + { + if (*iIndex == NULL) + continue; + + mrCache.Compress(*iIndex, mpCompressor); + if (mrCache.GetSize() < mnMaximalCacheSize) + break; + } + mrCache.ReCalculateTotalCacheSize(); +#ifdef VERBOSE + OSL_TRACE (" there are now %d bytes occupied", mrCache.GetSize()); +#endif + } +} + + +} // end of anonymous namespace diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx new file mode 100644 index 000000000000..3dbb962b3774 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCacheCompactor.hxx,v $ + * $Revision: 1.5 $ + * + * 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 SD_SLIDESORTER_CACHE_COMPACTOR_HXX +#define SD_SLIDESORTER_CACHE_COMPACTOR_HXX + +#include <sal/types.h> +#include <vcl/timer.hxx> +#include <memory> + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache; +class BitmapCompressor; + +/** This is an interface class whose implementations are created via the + Create() factory method. +*/ +class CacheCompactor +{ +public: + virtual ~CacheCompactor (void) {}; + + /** Create a new instance of the CacheCompactor interface class. The + type of compaction algorithm used depends on values from the + configuration: the SlideSorter/PreviewCache/CompactionPolicy + property of the Impress.xcs file currently supports the values + "None" and "Compress". With the later the CompressionPolicy + property is evaluated which implementation of the BitmapCompress + interface class to use as bitmap compressor. + @param rCache + The bitmap cache on which to operate. + @param nMaximalCacheSize + The total number of bytes the off-screen bitmaps in the cache + may have. When the Run() method is (indirectly) called the + compactor tries to reduce that summed size of off-screen bitmaps + under this number. However, it is not guaranteed that this + works in all cases. + */ + static ::std::auto_ptr<CacheCompactor> Create ( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize); + + /** Request a compaction of the off-screen previews in the bitmap + cache. This calls via a timer the Run() method. + */ + virtual void RequestCompaction (void); + +protected: + BitmapCache& mrCache; + sal_Int32 mnMaximalCacheSize; + + CacheCompactor( + BitmapCache& rCache, + sal_Int32 nMaximalCacheSize); + + /** This method actually tries to reduce the total number of bytes used + by the off-screen preview bitmaps. + */ + virtual void Run (void) = 0; + +private: + /** This timer is used to collect calles to RequestCompaction() and + eventually call Run(). + */ + Timer maCompactionTimer; + bool mbIsCompactionRunning; + DECL_LINK(CompactionCallback, Timer*); +}; + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx new file mode 100644 index 000000000000..69ae3e063e07 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx @@ -0,0 +1,184 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCacheConfiguration.cxx,v $ + * $Revision: 1.6 $ + * + * 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_sd.hxx" + +#include "SlsCacheConfiguration.hxx" +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#ifndef _COM_SUN_STAR_CONTAINER_PROPERTYVALUE_HPP_ +#include <com/sun/star/beans/PropertyValue.hpp> +#endif + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { namespace slidesorter { namespace cache { + +::boost::shared_ptr<CacheConfiguration> CacheConfiguration::mpInstance; +::boost::weak_ptr<CacheConfiguration> CacheConfiguration::mpWeakInstance; +Timer CacheConfiguration::maReleaseTimer; + + + +::boost::shared_ptr<CacheConfiguration> CacheConfiguration::Instance (void) +{ + ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + if (mpInstance.get() == NULL) + { + // Maybe somebody else kept a previously created instance alive. + if ( ! mpWeakInstance.expired()) + mpInstance = ::boost::shared_ptr<CacheConfiguration>(mpWeakInstance); + if (mpInstance.get() == NULL) + { + // We have to create a new instance. + mpInstance.reset(new CacheConfiguration()); + mpWeakInstance = mpInstance; + // Prepare to release this instance in the near future. + maReleaseTimer.SetTimeoutHdl( + LINK(mpInstance.get(),CacheConfiguration,TimerCallback)); + maReleaseTimer.SetTimeout(5000 /* 5s */); + maReleaseTimer.Start(); + } + } + return mpInstance; +} + + + + +CacheConfiguration::CacheConfiguration (void) +{ + // Get the cache size from configuration. + const ::rtl::OUString sConfigurationProviderServiceName( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.configuration.ConfigurationProvider")); + const ::rtl::OUString sPathToImpressConfigurationRoot( + RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.Office.Impress/")); + const ::rtl::OUString sPathToNode( + RTL_CONSTASCII_USTRINGPARAM( + "MultiPaneGUI/SlideSorter/PreviewCache")); + + try + { + do + { + // Obtain access to the configuration. + Reference<lang::XMultiServiceFactory> xProvider ( + ::comphelper::getProcessServiceFactory()->createInstance( + sConfigurationProviderServiceName), + UNO_QUERY); + if ( ! xProvider.is()) + break; + + // Obtain access to Impress configuration. + Sequence<Any> aCreationArguments(3); + aCreationArguments[0] = makeAny(beans::PropertyValue( + ::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("nodepath")), + 0, + makeAny(sPathToImpressConfigurationRoot), + beans::PropertyState_DIRECT_VALUE)); + aCreationArguments[1] = makeAny(beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("depth")), + 0, + makeAny((sal_Int32)-1), + beans::PropertyState_DIRECT_VALUE)); + aCreationArguments[2] = makeAny(beans::PropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("lazywrite")), + 0, + makeAny(true), + beans::PropertyState_DIRECT_VALUE)); + ::rtl::OUString sAccessService (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.configuration.ConfigurationAccess"))); + Reference<XInterface> xRoot (xProvider->createInstanceWithArguments( + sAccessService, aCreationArguments)); + if ( ! xRoot.is()) + break; + Reference<container::XHierarchicalNameAccess> xHierarchy (xRoot, UNO_QUERY); + if ( ! xHierarchy.is()) + break; + + // Get the node for the slide sorter preview cache. + mxCacheNode = Reference<container::XNameAccess>( + xHierarchy->getByHierarchicalName(sPathToNode), + UNO_QUERY); + } + while (false); + } + catch (RuntimeException aException) + { + (void)aException; + } + catch (Exception aException) + { + (void)aException; + } +} + + + + +Any CacheConfiguration::GetValue (const ::rtl::OUString& rName) +{ + Any aResult; + + if (mxCacheNode != NULL) + { + try + { + aResult = mxCacheNode->getByName(rName); + } + catch (Exception aException) + { + (void)aException; + } + } + + return aResult; +} + + + + +IMPL_LINK(CacheConfiguration,TimerCallback, Timer*,EMPTYARG) +{ + // Release out reference to the instance. + mpInstance.reset(); + return 0; +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx new file mode 100644 index 000000000000..f4c801a6259b --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx @@ -0,0 +1,77 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCacheConfiguration.hxx,v $ + * $Revision: 1.4 $ + * + * 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 SD_SLIDESORTER_CACHE_CONFIGURATION_HXX +#define SD_SLIDESORTER_CACHE_CONFIGURATION_HXX + +#include <com/sun/star/uno/Any.hxx> +#include <vcl/timer.hxx> +#include <com/sun/star/container/XNameAccess.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> + +namespace sd { namespace slidesorter { namespace cache { + +/** A very simple and easy-to-use access to configuration entries regarding + the slide sorter cache. +*/ +class CacheConfiguration +{ +public: + /** Return an instance to this class. The reference is released after 5 + seconds. Subsequent calls to this function will create a new + instance. + */ + static ::boost::shared_ptr<CacheConfiguration> Instance (void); + + /** Look up the specified value in + MultiPaneGUI/SlideSorter/PreviewCache. When the specified value + does not exist then an empty Any is returned. + */ + ::com::sun::star::uno::Any GetValue (const ::rtl::OUString& rName); + +private: + static ::boost::shared_ptr<CacheConfiguration> mpInstance; + /** When a caller holds a reference after we have released ours we use + this weak pointer to avoid creating a new instance. + */ + static ::boost::weak_ptr<CacheConfiguration> mpWeakInstance; + static Timer maReleaseTimer; + ::com::sun::star::uno::Reference< + ::com::sun::star::container::XNameAccess> mxCacheNode; + + CacheConfiguration (void); + + DECL_LINK(TimerCallback, Timer*); +}; + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx new file mode 100644 index 000000000000..702517029fb6 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx @@ -0,0 +1,334 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsGenericPageCache.cxx,v $ + * + * $Revision: 1.5 $ + * + * 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_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsGenericPageCache.hxx" + +#include "SlsQueueProcessor.hxx" +#include "SlsRequestPriorityClass.hxx" +#include "SlsRequestFactory.hxx" +#include "cache/SlsPageCacheManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "controller/SlideSorterController.hxx" + +namespace sd { namespace slidesorter { namespace cache { + +GenericPageCache::GenericPageCache ( + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext) + : mpBitmapCache(), + maRequestQueue(rpCacheContext), + mpQueueProcessor(), + mpCacheContext(rpCacheContext), + maPreviewSize(rPreviewSize) +{ +} + + + + +GenericPageCache::~GenericPageCache (void) +{ + OSL_TRACE("terminating queue processor %p", mpQueueProcessor.get()); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Stop(); + maRequestQueue.Clear(); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Terminate(); + mpQueueProcessor.reset(); + OSL_TRACE("queue processor stopped and terminated"); + + if (mpBitmapCache.get() != NULL) + PageCacheManager::Instance()->ReleaseCache(mpBitmapCache); + mpBitmapCache.reset(); +} + + + + +void GenericPageCache::ProvideCacheAndProcessor (void) +{ + if (mpBitmapCache.get() == NULL) + mpBitmapCache = PageCacheManager::Instance()->GetCache( + mpCacheContext->GetModel(), + maPreviewSize); + + if (mpQueueProcessor.get() == NULL) + mpQueueProcessor.reset(new QueueProcessor( + maRequestQueue, + mpBitmapCache, + maPreviewSize, + mpCacheContext)); +} + + + + +void GenericPageCache::ChangePreviewSize (const Size& rPreviewSize) +{ + if (rPreviewSize != maPreviewSize) + { + if (mpBitmapCache.get() != NULL) + { + mpBitmapCache = PageCacheManager::Instance()->ChangeSize( + mpBitmapCache, maPreviewSize, rPreviewSize); + if (mpQueueProcessor.get() != NULL) + { + mpQueueProcessor->SetPreviewSize(rPreviewSize); + mpQueueProcessor->SetBitmapCache(mpBitmapCache); + } + } + maPreviewSize = rPreviewSize; + } +} + + + + +BitmapEx GenericPageCache::GetPreviewBitmap ( + CacheKey aKey, + const Size& rSize) +{ + OSL_ASSERT(aKey != NULL); + + BitmapEx aPreview; + bool bMayBeUpToDate = true; + ProvideCacheAndProcessor(); + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + if (mpBitmapCache->HasBitmap(pPage)) + { + ::boost::shared_ptr<BitmapEx> pPreview(mpBitmapCache->GetBitmap(pPage)); + OSL_ASSERT(pPreview.get() != NULL); + aPreview = *pPreview; + Size aBitmapSize (aPreview.GetSizePixel()); + if (aBitmapSize != rSize) + { + // The bitmap has the wrong size. + DBG_ASSERT (rSize.Width() < 1000, + "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. " + "This may indicate an error."); + + // Scale the bitmap to the desired size when that is possible, + // i.e. the bitmap is not empty. + if (aBitmapSize.Width()>0 && aBitmapSize.Height()>0) + aPreview.Scale (rSize, BMP_SCALE_FAST); + } + bMayBeUpToDate = true; + } + else + bMayBeUpToDate = false; + + // Request the creation of a correctly sized preview bitmap. We do this + // even when the size of the bitmap in the cache is correct because its + // content may be not up-to-date anymore. + RequestPreviewBitmap(aKey, rSize, bMayBeUpToDate); + + return aPreview; +} + + + + +void GenericPageCache::RequestPreviewBitmap ( + CacheKey aKey, + const Size& rSize, + bool bMayBeUpToDate) +{ + OSL_ASSERT(aKey != NULL); + + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + + ProvideCacheAndProcessor(); + + // Determine if the available bitmap is up to date. + bool bIsUpToDate = false; + if (bMayBeUpToDate) + bIsUpToDate = mpBitmapCache->BitmapIsUpToDate (pPage); + if (bIsUpToDate) + { + ::boost::shared_ptr<BitmapEx> pPreview (mpBitmapCache->GetBitmap(pPage)); + if (pPreview.get()==NULL || pPreview->GetSizePixel()!=rSize) + bIsUpToDate = false; + } + + if ( ! bIsUpToDate) + { + // No, the bitmap is not up-to-date. Request a new one. + RequestPriorityClass ePriorityClass (NOT_VISIBLE); + if (mpCacheContext->IsVisible(aKey)) + { + if (mpBitmapCache->HasBitmap(pPage)) + ePriorityClass = VISIBLE_OUTDATED_PREVIEW; + else + ePriorityClass = VISIBLE_NO_PREVIEW; + } + maRequestQueue.AddRequest(aKey, ePriorityClass); + mpQueueProcessor->Start(ePriorityClass); + } +} + + + + +void GenericPageCache::InvalidatePreviewBitmap (CacheKey aKey) +{ + if (mpBitmapCache.get() != NULL) + mpBitmapCache->InvalidateBitmap(mpCacheContext->GetPage(aKey)); +} + + + + +void GenericPageCache::ReleasePreviewBitmap (CacheKey aKey) +{ + if (mpBitmapCache.get() != NULL) + { + // Suspend the queue processing temporarily to avoid the reinsertion + // of the request that is to be deleted. + mpQueueProcessor->Stop(); + + maRequestQueue.RemoveRequest(aKey); + mpQueueProcessor->RemoveRequest(aKey); + + // Resume the queue processing. + if ( ! maRequestQueue.IsEmpty()) + { + try + { + mpQueueProcessor->Start(maRequestQueue.GetFrontPriorityClass()); + } + catch (::com::sun::star::uno::RuntimeException) + { + } + } + } + + // We do not relase the preview bitmap that is associated with the page + // of the given request data because this method is called when the + // request data, typically a view-object-contact object, is destroyed. + // The page object usually lives longer than that and thus the preview + // bitmap may be used later on. +} + + + + +void GenericPageCache::InvalidateCache (bool bUpdateCache) +{ + if (mpBitmapCache.get() != NULL) + { + // When the cache is being invalidated then it makes no sense to + // continue creating preview bitmaps. However, this may be + // re-started below. + mpQueueProcessor->Stop(); + maRequestQueue.Clear(); + + // Mark the previews in the cache as not being up-to-date anymore. + // Depending on the given bUpdateCache flag we start to create new + // preview bitmaps. + mpBitmapCache->InvalidateCache(); + if (bUpdateCache) + RequestFactory()(maRequestQueue, mpCacheContext); + } +} + + + + +void GenericPageCache::SetPreciousFlag (CacheKey aKey, bool bIsPrecious) +{ + ProvideCacheAndProcessor(); + + // Change the request priority class according to the new precious flag. + if (bIsPrecious) + { + if (mpBitmapCache->HasBitmap(mpCacheContext->GetPage(aKey))) + maRequestQueue.ChangeClass(aKey,VISIBLE_OUTDATED_PREVIEW); + else + maRequestQueue.ChangeClass(aKey,VISIBLE_NO_PREVIEW); + } + else + { + if (mpBitmapCache->IsFull()) + { + // When the bitmap cache is full then requests for slides that + // are not visible are removed. + maRequestQueue.RemoveRequest(aKey); + } + else + maRequestQueue.ChangeClass(aKey,NOT_VISIBLE); + } + + mpBitmapCache->SetPrecious(mpCacheContext->GetPage(aKey), bIsPrecious); +} + + + + +bool GenericPageCache::IsEmpty (void) const +{ + if (mpBitmapCache.get() != NULL) + return mpBitmapCache->IsEmpty(); + else + return true; +} + + + + +void GenericPageCache::Pause (void) +{ + ProvideCacheAndProcessor(); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Pause(); +} + + + + +void GenericPageCache::Resume (void) +{ + ProvideCacheAndProcessor(); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Resume(); +} + + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx new file mode 100644 index 000000000000..d11c74c50839 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx @@ -0,0 +1,159 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsGenericPageCache.hxx,v $ + * $Revision: 1.11 $ + * + * 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 SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX +#define SD_SLIDESORTER_GENERIC_PAGE_CACHE_HXX + +#include "SlideSorter.hxx" +#include "SlsRequestQueue.hxx" +#include "SlsQueueProcessor.hxx" +#include <boost/function.hpp> +#include <boost/scoped_ptr.hpp> + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache; +class QueueProcessor; + +/** This basically is the implementation class for the PageCache class. +*/ +class GenericPageCache +{ +public: + /** The page chache is created with references both to the SlideSorter. + This allows access to both view and model and the cache can so fill + itself with requests for all or just the visible pages. + */ + GenericPageCache ( + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext); + + ~GenericPageCache (void); + + /** Change the size of the preview bitmaps. This may be caused by a + resize of the slide sorter window or a change of the number of + columns. + */ + void ChangePreviewSize (const Size& rPreviewSize); + + /** Request a preview bitmap for the specified page object in the + specified size. The returned bitmap may be preview of the preview, + i.e. either a scaled (up or down) version of a previous preview (of + the wrong size) or an empty bitmap. In this case a request for the + generation of a new preview is created and inserted into the request + queue. When the preview is available the page shape will be told to + paint itself again. When it then calls this method again if + receives the correctly sized preview bitmap. + @param rRequestData + This data is used to determine the preview. + @param rSize + The size of the requested preview bitmap. + @return + Returns a bitmap that is either empty, contains a scaled (up or + down) version or is the requested bitmap. + */ + BitmapEx GetPreviewBitmap ( + CacheKey aKey, + const Size& rSize); + + /** When the requested preview bitmap does not yet exist or is not + up-to-date then the rendering of one is scheduled. Otherwise this + method does nothing. + @param rRequestData + This data is used to determine the preview. + @param rSize + The size of the requested preview bitmap in pixel coordinates. + @param bMayBeUpToDate + This flag helps the method to determine whether an existing + preview that matches the request is up to date. If the caller + know that it is not then by passing <FALSE/> he tells us that we + do not have to check the up-to-date flag a second time. If + unsure pass <TRUE/>. + */ + void RequestPreviewBitmap ( + CacheKey aKey, + const Size& rSize, + bool bMayBeUpToDate = true); + + /** Tell the cache to replace the bitmap associated with the given + request data with a new one that reflects recent changes in the + content of the page object. + */ + void InvalidatePreviewBitmap (CacheKey aKey); + + /** Call this method when a view-object-contact object is being deleted + and does not need (a) its current bitmap in the cache and (b) a + requested a new bitmap. + */ + void ReleasePreviewBitmap (CacheKey aKey); + + /** Call this method when all preview bitmaps have to be generated anew. + This is the case when the size of the page objects on the screen has + changed or when the model has changed. + */ + void InvalidateCache (bool bUpdateCache); + + /** With the precious flag you can control whether a bitmap can be + removed from the cache or reduced in size to make room for other + bitmaps or is so precious that it will not be touched. A typical + use is to set the precious flag for the visible pages. + */ + void SetPreciousFlag (CacheKey aKey, bool bIsPrecious); + + /** Return <TRUE/> when there is no preview bitmap in the cache. + */ + bool IsEmpty (void) const; + + void Pause (void); + void Resume (void); + +private: + ::boost::shared_ptr<BitmapCache> mpBitmapCache; + + RequestQueue maRequestQueue; + + ::boost::scoped_ptr<QueueProcessor> mpQueueProcessor; + + SharedCacheContext mpCacheContext; + + /** The current size of preview bitmaps. + */ + Size maPreviewSize; + + /** Both bitmap cache and queue processor are created on demand by this + method. + */ + void ProvideCacheAndProcessor (void); +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsIdleDetector.cxx b/sd/source/ui/slidesorter/cache/SlsIdleDetector.cxx new file mode 100644 index 000000000000..3a1c854b8ae9 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsIdleDetector.cxx @@ -0,0 +1,70 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsIdleDetector.cxx,v $ + * + * $Revision: 1.5 $ + * + * 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_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsIdleDetector.hxx" + +#include "view/SlideSorterView.hxx" +#include "tools/IdleDetection.hxx" +#include "Window.hxx" + +namespace sd { namespace slidesorter { namespace cache { + +IdleDetector::IdleDetector ( + const ::Window* pWindow, + const bool bIsSuspendPreviewUpdatesDuringFullScreenPresentation) + : mpWindow(pWindow), + mbIsSuspendPreviewUpdatesDuringFullScreenPresentation( + bIsSuspendPreviewUpdatesDuringFullScreenPresentation) +{ +} + + + + +bool IdleDetector::operator() (void) +{ + // Determine whether the system is idle. + sal_Int32 nIdleState (tools::IdleDetection::GetIdleState(mpWindow)); + if (nIdleState == tools::IdleDetection::IDET_IDLE) + return true; + else + return false; +} + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsIdleDetector.hxx b/sd/source/ui/slidesorter/cache/SlsIdleDetector.hxx new file mode 100644 index 000000000000..c356047a220c --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsIdleDetector.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsIdleDetector.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_IDLE_DETECTOR_HXX +#define SD_SLIDESORTER_IDLE_DETECTOR_HXX + +class Window; + +namespace sd { namespace slidesorter { namespace cache { + +class IdleDetector +{ +public: + IdleDetector (const ::Window* pWindow, const bool bIsSuspendPreviewUpdatesDuringFullScreenPresentation); + bool operator() (void); + +private: + const ::Window* mpWindow; + const bool mbIsSuspendPreviewUpdatesDuringFullScreenPresentation; +}; + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx new file mode 100644 index 000000000000..1f9c7b1ccbd6 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx @@ -0,0 +1,147 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageCache.cxx,v $ + * $Revision: 1.9 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlsGenericPageCache.hxx" +#include "SlsRequestFactory.hxx" +#include "SlsIdleDetector.hxx" +#include "cache/SlsPageCache.hxx" +#include "model/SlideSorterModel.hxx" +#include <boost/bind.hpp> +#include <boost/bind/protect.hpp> + +using namespace ::com::sun::star; + + +namespace sd { namespace slidesorter { namespace cache { + + +//===== PageCache ============================================================= + +PageCache::PageCache ( + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext) + : mpImplementation( + new GenericPageCache( + rPreviewSize, + rpCacheContext)) +{ +} + + + + +PageCache::~PageCache (void) +{ +} + + + + +void PageCache::ChangeSize(const Size& rPreviewSize) +{ + mpImplementation->ChangePreviewSize(rPreviewSize); +} + + + + +BitmapEx PageCache::GetPreviewBitmap ( + CacheKey aKey, + const Size& rSize) +{ + return mpImplementation->GetPreviewBitmap(aKey, rSize); +} + + + + +void PageCache::RequestPreviewBitmap ( + CacheKey aKey, + const Size& rSize) +{ + return mpImplementation->RequestPreviewBitmap(aKey, rSize); +} + + + + +void PageCache::InvalidatePreviewBitmap ( + CacheKey aKey) +{ + mpImplementation->InvalidatePreviewBitmap(aKey); +} + + + + +void PageCache::ReleasePreviewBitmap ( + CacheKey aKey) +{ + mpImplementation->ReleasePreviewBitmap(aKey); +} + + + + +void PageCache::InvalidateCache (bool bUpdateCache) +{ + mpImplementation->InvalidateCache(bUpdateCache); +} + + + + +void PageCache::SetPreciousFlag ( + CacheKey aKey, + bool bIsPrecious) +{ + mpImplementation->SetPreciousFlag(aKey, bIsPrecious); +} + + + + +void PageCache::Pause (void) +{ + mpImplementation->Pause(); +} + + + + +void PageCache::Resume (void) +{ + mpImplementation->Resume(); +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx new file mode 100644 index 000000000000..4e079b48cc1a --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx @@ -0,0 +1,449 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageCacheManager.cxx,v $ + * $Revision: 1.11 $ + * + * 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_sd.hxx" + +#include "cache/SlsPageCacheManager.hxx" + +#include "SlsBitmapCache.hxx" +#include "view/SlideSorterView.hxx" +#include "model/SlideSorterModel.hxx" + +#include <deque> +#include <map> +#include <boost/weak_ptr.hpp> + +namespace { + +/** Collection of data that is stored for all active preview caches. +*/ +class CacheDescriptor +{ +public: + ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument; + Size maPreviewSize; + + CacheDescriptor( + ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument, + const Size& rPreviewSize) + :mpDocument(pDocument),maPreviewSize(rPreviewSize) + {} + /// Test for equality with respect to all members. + class Equal {public: bool operator() ( + const CacheDescriptor& rDescriptor1, const CacheDescriptor& rDescriptor2) const { + return rDescriptor1.mpDocument==rDescriptor2.mpDocument + && rDescriptor1.maPreviewSize==rDescriptor2.maPreviewSize; + } }; + /// Hash function that takes all members into account. + class Hash {public: size_t operator() (const CacheDescriptor& rDescriptor) const { + return (size_t)rDescriptor.mpDocument.get() + rDescriptor.maPreviewSize.Width(); + } }; +}; + + + + +/** Collection of data that is stored for the inactive, recently used + caches. +*/ +class RecentlyUsedCacheDescriptor +{ +public: + ::sd::slidesorter::cache::PageCacheManager::DocumentKey mpDocument; + Size maPreviewSize; + ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache> mpCache; + + RecentlyUsedCacheDescriptor( + ::sd::slidesorter::cache::PageCacheManager::DocumentKey pDocument, + const Size& rPreviewSize, + const ::boost::shared_ptr< ::sd::slidesorter::cache::PageCacheManager::Cache>& rpCache) + :mpDocument(pDocument),maPreviewSize(rPreviewSize),mpCache(rpCache) + {} +}; + + + + +/** The list of recently used caches is organized as queue. When elements + are added the list is shortened to the maximally allowed number of + elements by removing the least recently used elements. +*/ +typedef ::std::deque<RecentlyUsedCacheDescriptor> RecentlyUsedQueue; + + + + +/** Compare the caches by preview size. Those that match the given size + come first, then, regardless of the given size, the largest ones before + the smaller ones. +*/ +class BestFittingCacheComparer +{ +public: + BestFittingCacheComparer (const Size& rPreferredSize) + : maPreferredSize(rPreferredSize) + {} + bool operator()(const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement1, + const ::sd::slidesorter::cache::PageCacheManager::BestFittingPageCaches::value_type& rElement2) + { + if (rElement1.first == maPreferredSize) + return true; + else if (rElement2.first == maPreferredSize) + return false; + else + return (rElement1.first.Width()*rElement1.first.Height() + > rElement2.first.Width()*rElement2.first.Height()); + } + +private: + Size maPreferredSize; +}; + +} // end of anonymous namespace + + +namespace sd { namespace slidesorter { namespace cache { + +/** Container for the active caches. +*/ +class PageCacheManager::PageCacheContainer + : public ::std::hash_map<CacheDescriptor, + ::boost::shared_ptr<PageCacheManager::Cache>, + CacheDescriptor::Hash, + CacheDescriptor::Equal> +{ +public: + PageCacheContainer (void) {} + + /** Compare entries in the cache container with respect to the cache + address only. + */ + class CompareWithCache { public: + CompareWithCache(const ::boost::shared_ptr<PageCacheManager::Cache>& rpCache) + : mpCache(rpCache) {} + bool operator () (const PageCacheContainer::value_type& rValue) + { return rValue.second == mpCache; } + private: + ::boost::shared_ptr<PageCacheManager::Cache> mpCache; + }; +}; + + +/** The recently used caches are stored in one queue for each document. +*/ +class PageCacheManager::RecentlyUsedPageCaches + : public ::std::map<DocumentKey,RecentlyUsedQueue> +{ +public: + RecentlyUsedPageCaches (void) {}; +}; + + + + +class PageCacheManager::Deleter +{ +public: + void operator() (PageCacheManager* pObject) { delete pObject; } +}; + + + +//===== PageCacheManager ==================================================== + +::boost::weak_ptr<PageCacheManager> PageCacheManager::mpInstance; + +::boost::shared_ptr<PageCacheManager> PageCacheManager::Instance (void) +{ + ::boost::shared_ptr<PageCacheManager> pInstance; + + ::osl::MutexGuard aGuard (::osl::Mutex::getGlobalMutex()); + + pInstance = mpInstance.lock(); + if (pInstance.get() == NULL) + { + pInstance = ::boost::shared_ptr<PageCacheManager>( + new PageCacheManager(), + PageCacheManager::Deleter()); + mpInstance = pInstance; + } + + return pInstance; +} + + + + +PageCacheManager::PageCacheManager (void) + : mpPageCaches(new PageCacheContainer()), + mpRecentlyUsedPageCaches(new RecentlyUsedPageCaches()), + mnMaximalRecentlyCacheCount(2) +{ +} + + + + +PageCacheManager::~PageCacheManager (void) +{ +} + + + + +::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetCache ( + DocumentKey pDocument, + const Size& rPreviewSize) +{ + ::boost::shared_ptr<Cache> pResult; + + // Look for the cache in the list of active caches. + CacheDescriptor aKey (pDocument, rPreviewSize); + PageCacheContainer::iterator iCache (mpPageCaches->find(aKey)); + if (iCache != mpPageCaches->end()) + pResult = iCache->second; + + // Look for the cache in the list of recently used caches. + if (pResult.get() == NULL) + pResult = GetRecentlyUsedCache(pDocument, rPreviewSize); + + // Create the cache when no suitable one does exist. + if (pResult.get() == NULL) + pResult.reset(new Cache()); + + // The cache may be newly created and thus empty or is old and may + // contain previews that are not up-to-date. Recycle previews from + // other caches to fill in the holes. + Recycle(pResult, pDocument,rPreviewSize); + + // Put the new (or old) cache into the container. + if (pResult.get() != NULL) + mpPageCaches->insert(PageCacheContainer::value_type(aKey, pResult)); + + return pResult; +} + + + + +void PageCacheManager::Recycle ( + const ::boost::shared_ptr<Cache>& rpCache, + DocumentKey pDocument, + const Size& rPreviewSize) +{ + BestFittingPageCaches aCaches; + + // Add bitmap caches from active caches. + PageCacheContainer::iterator iActiveCache; + for (iActiveCache=mpPageCaches->begin(); iActiveCache!=mpPageCaches->end(); ++iActiveCache) + { + if (iActiveCache->first.mpDocument == pDocument) + aCaches.push_back(BestFittingPageCaches::value_type( + iActiveCache->first.maPreviewSize, iActiveCache->second)); + } + + // Add bitmap caches from recently used caches. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + RecentlyUsedQueue::const_iterator iRecentCache; + for (iRecentCache=iQueue->second.begin();iRecentCache!=iQueue->second.end();++iRecentCache) + aCaches.push_back(BestFittingPageCaches::value_type( + iRecentCache->maPreviewSize, iRecentCache->mpCache)); + } + + ::std::sort(aCaches.begin(), aCaches.end(), BestFittingCacheComparer(rPreviewSize)); + + BestFittingPageCaches::const_iterator iBestCache; + for (iBestCache=aCaches.begin(); iBestCache!=aCaches.end(); ++iBestCache) + { + rpCache->Recycle(*iBestCache->second); + } +} + + + + +void PageCacheManager::ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache) +{ + PageCacheContainer::iterator iCache (::std::find_if( + mpPageCaches->begin(), + mpPageCaches->end(), + PageCacheContainer::CompareWithCache(rpCache))); + + if (iCache != mpPageCaches->end()) + { + OSL_ASSERT(iCache->second == rpCache); + + PutRecentlyUsedCache(iCache->first.mpDocument,iCache->first.maPreviewSize,rpCache); + + mpPageCaches->erase(iCache); + } +} + + + + +::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::ChangeSize ( + const ::boost::shared_ptr<Cache>& rpCache, + const Size& rOldPreviewSize, + const Size& rNewPreviewSize) +{ + (void)rOldPreviewSize; + + ::boost::shared_ptr<Cache> pResult; + + if (rpCache.get() != NULL) + { + // Look up the given cache in the list of active caches. + PageCacheContainer::iterator iCacheToChange (::std::find_if( + mpPageCaches->begin(), + mpPageCaches->end(), + PageCacheContainer::CompareWithCache(rpCache))); + OSL_ASSERT(iCacheToChange != mpPageCaches->end()); + if (iCacheToChange != mpPageCaches->end()) + { + OSL_ASSERT(iCacheToChange->second == rpCache); + + // Now, we can change the preview size of the existing one by + // removing the cache from the list and re-insert it with the + // updated size. + const ::sd::slidesorter::cache::PageCacheManager::DocumentKey aKey ( + iCacheToChange->first.mpDocument); + mpPageCaches->erase(iCacheToChange); + mpPageCaches->insert(PageCacheContainer::value_type( + CacheDescriptor(aKey,rNewPreviewSize), + rpCache)); + + pResult = rpCache; + } + } + + return pResult; +} + + + + +void PageCacheManager::InvalidatePreviewBitmap ( + DocumentKey pDocument, + const SdrPage* pKey) +{ + if (pDocument!=NULL) + { + // Iterate over all caches that are currently in use and invalidate + // the previews in those that belong to the document. + PageCacheContainer::iterator iCache; + for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) + if (iCache->first.mpDocument == pDocument) + iCache->second->InvalidateBitmap(pKey); + + // Invalidate the previews in the recently used caches belonging to + // the given document. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + RecentlyUsedQueue::const_iterator iCache2; + for (iCache2=iQueue->second.begin(); iCache2!=iQueue->second.end(); ++iCache2) + iCache2->mpCache->InvalidateBitmap(pKey); + } + } +} + + + + +void PageCacheManager::InvalidateAllCaches (void) +{ + // Iterate over all caches that are currently in use and invalidate + // them. + PageCacheContainer::iterator iCache; + for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) + iCache->second->InvalidateCache(); + + // Remove all recently used caches, there is not much sense in storing + // invalidated and unused caches. + mpRecentlyUsedPageCaches->clear(); +} + + + + +::boost::shared_ptr<PageCacheManager::Cache> PageCacheManager::GetRecentlyUsedCache ( + DocumentKey pDocument, + const Size& rPreviewSize) +{ + ::boost::shared_ptr<Cache> pCache; + + // Look for the cache in the list of recently used caches. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + RecentlyUsedQueue::iterator iCache; + for (iCache=iQueue->second.begin(); iCache!= iQueue->second.end(); ++iCache) + if (iCache->maPreviewSize == rPreviewSize) + { + pCache = iCache->mpCache; + iQueue->second.erase(iCache); + break; + } + } + + return pCache; +} + + + + +void PageCacheManager::PutRecentlyUsedCache( + DocumentKey pDocument, + const Size& rPreviewSize, + const ::boost::shared_ptr<Cache>& rpCache) +{ + // Look up the list of recently used caches for the given document. + RecentlyUsedPageCaches::iterator iQueue (mpRecentlyUsedPageCaches->find(pDocument)); + if (iQueue == mpRecentlyUsedPageCaches->end()) + iQueue = mpRecentlyUsedPageCaches->insert( + RecentlyUsedPageCaches::value_type(pDocument, RecentlyUsedQueue()) + ).first; + + if (iQueue != mpRecentlyUsedPageCaches->end()) + { + iQueue->second.push_front(RecentlyUsedCacheDescriptor(pDocument,rPreviewSize,rpCache)); + // Shorten the list of recently used caches to the allowed maximal length. + while (iQueue->second.size() > mnMaximalRecentlyCacheCount) + iQueue->second.pop_back(); + } +} + + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx new file mode 100644 index 000000000000..09c633424c6d --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx @@ -0,0 +1,258 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsQueueProcessor.cxx,v $ + * $Revision: 1.10 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlsQueueProcessor.hxx" +#include "SlsCacheConfiguration.hxx" +#include "SlsRequestQueue.hxx" +#include "SlsIdleDetector.hxx" + +namespace sd { namespace slidesorter { namespace cache { + + +//===== QueueProcessor ====================================================== + +QueueProcessor::QueueProcessor ( + RequestQueue& rQueue, + const ::boost::shared_ptr<BitmapCache>& rpCache, + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext) + : maMutex(), + maTimer(), + mnTimeBetweenHighPriorityRequests (10/*ms*/), + mnTimeBetweenLowPriorityRequests (100/*ms*/), + mnTimeBetweenRequestsWhenNotIdle (1000/*ms*/), + maPreviewSize(rPreviewSize), + mpCacheContext(rpCacheContext), + mrQueue(rQueue), + mpCache(rpCache), + maBitmapFactory(), + mbIsPaused(false) +{ + // Look into the configuration if there for overriding values. + ::com::sun::star::uno::Any aTimeBetweenReqeusts; + aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenHighPriorityRequests"))); + if (aTimeBetweenReqeusts.has<sal_Int32>()) + aTimeBetweenReqeusts >>= mnTimeBetweenHighPriorityRequests; + + aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenLowPriorityRequests"))); + if (aTimeBetweenReqeusts.has<sal_Int32>()) + aTimeBetweenReqeusts >>= mnTimeBetweenLowPriorityRequests; + + aTimeBetweenReqeusts = CacheConfiguration::Instance()->GetValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("TimeBetweenRequestsDuringShow"))); + if (aTimeBetweenReqeusts.has<sal_Int32>()) + aTimeBetweenReqeusts >>= mnTimeBetweenRequestsWhenNotIdle; + + maTimer.SetTimeoutHdl (LINK(this,QueueProcessor,ProcessRequestHdl)); + maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests); +} + + + + + +QueueProcessor::~QueueProcessor (void) +{ +} + + + + +void QueueProcessor::Start (int nPriorityClass) +{ + if (mbIsPaused) + return; + if ( ! maTimer.IsActive()) + { + if (nPriorityClass == 0) + maTimer.SetTimeout (mnTimeBetweenHighPriorityRequests); + else + maTimer.SetTimeout (mnTimeBetweenLowPriorityRequests); + maTimer.Start(); + } +} + + + + +void QueueProcessor::Stop (void) +{ + if (maTimer.IsActive()) + maTimer.Stop(); +} + + + + +void QueueProcessor::Pause (void) +{ + mbIsPaused = true; +} + + + + +void QueueProcessor::Resume (void) +{ + mbIsPaused = false; + if ( ! mrQueue.IsEmpty()) + Start(mrQueue.GetFrontPriorityClass()); +} + + + + +void QueueProcessor::Terminate (void) +{ +} + + + + +void QueueProcessor::SetPreviewSize (const Size& rPreviewSize) +{ + maPreviewSize = rPreviewSize; +} + + + + +IMPL_LINK(QueueProcessor, ProcessRequestHdl, Timer*, EMPTYARG) +{ + ProcessRequests(); + return 1; +} + + + + +void QueueProcessor::ProcessRequests (void) +{ + OSL_ASSERT(mpCacheContext.get()!=NULL); + + // Never process more than one request at a time in order to prevent the + // lock up of the edit view. + if ( ! mrQueue.IsEmpty() + && ! mbIsPaused + && mpCacheContext->IsIdle()) + { + CacheKey aKey = NULL; + RequestPriorityClass ePriorityClass (NOT_VISIBLE); + { + ::osl::MutexGuard aGuard (mrQueue.GetMutex()); + + if ( ! mrQueue.IsEmpty()) + { + // Get the request with the highest priority from the queue. + ePriorityClass = mrQueue.GetFrontPriorityClass(); + aKey = mrQueue.GetFront(); + mrQueue.PopFront(); + } + } + + if (aKey != NULL) + ProcessOneRequest(aKey, ePriorityClass); + } + + // Schedule the processing of the next element(s). + { + ::osl::MutexGuard aGuard (mrQueue.GetMutex()); + if ( ! mrQueue.IsEmpty()) + Start(mrQueue.GetFrontPriorityClass()); + } +} + + + + +void QueueProcessor::ProcessOneRequest ( + CacheKey aKey, + const RequestPriorityClass ePriorityClass) +{ + try + { + ::osl::MutexGuard aGuard (maMutex); + + // Create a new preview bitmap and store it in the cache. + if (mpCache.get() != NULL + && mpCacheContext.get() != NULL) + { + const SdPage* pSdPage = dynamic_cast<const SdPage*>(mpCacheContext->GetPage(aKey)); + if (pSdPage != NULL) + { + const ::boost::shared_ptr<BitmapEx> pPreview ( + maBitmapFactory.CreateBitmap(*pSdPage, maPreviewSize)); + mpCache->SetBitmap ( + pSdPage, + pPreview, + ePriorityClass!=NOT_VISIBLE); + + // Initiate a repaint of the new preview. + mpCacheContext->NotifyPreviewCreation(aKey, pPreview); + } + } + } + catch (::com::sun::star::uno::RuntimeException aException) + { + (void) aException; + OSL_ASSERT("RuntimeException caught in QueueProcessor"); + } + catch (::com::sun::star::uno::Exception aException) + { + (void) aException; + OSL_ASSERT("Exception caught in QueueProcessor"); + } +} + + + + +void QueueProcessor::RemoveRequest (CacheKey aKey) +{ + (void)aKey; + // See the method declaration above for an explanation why this makes sense. + ::osl::MutexGuard aGuard (maMutex); +} + + + + +void QueueProcessor::SetBitmapCache ( + const ::boost::shared_ptr<BitmapCache>& rpCache) +{ + mpCache = rpCache; +} + + +} } } // end of namespace ::sd::slidesorter::cache diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx new file mode 100644 index 000000000000..f7f8a36190cd --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx @@ -0,0 +1,141 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsQueueProcessor.hxx,v $ + * $Revision: 1.19 $ + * + * 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 SD_SLIDESORTER_QUEUE_PROCESSOR_HXX +#define SD_SLIDESORTER_QUEUE_PROCESSOR_HXX + +#include "cache/SlsPageCache.hxx" +#include "SlsRequestPriorityClass.hxx" +#include "SlsBitmapFactory.hxx" +#include "view/SlsPageObject.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "tools/IdleDetection.hxx" +#include "SlsBitmapCache.hxx" +#include "sdpage.hxx" +#include "Window.hxx" + +#include <svx/svdpagv.hxx> +#include <vcl/svapp.hxx> +#include <vcl/timer.hxx> +#include <boost/function.hpp> + + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + + + +namespace sd { namespace slidesorter { namespace cache { + +class BitmapCache; +class RequestQueue; + + + +/** This queue processor is timer based, i.e. when an entry is added to the + queue and the processor is started with Start() in the base class a + timer is started that eventually calls ProcessRequest(). This is + repeated until the queue is empty or Stop() is called. +*/ +class QueueProcessor +{ +public: + typedef ::boost::function<bool()> IdleDetectionCallback; + QueueProcessor ( + RequestQueue& rQueue, + const ::boost::shared_ptr<BitmapCache>& rpCache, + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext); + virtual ~QueueProcessor(); + + /** Start the processor. This implementation is timer based and waits + an defined amount of time that depends on the given argument before + the next entry in the queue is processed. + @param nPriorityClass + A priority class of 0 tells the processor that a high priority + request is waiting in the queue. The time to wait is thus + shorter then that for a low priority request (denoted by a value + of 1.) When the timer is already running it is not modified. + */ + void Start (int nPriorityClass = 0); + void Stop (void); + void Pause (void); + void Resume (void); + + void Terminate (void); + + void SetPreviewSize (const Size& rSize); + + /** As we can not really terminate the rendering of a preview bitmap for + a request in midair this method acts more like a semaphor. It + returns only when it is save for the caller to delete the request. + For this to work it is important to remove the request from the + queue before calling this method. + */ + void RemoveRequest (CacheKey aKey); + + /** Use this method when the page cache is (maybe) using a different + BitmapCache. This is usually necessary after calling + PageCacheManager::ChangeSize(). + */ + void SetBitmapCache (const ::boost::shared_ptr<BitmapCache>& rpCache); + +private: + /** This mutex is used to guard the queue processor. Be carefull not to + mix its use with that of the solar mutex. + */ + ::osl::Mutex maMutex; + + Timer maTimer; + DECL_LINK(ProcessRequestHdl, Timer*); + sal_uInt32 mnTimeBetweenHighPriorityRequests; + sal_uInt32 mnTimeBetweenLowPriorityRequests; + sal_uInt32 mnTimeBetweenRequestsWhenNotIdle; + Size maPreviewSize; + SharedCacheContext mpCacheContext; + RequestQueue& mrQueue; + ::boost::shared_ptr<BitmapCache> mpCache; + BitmapFactory maBitmapFactory; + bool mbIsPaused; + + void ProcessRequests (void); + void ProcessOneRequest ( + CacheKey aKey, + const RequestPriorityClass ePriorityClass); +}; + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx new file mode 100644 index 000000000000..ca39843c9036 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx @@ -0,0 +1,368 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsQueueProcessorThread.hxx,v $ + * $Revision: 1.4 $ + * + * 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 SD_SLIDESORTER_QUEUE_PROCESSOR_THREAD_HXX +#define SD_SLIDESORTER_QUEUE_PROCESSOR_THREAD_HXX + +#include "view/SlsPageObjectViewObjectContact.hxx" +#include <vcl/svapp.hxx> +#include <osl/thread.hxx> + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + + +namespace sd { namespace slidesorter { namespace cache { + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +class QueueProcessorThread + : public ::osl::Thread +{ +public: + QueueProcessorThread ( + view::SlideSorterView& rView, + Queue& rQueue, + BitmapCache& rCache); + ~QueueProcessorThread (void); + + /** Start the execution of a suspended thread. A thread is suspended + after Stop() is called or when the queue on which it operates is + empty. Calling Start() on a running thread is OK. + */ + void Start (void); + + /** Stop the thread by suspending it. To re-start its execution call + Start(). + */ + void Stop (void); + + /** As we can not really terminate the rendering of a preview bitmap for + a request in midair this method acts more like a semaphor. It + returns only when it is save for the caller to delete the request. + For this to work it is important to remove the request from the + queue before calling this method. + */ + void RemoveRequest (RequestData& rRequest); + + /** Terminate the execution of the thread. When the thread is detached + it deletes itself. Otherwise the caller of this method may call + delete after this method returnes. + */ + void SAL_CALL Terminate (void); + +protected: + /** This virutal method is called (among others?) from the + inherited create method and acts as the main function of this + thread. + */ + virtual void SAL_CALL run (void); + + /** Called after the thread is terminated via the terminate + method. Used to kill the thread by calling delete on this. + */ + virtual void SAL_CALL onTerminated (void); + +private: + /** Flag that indicates wether the onTerminated method has been already + called. If so then a subsequent call to detach deletes the thread. + */ + volatile bool mbIsTerminated; + + volatile bool mbCanBeJoined; + + /** This mutex is used to guard the queue processor. Be carefull not to + mix its use with that of the solar mutex. + */ + ::osl::Mutex maMutex; + + view::SlideSorterView& mrView; + Queue& mrQueue; + BitmapCache& mrCache; + + void ProcessQueueEntry (void); +}; + + + + +//===== QueueProcessorThread ================================================ + +template <class Queue, class Request, class Cache, class Factory> + QueueProcessorThread<Queue, Request, Cache, Factory> + ::QueueProcessorThread ( + view::SlideSorterView& rView, + Queue& rQueue, + Cache& rCache) + : mbIsTerminated (false), + mbCanBeJoined (false), + mrView (rView), + mrQueue (rQueue), + mrCache (rCache) +{ + OSL_TRACE("QueueProcessorThread::constructor %p", this); + create(); +} + + + + +template <class Queue, class Request, class Cache, class Factory> + QueueProcessorThread<Queue, Request, Cache, Factory> + ::~QueueProcessorThread (void) +{ + OSL_TRACE("QueueProcessorThread::destructor %p", this); +} + + + + +template <class Queue, class Request, class Cache, class Factory> +void SAL_CALL QueueProcessorThread<Queue, Request, Cache, Factory>::run (void) +{ + OSL_TRACE("QueueProcessorThread::run(): running thread %p", this); + while ( ! mbIsTerminated) + { + OSL_TRACE("QueueProcessorThread::run(): still running thread %p: %d", this, mbIsTerminated?1:0); + if (mrQueue.IsEmpty()) + { + // Sleep while the queue is empty. + OSL_TRACE("QueueProcessorThread::run(): suspending thread %p", this); + suspend(); + OSL_TRACE("QueueProcessorThread::run(): running again thread %p", this); + } + + else if (GetpApp()->AnyInput()) + { + yield(); + // When there is input waiting to be processed we wait a short + // time and try again. + TimeValue aTimeToWait; + aTimeToWait.Seconds = 0; + aTimeToWait.Nanosec = 50*1000*1000; + OSL_TRACE("QueueProcessorThread::run(): input pending: waiting %d nanoseconds", + aTimeToWait.Nanosec); + wait (aTimeToWait); + } + + else + { + OSL_TRACE ("QueueProcessorThread::run(): Processing Query"); + ProcessQueueEntry(); + yield (); + } + } + OSL_TRACE("QueueProcessorThread::run(): exiting run %p", this); +} + + + + +template <class Queue, class Request, class Cache, class Factory> +void QueueProcessorThread<Queue, Request, Cache, Factory> + ::ProcessQueueEntry (void) +{ + Request* pRequest = NULL; + int nPriorityClass; + bool bRequestIsValid = false; + + do + { + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): testing for mbIsTerminated %p", this); + { + ::osl::MutexGuard aGuard (maMutex); + if (mbIsTerminated) + break; + if (mrQueue.IsEmpty()) + break; + } + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():acquiring mutex for bitmap creation %p", this); + ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + ::osl::MutexGuard aGuard (maMutex); + if (mbIsTerminated) + break; + + if (mrQueue.IsEmpty()) + break; + + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): have mutexes %p", this); + + // Get the requeuest with the highest priority from the queue. + nPriorityClass = mrQueue.GetFrontPriorityClass(); + pRequest = &mrQueue.GetFront(); + mrQueue.PopFront(); + bRequestIsValid = true; + + + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():using request %p for creating bitmap", pRequest); + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry():processing request for page %d with priority class ", + pRequest->GetPage()->GetPageNum(), nPriorityClass); + try + { + // Create a new preview bitmap and store it in the cache. + if (mbIsTerminated) + break; + BitmapEx aBitmap (Factory::CreateBitmap (*pRequest, mrView)); + if (mbIsTerminated) + break; + mrCache.SetBitmap ( + pRequest->GetPage(), + aBitmap, + nPriorityClass==0); + } + catch (...) + { + OSL_TRACE ("QueueProcessorThread::ProcessQueueEntry(): caught exception; %p", this); + // We are rendering a preview and can do without if need + // be. So keep going if something happens that should + // not happen. + } + } + while (false); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::Start (void) +{ + OSL_TRACE ("QueueProcessorThread::Start %p", this); + resume (); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::Stop (void) +{ + OSL_TRACE ("QueueProcessorThread::Stop %p", this); + suspend(); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::RemoveRequest (RequestData& rRequest) +{ + OSL_TRACE ("QueueProcessorThread::RemoveRequest %p", this); + // Do nothing else then wait for the mutex to be released. + ::osl::MutexGuard aGuard (mrQueue.GetMutex()); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::Terminate (void) +{ + // ::vos::OGuard aSolarGuard (Application::GetSolarMutex()); + OSL_TRACE("QueueProcessorThread::Terminate(): terminating thread %p", this); + ::osl::Thread::terminate (); + { + ::osl::MutexGuard aGuard (maMutex); + OSL_TRACE("QueueProcessorThread::Terminate(): starting to join %p, %d", this, mbIsTerminated?1:0); + mbIsTerminated = true; + } + Start(); +} + + + + +/** This callback method is called when the run() method terminates. +*/ +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void SAL_CALL QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::onTerminated (void) +{ + ::osl::MutexGuard aGuard (maMutex); + mbCanBeJoined = true; + /* + OSL_TRACE("QueueProcessorThread::Terminate():join %p, %d", this, mbIsTerminated?1:0); + while (true) + { + { + ::osl::MutexGuard aGuard (maMutex); + if (mbCanBeJoined) + break; + } + Start(); + TimeValue aTimeToWait; + aTimeToWait.Seconds = 0; + aTimeToWait.Nanosec = 50*1000*1000; + OSL_TRACE("QueueProcessorThread::Terminate(): waiting for join"); + wait (aTimeToWait); + } + if (mbCanBeJoined) + join(); + else + OSL_TRACE("Can not join"); + OSL_TRACE("QueueProcessorThread::Terminate():terminated thread %p :%d", + this, mbIsTerminated?1:0); + */ +} + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx new file mode 100644 index 000000000000..8e6a3e164a23 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx @@ -0,0 +1,82 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsRequestFactory.cxx,v $ + * + * $Revision: 1.5 $ + * + * 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_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsRequestFactory.hxx" + +#include "SlsGenericPageCache.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include <svx/svdpagv.hxx> +#include <svx/sdrpagewindow.hxx> +#include <svx/sdr/contact/viewcontact.hxx> + + +namespace sd { namespace slidesorter { namespace cache { + +void RequestFactory::operator()( + RequestQueue& rRequestQueue, + const SharedCacheContext& rpCacheContext) +{ + ::boost::shared_ptr<std::vector<CacheKey> > aKeys; + + // Add the requests for the visible pages. + aKeys = rpCacheContext->GetEntryList(true); + if (aKeys.get() != NULL) + { + std::vector<CacheKey>::const_iterator iKey; + std::vector<CacheKey>::const_iterator iEnd (aKeys->end()); + for (iKey=aKeys->begin(); iKey!=iEnd; ++iKey) + rRequestQueue.AddRequest(*iKey, VISIBLE_NO_PREVIEW); + } + + // Add the requests for the non-visible pages. + aKeys = rpCacheContext->GetEntryList(false); + if (aKeys.get() != NULL) + { + std::vector<CacheKey>::const_iterator iKey; + std::vector<CacheKey>::const_iterator iEnd (aKeys->end()); + for (iKey=aKeys->begin(); iKey!=iEnd; ++iKey) + rRequestQueue.AddRequest(*iKey, NOT_VISIBLE); + } +} + + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx new file mode 100644 index 000000000000..c86e0ffbe6ce --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx @@ -0,0 +1,51 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsRequestFactory.hxx,v $ + * $Revision: 1.8 $ + * + * 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 SD_SLIDESORTER_REQUEST_FACTORY_HXX +#define SD_SLIDESORTER_REQUEST_FACTORY_HXX + +#include "cache/SlsCacheContext.hxx" + +namespace sd { namespace slidesorter { namespace cache { + +class RequestQueue; + +class RequestFactory +{ +public: + void operator() ( + RequestQueue& rRequestQueue, + const SharedCacheContext& rpCacheContext); +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx new file mode 100644 index 000000000000..377e3f40495f --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx @@ -0,0 +1,58 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsRequestPriorityClass.hxx,v $ + * $Revision: 1.4 $ + * + * 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 SD_SLIDESORTER_CACHE_REQUEST_PRIORITY_CLASS_HXX +#define SD_SLIDESORTER_CACHE_REQUEST_PRIORITY_CLASS_HXX + +namespace sd { namespace slidesorter { namespace cache { + + +/** Each request for a preview creation has a priority. This enum defines + the available priorities. The special values MIN__CLASS and MAX__CLASS + are/can be used for validation and have to be kept up-to-date. +*/ +enum RequestPriorityClass +{ + MIN__CLASS = 0, + + // The slide is visible. A preview does not yet exist. + VISIBLE_NO_PREVIEW = MIN__CLASS, + // The slide is visible. A preview exists but is not up-to-date anymore. + VISIBLE_OUTDATED_PREVIEW, + // The slide is not visible. + NOT_VISIBLE, + + MAX__CLASS = NOT_VISIBLE +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx new file mode 100644 index 000000000000..41898c889095 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx @@ -0,0 +1,295 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsRequestQueue.cxx,v $ + * + * $Revision: 1.5 $ + * + * 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_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsRequestQueue.hxx" + +#include <set> + + +#undef VERBOSE +//#define VERBOSE + +namespace sd { namespace slidesorter { namespace cache { + +/** This class extends the actual request data with additional information + that is used by the priority queues. +*/ +class Request +{ +public: + Request ( + CacheKey aKey, sal_Int32 nPriority, RequestPriorityClass eClass) + : maKey(aKey), mnPriorityInClass(nPriority), meClass(eClass) + {} + /** Sort requests according to priority classes and then to priorities. + */ + class Comparator { public: + bool operator() (const Request& rRequest1, const Request& rRequest2) + { + if (rRequest1.meClass == rRequest2.meClass) + return (rRequest1.mnPriorityInClass > rRequest2.mnPriorityInClass); + else + return (rRequest1.meClass < rRequest2.meClass); + } + }; + /** Request data is compared arbitrarily by their addresses in memory. + This just establishes an order so that the STL containers are happy. + The order is not semantically interpreted. + */ + class DataComparator { public: + DataComparator (const Request&rRequest):maKey(rRequest.maKey){} + DataComparator (const CacheKey aKey):maKey(aKey){} + bool operator() (const Request& rRequest) { return maKey == rRequest.maKey; } + private: const CacheKey maKey; + }; + + CacheKey maKey; + sal_Int32 mnPriorityInClass; + RequestPriorityClass meClass; +}; + + +class RequestQueue::Container + : public ::std::set< + Request, + Request::Comparator> +{ +}; + + + + +//===== GenericRequestQueue ================================================= + + +RequestQueue::RequestQueue (const SharedCacheContext& rpCacheContext) + : maMutex(), + mpRequestQueue(new Container()), + mpCacheContext(rpCacheContext), + mnMinimumPriority(0), + mnMaximumPriority(1) +{ +} + + + + +RequestQueue::~RequestQueue (void) +{ +} + + + + +void RequestQueue::AddRequest ( + CacheKey aKey, + RequestPriorityClass eRequestClass, + bool /*bInsertWithHighestPriority*/) +{ + ::osl::MutexGuard aGuard (maMutex); + + OSL_ASSERT(eRequestClass>=MIN__CLASS && eRequestClass<=MAX__CLASS); + + // If the request is already a member of the queue then remove it so + // that the following insertion will use the new prioritization. +#ifdef VERBOSE + bool bRemoved = +#endif + RemoveRequest(aKey); + + // The priority of the request inside its priority class is defined by + // the page number. This ensures a strict top-to-bottom, left-to-right + // order. + sal_Int32 nPriority (mpCacheContext->GetPriority(aKey)); + Request aRequest (aKey, nPriority, eRequestClass); + mpRequestQueue->insert(aRequest); + + SSCD_SET_REQUEST_CLASS(rRequestData.GetPage(),eRequestClass); + +#ifdef VERBOSE + OSL_TRACE("%s request for page %d with priority class %d", + bRemoved?"replaced":"added", + (rRequestData.GetPage()->GetPageNum()-1)/2, + eRequestClass); +#endif +} + + + + +bool RequestQueue::RemoveRequest ( + CacheKey aKey) +{ + bool bRequestWasRemoved (false); + ::osl::MutexGuard aGuard (maMutex); + + while(true) + { + Container::const_iterator aRequestIterator = ::std::find_if ( + mpRequestQueue->begin(), + mpRequestQueue->end(), + Request::DataComparator(aKey)); + if (aRequestIterator != mpRequestQueue->end()) + { + if (aRequestIterator->mnPriorityInClass == mnMinimumPriority+1) + mnMinimumPriority++; + else if (aRequestIterator->mnPriorityInClass == mnMaximumPriority-1) + mnMaximumPriority--; + mpRequestQueue->erase(aRequestIterator); + bRequestWasRemoved = true; + + if (bRequestWasRemoved) + { + SSCD_SET_STATUS(rRequest.GetPage(),NONE); + } + } + else + break; + } + + return bRequestWasRemoved; +} + + + + +void RequestQueue::ChangeClass ( + CacheKey aKey, + RequestPriorityClass eNewRequestClass) +{ + ::osl::MutexGuard aGuard (maMutex); + + OSL_ASSERT(eNewRequestClass>=MIN__CLASS && eNewRequestClass<=MAX__CLASS); + + Container::const_iterator iRequest ( + ::std::find_if ( + mpRequestQueue->begin(), + mpRequestQueue->end(), + Request::DataComparator(aKey))); + if (iRequest!=mpRequestQueue->end() && iRequest->meClass!=eNewRequestClass) + { + AddRequest(aKey, eNewRequestClass, true); + SSCD_SET_REQUEST_CLASS(rRequestData.GetPage(),eNewRequestClass); + } +} + + + + +CacheKey RequestQueue::GetFront (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + if (mpRequestQueue->empty()) + throw ::com::sun::star::uno::RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "RequestQueue::GetFront(): queue is empty")), + NULL); + + return mpRequestQueue->begin()->maKey; +} + + + + +RequestPriorityClass RequestQueue::GetFrontPriorityClass (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + if (mpRequestQueue->empty()) + throw ::com::sun::star::uno::RuntimeException( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "RequestQueue::GetFrontPriorityClass(): queue is empty")), + NULL); + + return mpRequestQueue->begin()->meClass; +} + + + + +void RequestQueue::PopFront (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + if ( ! mpRequestQueue->empty()) + { + SSCD_SET_STATUS(maRequestQueue.begin()->mpData->GetPage(),NONE); + + mpRequestQueue->erase(mpRequestQueue->begin()); + + // Reset the priority counter if possible. + if (mpRequestQueue->empty()) + { + mnMinimumPriority = 0; + mnMaximumPriority = 1; + } + } +} + + + + +bool RequestQueue::IsEmpty (void) +{ + ::osl::MutexGuard aGuard (maMutex); + return mpRequestQueue->empty(); +} + + + + +void RequestQueue::Clear (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + mpRequestQueue->clear(); + mnMinimumPriority = 0; + mnMaximumPriority = 1; +} + + + + +::osl::Mutex& RequestQueue::GetMutex (void) +{ + return maMutex; +} + + +} } } // end of namespace ::sd::slidesorter::cache + + + diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx new file mode 100644 index 000000000000..f247ecff3729 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx @@ -0,0 +1,137 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsRequestQueue.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_REQUEST_QUEUE_HXX +#define SD_SLIDESORTER_REQUEST_QUEUE_HXX + +#include "SlsRequestPriorityClass.hxx" +#include "cache/SlsCacheContext.hxx" +#include "taskpane/SlideSorterCacheDisplay.hxx" +#include <drawdoc.hxx> +#include "osl/mutex.hxx" + + +namespace sd { namespace slidesorter { namespace cache { + +class RequestData; + +/** The request queue stores requests that are described by the RequestData + sorted according to priority class and then priority. +*/ +class RequestQueue +{ +public: + RequestQueue (const SharedCacheContext& rpCacheContext); + ~RequestQueue (void); + + /** Insert a request with highest or lowest priority in its priority + class. When the request is already present then it is first + removed. This effect is then a re-prioritization. + @param rRequestData + The request. + @param eRequestClass + The priority class in which to insert the request with highest + or lowest priority. + @param bInsertWithHighestPriority + When this flag is <TRUE/> the request is inserted with highes + priority in its class. When <FALSE/> the request is inserted + with lowest priority. + */ + void AddRequest ( + CacheKey aKey, + RequestPriorityClass eRequestClass, + bool bInsertWithHighestPriority = false); + + /** Remove the specified request from the queue. + @param rRequestData + It is OK when the specified request is not a member of the + queue. + @return + Returns <TRUE/> when the request has been successfully been + removed from the queue. Otherwise, e.g. because the request was + not a member of the queue, <FALSE/> is returned. + */ + bool RemoveRequest (CacheKey aKey); + + /** Change the priority class of the specified request. + */ + void ChangeClass ( + CacheKey aKey, + RequestPriorityClass eNewRequestClass); + + /** Get the request with the highest priority int the highest priority class. + */ + CacheKey GetFront (void); + + // For debugging. + RequestPriorityClass GetFrontPriorityClass (void); + + /** Really a synonym for RemoveRequest(GetFront()); + */ + void PopFront (void); + + /** Returns <TRUE/> when there is no element in the queue. + */ + bool IsEmpty (void); + + /** Remove all requests from the queue. This resets the minimum and + maximum priorities to their default values. + */ + void Clear (void); + + /** Return the mutex that guards the access to the priority queue. + */ + ::osl::Mutex& GetMutex (void); + +private: + ::osl::Mutex maMutex; + class Container; + ::boost::scoped_ptr<Container> mpRequestQueue; + SharedCacheContext mpCacheContext; + + /** A lower bound of the lowest priority of all elements in the queues. + The start value is 0. It is assigned and then decreased every time + when an element is inserted or marked as the request with lowest + priority. + */ + int mnMinimumPriority; + /** An upper bound of the highest priority of all elements in the queues. + The start value is 1. It is assigned and then increased every time + when an element is inserted or marked as the request with highest + priority. + */ + int mnMaximumPriority; +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/cache/makefile.mk b/sd/source/ui/slidesorter/cache/makefile.mk new file mode 100644 index 000000000000..f16cd184b054 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/makefile.mk @@ -0,0 +1,69 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.8 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slscache +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/SlsBitmapCache.obj \ + $(SLO)$/SlsBitmapCompressor.obj \ + $(SLO)$/SlsBitmapFactory.obj \ + $(SLO)$/SlsCacheCompactor.obj \ + $(SLO)$/SlsCacheConfiguration.obj \ + $(SLO)$/SlsGenericPageCache.obj \ + $(SLO)$/SlsIdleDetector.obj \ + $(SLO)$/SlsPageCache.obj \ + $(SLO)$/SlsPageCacheManager.obj \ + $(SLO)$/SlsQueueProcessor.obj \ + $(SLO)$/SlsRequestFactory.obj \ + $(SLO)$/SlsRequestQueue.obj + + +EXCEPTIONSFILES= + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sd/source/ui/slidesorter/controller/SlideSorterController.cxx b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx new file mode 100644 index 000000000000..f355ada7089f --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx @@ -0,0 +1,1073 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterController.cxx,v $ + * $Revision: 1.45 $ + * + * 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 "precompiled_sd.hxx" + +#include "controller/SlideSorterController.hxx" + +#include "SlideSorter.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "SlsListener.hxx" +#include "controller/SlsFocusManager.hxx" +#include "SlsSelectionCommand.hxx" +#include "controller/SlsAnimator.hxx" +#include "controller/SlsClipboard.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsPageObjectFactory.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSlotManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsViewOverlay.hxx" +#include "view/SlsFontProvider.hxx" +#include "cache/SlsPageCache.hxx" +#include "cache/SlsPageCacheManager.hxx" + +#include "drawdoc.hxx" +#include "DrawViewShell.hxx" +#include "TextLogger.hxx" +#include "ViewShellBase.hxx" +#include "Window.hxx" +#include "FrameView.hxx" +#include "DrawDocShell.hxx" +#include "sdpage.hxx" +#include "res_bmp.hrc" +#include "sdresid.hxx" +#include "strings.hrc" +#include "app.hrc" +#include "glob.hrc" +#include "sdmod.hxx" +#include "sdxfer.hxx" +#include "FrameView.hxx" +#include "ViewShellHint.hxx" +#include "AccessibleSlideSorterView.hxx" +#include "AccessibleSlideSorterObject.hxx" + +#include <vcl/window.hxx> +#include <svx/svdopage.hxx> +#include <svx/svxids.hrc> +#include <svx/ruler.hxx> +#include <svx/zoomitem.hxx> +#include <svtools/tabbar.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/topfrm.hxx> +#include <tools/link.hxx> +#include <vcl/svapp.hxx> + +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPages.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::sd::slidesorter::model; +using namespace ::sd::slidesorter::view; +using namespace ::sd::slidesorter::controller; + +namespace sd { namespace slidesorter { namespace controller { + + +SlideSorterController::SlideSorterController (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mrModel(mrSlideSorter.GetModel()), + mrView(mrSlideSorter.GetView()), + mpPageSelector(), + mpFocusManager(), + mpSlotManager(), + mpClipboard(), + mpScrollBarManager(), + mpCurrentSlideManager(), + mpSelectionManager(), + mpAnimator(new Animator(rSlideSorter)), + mpListener(), + mnModelChangeLockCount(0), + mbPreModelChangeDone(false), + mbPostModelChangePending(false), + maSelectionBeforeSwitch(), + mnCurrentPageBeforeSwitch(0), + mpEditModeChangeMasterPage(NULL), + maTotalWindowArea(), + mnPaintEntranceCount(0), + mbIsContextMenuOpen(false), + mpProperties(new Properties()) +{ + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + OSL_ASSERT(pWindow!=NULL); + if (pWindow != NULL) + { + // The whole background is painted by the view and controls. + ::Window* pParentWindow = pWindow->GetParent(); + OSL_ASSERT(pParentWindow!=NULL); + pParentWindow->SetBackground (Wallpaper()); + + // Connect the view with the window that has been created by our base + // class. + pWindow->SetBackground (Wallpaper()); + mrView.AddWindowToPaintView(pWindow); + mrView.SetActualWin(pWindow); + pWindow->SetCenterAllowed (false); + pWindow->SetViewSize (mrView.GetModelArea().GetSize()); + pWindow->EnableRTL(FALSE); + + // Reinitialize colors in Properties with window specific values. + mpProperties->SetBackgroundColor( + pWindow->GetSettings().GetStyleSettings().GetWindowColor()); + mpProperties->SetTextColor( + pWindow->GetSettings().GetStyleSettings().GetWindowTextColor()); + mpProperties->SetSelectionColor( + pWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + mpProperties->SetHighlightColor( + pWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + } +} + + + + +void SlideSorterController::Init (void) +{ + mrView.HandleModelChange(); + + mpCurrentSlideManager.reset(new CurrentSlideManager(mrSlideSorter)); + mpPageSelector.reset(new PageSelector(mrSlideSorter)); + mpFocusManager.reset(new FocusManager(mrSlideSorter)); + mpSlotManager.reset(new SlotManager(mrSlideSorter)); + mpClipboard.reset(new Clipboard(mrSlideSorter)); + mpScrollBarManager.reset(new ScrollBarManager(mrSlideSorter)); + mpSelectionManager.reset(new SelectionManager(mrSlideSorter)); + + mpScrollBarManager->LateInitialization(); + + // Create the selection function. + SfxRequest aRequest ( + SID_OBJECT_SELECT, + 0, + mrModel.GetDocument()->GetItemPool()); + mrSlideSorter.SetCurrentFunction(CreateSelectionFunction(aRequest)); + + mpListener = new Listener(mrSlideSorter); + + mpPageSelector->UpdateAllPages(); + GetSelectionManager()->SelectionHasChanged(); +} + + + + +SlideSorterController::~SlideSorterController (void) +{ + try + { + uno::Reference<lang::XComponent> xComponent ( + static_cast<XWeak*>(mpListener.get()), uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + } + catch( uno::Exception& e ) + { + (void)e; + DBG_ERROR( "sd::SlideSorterController::~SlideSorterController(), exception caught!" ); + } + + // dispose should have been called by now so that nothing is to be done + // to shut down cleanly. +} + + + + +SlideSorter& SlideSorterController::GetSlideSorter (void) const +{ + return mrSlideSorter; +} + + + + +model::SharedPageDescriptor SlideSorterController::GetPageAt ( + const Point& aPixelPosition) +{ + sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aPixelPosition)); + model::SharedPageDescriptor pDescriptorAtPoint; + if (nHitPageIndex >= 0) + pDescriptorAtPoint = mrModel.GetPageDescriptor(nHitPageIndex); + + return pDescriptorAtPoint; +} + + + + +model::SharedPageDescriptor SlideSorterController::GetFadePageAt ( + const Point& aPixelPosition) +{ + sal_Int32 nHitPageIndex (mrView.GetFadePageIndexAtPoint(aPixelPosition)); + model::SharedPageDescriptor pDescriptorAtPoint; + if (nHitPageIndex >= 0) + pDescriptorAtPoint = mrModel.GetPageDescriptor(nHitPageIndex); + + return pDescriptorAtPoint; +} + + + + +PageSelector& SlideSorterController::GetPageSelector (void) +{ + OSL_ASSERT(mpPageSelector.get()!=NULL); + return *mpPageSelector.get(); +} + + + + +FocusManager& SlideSorterController::GetFocusManager (void) +{ + OSL_ASSERT(mpFocusManager.get()!=NULL); + return *mpFocusManager.get(); +} + + + + +Clipboard& SlideSorterController::GetClipboard (void) +{ + OSL_ASSERT(mpClipboard.get()!=NULL); + return *mpClipboard.get(); +} + + + + +ScrollBarManager& SlideSorterController::GetScrollBarManager (void) +{ + OSL_ASSERT(mpScrollBarManager.get()!=NULL); + return *mpScrollBarManager.get(); +} + + + + +::boost::shared_ptr<CurrentSlideManager> SlideSorterController::GetCurrentSlideManager (void) const +{ + OSL_ASSERT(mpCurrentSlideManager.get()!=NULL); + return mpCurrentSlideManager; +} + + + + +::boost::shared_ptr<SlotManager> SlideSorterController::GetSlotManager (void) const +{ + OSL_ASSERT(mpSlotManager.get()!=NULL); + return mpSlotManager; +} + + + + +::boost::shared_ptr<SelectionManager> SlideSorterController::GetSelectionManager (void) const +{ + OSL_ASSERT(mpSelectionManager.get()!=NULL); + return mpSelectionManager; +} + + + + +void SlideSorterController::PrePaint() +{ + // forward VCLs PrePaint window event to DrawingLayer + mrView.PrePaint(); +} + + + + +void SlideSorterController::Paint ( + const Rectangle& rBBox, + ::Window* pWindow) +{ + // if (mnPaintEntranceCount == 0) + { + ++mnPaintEntranceCount; + + try + { + if (GetSelectionManager()->IsMakeSelectionVisiblePending()) + GetSelectionManager()->MakeSelectionVisible(); + + mrView.SetApplicationDocumentColor(GetProperties()->GetBackgroundColor()); + mrView.CompleteRedraw(pWindow, Region(rBBox), 0); + } + catch (const Exception&) + { + // Ignore all exceptions. + } + + --mnPaintEntranceCount; + } +} + + + + +void SlideSorterController::FuTemporary (SfxRequest& rRequest) +{ + mpSlotManager->FuTemporary (rRequest); +} + + + + +void SlideSorterController::FuPermanent (SfxRequest &rRequest) +{ + mpSlotManager->FuPermanent (rRequest); +} + + + + +void SlideSorterController::FuSupport (SfxRequest &rRequest) +{ + mpSlotManager->FuSupport (rRequest); +} + + + + +bool SlideSorterController::Command ( + const CommandEvent& rEvent, + ::sd::Window* pWindow) +{ + bool bEventHasBeenHandled = false; + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + + switch (rEvent.GetCommand()) + { + case COMMAND_CONTEXTMENU: + { + SdPage* pPage = NULL; + USHORT nPopupId; + + model::PageEnumeration aSelectedPages ( + PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel)); + if (aSelectedPages.HasMoreElements()) + pPage = aSelectedPages.GetNextElement()->GetPage(); + + // Choose the popup menu depending on a) the type of the main + // view shell, b) the edit mode, and c) on whether the selection + // is empty or not. + ViewShell::ShellType eMainViewShellType (ViewShell::ST_NONE); + ::boost::shared_ptr<ViewShell> pMainViewShell ( + pViewShell->GetViewShellBase().GetMainViewShell()); + if (pMainViewShell.get() != NULL) + eMainViewShellType = pMainViewShell->GetShellType(); + switch (eMainViewShellType) + { + case ViewShell::ST_DRAW: + if (pPage != NULL) + nPopupId = RID_SLIDE_SORTER_DRAW_SEL_POPUP; + else + nPopupId = RID_SLIDE_SORTER_DRAW_NOSEL_POPUP; + break; + + default: + if (mrModel.GetEditMode() == EM_PAGE) + if (pPage != NULL) + nPopupId = RID_SLIDE_SORTER_IMPRESS_SEL_POPUP; + else + nPopupId = RID_SLIDE_SORTER_IMPRESS_NOSEL_POPUP; + else + if (pPage != NULL) + nPopupId = RID_SLIDE_SORTER_MASTER_SEL_POPUP; + else + nPopupId = RID_SLIDE_SORTER_MASTER_NOSEL_POPUP; + } + + if (pPage == NULL) + { + // When there is no selection, then we show the insertion + // indicator so that the user knows where a page insertion + // would take place. + mrView.GetOverlay().GetInsertionIndicatorOverlay().SetPosition( + pWindow->PixelToLogic(rEvent.GetMousePosPixel())); + mrView.GetOverlay().GetInsertionIndicatorOverlay().setVisible(true); + } + + pWindow->ReleaseMouse(); + if (rEvent.IsMouseEvent()) + { + mbIsContextMenuOpen = true; + if (pViewShell != NULL) + { + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher != NULL) + pDispatcher->ExecutePopup(SdResId(nPopupId)); + } + } + else + { + // The event is not a mouse event. Use the center of the + // focused page as top left position of the context menu. + if (pPage != NULL) + { + model::SharedPageDescriptor pDescriptor ( + GetFocusManager().GetFocusedPageDescriptor()); + if (pDescriptor.get() != NULL) + { + Rectangle aBBox (mrView.GetPageBoundingBox ( + pDescriptor, + view::SlideSorterView::CS_SCREEN, + view::SlideSorterView::BBT_SHAPE)); + Point aPosition (aBBox.Center()); + mbIsContextMenuOpen = true; + if (pViewShell != NULL) + pViewShell->GetViewFrame()->GetDispatcher()->ExecutePopup( + SdResId(nPopupId), + pWindow, + &aPosition); + } + } + } + mbIsContextMenuOpen = false; + if (pPage == NULL) + { + // Remember the position of the insertion indicator before + // it is hidden, so that a pending slide insertion slot call + // finds the right place to insert a new slide. + GetSelectionManager()->SetInsertionPosition( + mrView.GetOverlay().GetInsertionIndicatorOverlay().GetInsertionPageIndex()); + mrView.GetOverlay().GetInsertionIndicatorOverlay().setVisible(false); + } + bEventHasBeenHandled = true; + } + break; + + case COMMAND_WHEEL: + { + // We ignore zooming with control+mouse wheel. + const CommandWheelData* pData = rEvent.GetWheelData(); + if (pData!=NULL && pData->IsMod1()) + bEventHasBeenHandled = true; + } + break; + } + + return bEventHasBeenHandled; +} + + + + +void SlideSorterController::LockModelChange (void) +{ + mnModelChangeLockCount += 1; +} + + + + +void SlideSorterController::UnlockModelChange (void) +{ + mnModelChangeLockCount -= 1; + if (mnModelChangeLockCount==0 && mbPostModelChangePending) + PostModelChange(); +} + + + + +void SlideSorterController::PreModelChange (void) +{ + // Prevent PreModelChange to execute more than once per model lock. + if (mbPostModelChangePending) + return; + mbPreModelChangeDone = true; + + if (mrSlideSorter.GetViewShell() != NULL) + mrSlideSorter.GetViewShell()->Broadcast( + ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START)); + + mpPageSelector->PrepareModelChange(); + GetCurrentSlideManager()->PrepareModelChange(); + + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + if (pWindow != NULL) + mrView.PreModelChange(); + + mbPostModelChangePending = true; +} + + + + +void SlideSorterController::PostModelChange (void) +{ + mbPostModelChangePending = false; + mrModel.Resync(); + + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + if (pWindow != NULL) + { + GetCurrentSlideManager()->HandleModelChange(); + + mrView.PostModelChange (); + + pWindow->SetViewOrigin (Point (0,0)); + pWindow->SetViewSize (mrView.GetModelArea().GetSize()); + + // The visibility of the scroll bars may have to be changed. Then + // the size of the view has to change, too. Let Rearrange() handle + // that. + Rearrange(); + } + + mpPageSelector->HandleModelChange (); + + if (mrSlideSorter.GetViewShell() != NULL) + mrSlideSorter.GetViewShell()->Broadcast( + ViewShellHint(ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END)); +} + + + + +void SlideSorterController::HandleModelChange (void) +{ + // Ignore this call when the document is not in a valid state, i.e. has + // not the same number of regular and notes pages. + bool bIsDocumentValid = (mrModel.GetDocument()->GetPageCount() % 2 == 1); + + if (bIsDocumentValid) + { + ModelChangeLock aLock (*this); + PreModelChange(); + } +} + + + + +IMPL_LINK(SlideSorterController, WindowEventHandler, VclWindowEvent*, pEvent) +{ + if (pEvent != NULL) + { + ::Window* pWindow = pEvent->GetWindow(); + ::sd::Window* pActiveWindow = mrSlideSorter.GetActiveWindow(); + switch (pEvent->GetId()) + { + case VCLEVENT_WINDOW_ACTIVATE: + case VCLEVENT_WINDOW_SHOW: + if (pActiveWindow != NULL && pWindow == pActiveWindow->GetParent()) + mrView.RequestRepaint(); + break; + + case VCLEVENT_WINDOW_GETFOCUS: + if (pActiveWindow != NULL && pWindow == pActiveWindow) + GetFocusManager().ShowFocus(); + break; + + case VCLEVENT_WINDOW_LOSEFOCUS: + if (pActiveWindow != NULL && pWindow == pActiveWindow) + GetFocusManager().HideFocus(); + break; + + case VCLEVENT_APPLICATION_DATACHANGED: + { + // Invalidate the preview cache. + cache::PageCacheManager::Instance()->InvalidateAllCaches(); + + // Update the draw mode. + ULONG nDrawMode (Application::GetSettings().GetStyleSettings().GetHighContrastMode() + ? ViewShell::OUTPUT_DRAWMODE_CONTRAST + : ViewShell::OUTPUT_DRAWMODE_COLOR); + if (mrSlideSorter.GetViewShell() != NULL) + mrSlideSorter.GetViewShell()->GetFrameView()->SetDrawMode(nDrawMode); + if (pActiveWindow != NULL) + pActiveWindow->SetDrawMode(nDrawMode); + mrView.HandleDrawModeChange(); + + // When the system font has changed a layout has to be done. + mrView.Resize(); + FontProvider::Instance().Invalidate(); + } + break; + + default: + break; + } + } + + return TRUE; +} + + + + +void SlideSorterController::GetCtrlState (SfxItemSet& rSet) +{ + if (rSet.GetItemState(SID_RELOAD) != SFX_ITEM_UNKNOWN) + { + // "Letzte Version" vom SFx en/disablen lassen + SfxViewFrame* pSlideViewFrame = SfxViewFrame::Current(); + DBG_ASSERT(pSlideViewFrame!=NULL, + "SlideSorterController::GetCtrlState: ViewFrame not found"); + if (pSlideViewFrame && pSlideViewFrame->ISA(SfxTopViewFrame)) + { + pSlideViewFrame->GetSlotState (SID_RELOAD, NULL, &rSet); + } + else // MI sagt: kein MDIFrame --> disablen + { + rSet.DisableItem(SID_RELOAD); + } + } + + // Output quality. + if (rSet.GetItemState(SID_OUTPUT_QUALITY_COLOR)==SFX_ITEM_AVAILABLE + ||rSet.GetItemState(SID_OUTPUT_QUALITY_GRAYSCALE)==SFX_ITEM_AVAILABLE + ||rSet.GetItemState(SID_OUTPUT_QUALITY_BLACKWHITE)==SFX_ITEM_AVAILABLE + ||rSet.GetItemState(SID_OUTPUT_QUALITY_CONTRAST)==SFX_ITEM_AVAILABLE) + { + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + if (pWindow != NULL) + { + ULONG nMode = pWindow->GetDrawMode(); + UINT16 nQuality = 0; + + switch (nMode) + { + case ViewShell::OUTPUT_DRAWMODE_COLOR: + nQuality = 0; + break; + case ViewShell::OUTPUT_DRAWMODE_GRAYSCALE: + nQuality = 1; + break; + case ViewShell::OUTPUT_DRAWMODE_BLACKWHITE: + nQuality = 2; + break; + case ViewShell::OUTPUT_DRAWMODE_CONTRAST: + nQuality = 3; + break; + } + + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_COLOR, + (BOOL)(nQuality==0))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_GRAYSCALE, + (BOOL)(nQuality==1))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_BLACKWHITE, + (BOOL)(nQuality==2))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_CONTRAST, + (BOOL)(nQuality==3))); + } + } + + if (rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) == SFX_ITEM_AVAILABLE) + { + rSet.Put (SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, TRUE)); + } +} + + + + +void SlideSorterController::GetStatusBarState (SfxItemSet& rSet) +{ + mpSlotManager->GetStatusBarState (rSet); +} + + + + +void SlideSorterController::ExecCtrl (SfxRequest& rRequest) +{ + mpSlotManager->ExecCtrl (rRequest); +} + + + + +void SlideSorterController::GetAttrState (SfxItemSet& rSet) +{ + mpSlotManager->GetAttrState (rSet); +} + + + + +void SlideSorterController::ExecStatusBar (SfxRequest& ) +{ +} + + + + +void SlideSorterController::UpdateAllPages (void) +{ + // Do a redraw. + mrView.InvalidateAllWin(); +} + + + + +Rectangle SlideSorterController::Resize (const Rectangle& rAvailableSpace) +{ + Rectangle aContentArea (rAvailableSpace); + + if (maTotalWindowArea != rAvailableSpace) + { + maTotalWindowArea = rAvailableSpace; + aContentArea = Rearrange(true); + } + + return aContentArea; +} + + + + +Rectangle SlideSorterController::Rearrange (bool bForce) +{ + Rectangle aNewContentArea (maTotalWindowArea); + + ::boost::shared_ptr<sd::Window> pWindow = mrSlideSorter.GetContentWindow(); + if (pWindow.get() != NULL) + { + // Place the scroll bars. + aNewContentArea = GetScrollBarManager().PlaceScrollBars(maTotalWindowArea); + + bool bSizeHasChanged (false); + // Only when bForce is not true we have to test for a size change in + // order to determine whether the window and the view have to be resized. + if ( ! bForce) + { + Rectangle aCurrentContentArea ( + pWindow->GetPosPixel(), + pWindow->GetOutputSizePixel()); + bSizeHasChanged = (aNewContentArea != aCurrentContentArea); + } + if (bForce || bSizeHasChanged) + { + // The browser window gets the remaining space. + pWindow->SetPosSizePixel (aNewContentArea.TopLeft(), aNewContentArea.GetSize()); + mrView.Resize(); + } + + // Adapt the scroll bars to the new zoom factor of the browser + // window and the arrangement of the page objects. + GetScrollBarManager().UpdateScrollBars(false, !bForce); + } + + return aNewContentArea; +} + + + + +void SlideSorterController::SetZoom (long int nZoom) +{ + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + long int nCurrentZoom ((long int)( + pWindow->GetMapMode().GetScaleX().operator double() * 100)); + + if (nZoom > nCurrentZoom) + { + Size aPageSize (mrView.GetPageBoundingBox( + 0, + view::SlideSorterView::CS_MODEL, + view::SlideSorterView::BBT_SHAPE).GetSize()); + Size aWindowSize (pWindow->PixelToLogic( + pWindow->GetOutputSizePixel())); + + // The zoom factor must not grow by more then the ratio of the + // widths of the output window and the page objects. + long nMaxFactor + = nCurrentZoom * aWindowSize.Width() / aPageSize.Width(); + // Apply rounding, so that a current zoom factor of 1 is still + // increased. + nMaxFactor = (nCurrentZoom * 18 + 5) / 10; + nZoom = Min(nMaxFactor, nZoom); + } + if (nZoom < 1) + nZoom = 1; + + mrView.LockRedraw (TRUE); + mrView.GetLayouter().SetZoom(nZoom/100.0, pWindow); + mrView.Layout(); + GetScrollBarManager().UpdateScrollBars (false); + mrView.GetPreviewCache()->InvalidateCache(); + mrView.RequestRepaint(); + mrView.LockRedraw (FALSE); + + /* + ViewShell::SetZoom (nZoom); + GetViewFrame()->GetBindings().Invalidate (SID_ATTR_ZOOM); + */ +} + + + + +FunctionReference SlideSorterController::CreateSelectionFunction (SfxRequest& rRequest) +{ + FunctionReference xFunc( SelectionFunction::Create(mrSlideSorter, rRequest) ); + return xFunc; +} + + + + +void SlideSorterController::PrepareEditModeChange (void) +{ + // Before we throw away the page descriptors we prepare for selecting + // descriptors in the other mode and for restoring the current + // selection when switching back to the current mode. + if (mrModel.GetEditMode() == EM_PAGE) + { + maSelectionBeforeSwitch.clear(); + + // Search for the first selected page and determine the master page + // used by its page object. It will be selected after the switch. + // In the same loop the current selection is stored. + PageEnumeration aSelectedPages ( + PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel)); + while (aSelectedPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + SdPage* pPage = pDescriptor->GetPage(); + // Remember the master page of the first selected descriptor. + if (pPage!=NULL && mpEditModeChangeMasterPage==NULL) + mpEditModeChangeMasterPage = &static_cast<SdPage&>( + pPage->TRG_GetMasterPage()); + + maSelectionBeforeSwitch.push_back(pPage); + } + + // Remember the current page. + if (mrSlideSorter.GetViewShell() != NULL) + mnCurrentPageBeforeSwitch = (mrSlideSorter.GetViewShell()->GetViewShellBase() + .GetMainViewShell()->GetActualPage()->GetPageNum()-1)/2; + } +} + + + + +bool SlideSorterController::ChangeEditMode (EditMode eEditMode) +{ + bool bResult (false); + if (mrModel.GetEditMode() != eEditMode) + { + ModelChangeLock aLock (*this); + PreModelChange(); + // Do the actual edit mode switching. + bResult = mrModel.SetEditMode(eEditMode); + if (bResult) + HandleModelChange(); + } + return bResult; +} + + + + +void SlideSorterController::FinishEditModeChange (void) +{ + if (mrModel.GetEditMode() == EM_MASTERPAGE) + { + // Search for the master page that was determined in + // PrepareEditModeChange() and make it the current page. + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + if (pDescriptor->GetPage() == mpEditModeChangeMasterPage) + { + GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + break; + } + } + } + else + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(mnCurrentPageBeforeSwitch)); + GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + + // Restore the selection. + ::std::vector<SdPage*>::iterator iPage; + for (iPage=maSelectionBeforeSwitch.begin(); + iPage!=maSelectionBeforeSwitch.end(); + ++iPage) + { + mpPageSelector->SelectPage(*iPage); + } + maSelectionBeforeSwitch.clear( ); + } + mpEditModeChangeMasterPage = NULL; +} + + + + +void SlideSorterController::PageNameHasChanged (int nPageIndex, const String& rsOldName) +{ + // Request a repaint for the page object whose name has changed. + model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get() != NULL) + mrView.RequestRepaint(pDescriptor); + + // Get a pointer to the corresponding accessible object and notify + // that of the name change. + do + { + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + if (pWindow == NULL) + break; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + xAccessible (pWindow->GetAccessible(FALSE)); + if ( ! xAccessible.is()) + break; + + // Now comes a small hack. We assume that the accessible object is + // an instantiation of AccessibleSlideSorterView and cast it to that + // class. The cleaner alternative to this cast would be a new member + // in which we would store the last AccessibleSlideSorterView object + // created by SlideSorterViewShell::CreateAccessibleDocumentView(). + // But then there is no guaranty that the accessible object obtained + // from the window really is that instance last created by + // CreateAccessibleDocumentView(). + // However, the dynamic cast together with the check of the result + // being NULL should be safe enough. + ::accessibility::AccessibleSlideSorterView* pAccessibleView + = dynamic_cast< ::accessibility::AccessibleSlideSorterView*>(xAccessible.get()); + if (pAccessibleView == NULL) + break; + + ::accessibility::AccessibleSlideSorterObject* pChild + = pAccessibleView->GetAccessibleChildImplementation(nPageIndex); + if (pChild == NULL || pChild->GetPage() == NULL) + break; + + ::rtl::OUString sOldName (rsOldName); + ::rtl::OUString sNewName (pChild->GetPage()->GetName()); + pChild->FireAccessibleEvent( + ::com::sun::star::accessibility::AccessibleEventId::NAME_CHANGED, + makeAny(sOldName), + makeAny(sNewName)); + } + while (false); +} + + + + +bool SlideSorterController::IsContextMenuOpen (void) const +{ + return mbIsContextMenuOpen; +} + + + + +::boost::shared_ptr<Properties> SlideSorterController::GetProperties (void) const +{ + return mpProperties; +} + + + + +void SlideSorterController::SetDocumentSlides (const Reference<container::XIndexAccess>& rxSlides) +{ + if (mrModel.GetDocumentSlides() != rxSlides) + { + ModelChangeLock aLock (*this); + PreModelChange(); + + mrModel.SetDocumentSlides(rxSlides); + mrView.Layout(); + } +} + + + + +::boost::shared_ptr<Animator> SlideSorterController::GetAnimator (void) const +{ + return mpAnimator; +} + + + + +//===== SlideSorterController::ModelChangeLock ================================ + +SlideSorterController::ModelChangeLock::ModelChangeLock ( + SlideSorterController& rController) + : mpController(&rController) +{ + mpController->LockModelChange(); +} + + + + +SlideSorterController::ModelChangeLock::~ModelChangeLock (void) +{ + Release(); +} + + + + +void SlideSorterController::ModelChangeLock::Release (void) +{ + if (mpController != NULL) + { + mpController->UnlockModelChange(); + mpController = NULL; + } +} + +} } } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/controller/SlsAnimator.cxx b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx new file mode 100644 index 000000000000..9878d7b36a47 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsAnimator.cxx,v $ + * + * $Revision: 1.3 $ + * + * 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 "precompiled_sd.hxx" +#include "controller/SlsAnimator.hxx" +#include "view/SlideSorterView.hxx" +#include "View.hxx" + +namespace sd { namespace slidesorter { namespace controller { + +namespace { + static const sal_Int32 gnResolution = 25; +} +/** Handle one animation function by using a timer for frequent calls to + the animations operator(). +*/ +class Animator::Animation +{ +public: + Animation ( + const Animator::AnimationFunction& rAnimation, + const double nDelta); + ~Animation (void); + bool Run (void); + bool IsExpired (void); + Animator::AnimationFunction maAnimation; + double mnValue; + double mnDelta; +}; + + + + +class Animator::DrawLock +{ +public: + DrawLock (View& rView); + ~DrawLock (void); + +private: + View& mrView; +}; + + + + +Animator::Animator (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maTimer(), + maAnimations(), + mpDrawLock() +{ + maTimer.SetTimeout(gnResolution); + maTimer.SetTimeoutHdl(LINK(this,Animator,TimeoutHandler)); +} + + + + +Animator::~Animator (void) +{ + maTimer.Stop(); + mpDrawLock.reset(); +} + + + + +void Animator::AddAnimation ( + const AnimationFunction& rAnimation, + const sal_Int32 nDuration) +{ + const double nDelta = double(gnResolution) / double(nDuration); + maAnimations.push_back(boost::shared_ptr<Animation>(new Animation(rAnimation, nDelta))); + + // Prevent redraws except for the ones in TimeoutHandler. + // While the Animator is active it will schedule repaints regularly. + // Repaints in between would only lead to visual artifacts. + mpDrawLock.reset(new DrawLock(mrSlideSorter.GetView())); + maTimer.Start(); +} + + + + +bool Animator::ServeAnimations (void) +{ + bool bExpired (false); + + AnimationList aCopy (maAnimations); + AnimationList::const_iterator iAnimation; + for (iAnimation=aCopy.begin(); iAnimation!=aCopy.end(); ++iAnimation) + { + bExpired |= (*iAnimation)->Run(); + } + + return bExpired; +} + + + + +void Animator::CleanUpAnimationList (void) +{ + AnimationList aActiveAnimations; + + AnimationList::const_iterator iAnimation; + for (iAnimation=maAnimations.begin(); iAnimation!=maAnimations.end(); ++iAnimation) + { + if ( ! (*iAnimation)->IsExpired()) + aActiveAnimations.push_back(*iAnimation); + } + + maAnimations.swap(aActiveAnimations); +} + + + + +IMPL_LINK(Animator, TimeoutHandler, Timer*, EMPTYARG) +{ + if (ServeAnimations()) + CleanUpAnimationList(); + + // Unlock the draw lock. This should lead to a repaint. + mpDrawLock.reset(); + + if (maAnimations.size() > 0) + { + mpDrawLock.reset(new DrawLock(mrSlideSorter.GetView())); + maTimer.Start(); + } + + return 0; +} + + + + +//===== Animator::Animation =================================================== + +Animator::Animation::Animation ( + const Animator::AnimationFunction& rAnimation, + const double nDelta) + : maAnimation(rAnimation), + mnValue(0), + mnDelta(nDelta) +{ + + maAnimation(mnValue); + mnValue = mnDelta; + +} + + + + +Animator::Animation::~Animation (void) +{ +} + + + + +bool Animator::Animation::Run (void) +{ + if (mnValue < 1.0) + { + maAnimation(mnValue); + mnValue += mnDelta; + return false; + } + else + { + maAnimation(1.0); + return true; + } +} + + + + +bool Animator::Animation::IsExpired (void) +{ + return mnValue >= 1.0; +} + + + + +//===== Animator::DrawLock ==================================================== + +Animator::DrawLock::DrawLock (View& rView) + : mrView(rView) +{ + mrView.LockRedraw(TRUE); +} + + + + +Animator::DrawLock::~DrawLock (void) +{ + mrView.LockRedraw(FALSE); +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx new file mode 100644 index 000000000000..805628396a35 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx @@ -0,0 +1,781 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsClipboard.cxx,v $ + * $Revision: 1.27 $ + * + * 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 "precompiled_sd.hxx" + +#include "controller/SlsClipboard.hxx" + +#include "SlideSorterViewShell.hxx" +#include "SlideSorter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsViewOverlay.hxx" +#include "view/SlsPageObject.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "SlsTransferable.hxx" + +#include "ViewShellBase.hxx" +#include "DrawViewShell.hxx" +#include "Window.hxx" +#include "fupoor.hxx" +#include "fuslhide.hxx" +#include "fuzoom.hxx" +#include "fucushow.hxx" +#include "fusldlg.hxx" +#include "fuexpand.hxx" +#include "fusumry.hxx" +#include "app.hrc" +#include "glob.hrc" +#include "strings.hrc" +#include "sdresid.hxx" +#include "sdxfer.hxx" +#include "sdmod.hxx" +#include "sddll.hxx" +#include "ins_paste.hxx" +#include "drawdoc.hxx" +#include "DrawDocShell.hxx" +#include "sdpage.hxx" + +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/docfile.hxx> +#include <svx/svxids.hrc> +#include <vcl/msgbox.hxx> +#include <tools/urlobj.hxx> +#include <rtl/ustring.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +namespace sd { namespace slidesorter { namespace controller { + + +Clipboard::Clipboard (SlideSorter& rSlideSorter) + : ViewClipboard(rSlideSorter.GetView()), + mrSlideSorter(rSlideSorter), + mrController(mrSlideSorter.GetController()), + maPagesToRemove(), + maPagesToSelect(), + mbUpdateSelectionPending(false) +{ +} + + + + +Clipboard::~Clipboard (void) +{ +} + + + + +/** With the current implementation the forwarded calls to the current + function will come back eventually to call the local Do(Cut|Copy|Paste) + methods. A shortcut is possible but would be an unclean hack. +*/ +void Clipboard::HandleSlotCall (SfxRequest& rRequest) +{ + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + FunctionReference xFunc; + if (pViewShell != NULL) + xFunc = pViewShell->GetCurrentFunction(); + switch (rRequest.GetSlot()) + { + case SID_CUT: + if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE) + { + if(xFunc.is()) + xFunc->DoCut(); + else + DoCut(); + } + rRequest.Done(); + break; + + case SID_COPY: + if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE) + { + if(xFunc.is()) + xFunc->DoCopy(); + else + DoCopy(); + } + rRequest.Done(); + break; + + case SID_PASTE: + // Prevent redraws while inserting pages from the clipboard + // because the intermediate inconsistent state might lead to + // a crash. + if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE) + { + mrSlideSorter.GetView().LockRedraw (TRUE); + if(xFunc.is()) + xFunc->DoPaste(); + else + DoPaste(); + mrController.GetSelectionManager()->MakeSelectionVisible(); + mrSlideSorter.GetView().LockRedraw(FALSE); + } + rRequest.Done(); + break; + + case SID_DELETE: + DoDelete(); + rRequest.Done(); + break; + } +} + + + + +void Clipboard::DoCut (::Window* pWindow) +{ + if (mrSlideSorter.GetModel().GetPageCount() > 1) + { + DoCopy(pWindow); + DoDelete(pWindow); + } +} + + + + +void Clipboard::DoDelete (::Window* ) +{ + if (mrSlideSorter.GetModel().GetPageCount() > 1) + { + mrController.GetSelectionManager()->DeleteSelectedPages(); + } +} + + + + +void Clipboard::DoCopy (::Window* pWindow ) +{ + CreateSlideTransferable( pWindow, FALSE ); +} + + + + +void Clipboard::DoPaste (::Window* pWindow) +{ + SdTransferable* pClipTransferable = SD_MOD()->pTransferClip; + + if (pClipTransferable!=NULL && pClipTransferable->IsPageTransferable()) + { + sal_Int32 nInsertPosition = GetInsertionPosition(pWindow); + + if (nInsertPosition >= 0) + { + // Paste the pages from the clipboard. + sal_Int32 nInsertPageCount = PasteTransferable(nInsertPosition); + // Select the pasted pages and make the first of them the + // current page. + mrSlideSorter.GetView().GetWindow()->GrabFocus(); + SelectPageRange(nInsertPosition, nInsertPageCount); + } + } +} + + + + +sal_Int32 Clipboard::GetInsertionPosition (::Window* pWindow) +{ + sal_Int32 nInsertPosition = -1; + + // Determine the insertion position: + // a) When the insertion indicator is visible, then at that position. + // b) When the focus indicator is visible, then before or after the + // focused page, depending on user input to a dialog. + // c) When there is a selection but no focus, then after the + // selection. + // d) After the last page when there is no selection and no focus. + + view::InsertionIndicatorOverlay& rInsertionIndicatorOverlay ( + mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay()); + if (rInsertionIndicatorOverlay.isVisible()) + { + nInsertPosition = rInsertionIndicatorOverlay.GetInsertionPageIndex(); + } + else if (mrController.GetFocusManager().IsFocusShowing()) + { + SdInsertPasteDlg aDialog (pWindow); + if (aDialog.Execute() == RET_OK) + { + nInsertPosition = mrController.GetFocusManager().GetFocusedPageIndex(); + if ( ! aDialog.IsInsertBefore()) + nInsertPosition ++; + } + } + else + { + nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition(); + } + + return nInsertPosition; +} + + + + +sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) +{ + SdTransferable* pClipTransferable = SD_MOD()->pTransferClip; + bool bMergeMasterPages = !pClipTransferable->HasSourceDoc ( + mrSlideSorter.GetModel().GetDocument()); + USHORT nInsertIndex ((USHORT)(nInsertPosition * 2 + 1)); + sal_Int32 nInsertPageCount (0); + if (pClipTransferable->HasPageBookmarks()) + { + const List& rBookmarkList = pClipTransferable->GetPageBookmarks(); + const ::vos::OGuard aGuard (Application::GetSolarMutex()); + + nInsertPageCount = (USHORT) rBookmarkList.Count(); + mrSlideSorter.GetModel().GetDocument()->InsertBookmarkAsPage( + const_cast<List*>(&rBookmarkList), + NULL, + FALSE, + FALSE, + nInsertIndex, + FALSE, + pClipTransferable->GetPageDocShell(), + TRUE, + bMergeMasterPages, + FALSE); + } + else + { + SfxObjectShell* pShell = pClipTransferable->GetDocShell(); + DrawDocShell* pDataDocSh = (DrawDocShell*)pShell; + SdDrawDocument* pDataDoc = pDataDocSh->GetDoc(); + + if (pDataDoc!=NULL + && pDataDoc->GetSdPageCount(PK_STANDARD)) + { + const ::vos::OGuard aGuard (Application::GetSolarMutex()); + + bMergeMasterPages = (pDataDoc != mrSlideSorter.GetModel().GetDocument()); + nInsertPageCount = pDataDoc->GetSdPageCount( PK_STANDARD ); + mrSlideSorter.GetModel().GetDocument()->InsertBookmarkAsPage( + NULL, + NULL, + FALSE, + FALSE, + nInsertIndex, + FALSE, + pDataDocSh, + TRUE, + bMergeMasterPages, + FALSE); + } + } + mrController.HandleModelChange(); + return nInsertPageCount; +} + + + + +void Clipboard::SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount) +{ + // Select the newly inserted pages. That are the nInsertPageCount pages + // after the nInsertIndex position. + PageSelector& rSelector (mrController.GetPageSelector()); + rSelector.DeselectAllPages(); + for (USHORT i=0; i<nPageCount; i++) + { + model::SharedPageDescriptor pDescriptor ( + mrSlideSorter.GetModel().GetPageDescriptor(nFirstIndex + i)); + if (pDescriptor.get() != NULL) + { + rSelector.SelectPage(pDescriptor); + // The first page of the new selection is made the current page. + if (i == 0) + { + mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + mrController.GetFocusManager().SetFocusedPage(pDescriptor); + } + } + } +} + + + + +void Clipboard::CreateSlideTransferable ( + ::Window* pWindow, + bool bDrag) +{ + List aBookmarkList; + + // Insert all selected pages into a bookmark list and remember them in + // maPagesToRemove for possible later removal. + model::PageEnumeration aSelectedPages + (model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + aBookmarkList.Insert ( + new String(pDescriptor->GetPage()->GetName()), + LIST_APPEND); + maPagesToRemove.push_back (pDescriptor->GetPage()); + } + + if (aBookmarkList.Count() > 0) + { + mrSlideSorter.GetView().BrkAction(); + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + SdTransferable* pTransferable = new Transferable ( + pDocument, + NULL, + FALSE, + dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell())); + + if (bDrag) + SD_MOD()->pTransferDrag = pTransferable; + else + SD_MOD()->pTransferClip = pTransferable; + + pDocument->CreatingDataObj (pTransferable); + pTransferable->SetWorkDocument( dynamic_cast<SdDrawDocument*>(pDocument->AllocModel()) ); + pDocument->CreatingDataObj (NULL); + TransferableObjectDescriptor aObjDesc; + pTransferable->GetWorkDocument()->GetDocSh() + ->FillTransferableObjectDescriptor (aObjDesc); + + if (pDocument->GetDocSh() != NULL) + aObjDesc.maDisplayName = pDocument->GetDocSh() + ->GetMedium()->GetURLObject().GetURLNoPass(); + + ::Window* pActionWindow = pWindow; + if (pActionWindow == NULL) + { + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL) + pActionWindow = pViewShell->GetActiveWindow(); + } + + pTransferable->SetStartPos (pActionWindow->PixelToLogic( + pActionWindow->GetPointerPosPixel())); + pTransferable->SetObjectDescriptor (aObjDesc); + pTransferable->SetPageBookmarks (aBookmarkList, !bDrag); + + for (void* p=aBookmarkList.First(); p!=NULL; p=aBookmarkList.Next()) + delete static_cast<String*>(p); + + if (bDrag) + { + pTransferable->SetView (&mrSlideSorter.GetView()); + sal_Int8 nDragSourceActions (DND_ACTION_COPY); + // The move action is available only when not all pages would be + // moved. Otherwise an empty document would remain. Crash. + sal_Int32 nRemainingPages = mrSlideSorter.GetModel().GetPageCount() - aBookmarkList.Count(); + if (nRemainingPages > 0) + nDragSourceActions |= DND_ACTION_MOVE; + pTransferable->StartDrag (pActionWindow, nDragSourceActions); + } + else + pTransferable->CopyToClipboard (pActionWindow); + } +} + + + + +void Clipboard::StartDrag ( + const Point&, + ::Window* pWindow) +{ + maPagesToRemove.clear(); + maPagesToSelect.clear(); + mbUpdateSelectionPending = false; + CreateSlideTransferable (pWindow, TRUE); +} + + + + +void Clipboard::DragFinished (sal_Int8 nDropAction) +{ + // Hide the substitution display and insertion indicator. + mrSlideSorter.GetView().GetOverlay().GetSubstitutionOverlay().setVisible(false); + mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay().setVisible(false); + + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + + if (pDragTransferable != NULL) + pDragTransferable->SetView (NULL); + + PageSelector& rSelector (mrController.GetPageSelector()); + if ((nDropAction & DND_ACTION_MOVE) != 0 + && ! maPagesToRemove.empty()) + { + // Remove the pages that have been moved to another place (possibly + // in the same document.) + rSelector.DeselectAllPages(); + PageList::iterator aDraggedPage; + for (aDraggedPage=maPagesToRemove.begin(); + aDraggedPage!=maPagesToRemove.end(); + aDraggedPage++) + { + rSelector.SelectPage (*aDraggedPage); + } + mrController.GetSelectionManager()->DeleteSelectedPages (); + } + + SelectPages(); +} + + + + +void Clipboard::SelectPages (void) +{ + PageSelector& rSelector (mrController.GetPageSelector()); + + // Select the dropped pages. + PageList::iterator iPage; + rSelector.DeselectAllPages(); + for (iPage=maPagesToSelect.begin(); iPage!=maPagesToSelect.end(); ++iPage) + { + rSelector.SelectPage(*iPage); + } +} + + + + +sal_Int8 Clipboard::AcceptDrop ( + const AcceptDropEvent& rEvent, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow, + USHORT nPage, + USHORT nLayer) +{ + sal_Int8 nResult = DND_ACTION_NONE; + + switch (IsDropAccepted()) + { + case DT_PAGE: + { + // Accept a drop. + nResult = rEvent.mnAction; + + // Use the copy action when the drop action is the default, i.e. not + // explicitly set to move or link, and when the source and + // target models are not the same. + const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + if (pDragTransferable != NULL + && pDragTransferable->IsPageTransferable() + && ((rEvent.maDragEvent.DropAction + & ::com::sun::star::datatransfer::dnd::DNDConstants::ACTION_DEFAULT) != 0) + && (mrSlideSorter.GetModel().GetDocument()->GetDocSh() + != pDragTransferable->GetPageDocShell())) + { + nResult = DND_ACTION_COPY; + } + + // Show the insertion marker and the substitution for a drop. + Point aPosition = pTargetWindow->PixelToLogic (rEvent.maPosPixel); + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + rOverlay.GetInsertionIndicatorOverlay().SetPosition (aPosition); + rOverlay.GetInsertionIndicatorOverlay().setVisible(true); + rOverlay.GetSubstitutionOverlay().SetPosition (aPosition); + + // Scroll the window when the mouse reaches the window border. + mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel); + } + break; + + case DT_SHAPE: + nResult = ExecuteOrAcceptShapeDrop( + DC_ACCEPT, + rEvent.maPosPixel, + &rEvent, + rTargetHelper, + pTargetWindow, + nPage, + nLayer); + break; + default: + break; + } + + return nResult; +} + + + + +sal_Int8 Clipboard::ExecuteDrop ( + const ExecuteDropEvent& rEvent, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow, + USHORT nPage, + USHORT nLayer) +{ + sal_Int8 nResult = DND_ACTION_NONE; + + switch (IsDropAccepted()) + { + case DT_PAGE: + { + const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + const Point aEventModelPosition ( + pTargetWindow->PixelToLogic (rEvent.maPosPixel)); + long int nXOffset = labs (pDragTransferable->GetStartPos().X() + - aEventModelPosition.X()); + long int nYOffset = labs (pDragTransferable->GetStartPos().Y() + - aEventModelPosition.Y()); + const bool bContinue = + ( pDragTransferable->GetView() != &mrSlideSorter.GetView() ) + || ( nXOffset >= 2 && nYOffset >= 2 ); + + // Get insertion position and then turn off the insertion indicator. + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + rOverlay.GetInsertionIndicatorOverlay().SetPosition( + aEventModelPosition); + USHORT nIndex = DetermineInsertPosition (*pDragTransferable); + OSL_TRACE ("Clipboard::AcceptDrop() called for index %d", + nIndex); + rOverlay.GetInsertionIndicatorOverlay().setVisible(false); + + if (bContinue) + { + SlideSorterController::ModelChangeLock aModelChangeLock (mrController); + + if (pDragTransferable->GetView() == &mrSlideSorter.GetView() + && rEvent.mnAction == DND_ACTION_MOVE) + { + // We are asked to move pages inside one view. For this we + // call MoveSelectedPages() which is faster than going the + // generic way. + + // Remember to select the moved pages afterwards. + maPagesToRemove.swap(maPagesToSelect); + maPagesToRemove.clear(); + + USHORT nSdrModelIndex; + if (nIndex != SDRPAGE_NOTFOUND) + nSdrModelIndex = nIndex / 2 - 1; + else + nSdrModelIndex = SDRPAGE_NOTFOUND; + mrController.GetSelectionManager()->MoveSelectedPages(nSdrModelIndex); + mbUpdateSelectionPending = true; + nResult = DND_ACTION_NONE; + } + else + { + // Handle a general drop operation. + HandlePageDrop (*pDragTransferable); + nResult = rEvent.mnAction; + } + } + } + break; + + case DT_SHAPE: + nResult = ExecuteOrAcceptShapeDrop( + DC_EXECUTE, + rEvent.maPosPixel, + &rEvent, + rTargetHelper, + pTargetWindow, + nPage, + nLayer); + break; + default: + break; + } + + return nResult; +} + + + + +USHORT Clipboard::DetermineInsertPosition (const SdTransferable& ) +{ + USHORT nInsertPosition = SDRPAGE_NOTFOUND; + + // Tell the model to move the dragged pages behind the one with the + // index nInsertionIndex which first has to be transformed into an index + // understandable by the document. + view::InsertionIndicatorOverlay& rOverlay ( + mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay()); + sal_Int32 nInsertionIndex (rOverlay.GetInsertionPageIndex()); + + // The index returned by the overlay starts with 1 for the first slide. + // This is now converted that to an SdModel index that also starts with 1. + if (nInsertionIndex >= 0) + nInsertPosition = (USHORT)nInsertionIndex * 2 + 1; + + return nInsertPosition; +} + + + + +USHORT Clipboard::InsertSlides ( + const SdTransferable& rTransferable, + USHORT nInsertPosition) +{ + USHORT nInsertedPageCount = ViewClipboard::InsertSlides ( + rTransferable, + nInsertPosition); + + // Remember the inserted pages so that they can be selected when the + // operation is finished. + int nDocumentIndex = nInsertPosition / 2 - 1; + for (USHORT i=1; i<=nInsertedPageCount; i++) + { + model::SharedPageDescriptor pDescriptor ( + mrSlideSorter.GetModel().GetPageDescriptor(nDocumentIndex + i)); + if (pDescriptor.get() != NULL) + maPagesToSelect.push_back (pDescriptor->GetPage()); + } + + mbUpdateSelectionPending |= (nInsertedPageCount>0); + + return nInsertedPageCount; +} + + + + +Clipboard::DropType Clipboard::IsDropAccepted (void) const +{ + DropType eResult (DT_NONE); + + const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + if (pDragTransferable != NULL) + { + if (pDragTransferable->IsPageTransferable()) + { + if (mrSlideSorter.GetModel().GetEditMode() != EM_MASTERPAGE) + eResult = DT_PAGE; + } + else + { + eResult = DT_SHAPE; + } + } + + return eResult; +} + + + + +sal_Int8 Clipboard::ExecuteOrAcceptShapeDrop ( + DropCommand eCommand, + const Point& rPosition, + const void* pDropEvent, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow, + USHORT nPage, + USHORT nLayer) +{ + sal_Int8 nResult = 0; + + // The dropping of a shape is accepted or executed only when there is + // DrawViewShell available to which we can forward this call. This has + // technical reasons: The actual code to accept or execute a shape drop + // is implemented in the ViewShell class and uses the page view of the + // main edit view. This is not possible without a DrawViewShell. + ::boost::shared_ptr<DrawViewShell> pDrawViewShell; + if (mrSlideSorter.GetViewShell() != NULL) + pDrawViewShell = ::boost::dynamic_pointer_cast<DrawViewShell>( + mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell()); + if (pDrawViewShell.get() != NULL + && (pDrawViewShell->GetShellType() == ViewShell::ST_IMPRESS + || pDrawViewShell->GetShellType() == ViewShell::ST_DRAW)) + { + // The drop is only accepted or executed when it takes place over a + // page object. Therefore we replace a missing page number by the + // number of the page under the mouse. + if (nPage == SDRPAGE_NOTFOUND) + { + model::SharedPageDescriptor pDescriptor ( + mrSlideSorter.GetModel().GetPageDescriptor( + mrSlideSorter.GetView().GetPageIndexAtPoint(rPosition))); + if (pDescriptor.get() != NULL && pDescriptor->GetPage()!=NULL) + nPage = (pDescriptor->GetPage()->GetPageNum() - 1) / 2; + } + + // Now comes the code that is different for the Execute and Accept: + // We simply forward the call to the AcceptDrop() or ExecuteDrop() + // methods of the DrawViewShell in the center pane. + if (nPage != SDRPAGE_NOTFOUND) + switch (eCommand) + { + case DC_ACCEPT: + nResult = pDrawViewShell->AcceptDrop( + *reinterpret_cast<const AcceptDropEvent*>(pDropEvent), + rTargetHelper, + pTargetWindow, + nPage, + nLayer); + break; + + case DC_EXECUTE: + nResult = pDrawViewShell->ExecuteDrop( + *reinterpret_cast<const ExecuteDropEvent*>(pDropEvent), + rTargetHelper, + pTargetWindow, + nPage, + nLayer); + break; + } + } + + return nResult; +} + + + +} } } // end of namespace ::sd::slidesorter::controller + diff --git a/sd/source/ui/slidesorter/controller/SlsCommand.hxx b/sd/source/ui/slidesorter/controller/SlsCommand.hxx new file mode 100644 index 000000000000..1ef89357eebc --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsCommand.hxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCommand.hxx,v $ + * $Revision: 1.4 $ + * + * 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 SD_SLIDESORTER_COMMAND_HXX +#define SD_SLIDESORTER_COMMAND_HXX + +namespace sd { namespace slidesorter { namespace controller { + +/** Base class for command objects. It specifies the interface for commands + whose execution can be scheduled via the SlotManager. +*/ +class Command +{ +public: + virtual ~Command (void) {}; + virtual void operator() (void) = 0; +}; + +} } } // end of namespace sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx new file mode 100644 index 000000000000..9220532239ab --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx @@ -0,0 +1,275 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCurrentSlideManager.cxx,v $ + * + * $Revision: 1.5 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlideSorter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "ViewShellBase.hxx" +#include "ViewShell.hxx" +#include "DrawViewShell.hxx" +#include "sdpage.hxx" +#include "FrameView.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using namespace ::sd::slidesorter::model; + +namespace sd { namespace slidesorter { namespace controller { + +CurrentSlideManager::CurrentSlideManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mnCurrentSlideIndex(-1), + mpCurrentSlide() +{ +} + + + + +CurrentSlideManager::~CurrentSlideManager (void) +{ +} + + + + +void CurrentSlideManager::CurrentSlideHasChanged (const sal_Int32 nSlideIndex) +{ + if (mnCurrentSlideIndex != nSlideIndex) + { + ReleaseCurrentSlide(); + AcquireCurrentSlide(nSlideIndex); + + // Update the selection. + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + if (mpCurrentSlide.get() != NULL) + mrSlideSorter.GetController().GetPageSelector().SelectPage(mpCurrentSlide); + } +} + + + + +void CurrentSlideManager::ReleaseCurrentSlide (void) +{ + if (mpCurrentSlide.get() != NULL) + { + mpCurrentSlide->SetIsCurrentPage(false); + mrSlideSorter.GetView().RequestRepaint(mpCurrentSlide); + } + + mpCurrentSlide.reset(); + mnCurrentSlideIndex = -1; +} + + + + +bool CurrentSlideManager::IsCurrentSlideIsValid (void) +{ + return mnCurrentSlideIndex >= 0 && mnCurrentSlideIndex<mrSlideSorter.GetModel().GetPageCount(); +} + + + + +void CurrentSlideManager::AcquireCurrentSlide (const sal_Int32 nSlideIndex) +{ + mnCurrentSlideIndex = nSlideIndex; + + if (IsCurrentSlideIsValid()) + { + // Get a descriptor for the XDrawPage reference. Note that the + // given XDrawPage may or may not be member of the slide sorter + // document. + mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor(mnCurrentSlideIndex); + if (mpCurrentSlide.get() != NULL) + { + mpCurrentSlide->SetIsCurrentPage(true); + mrSlideSorter.GetView().RequestRepaint(mpCurrentSlide); + } + } +} + + + + +void CurrentSlideManager::SwitchCurrentSlide (const sal_Int32 nSlideIndex) +{ + SwitchCurrentSlide(mrSlideSorter.GetModel().GetPageDescriptor(nSlideIndex)); +} + + + + +void CurrentSlideManager::SwitchCurrentSlide (const SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get() != NULL) + { + mpCurrentSlide = rpDescriptor; + mnCurrentSlideIndex = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL && pViewShell->IsMainViewShell()) + { + FrameView* pFrameView = pViewShell->GetFrameView(); + if (pFrameView != NULL) + pFrameView->SetSelectedPage(sal::static_int_cast<USHORT>(mnCurrentSlideIndex)); + } + else + { + // Set current page. At the moment we have to do this in two + // different ways. The UNO way is the preferable one but, alas, + // it does not work always correctly (after some kinds of model + // changes). Therefore, we call DrawViewShell::SwitchPage(), + // too. + SetCurrentSlideAtViewShellBase(rpDescriptor); + SetCurrentSlideAtXController(rpDescriptor); + } + } +} + + + + +void CurrentSlideManager::SetCurrentSlideAtViewShellBase (const SharedPageDescriptor& rpDescriptor) +{ + OSL_ASSERT(rpDescriptor.get() != NULL); + + ViewShellBase* pBase = mrSlideSorter.GetViewShellBase(); + if (pBase != NULL) + { + DrawViewShell* pDrawViewShell = dynamic_cast<DrawViewShell*>( + pBase->GetMainViewShell().get()); + if (pDrawViewShell != NULL) + { + USHORT nPageNumber = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + pDrawViewShell->SwitchPage(nPageNumber); + pDrawViewShell->GetPageTabControl()->SetCurPageId(nPageNumber+1); + } + /* + else + { + presenter::PresenterViewShell* pPresenterViewShell + = dynamic_cast<presenter::PresenterViewShell*>(pBase->GetMainViewShell()); + if (pPresenterViewShell != NULL) + { + pPresenterViewShell->SetCurrentSlide( + Reference<drawing::XDrawPage>( + rpDescriptor->GetPage()->getUnoPage(), UNO_QUERY)); + } + } + */ + } +} + + + + +void CurrentSlideManager::SetCurrentSlideAtXController (const SharedPageDescriptor& rpDescriptor) +{ + OSL_ASSERT(rpDescriptor.get() != NULL); + + try + { + Reference<beans::XPropertySet> xSet (mrSlideSorter.GetXController(), UNO_QUERY); + if (xSet.is()) + { + Any aPage; + aPage <<= rpDescriptor->GetPage()->getUnoPage(); + xSet->setPropertyValue ( + String::CreateFromAscii("CurrentPage"), + aPage); + } + } + catch (beans::UnknownPropertyException aException) + { + // We have not been able to set the current page at the main view. + // This is sad but still leaves us in a valid state. Therefore, + // this exception is silently ignored. + } +} + + + + +SharedPageDescriptor CurrentSlideManager::GetCurrentSlide (void) +{ + return mpCurrentSlide; +} + + + + +void CurrentSlideManager::PrepareModelChange (void) +{ + mpCurrentSlide.reset(); +} + + + + +void CurrentSlideManager::HandleModelChange (void) +{ + if (mnCurrentSlideIndex >= 0) + { + mpCurrentSlide = mrSlideSorter.GetModel().GetPageDescriptor( + mnCurrentSlideIndex); + if (mpCurrentSlide.get() != NULL) + mpCurrentSlide->SetIsCurrentPage(true); + } +} + + + + +SdPage* GetCurrentSdPage (SlideSorter& rSlideSorter) +{ + SharedPageDescriptor pDescriptor ( + rSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); + if (pDescriptor.get() == NULL) + return NULL; + else + return pDescriptor->GetPage(); +} + + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx new file mode 100644 index 000000000000..009a24910d5a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx @@ -0,0 +1,360 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsFocusManager.cxx,v $ + * $Revision: 1.14 $ + * + * 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 "precompiled_sd.hxx" +#include "controller/SlsFocusManager.hxx" + +#include "SlideSorter.hxx" +#include "PaneDockingWindow.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include <vcl/toolbox.hxx> + +#include "Window.hxx" +#include "sdpage.hxx" + +namespace sd { namespace slidesorter { namespace controller { + +FocusManager::FocusManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mnPageIndex(0), + mbPageIsFocused(false) +{ + if (mrSlideSorter.GetModel().GetPageCount() > 0) + mnPageIndex = 0; +} + + + + +FocusManager::~FocusManager (void) +{ +} + + + + +void FocusManager::MoveFocus (FocusMoveDirection eDirection) +{ + if (mnPageIndex >= 0 && mbPageIsFocused) + { + HideFocusIndicator (GetFocusedPageDescriptor()); + + int nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount()); + switch (eDirection) + { + case FMD_NONE: + if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) + mnPageIndex = mrSlideSorter.GetModel().GetPageCount() - 1; + break; + + case FMD_LEFT: + mnPageIndex -= 1; + if (mnPageIndex < 0) + { + mnPageIndex = mrSlideSorter.GetModel().GetPageCount() - 1; + SetFocusToToolBox(); + } + break; + + case FMD_RIGHT: + mnPageIndex += 1; + if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) + { + mnPageIndex = 0; + SetFocusToToolBox(); + } + break; + + case FMD_UP: + { + int nColumn = mnPageIndex % nColumnCount; + mnPageIndex -= nColumnCount; + if (mnPageIndex < 0) + { + // Wrap arround to the bottom row or the one above and + // go to the correct column. + int nCandidate = mrSlideSorter.GetModel().GetPageCount()-1; + int nCandidateColumn = nCandidate % nColumnCount; + if (nCandidateColumn > nColumn) + mnPageIndex = nCandidate - (nCandidateColumn-nColumn); + else if (nCandidateColumn < nColumn) + mnPageIndex = nCandidate + - nColumnCount + + (nColumn - nCandidateColumn); + else + mnPageIndex = nCandidate; + } + } + break; + + case FMD_DOWN: + { + int nColumn = mnPageIndex % nColumnCount; + mnPageIndex += nColumnCount; + if (mnPageIndex >= mrSlideSorter.GetModel().GetPageCount()) + { + // Wrap arround to the correct column. + mnPageIndex = nColumn; + } + } + break; + } + + if (mbPageIsFocused) + ShowFocusIndicator(GetFocusedPageDescriptor()); + } +} + + + + +void FocusManager::ShowFocus (void) +{ + mbPageIsFocused = true; + ShowFocusIndicator(GetFocusedPageDescriptor()); +} + + + + +void FocusManager::HideFocus (void) +{ + mbPageIsFocused = false; + HideFocusIndicator(GetFocusedPageDescriptor()); +} + + + + +bool FocusManager::ToggleFocus (void) +{ + if (mnPageIndex >= 0) + { + if (mbPageIsFocused) + HideFocus (); + else + ShowFocus (); + } + return mbPageIsFocused; +} + + + + +bool FocusManager::HasFocus (void) const +{ + return mrSlideSorter.GetView().GetWindow()->HasFocus(); +} + + + + +model::SharedPageDescriptor FocusManager::GetFocusedPageDescriptor (void) const +{ + return mrSlideSorter.GetModel().GetPageDescriptor(mnPageIndex); +} + + + + +sal_Int32 FocusManager::GetFocusedPageIndex (void) const +{ + return mnPageIndex; +} + + + + +void FocusManager::FocusPage (sal_Int32 nPageIndex) +{ + if (nPageIndex != mnPageIndex) + { + // Hide the focus while switching it to the specified page. + FocusHider aHider (*this); + mnPageIndex = nPageIndex; + } + + if (HasFocus() && !IsFocusShowing()) + ShowFocus(); +} + + + + +void FocusManager::SetFocusedPage (const model::SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get() != NULL) + { + FocusHider aFocusHider (*this); + mnPageIndex = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + } +} + + + + +void FocusManager::SetFocusedPage (sal_Int32 nPageIndex) +{ + FocusHider aFocusHider (*this); + mnPageIndex = nPageIndex; +} + + + + +bool FocusManager::IsFocusShowing (void) const +{ + return HasFocus() && mbPageIsFocused; +} + + + + +void FocusManager::HideFocusIndicator (const model::SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get() != NULL) + { + rpDescriptor->RemoveFocus(); + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); + } +} + + + + +void FocusManager::ShowFocusIndicator (const model::SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get() != NULL) + { + rpDescriptor->SetFocus (); + + // Scroll the focused page object into the visible area and repaint + // it, so that the focus indicator becomes visible. + view::SlideSorterView& rView (mrSlideSorter.GetView()); + mrSlideSorter.GetController().GetSelectionManager()->MakeRectangleVisible ( + rView.GetPageBoundingBox ( + GetFocusedPageDescriptor(), + view::SlideSorterView::CS_MODEL, + view::SlideSorterView::BBT_INFO)); + + mrSlideSorter.GetView().RequestRepaint (rpDescriptor); + NotifyFocusChangeListeners(); + } +} + + + + +void FocusManager::AddFocusChangeListener (const Link& rListener) +{ + if (::std::find (maFocusChangeListeners.begin(), maFocusChangeListeners.end(), rListener) + == maFocusChangeListeners.end()) + { + maFocusChangeListeners.push_back (rListener); + } +} + + + + +void FocusManager::RemoveFocusChangeListener (const Link& rListener) +{ + maFocusChangeListeners.erase ( + ::std::find (maFocusChangeListeners.begin(), maFocusChangeListeners.end(), rListener)); +} + + + + +void FocusManager::SetFocusToToolBox (void) +{ + HideFocus(); + + if (mrSlideSorter.GetViewShell() != NULL) + { + ::Window* pParentWindow = mrSlideSorter.GetViewShell()->GetParentWindow(); + DockingWindow* pDockingWindow = NULL; + while (pParentWindow!=NULL && pDockingWindow==NULL) + { + pDockingWindow = dynamic_cast<DockingWindow*>(pParentWindow); + pParentWindow = pParentWindow->GetParent(); + } + if (pDockingWindow) + { + PaneDockingWindow* pPaneDockingWindow = dynamic_cast<PaneDockingWindow*>(pDockingWindow); + if (pPaneDockingWindow != NULL) + pPaneDockingWindow->GetTitleToolBox()->GrabFocus(); + } + } +} + + + + +void FocusManager::NotifyFocusChangeListeners (void) const +{ + // Create a copy of the listener list to be safe when that is modified. + ::std::vector<Link> aListeners (maFocusChangeListeners); + + // Tell the slection change listeners that the selection has changed. + ::std::vector<Link>::iterator iListener (aListeners.begin()); + ::std::vector<Link>::iterator iEnd (aListeners.end()); + for (; iListener!=iEnd; ++iListener) + { + iListener->Call(NULL); + } +} + + + + +FocusManager::FocusHider::FocusHider (FocusManager& rManager) +: mbFocusVisible(rManager.IsFocusShowing()) +, mrManager(rManager) +{ + mrManager.HideFocus(); +} + + + + +FocusManager::FocusHider::~FocusHider (void) +{ + if (mbFocusVisible) + mrManager.ShowFocus(); +} + +} } } // end of namespace ::sd::slidesorter::controller + diff --git a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx new file mode 100644 index 000000000000..035f6ecd2dd1 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx @@ -0,0 +1,172 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsHideSlideFunction.cxx,v $ + * $Revision: 1.10 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlsHideSlideFunction.hxx" + +#include "SlideSorter.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" + +#include "app.hrc" +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "ViewShell.hxx" + +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/request.hxx> +#include <svx/svxids.hrc> + +namespace sd { namespace slidesorter { namespace controller { + +TYPEINIT1(HideSlideFunction, SlideFunction); + +HideSlideFunction::HideSlideFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest) + : SlideFunction( rSlideSorter, rRequest), + mrSlideSorter(rSlideSorter) +{ +} + + + + +HideSlideFunction::~HideSlideFunction (void) +{ +} + + + + +FunctionReference HideSlideFunction::Create ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest ) +{ + FunctionReference xFunc( new HideSlideFunction( rSlideSorter, rRequest ) ); + xFunc->DoExecute(rRequest); + return xFunc; +} + + + + +void HideSlideFunction::DoExecute (SfxRequest& rRequest) +{ + SlideFunction::DoExecute(rRequest); + + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); + + ExclusionState eState (UNDEFINED); + + switch (rRequest.GetSlot()) + { + case SID_HIDE_SLIDE: + eState = EXCLUDED; + break; + + case SID_SHOW_SLIDE: + eState = INCLUDED; + break; + + default: + eState = UNDEFINED; + break; + } + + if (eState != UNDEFINED) + { + // Set status at the selected pages. + aSelectedPages.Rewind (); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + pDescriptor->GetPage()->SetExcluded (eState==EXCLUDED); + static_cast<view::SlideSorterView*>(mpView)->RequestRepaint(pDescriptor); + } + } + + SfxBindings& rBindings = mpViewShell->GetViewFrame()->GetBindings(); + rBindings.Invalidate (SID_PRESENTATION); + rBindings.Invalidate (SID_REHEARSE_TIMINGS); + rBindings.Invalidate (SID_HIDE_SLIDE); + rBindings.Invalidate (SID_SHOW_SLIDE); + mpDoc->SetChanged(); +} + + + + +HideSlideFunction::ExclusionState HideSlideFunction::GetExclusionState ( + model::PageEnumeration& rPageSet) +{ + ExclusionState eState (UNDEFINED); + BOOL bState; + + // Get toggle state of the selected pages. + while (rPageSet.HasMoreElements() && eState!=MIXED) + { + bState = rPageSet.GetNextElement()->GetPage()->IsExcluded(); + switch (eState) + { + case UNDEFINED: + // Use the first selected page to set the inital value. + eState = bState ? EXCLUDED : INCLUDED; + break; + + case EXCLUDED: + // The pages before where all not part of the show, + // this one is. + if ( ! bState) + eState = MIXED; + break; + + case INCLUDED: + // The pages before where all part of the show, + // this one is not. + if (bState) + eState = MIXED; + break; + + case MIXED: + default: + // No need to change anything. + break; + } + } + + return eState; +} + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.hxx b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.hxx new file mode 100644 index 000000000000..392a3ee3e21b --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.hxx @@ -0,0 +1,76 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsHideSlideFunction.hxx,v $ + * $Revision: 1.7 $ + * + * 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 SD_SLIDESORTER_HIDE_SLIDE_FUNCTION_HXX +#define SD_SLIDESORTER_HIDE_SLIDE_FUNCTION_HXX + +#include "controller/SlsSlideFunction.hxx" +#include "model/SlsPageEnumeration.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +/** Toggle the hidden flag of the selected slides. + When the selected pages have not all the same state they will all set to + hidden. When all selected pages have the same state this state is + toggled for all of them +*/ +class HideSlideFunction + : public SlideFunction +{ +public: + TYPEINFO(); + + virtual ~HideSlideFunction (void); + + static FunctionReference Create( SlideSorter& rSlideSorter, SfxRequest& rRequest ); + virtual void DoExecute( SfxRequest& rReq ); + + // The state of a set of slides with respect to being excluded from the + // slide show. + enum ExclusionState {UNDEFINED, EXCLUDED, INCLUDED, MIXED}; + + /** Return for the given set of slides whether they included are + excluded from the slide show. + */ + static ExclusionState GetExclusionState (model::PageEnumeration& rPageSet); + +protected: + HideSlideFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest); + + SlideSorter& mrSlideSorter; +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + diff --git a/sd/source/ui/slidesorter/controller/SlsListener.cxx b/sd/source/ui/slidesorter/controller/SlsListener.cxx new file mode 100644 index 000000000000..9c51643b2b49 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsListener.cxx @@ -0,0 +1,607 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsListener.cxx,v $ + * $Revision: 1.19 $ + * + * 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_sd.hxx" +#include "SlsListener.hxx" + +#include "SlideSorter.hxx" +#include "SlideSorterViewShell.hxx" +#include "ViewShellHint.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "view/SlideSorterView.hxx" +#include "drawdoc.hxx" + +#include "glob.hrc" +#include "ViewShellBase.hxx" +#include "ViewShellManager.hxx" +#include "FrameView.hxx" +#include "EventMultiplexer.hxx" +#include <com/sun/star/document/XEventBroadcaster.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/FrameActionEvent.hpp> +#include <com/sun/star/frame/FrameAction.hpp> +#include <sfx2/viewfrm.hxx> + + +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +namespace sd { namespace slidesorter { namespace controller { + + +Listener::Listener ( + SlideSorter& rSlideSorter) + : ListenerInterfaceBase(maMutex), + mrSlideSorter(rSlideSorter), + mrController(mrSlideSorter.GetController()), + mpBase(mrSlideSorter.GetViewShellBase()), + mbListeningToDocument (false), + mbListeningToUNODocument (false), + mbListeningToController (false), + mbListeningToFrame (false), + mbIsMainViewChangePending(false), + mxControllerWeak(), + mxFrameWeak(), + mpModelChangeLock() +{ + StartListening (*mrSlideSorter.GetModel().GetDocument()); + mbListeningToDocument = true; + + // Connect to the UNO document. + Reference<document::XEventBroadcaster> xBroadcaster ( + mrSlideSorter.GetModel().GetDocument()->getUnoModel(), uno::UNO_QUERY); + if (xBroadcaster.is()) + { + xBroadcaster->addEventListener (this); + mbListeningToUNODocument = true; + } + + // Listen for disposing events from the document. + Reference<XComponent> xComponent (xBroadcaster, UNO_QUERY); + if (xComponent.is()) + xComponent->addEventListener ( + Reference<lang::XEventListener>( + static_cast<XWeak*>(this), UNO_QUERY)); + + // Connect to the frame to listen for controllers being exchanged. + bool bIsMainViewShell (false); + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL) + bIsMainViewShell = pViewShell->IsMainViewShell(); + if ( ! bIsMainViewShell) + { + // Listen to changes of certain properties. + Reference<frame::XFrame> xFrame; + Reference<frame::XController> xController (mrSlideSorter.GetXController()); + if (xController.is()) + xFrame = xController->getFrame(); + mxFrameWeak = xFrame; + if (xFrame.is()) + { + xFrame->addFrameActionListener ( + Reference<frame::XFrameActionListener>( + static_cast<XWeak*>(this), UNO_QUERY)); + mbListeningToFrame = true; + } + + // Connect to the current controller. + ConnectToController (); + } + + // Listen for hints of the MainViewShell as well. If that is not yet + // present then the EventMultiplexer will tell us when it is available. + if (mpBase != NULL) + { + ViewShell* pMainViewShell = mpBase->GetMainViewShell().get(); + if (pMainViewShell != NULL + && pMainViewShell!=pViewShell) + { + StartListening (*pMainViewShell); + } + + Link aLink (LINK(this, Listener, EventMultiplexerCallback)); + mpBase->GetEventMultiplexer()->AddEventListener( + aLink, + tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED + | tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED + | tools::EventMultiplexerEvent::EID_CONTROLLER_ATTACHED + | tools::EventMultiplexerEvent::EID_CONTROLLER_DETACHED + | tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED); + } +} + + + + +Listener::~Listener (void) +{ + DBG_ASSERT( !mbListeningToDocument && !mbListeningToUNODocument && !mbListeningToFrame, + "sd::Listener::~Listener(), disposing() was not called, ask DBO!" ); +} + + + + +void Listener::ReleaseListeners (void) +{ + if (mbListeningToDocument) + { + EndListening (*mrSlideSorter.GetModel().GetDocument()); + mbListeningToDocument = false; + } + + if (mbListeningToUNODocument) + { + Reference<document::XEventBroadcaster> xBroadcaster ( + mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeEventListener (this); + + // Remove the dispose listener. + Reference<XComponent> xComponent (xBroadcaster, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener ( + Reference<lang::XEventListener>( + static_cast<XWeak*>(this), UNO_QUERY)); + + mbListeningToUNODocument = false; + } + + if (mbListeningToFrame) + { + // Listen to changes of certain properties. + Reference<frame::XFrame> xFrame (mxFrameWeak); + if (xFrame.is()) + { + xFrame->removeFrameActionListener ( + Reference<frame::XFrameActionListener>( + static_cast<XWeak*>(this), UNO_QUERY)); + mbListeningToFrame = false; + } + } + + DisconnectFromController (); + + if (mpBase != NULL) + { + Link aLink (LINK(this, Listener, EventMultiplexerCallback)); + mpBase->GetEventMultiplexer()->RemoveEventListener( + aLink, + tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED + | tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED + | tools::EventMultiplexerEvent::EID_CONTROLLER_ATTACHED + | tools::EventMultiplexerEvent::EID_CONTROLLER_DETACHED + | tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED); + } +} + + + + +void Listener::ConnectToController (void) +{ + ViewShell* pShell = mrSlideSorter.GetViewShell(); + + // Register at the controller of the main view shell (if we are that not + // ourself). + if (pShell==NULL || ! pShell->IsMainViewShell()) + { + Reference<frame::XController> xController (mrSlideSorter.GetXController()); + + // Listen to changes of certain properties. + Reference<beans::XPropertySet> xSet (xController, UNO_QUERY); + if (xSet.is()) + { + try + { + xSet->addPropertyChangeListener(String::CreateFromAscii("CurrentPage"), this); + } + catch (beans::UnknownPropertyException aEvent) + { + OSL_TRACE ("caught exception in SlideSorterController::SetupListeners: %s", + ::rtl::OUStringToOString(aEvent.Message, RTL_TEXTENCODING_UTF8).getStr()); + } + try + { + xSet->addPropertyChangeListener(String::CreateFromAscii("IsMasterPageMode"), this); + } + catch (beans::UnknownPropertyException aEvent) + { + OSL_TRACE ("caught exception in SlideSorterController::SetupListeners: %s", + ::rtl::OUStringToOString(aEvent.Message, RTL_TEXTENCODING_UTF8).getStr()); + } + } + + // Listen for disposing events. + Reference<XComponent> xComponent (xController, UNO_QUERY); + if (xComponent.is()) + { + xComponent->addEventListener ( + Reference<lang::XEventListener>(static_cast<XWeak*>(this), UNO_QUERY)); + + mxControllerWeak = xController; + mbListeningToController = true; + } + } +} + + + + +void Listener::DisconnectFromController (void) +{ + if (mbListeningToController) + { + Reference<frame::XController> xController = mxControllerWeak; + Reference<beans::XPropertySet> xSet (xController, UNO_QUERY); + try + { + // Remove the property listener. + if (xSet.is()) + { + xSet->removePropertyChangeListener ( + String::CreateFromAscii("CurrentPage"), + this); + xSet->removePropertyChangeListener ( + String::CreateFromAscii("IsMasterPageMode"), + this); + } + + // Remove the dispose listener. + Reference<XComponent> xComponent (xController, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener ( + Reference<lang::XEventListener>( + static_cast<XWeak*>(this), UNO_QUERY)); + } + catch (beans::UnknownPropertyException aEvent) + { + OSL_TRACE ("caught exception in destructor of SlideSorterController: %s", + ::rtl::OUStringToOString(aEvent.Message, + RTL_TEXTENCODING_UTF8).getStr()); + } + + mbListeningToController = false; + mxControllerWeak = Reference<frame::XController>(); + } +} + + + + +void Listener::Notify ( + SfxBroadcaster& rBroadcaster, + const SfxHint& rHint) +{ + if (rHint.ISA(SdrHint)) + { + SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint)); + if(rSdrHint.GetKind() == HINT_PAGEORDERCHG ) + { + if (rBroadcaster.ISA(SdDrawDocument)) + { + SdDrawDocument& rDocument ( + static_cast<SdDrawDocument&>(rBroadcaster)); + if (rDocument.GetMasterSdPageCount(PK_STANDARD) + == rDocument.GetMasterSdPageCount(PK_NOTES)) + { + mrController.HandleModelChange(); + } + } + } + } + else if (rHint.ISA(ViewShellHint)) + { + ViewShellHint& rViewShellHint (*PTR_CAST(ViewShellHint,&rHint)); + switch (rViewShellHint.GetHintId()) + { + case ViewShellHint::HINT_PAGE_RESIZE_START: + // Initiate a model change but do nothing (well, not much) + // until we are told that all slides have been resized. + mpModelChangeLock.reset(new SlideSorterController::ModelChangeLock(mrController)); + mrController.HandleModelChange(); + break; + + case ViewShellHint::HINT_PAGE_RESIZE_END: + // All slides have been resized. The model has to be updated. + mpModelChangeLock.reset(); + break; + + case ViewShellHint::HINT_CHANGE_EDIT_MODE_START: + mrController.PrepareEditModeChange(); + break; + + case ViewShellHint::HINT_CHANGE_EDIT_MODE_END: + mrController.FinishEditModeChange(); + break; + + case ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_START: + mpModelChangeLock.reset(new SlideSorterController::ModelChangeLock(mrController)); + break; + + case ViewShellHint::HINT_COMPLEX_MODEL_CHANGE_END: + mpModelChangeLock.reset(); + break; + } + } +} + + + + +IMPL_LINK(Listener, EventMultiplexerCallback, ::sd::tools::EventMultiplexerEvent*, pEvent) +{ + switch (pEvent->meEventId) + { + case tools::EventMultiplexerEvent::EID_MAIN_VIEW_REMOVED: + { + if (mpBase != NULL) + { + ViewShell* pMainViewShell = mpBase->GetMainViewShell().get(); + if (pMainViewShell != NULL) + EndListening(*pMainViewShell); + } + } + break; + + + case tools::EventMultiplexerEvent::EID_MAIN_VIEW_ADDED: + mbIsMainViewChangePending = true; + break; + + case tools::EventMultiplexerEvent::EID_CONFIGURATION_UPDATED: + if (mbIsMainViewChangePending && mpBase != NULL) + { + mbIsMainViewChangePending = false; + ViewShell* pMainViewShell = mpBase->GetMainViewShell().get(); + if (pMainViewShell != NULL + && pMainViewShell!=mrSlideSorter.GetViewShell()) + { + StartListening (*pMainViewShell); + } + } + break; + + case tools::EventMultiplexerEvent::EID_CONTROLLER_ATTACHED: + { + ConnectToController(); + mrController.GetPageSelector().UpdateAllPages(); + UpdateEditMode(); + } + break; + + + case tools::EventMultiplexerEvent::EID_CONTROLLER_DETACHED: + DisconnectFromController(); + break; + + default: + break; + } + + return 0; +} + + + + +//===== lang::XEventListener ================================================ + +void SAL_CALL Listener::disposing ( + const lang::EventObject& rEventObject) + throw (RuntimeException) +{ + if ((mbListeningToDocument || mbListeningToUNODocument) + && mrSlideSorter.GetModel().GetDocument()!=NULL + && rEventObject.Source + == mrSlideSorter.GetModel().GetDocument()->getUnoModel()) + { + mbListeningToDocument = false; + mbListeningToUNODocument = false; + } + else if (mbListeningToController) + { + Reference<frame::XController> xController (mxControllerWeak); + if (rEventObject.Source == xController) + { + mbListeningToController = false; + } + } +} + + + + +//===== document::XEventListener ============================================ + +void SAL_CALL Listener::notifyEvent ( + const document::EventObject& ) + throw (RuntimeException) +{ +} + + + + +//===== beans::XPropertySetListener ========================================= + +void SAL_CALL Listener::propertyChange ( + const PropertyChangeEvent& rEvent) + throw (RuntimeException) +{ + ThrowIfDisposed(); + + static const ::rtl::OUString sCurrentPagePropertyName ( + RTL_CONSTASCII_USTRINGPARAM("CurrentPage")); + static const ::rtl::OUString sEditModePropertyName ( + RTL_CONSTASCII_USTRINGPARAM("IsMasterPageMode")); + + if (rEvent.PropertyName.equals (sCurrentPagePropertyName)) + { + Any aCurrentPage = rEvent.NewValue; + Reference<beans::XPropertySet> xPageSet (aCurrentPage, UNO_QUERY); + if (xPageSet.is()) + { + try + { + Any aPageNumber = xPageSet->getPropertyValue ( + String(RTL_CONSTASCII_USTRINGPARAM("Number"))); + sal_Int32 nCurrentPage = 0; + aPageNumber >>= nCurrentPage; + mrController.GetPageSelector().UpdateAllPages (); + // The selection is already set but we call SelectPage() + // nevertheless in order to make the new current page the + // last recently selected page of the PageSelector. This is + // used when making the selection visible. + mrController.GetPageSelector().SelectPage(nCurrentPage-1); + mrController.GetCurrentSlideManager()->CurrentSlideHasChanged(nCurrentPage-1); + } + catch (beans::UnknownPropertyException aEvent) + { + OSL_TRACE ("caught exception while accessing the page number of a slide: %s", + ::rtl::OUStringToOString(aEvent.Message, + RTL_TEXTENCODING_UTF8).getStr()); + } + catch (lang::DisposedException&) + { + // Something is already disposed. There is not much we can + // do, except not to crash. + } + } + } + else if (rEvent.PropertyName.equals (sEditModePropertyName)) + { + sal_Bool bIsMasterPageMode = sal_False; + rEvent.NewValue >>= bIsMasterPageMode; + mrController.ChangeEditMode ( + bIsMasterPageMode ? EM_MASTERPAGE : EM_PAGE); + } +} + + + + +//===== frame::XFrameActionListener ========================================== + +void SAL_CALL Listener::frameAction (const frame::FrameActionEvent& rEvent) + throw (::com::sun::star::uno::RuntimeException) +{ + switch (rEvent.Action) + { + case frame::FrameAction_COMPONENT_DETACHING: + DisconnectFromController(); + break; + + case frame::FrameAction_COMPONENT_REATTACHED: + { + ConnectToController(); + mrController.GetPageSelector().UpdateAllPages(); + UpdateEditMode(); + } + break; + + default: + break; + } +} + + + + +//===== accessibility::XAccessibleEventListener ============================== + +void SAL_CALL Listener::notifyEvent ( + const AccessibleEventObject& ) + throw (RuntimeException) +{ +} + + + + +void SAL_CALL Listener::disposing (void) +{ + ReleaseListeners(); +} + + + + +void Listener::UpdateEditMode (void) +{ + // When there is a new controller then the edit mode may have changed at + // the same time. + Reference<frame::XController> xController (mxControllerWeak); + Reference<beans::XPropertySet> xSet (xController, UNO_QUERY); + bool bIsMasterPageMode = false; + if (xSet != NULL) + { + try + { + Any aValue (xSet->getPropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsMasterPageMode")))); + aValue >>= bIsMasterPageMode; + } + catch (beans::UnknownPropertyException e) + { + // When the property is not supported then the master page mode + // is not supported, too. + bIsMasterPageMode = false; + } + } + mrController.ChangeEditMode ( + bIsMasterPageMode ? EM_MASTERPAGE : EM_PAGE); +} + + + + +void Listener::ThrowIfDisposed (void) + throw (::com::sun::star::lang::DisposedException) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + throw lang::DisposedException ( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "SlideSorterController object has already been disposed")), + static_cast<uno::XWeak*>(this)); + } +} + + + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsListener.hxx b/sd/source/ui/slidesorter/controller/SlsListener.hxx new file mode 100644 index 000000000000..f91c7337713a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsListener.hxx @@ -0,0 +1,188 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsListener.hxx,v $ + * $Revision: 1.8 $ + * + * 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 SD_SLIDESORTER_SLIDE_SORTER_LISTENER_HXX +#define SD_SLIDESORTER_SLIDE_SORTER_LISTENER_HXX + +#include "MutexOwner.hxx" +#include "controller/SlideSorterController.hxx" +#include <com/sun/star/document/XEventListener.hpp> +#ifndef _COM_SUN_STAR_DOCUMENT_XPROPERTYCHANGELISTENER_HPP_ +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#endif +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XFrameActionListener.hpp> +#include <cppuhelper/compbase4.hxx> + +#include <svtools/lstner.hxx> +#include <tools/link.hxx> +#include <boost/shared_ptr.hpp> + +namespace sd { +class ViewShellBase; +} + +namespace sd { namespace tools { +class EventMultiplexerEvent; +} } + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace controller { + +typedef cppu::WeakComponentImplHelper4< + ::com::sun::star::document::XEventListener, + ::com::sun::star::beans::XPropertyChangeListener, + ::com::sun::star::accessibility::XAccessibleEventListener, + ::com::sun::star::frame::XFrameActionListener + > ListenerInterfaceBase; + +class SlideSorterController; + +/** Listen for events of various types and sources and react to them. This + class is a part of the controller. + + When the view shell in the center pane is replaced by another the + associated controller is replaced as well. Therefore we have to + register at the frame and on certain FrameActionEvents to stop listening + to the old controller and register as listener at the new one. +*/ +class Listener + : protected MutexOwner, + public ListenerInterfaceBase, + public SfxListener +{ +public: + Listener (SlideSorter& rSlideSorter); + virtual ~Listener (void); + + /** Connect to the current controller of the view shell as listener. + This method is called once during initialization and every time a + FrameActionEvent signals the current controller being exchanged. + When the connection is successfull then the flag + mbListeningToController is set to <TRUE/>. + */ + void ConnectToController (void); + + /** Disconnect from the current controller of the view shell as + listener. This method is called once during initialization and + every time a FrameActionEvent signals the current controller being + exchanged. When this method terminates then mbListeningToController + is <FALSE/>. + */ + void DisconnectFromController (void); + + virtual void Notify ( + SfxBroadcaster& rBroadcaster, + const SfxHint& rHint); + + //===== lang::XEventListener ============================================ + virtual void SAL_CALL + disposing (const ::com::sun::star::lang::EventObject& rEventObject) + throw (::com::sun::star::uno::RuntimeException); + + + //===== document::XEventListener ======================================== + virtual void SAL_CALL + notifyEvent ( + const ::com::sun::star::document::EventObject& rEventObject) + throw (::com::sun::star::uno::RuntimeException); + + //===== beans::XPropertySetListener ===================================== + virtual void SAL_CALL + propertyChange ( + const com::sun::star::beans::PropertyChangeEvent& rEvent) + throw (::com::sun::star::uno::RuntimeException); + + //===== accessibility::XAccessibleEventListener ========================== + virtual void SAL_CALL + notifyEvent ( + const ::com::sun::star::accessibility::AccessibleEventObject& + rEvent) + throw (::com::sun::star::uno::RuntimeException); + + //===== frame::XFrameActionListener ====================================== + /** For certain actions the listener connects to a new controller of the + frame it is listening to. This usually happens when the view shell + in the center pane is replaced by another view shell. + */ + virtual void SAL_CALL + frameAction (const ::com::sun::star::frame::FrameActionEvent& rEvent) + throw (::com::sun::star::uno::RuntimeException); + + virtual void SAL_CALL disposing (void); + +private: + SlideSorter& mrSlideSorter; + SlideSorterController& mrController; + ViewShellBase* mpBase; + + /// Remember whether we are listening to the document. + bool mbListeningToDocument; + /// Remember whether we are listening to the UNO document. + bool mbListeningToUNODocument; + /// Remember whether we are listening to the UNO controller. + bool mbListeningToController; + /// Remember whether we are listening to the frame. + bool mbListeningToFrame; + bool mbIsMainViewChangePending; + + ::com::sun::star::uno::WeakReference< ::com::sun::star::frame::XController> mxControllerWeak; + ::com::sun::star::uno::WeakReference< ::com::sun::star::frame::XFrame> mxFrameWeak; + + /** This object is used to lock the model between some + events. It is refernce counted in order to cope with events that + are expected but never sent. + */ + ::boost::shared_ptr<SlideSorterController::ModelChangeLock> mpModelChangeLock; + + void ReleaseListeners (void); + + /** Called when the edit mode has changed. Update model accordingly. + */ + void UpdateEditMode (void); + + /** This method throws a DisposedException when the object has already been + disposed. + */ + void ThrowIfDisposed (void) + throw (::com::sun::star::lang::DisposedException); + + DECL_LINK(EventMultiplexerCallback, tools::EventMultiplexerEvent*); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/controller/SlsPageObjectFactory.cxx b/sd/source/ui/slidesorter/controller/SlsPageObjectFactory.cxx new file mode 100644 index 000000000000..89e76a06a8f9 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsPageObjectFactory.cxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObjectFactory.cxx,v $ + * $Revision: 1.7 $ + * + * 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_sd.hxx" + +#include "controller/SlsPageObjectFactory.hxx" + +#include "view/SlsPageObject.hxx" +#include "view/SlsPageObjectViewContact.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" + +#include "sdpage.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + + +PageObjectFactory::PageObjectFactory ( + const ::boost::shared_ptr<cache::PageCache>& rpCache, + const ::boost::shared_ptr<controller::Properties>& rpProperties) + : mpPageCache(rpCache), + mpProperties(rpProperties) +{ +} + + + + +PageObjectFactory::~PageObjectFactory (void) +{ +} + + + + +view::PageObject* PageObjectFactory::CreatePageObject ( + SdPage* pPage, + const model::SharedPageDescriptor& rpDescriptor) const +{ + return new view::PageObject( + Rectangle (Point(0,0), pPage->GetSize()), + pPage, + rpDescriptor); +} + + + + +::sdr::contact::ViewContact* + PageObjectFactory::CreateViewContact ( + view::PageObject* pPageObject, + const model::SharedPageDescriptor& rpDescriptor) const +{ + return new view::PageObjectViewContact ( + *pPageObject, + rpDescriptor); +} + + + + +::sdr::contact::ViewObjectContact* + PageObjectFactory::CreateViewObjectContact ( + ::sdr::contact::ObjectContact& rObjectContact, + ::sdr::contact::ViewContact& rViewContact) const +{ + return new view::PageObjectViewObjectContact ( + rObjectContact, + rViewContact, + mpPageCache, + mpProperties); +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx new file mode 100644 index 000000000000..0c69a2b27c11 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx @@ -0,0 +1,338 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageSelector.cxx,v $ + * $Revision: 1.11 $ + * + * 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 "precompiled_sd.hxx" + +#include "controller/SlsPageSelector.hxx" + +#include "SlideSorter.hxx" +#include "SlideSorterViewShell.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlideSorterModel.hxx" +#include "view/SlideSorterView.hxx" + +#include "sdpage.hxx" +#include "ViewShell.hxx" +#include "DrawViewShell.hxx" +#include "ViewShellBase.hxx" +#include <com/sun/star/drawing/XDrawView.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::sd::slidesorter::model; +using namespace ::sd::slidesorter::view; + +namespace sd { namespace slidesorter { namespace controller { + + +PageSelector::PageSelector (SlideSorter& rSlideSorter) + : mrModel(rSlideSorter.GetModel()), + mrSlideSorter(rSlideSorter), + mrController(mrSlideSorter.GetController()), + mnSelectedPageCount(0), + mnBroadcastDisableLevel(0), + mbSelectionChangeBroadcastPending(false), + mpMostRecentlySelectedPage(), + mpSelectionAnchor() +{ + CountSelectedPages (); +} + + + + +void PageSelector::SelectAllPages (void) +{ + int nPageCount = mrModel.GetPageCount(); + for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++) + SelectPage (nPageIndex); +} + + + + +void PageSelector::DeselectAllPages (void) +{ + int nPageCount = mrModel.GetPageCount(); + for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++) + DeselectPage (nPageIndex); + DBG_ASSERT (mnSelectedPageCount==0, + "PageSelector::DeselectAllPages: the selected pages counter is not 0"); + mnSelectedPageCount = 0; + mpMostRecentlySelectedPage.reset(); + mpSelectionAnchor.reset(); +} + + + + +void PageSelector::UpdateAllPages (void) +{ + bool bSelectionHasChanged (true); + mnSelectedPageCount = 0; + model::PageEnumeration aAllPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + if (pDescriptor->UpdateSelection()) + { + mrSlideSorter.GetView().RequestRepaint(pDescriptor); + bSelectionHasChanged = true; + } + + if (pDescriptor->IsSelected()) + mnSelectedPageCount++; + } + + if (bSelectionHasChanged) + { + if (mnBroadcastDisableLevel > 0) + mbSelectionChangeBroadcastPending = true; + else + mrController.GetSelectionManager()->SelectionHasChanged(); + } +} + + + + +void PageSelector::SelectPage (int nPageIndex) +{ + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get() != NULL) + SelectPage(pDescriptor); +} + + + + +void PageSelector::SelectPage (const SdPage* pPage) +{ + int nPageIndex = (pPage->GetPageNum()-1) / 2; + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage) + SelectPage(pDescriptor); +} + + + + +void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get()!=NULL && rpDescriptor->Select()) + { + mnSelectedPageCount ++; + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); + + mpMostRecentlySelectedPage = rpDescriptor; + if (mpSelectionAnchor == NULL) + mpSelectionAnchor = rpDescriptor; + + if (mnBroadcastDisableLevel > 0) + mbSelectionChangeBroadcastPending = true; + else + mrController.GetSelectionManager()->SelectionHasChanged(); + } +} + + + + +void PageSelector::DeselectPage (int nPageIndex) +{ + model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get() != NULL) + DeselectPage(pDescriptor); +} + + + + +void PageSelector::DeselectPage (const SdPage* pPage) +{ + int nPageIndex = (pPage->GetPageNum()-1) / 2; + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage) + DeselectPage(pDescriptor); +} + + + + +void PageSelector::DeselectPage (const SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get()!=NULL && rpDescriptor->Deselect()) + { + mnSelectedPageCount --; + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); + if (mpMostRecentlySelectedPage == rpDescriptor) + mpMostRecentlySelectedPage.reset(); + if (mnBroadcastDisableLevel > 0) + mbSelectionChangeBroadcastPending = true; + else + mrController.GetSelectionManager()->SelectionHasChanged(); + } +} + + + + +bool PageSelector::IsPageSelected (int nPageIndex) +{ + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get() != NULL) + return pDescriptor->IsSelected(); + else + return false; +} + + + + +int PageSelector::GetPageCount (void) const +{ + return mrModel.GetPageCount(); +} + + + + +int PageSelector::GetSelectedPageCount (void) const +{ + return mnSelectedPageCount; +} + + + + +void PageSelector::PrepareModelChange (void) +{ + DeselectAllPages (); +} + + + + +void PageSelector::HandleModelChange (void) +{ + UpdateAllPages(); +} + + + + +SharedPageDescriptor PageSelector::GetMostRecentlySelectedPage (void) const +{ + return mpMostRecentlySelectedPage; +} + + + + +SharedPageDescriptor PageSelector::GetSelectionAnchor (void) const +{ + return mpSelectionAnchor; +} + + + + +void PageSelector::CountSelectedPages (void) +{ + mnSelectedPageCount = 0; + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrModel)); + while (aSelectedPages.HasMoreElements()) + { + mnSelectedPageCount++; + aSelectedPages.GetNextElement(); + } +} + + + + +void PageSelector::EnableBroadcasting (bool bMakeSelectionVisible) +{ + if (mnBroadcastDisableLevel > 0) + mnBroadcastDisableLevel --; + if (mnBroadcastDisableLevel==0 && mbSelectionChangeBroadcastPending) + { + mrController.GetSelectionManager()->SelectionHasChanged(bMakeSelectionVisible); + mbSelectionChangeBroadcastPending = false; + } +} + + + + +void PageSelector::DisableBroadcasting (void) +{ + mnBroadcastDisableLevel ++; +} + + + + +::boost::shared_ptr<PageSelector::PageSelection> PageSelector::GetPageSelection (void) const +{ + ::boost::shared_ptr<PageSelection> pSelection (new PageSelection()); + pSelection->reserve(GetSelectedPageCount()); + + int nPageCount = GetPageCount(); + for (int nIndex=0; nIndex<nPageCount; nIndex++) + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (pDescriptor.get()!=NULL && pDescriptor->IsSelected()) + pSelection->push_back(pDescriptor->GetPage()); + } + + return pSelection; +} + + + + +void PageSelector::SetPageSelection (const ::boost::shared_ptr<PageSelection>& rpSelection) +{ + PageSelection::const_iterator iPage; + for (iPage=rpSelection->begin(); iPage!=rpSelection->end(); ++iPage) + SelectPage(*iPage); +} + + + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsProperties.cxx b/sd/source/ui/slidesorter/controller/SlsProperties.cxx new file mode 100644 index 000000000000..6015c36e9510 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsProperties.cxx @@ -0,0 +1,237 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsProperties.cxx,v $ + * + * $Revision: 1.3 $ + * + * 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 "precompiled_sd.hxx" + +#include "controller/SlsProperties.hxx" +#include <vcl/svapp.hxx> + +namespace sd { namespace slidesorter { namespace controller { + +Properties::Properties (void) + : mbIsHighlightCurrentSlide(false), + mbIsShowSelection(true), + mbIsShowFocus(true), + mbIsCenterSelection(false), + mbIsSmoothSelectionScrolling(false), + mbIsSuspendPreviewUpdatesDuringFullScreenPresentation(true), + maBackgroundColor(Application::GetSettings().GetStyleSettings().GetWindowColor()), + maTextColor(Application::GetSettings().GetStyleSettings().GetActiveTextColor()), + maSelectionColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()), + maHighlightColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()), + mbIsUIReadOnly(false) +{ +} + + + + +Properties::~Properties (void) +{ +} + + + + +bool Properties::IsHighlightCurrentSlide (void) const +{ + return mbIsHighlightCurrentSlide; +} + + + + +void Properties::SetHighlightCurrentSlide (const bool bIsHighlightCurrentSlide) +{ + mbIsHighlightCurrentSlide = bIsHighlightCurrentSlide; +} + + + + +bool Properties::IsShowSelection (void) const +{ + return mbIsShowSelection; +} + + + + +void Properties::SetShowSelection (const bool bIsShowSelection) +{ + mbIsShowSelection = bIsShowSelection; +} + + + + +bool Properties::IsShowFocus (void) const +{ + return mbIsShowFocus; +} + + + + +void Properties::SetShowFocus (const bool bIsShowFocus) +{ + mbIsShowFocus = bIsShowFocus; +} + + + + +bool Properties::IsCenterSelection (void) const +{ + return mbIsCenterSelection; +} + + + + +void Properties::SetCenterSelection (const bool bIsCenterSelection) +{ + mbIsCenterSelection = bIsCenterSelection; +} + + + + +bool Properties::IsSmoothSelectionScrolling (void) const +{ + return mbIsSmoothSelectionScrolling; +} + + + + +void Properties::SetSmoothSelectionScrolling (const bool bIsSmoothSelectionScrolling) +{ + mbIsSmoothSelectionScrolling = bIsSmoothSelectionScrolling; +} + + + + +bool Properties::IsSuspendPreviewUpdatesDuringFullScreenPresentation (void) const +{ + return mbIsSuspendPreviewUpdatesDuringFullScreenPresentation; +} + + + + +void Properties::SetSuspendPreviewUpdatesDuringFullScreenPresentation (const bool bFlag) +{ + mbIsSuspendPreviewUpdatesDuringFullScreenPresentation = bFlag; +} + + + + +Color Properties::GetBackgroundColor (void) const +{ + return maBackgroundColor; +} + + + + +void Properties::SetBackgroundColor (const Color& rColor) +{ + maBackgroundColor = rColor; +} + + + +Color Properties::GetTextColor (void) const +{ + return maTextColor; +} + + + + +void Properties::SetTextColor (const Color& rColor) +{ + maTextColor = rColor; +} + + + + +Color Properties::GetSelectionColor (void) const +{ + return maSelectionColor; +} + + + + +void Properties::SetSelectionColor (const Color& rColor) +{ + maSelectionColor = rColor; +} + + + + +Color Properties::GetHighlightColor (void) const +{ + return maHighlightColor; +} + + + + +void Properties::SetHighlightColor (const Color& rColor) +{ + maHighlightColor = rColor; +} + + + + +bool Properties::IsUIReadOnly (void) const +{ + return mbIsUIReadOnly; +} + + + + +void Properties::SetUIReadOnly (const bool bIsUIReadOnly) +{ + mbIsUIReadOnly = bIsUIReadOnly; +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx new file mode 100644 index 000000000000..ed363dc6743e --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx @@ -0,0 +1,654 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsScrollBarManager.cxx,v $ + * $Revision: 1.13 $ + * + * 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 "precompiled_sd.hxx" + +#include "controller/SlsScrollBarManager.hxx" + +#include "SlideSorter.hxx" +#include "controller/SlideSorterController.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsViewOverlay.hxx" +#include "Window.hxx" +#include "sdpage.hxx" + +#include <boost/limits.hpp> + +#include <vcl/scrbar.hxx> + +namespace sd { namespace slidesorter { namespace controller { + +ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mpHorizontalScrollBar(mrSlideSorter.GetHorizontalScrollBar()), + mpVerticalScrollBar(mrSlideSorter.GetVerticalScrollBar()), + mnHorizontalPosition (0), + mnVerticalPosition (0), + maScrollBorder (10,10), + mnHorizontalScrollFactor (0.1), + mnVerticalScrollFactor (0.1), + mpScrollBarFiller(mrSlideSorter.GetScrollBarFiller()), + mpContentWindow(mrSlideSorter.GetContentWindow()) +{ + // Hide the scroll bars by default to prevent display errors while + // switching between view shells: In the short time between initiating + // such a switch and the final rearrangement of UI controls the scroll + // bars and the filler where displayed in the upper left corner of the + // ViewTabBar. + mpHorizontalScrollBar->Hide(); + mpVerticalScrollBar->Hide(); + mpScrollBarFiller->Hide(); + + maAutoScrollTimer.SetTimeout(50); + maAutoScrollTimer.SetTimeoutHdl ( + LINK(this, ScrollBarManager, AutoScrollTimeoutHandler)); +} + + + + +ScrollBarManager::~ScrollBarManager (void) +{ +} + + + + +void ScrollBarManager::LateInitialization (void) +{ +} + + + + +void ScrollBarManager::Connect (void) +{ + if (mpVerticalScrollBar != NULL) + mpVerticalScrollBar->SetScrollHdl ( + LINK( + this, + ScrollBarManager, + VerticalScrollBarHandler)); + if (mpHorizontalScrollBar != NULL) + mpHorizontalScrollBar->SetScrollHdl ( + LINK( + this, + ScrollBarManager, + HorizontalScrollBarHandler)); +} + + + + +void ScrollBarManager::Disconnect (void) +{ + if (mpVerticalScrollBar != NULL) + mpVerticalScrollBar->SetScrollHdl (Link()); + if (mpHorizontalScrollBar != NULL) + mpHorizontalScrollBar->SetScrollHdl (Link()); +} + + + + +/** Placing the scroll bars is an iterative process. The visibility of one + scroll bar affects the remaining size and thus may lead to the other + scroll bar becoming visible. + + First we determine the visibility of the horizontal scroll bar. After + that we do the same for the vertical scroll bar. To have an initial + value for the required size we call the layouter before that. When one + of the two scroll bars is made visible then the size of the browser + window changes and a second call to the layouter becomes necessary. + That call is made anyway after this method returns. +*/ +Rectangle ScrollBarManager::PlaceScrollBars (const Rectangle& rAvailableArea) +{ + Rectangle aRemainingSpace (DetermineScrollBarVisibilities(rAvailableArea)); + PlaceHorizontalScrollBar (rAvailableArea); + PlaceVerticalScrollBar (rAvailableArea); + PlaceFiller (rAvailableArea); + + return aRemainingSpace; +} + + + + +void ScrollBarManager::PlaceHorizontalScrollBar (const Rectangle& aAvailableArea) +{ + if (mpHorizontalScrollBar != NULL + && mpHorizontalScrollBar->IsVisible()) + { + // Save the current relative position. + mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos()) + / double(mpHorizontalScrollBar->GetRange().Len()); + + // Place the scroll bar. + Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel()); + mpHorizontalScrollBar->SetPosSizePixel ( + Point(aAvailableArea.Left(), + aAvailableArea.Bottom()-aScrollBarSize.Height()+1), + Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(), + aScrollBarSize.Height())); + + // Restore the relative position. + mpHorizontalScrollBar->SetThumbPos( + (long)(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len())); + } +} + + + + +void ScrollBarManager::PlaceVerticalScrollBar (const Rectangle& aArea) +{ + if (mpVerticalScrollBar != NULL + && mpVerticalScrollBar->IsVisible()) + { + view::Layouter::DoublePoint aLayouterPosition + = mrSlideSorter.GetView().GetLayouter().ConvertModelToLayouterCoordinates ( + Point (0, mpVerticalScrollBar->GetThumbPos())); + + // Place the scroll bar. + Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel()); + Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top()); + Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight()); + mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize); + + // Restore the position. + mpVerticalScrollBar->SetThumbPos( + mrSlideSorter.GetView().GetLayouter().ConvertLayouterToModelCoordinates( + aLayouterPosition).Y()); + mnVerticalPosition = double(mpVerticalScrollBar->GetThumbPos()) + / double(mpVerticalScrollBar->GetRange().Len()); + } +} + + + + +void ScrollBarManager::PlaceFiller (const Rectangle& aArea) +{ + // Place the filler when both scroll bars are visible. + if (mpHorizontalScrollBar != NULL + && mpVerticalScrollBar != NULL + && mpHorizontalScrollBar->IsVisible() + && mpVerticalScrollBar->IsVisible()) + { + mpScrollBarFiller->SetPosSizePixel( + Point( + aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1, + aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1), + Size ( + mpVerticalScrollBar->GetSizePixel().Width(), + mpHorizontalScrollBar->GetSizePixel().Height())); + mpScrollBarFiller->Show(); + } + else + mpScrollBarFiller->Hide(); +} + + + + +void ScrollBarManager::AdaptWindowSize (const Rectangle& rArea) +{ + Size aPixelContentSize (mpContentWindow->LogicToPixel( + mrSlideSorter.GetView().GetLayouter().GetPageBox ( + mrSlideSorter.GetModel().GetPageCount()).GetSize())); + int nHeightDifference = aPixelContentSize.Height() - rArea.GetHeight(); + ::Window* pParentWindow = mpContentWindow->GetParent(); + Size aNewWindowSize (pParentWindow->GetSizePixel()); + if (nHeightDifference != 0) + { + aNewWindowSize.Height() += nHeightDifference; + pParentWindow->SetPosSizePixel( + pParentWindow->GetPosPixel(), + aNewWindowSize); + } +} + + + + +void ScrollBarManager::UpdateScrollBars (bool bResetThumbPosition, bool bUseScrolling) +{ + Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); + ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + Size aWindowModelSize (pWindow->PixelToLogic(pWindow->GetSizePixel())); + + // The horizontal scroll bar is only shown when the window is + // horizontally smaller than the view. + if (mpHorizontalScrollBar != NULL && mpHorizontalScrollBar->IsVisible()) + { + mpHorizontalScrollBar->Show(); + mpHorizontalScrollBar->SetRange ( + Range(aModelArea.Left(), aModelArea.Right())); + if (bResetThumbPosition) + { + mpHorizontalScrollBar->SetThumbPos (0); + mnHorizontalPosition = 0; + } + else + mnHorizontalPosition = + double(mpHorizontalScrollBar->GetThumbPos()) + / double(mpHorizontalScrollBar->GetRange().Len()); + + mpHorizontalScrollBar->SetVisibleSize (aWindowModelSize.Width()); + + const long nWidth (mpContentWindow->PixelToLogic( + mpContentWindow->GetSizePixel()).Width()); + // Make the line size about 10% of the visible width. + mpHorizontalScrollBar->SetLineSize (nWidth / 10); + // Make the page size about 90% of the visible width. + mpHorizontalScrollBar->SetPageSize ((nWidth * 9) / 10); + } + else + { + mnHorizontalPosition = 0; + } + + // The vertical scroll bar is always shown. + if (mpVerticalScrollBar != NULL && mpVerticalScrollBar->IsVisible()) + { + mpVerticalScrollBar->SetRange ( + Range(aModelArea.Top(), aModelArea.Bottom())); + if (bResetThumbPosition) + { + mpVerticalScrollBar->SetThumbPos (0); + mnVerticalPosition = 0; + } + else + mnVerticalPosition = + double(mpVerticalScrollBar->GetThumbPos()) + / double(mpVerticalScrollBar->GetRange().Len()); + + mpVerticalScrollBar->SetVisibleSize (aWindowModelSize.Height()); + + const long nHeight (mpContentWindow->PixelToLogic( + mpContentWindow->GetSizePixel()).Height()); + // Make the line size about 10% of the visible height. + mpVerticalScrollBar->SetLineSize (nHeight / 10); + // Make the page size about 90% of the visible height. + mpVerticalScrollBar->SetPageSize ((nHeight * 9) / 10); + } + else + { + mnVerticalPosition = 0; + } + + + double nEps (::std::numeric_limits<double>::epsilon()); + if (fabs(mnHorizontalPosition-pWindow->GetVisibleX()) > nEps + || fabs(mnVerticalPosition-pWindow->GetVisibleY()) > nEps) + { + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + if (bUseScrolling) + pWindow->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition); + else + SetWindowOrigin(mnHorizontalPosition, mnVerticalPosition); + } +} + + + + +IMPL_LINK(ScrollBarManager, VerticalScrollBarHandler, ScrollBar*, pScrollBar) +{ + if (pScrollBar!=NULL + && pScrollBar==mpVerticalScrollBar.get() + && pScrollBar->IsVisible() + && mrSlideSorter.GetView().GetWindow()!=NULL) + { + double nRelativePosition = double(pScrollBar->GetThumbPos()) + / double(pScrollBar->GetRange().Len()); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( + -1, + nRelativePosition); + } + return TRUE; +} + + + + +IMPL_LINK(ScrollBarManager, HorizontalScrollBarHandler, ScrollBar*, pScrollBar) +{ + if (pScrollBar!=NULL + && pScrollBar==mpHorizontalScrollBar.get() + && pScrollBar->IsVisible() + && mrSlideSorter.GetView().GetWindow()!=NULL) + { + double nRelativePosition = double(pScrollBar->GetThumbPos()) + / double(pScrollBar->GetRange().Len()); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + mrSlideSorter.GetView().GetWindow()->SetVisibleXY (nRelativePosition, -1); + } + return TRUE; +} + + + + +void ScrollBarManager::SetWindowOrigin ( + double nHorizontalPosition, + double nVerticalPosition) +{ + mnHorizontalPosition = nHorizontalPosition; + mnVerticalPosition = nVerticalPosition; + + ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + Size aViewSize (pWindow->GetViewSize()); + Point aOrigin ( + (long int) (mnHorizontalPosition * aViewSize.Width()), + (long int) (mnVerticalPosition * aViewSize.Height())); + + pWindow->SetWinViewPos (aOrigin); + pWindow->UpdateMapMode (); + pWindow->Invalidate (); +} + + + + +/** Determining the visibility of the scroll bars is quite complicated. The + visibility of one influences that of the other because showing a scroll + bar makes the available space smaller and may lead to the need of + displaying the other. + To solve this we test all four combinations of showing or hiding each + scroll bar and use the best one. The best one is that combination that + a) shows the least number of scroll bars with preference of showing the + vertical over showing the horizontal and + b) when not showing a scroll bar the area used by the page objects fits + into the available area in the scroll bars orientation. +*/ +Rectangle ScrollBarManager::DetermineScrollBarVisibilities (const Rectangle& rAvailableArea) +{ + // Test which combination of scroll bars is the best. + bool bShowHorizontal = false; + bool bShowVertical = false; + do + { + if (mrSlideSorter.GetModel().GetPageCount() == 0) + // No pages => no scroll bars. + break; + + if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=false, rAvailableArea)) + break; + if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=false, rAvailableArea)) + break; + if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=true, rAvailableArea)) + break; + if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=true, rAvailableArea)) + break; + } + while (false); + + // Make the visibility of the scroll bars permanent. + mpVerticalScrollBar->Show(bShowVertical); + mpHorizontalScrollBar->Show(bShowHorizontal); + + // Adapt the remaining space accordingly. + Rectangle aRemainingSpace (rAvailableArea); + if (bShowVertical) + aRemainingSpace.Right() -= mpVerticalScrollBar->GetSizePixel().Width(); + if (bShowHorizontal) + aRemainingSpace.Bottom() -= mpHorizontalScrollBar->GetSizePixel().Height(); + + return aRemainingSpace; +} + + + + +bool ScrollBarManager::TestScrollBarVisibilities ( + bool bHorizontalScrollBarVisible, + bool bVerticalScrollBarVisible, + const Rectangle& rAvailableArea) +{ + bool bAreVisibilitiesOK = true; + + // Adapt the available size by subtracting the sizes of the scroll bars + // visible in this combination. + Size aBrowserSize (rAvailableArea.GetSize()); + if (bHorizontalScrollBarVisible) + aBrowserSize.Height() -= mpHorizontalScrollBar->GetSizePixel().Height(); + if (bVerticalScrollBarVisible) + aBrowserSize.Width() -= mpVerticalScrollBar->GetSizePixel().Width(); + + // Tell the view to rearrange its page objects and check whether the + // page objects can be shown without clipping. + bool bRearrangeSuccess (false); + if (mrSlideSorter.GetView().GetOrientation() == view::SlideSorterView::HORIZONTAL) + { + bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeHorizontal ( + aBrowserSize, + mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(), + mpContentWindow.get(), + mrSlideSorter.GetModel().GetPageCount()); + } + else + { + bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeVertical ( + aBrowserSize, + mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(), + mpContentWindow.get()); + } + + if (bRearrangeSuccess) + { + Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetPageBox ( + mrSlideSorter.GetModel().GetPageCount()).GetSize(); + Size aWindowModelSize = mpContentWindow->PixelToLogic(aBrowserSize); + + bool bHorizontallyClipped = (aPageSize.Width() > aWindowModelSize.Width()); + bool bVerticallyClipped = (aPageSize.Height() > aWindowModelSize.Height()); + bAreVisibilitiesOK = (bHorizontallyClipped == bHorizontalScrollBarVisible) + && (bVerticallyClipped == bVerticalScrollBarVisible); + } + else + bAreVisibilitiesOK = false; + + return bAreVisibilitiesOK; +} + + + + +void ScrollBarManager::SetTop (const sal_Int32 nNewTop) +{ + if (mpVerticalScrollBar != NULL + && mpVerticalScrollBar->GetThumbPos() != nNewTop) + { + // Flush pending repaints before scrolling to avoid temporary artifacts. + mrSlideSorter.GetView().GetWindow()->Update(); + + mpVerticalScrollBar->SetThumbPos(nNewTop); + mnVerticalPosition = double(nNewTop) / double(mpVerticalScrollBar->GetRange().Len()); + mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( + mnHorizontalPosition, mnVerticalPosition); + } +} + + + + +void ScrollBarManager::SetLeft (const sal_Int32 nNewLeft) +{ + if (mpHorizontalScrollBar != NULL + && mpHorizontalScrollBar->GetThumbPos() != nNewLeft) + { + // Flush pending repaints before scrolling to avoid temporary artifacts. + mrSlideSorter.GetView().GetWindow()->Update(); + + mpHorizontalScrollBar->SetThumbPos(nNewLeft); + mnHorizontalPosition = double(nNewLeft) / double(mpHorizontalScrollBar->GetRange().Len()); + mrSlideSorter.GetView().GetWindow()->SetVisibleXY ( + mnHorizontalPosition, mnVerticalPosition); + } +} + + + + +int ScrollBarManager::GetVerticalScrollBarWidth (void) const +{ + if (mpVerticalScrollBar != NULL && mpVerticalScrollBar->IsVisible()) + return mpVerticalScrollBar->GetSizePixel().Width(); + else + return 0; +} + + + + +int ScrollBarManager::GetHorizontalScrollBarHeight (void) const +{ + if (mpHorizontalScrollBar != NULL && mpHorizontalScrollBar->IsVisible()) + return mpHorizontalScrollBar->GetSizePixel().Height(); + else + return 0; +} + + + + +void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition) +{ + ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow(); + + int nDx = 0; + int nDy = 0; + + Size aWindowSize = pWindow->GetOutputSizePixel(); + Rectangle aWindowArea (pWindow->GetPosPixel(), aWindowSize); + Rectangle aViewPixelArea ( + pWindow->LogicToPixel(mrSlideSorter.GetView().GetModelArea())); + + if (aWindowSize.Width() > maScrollBorder.Width() * 3 + && mpHorizontalScrollBar != NULL + && mpHorizontalScrollBar->IsVisible()) + { + if (rMouseWindowPosition.X() < maScrollBorder.Width() + && aWindowArea.Left() > aViewPixelArea.Left()) + { + nDx = -1 + (int)(mnHorizontalScrollFactor + * (rMouseWindowPosition.X() - maScrollBorder.Width())); + } + + if (rMouseWindowPosition.X() >= (aWindowSize.Width() - maScrollBorder.Width()) + && aWindowArea.Right() < aViewPixelArea.Right()) + { + nDx = 1 + (int)(mnHorizontalScrollFactor + * (rMouseWindowPosition.X() - aWindowSize.Width() + + maScrollBorder.Width())); + } + } + + if (aWindowSize.Height() > maScrollBorder.Height() * 3 + && aWindowSize.Height() < aViewPixelArea.GetHeight()) + { + if (rMouseWindowPosition.Y() < maScrollBorder.Height() + && aWindowArea.Top() > aViewPixelArea.Top()) + { + nDy = -1 + (int)(mnVerticalScrollFactor + * (rMouseWindowPosition.Y() - maScrollBorder.Height())); + } + + if (rMouseWindowPosition.Y() >= (aWindowSize.Height() - maScrollBorder.Height()) + && aWindowArea.Bottom() < aViewPixelArea.Bottom()) + { + nDy = 1 + (int)(mnVerticalScrollFactor + * (rMouseWindowPosition.Y() - aWindowSize.Height() + + maScrollBorder.Height())); + } + } + + maAutoScrollOffset = Size(nDx,nDy); +} + + + + +bool ScrollBarManager::AutoScroll (const Point& rMouseWindowPosition) +{ + CalcAutoScrollOffset (rMouseWindowPosition); + bool bResult = RepeatAutoScroll(); + if (bResult) + { + maAutoScrollTimer.Start(); + } + return bResult; +} + + + + +void ScrollBarManager::StopAutoScroll (void) +{ + maAutoScrollTimer.Stop(); +} + + + + +bool ScrollBarManager::RepeatAutoScroll (void) +{ + if (maAutoScrollOffset != Size(0,0)) + { + if (mrSlideSorter.GetViewShell() != NULL) + { + mrSlideSorter.GetViewShell()->ScrollLines( + maAutoScrollOffset.Width(), + maAutoScrollOffset.Height()); + return true; + } + } + + return false; +} + + + + +IMPL_LINK(ScrollBarManager, AutoScrollTimeoutHandler, Timer *, EMPTYARG) +{ + RepeatAutoScroll(); + + return 0; +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionCommand.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.cxx new file mode 100644 index 000000000000..ba0b5f2f975b --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.cxx @@ -0,0 +1,108 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSelectionCommand.cxx,v $ + * $Revision: 1.8 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlsSelectionCommand.hxx" + +#include "controller/SlsCurrentSlideManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" + +#include "sdpage.hxx" + +namespace sd { namespace slidesorter { namespace controller { + + + +SelectionCommand::SelectionCommand ( + PageSelector& rSelector, + const ::boost::shared_ptr<CurrentSlideManager>& rpCurrentSlideManager, + const model::SlideSorterModel& rModel) + : mrPageSelector(rSelector), + mpCurrentSlideManager(rpCurrentSlideManager), + mrModel(rModel), + maPagesToSelect(), + mnCurrentPageIndex(-1) +{ +} + + + + +void SelectionCommand::AddSlides ( + const ::boost::shared_ptr<PageSelector::PageSelection>& rpSelection) +{ + PageSelector::PageSelection::iterator iPage = rpSelection->begin(); + PageSelector::PageSelection::iterator iEnd = rpSelection->end(); + for (; iPage!=iEnd; ++iPage) + AddSlide(((*iPage)->GetPageNum()-1)/2); +} + + + + +void SelectionCommand::AddSlide (USHORT nPageIndex) +{ + maPagesToSelect.push_back(nPageIndex); +} + + + + +void SelectionCommand::SetCurrentSlide (USHORT nPageIndex) +{ + mnCurrentPageIndex = nPageIndex; +} + + + + +void SelectionCommand::operator() (void) +{ + OSL_ASSERT(mpCurrentSlideManager.get()!=NULL); + + mrPageSelector.DeselectAllPages(); + + if (mnCurrentPageIndex >= 0) + mpCurrentSlideManager->SwitchCurrentSlide(mnCurrentPageIndex); + + PageList::iterator iPage = maPagesToSelect.begin(); + PageList::iterator iEnd = maPagesToSelect.end(); + for (; iPage!=iEnd; ++iPage) + { + sal_Int32 nIndex (*iPage); + if (nIndex >= 0) + mrPageSelector.SelectPage(mrModel.GetPageDescriptor(nIndex)); + } +} + + +} } } // end of namespace sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionCommand.hxx b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.hxx new file mode 100644 index 000000000000..0f6b269f3ef9 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.hxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSelectionCommand.hxx,v $ + * $Revision: 1.5 $ + * + * 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 SD_SLIDESORTER_SELECTION_COMMAND_HXX +#define SD_SLIDESORTER_SELECTION_COMMAND_HXX + +#include "controller/SlsPageSelector.hxx" +#include "SlsCommand.hxx" +#include <tools/solar.h> +#include <com/sun/star/drawing/XDrawPage.hpp> + +#include <boost/shared_ptr.hpp> +#include <vector> + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + + +namespace sd { namespace slidesorter { namespace controller { + +class CurrentSlideManager; +class PageSelector; + +/** The SelectionCommand stores a list of pages that it will select on its + execution. Furthermore it will make a page the current page. Note that + internally pages are stored with pointers because this command is designed + to be executed after model changes where page indices may change but + page object identities remain. +*/ +class SelectionCommand + : public Command +{ +public: + /** Create a new command object that will on its exection use the given + PageSelector to select a set of pages. + */ + SelectionCommand ( + PageSelector& rSelector, + const ::boost::shared_ptr<controller::CurrentSlideManager>& rpCurrentSlideManager, + const model::SlideSorterModel& rModel); + + /** Add the pages in the given list of selected pages to those that will + be selected when this command is executed, i.e. its operator() + method is called. + The first page will be set as current page when the new current page + has not been specified previously. + */ + void AddSlides (const ::boost::shared_ptr<PageSelector::PageSelection>& rpSelection); + + /** Remember the specified page to be selected when this command is + executed. + */ + void AddSlide (USHORT nPageIndex); + + /** Call this method to explicitly set the page that will be made the + current page when this command is executed. + */ + void SetCurrentSlide (USHORT nPageIndex); + + /** Execute the command and select the pages added by previous calls to + AddPages() and AddPage(). + */ + virtual void operator() (void); + +private: + /// The page selector is used to select pages and set the current page. + PageSelector& mrPageSelector; + /// Used for setting the current slide. + ::boost::shared_ptr<controller::CurrentSlideManager> mpCurrentSlideManager; + /// The model is used to translate page indices into page pointers. + const model::SlideSorterModel& mrModel; + /// The list of pages to be selected when the command is executed. + typedef ::std::vector<sal_Int32> PageList; + PageList maPagesToSelect; + /** The page that will be made the current page when the command is + executed. + */ + sal_Int32 mnCurrentPageIndex; +}; + +} } } // end of namespace sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx new file mode 100644 index 000000000000..9ed68156f701 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx @@ -0,0 +1,1407 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSelectionFunction.cxx,v $ + * $Revision: 1.37 $ + * + * 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 "precompiled_sd.hxx" + +#include "controller/SlsSelectionFunction.hxx" + +#include "SlideSorter.hxx" +#include "SlideSorterViewShell.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsClipboard.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsProperties.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsViewOverlay.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "framework/FrameworkHelper.hxx" +#include "showview.hxx" +#include "ViewShellBase.hxx" +#include "DrawController.hxx" +#include <vcl/sound.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdpagv.hxx> +#include <vcl/msgbox.hxx> +#include "Window.hxx" +#include "sdpage.hxx" +#include "drawdoc.hxx" +#include "ViewShell.hxx" +#include "ViewShellBase.hxx" +#include "FrameView.hxx" +#include "app.hrc" +#include "sdresid.hxx" +#include "strings.hrc" + +namespace { +static const sal_uInt32 SINGLE_CLICK (0x00000001); +static const sal_uInt32 DOUBLE_CLICK (0x00000002); +static const sal_uInt32 LEFT_BUTTON (0x00000010); +static const sal_uInt32 RIGHT_BUTTON (0x00000020); +static const sal_uInt32 MIDDLE_BUTTON (0x00000040); +static const sal_uInt32 BUTTON_DOWN (0x00000100); +static const sal_uInt32 BUTTON_UP (0x00000200); +static const sal_uInt32 MOUSE_MOTION (0x00000400); +// The rest leaves the lower 16 bit untouched so that it can be used with +// key codes. +static const sal_uInt32 OVER_SELECTED_PAGE (0x00010000); +static const sal_uInt32 OVER_UNSELECTED_PAGE (0x00020000); +static const sal_uInt32 OVER_FADE_INDICATOR (0x00040000); +static const sal_uInt32 SHIFT_MODIFIER (0x00100000); +static const sal_uInt32 CONTROL_MODIFIER (0x00200000); +static const sal_uInt32 SUBSTITUTION_VISIBLE (0x01000000); +static const sal_uInt32 RECTANGLE_VISIBLE (0x02000000); + +static const sal_uInt32 KEY_EVENT (0x10000000); + +// Some absent events are defined so they can be expressed explicitly. +static const sal_uInt32 NO_MODIFIER (0x00000000); +static const sal_uInt32 SUBSTITUTION_NOT_VISIBLE (0x00000000); +static const sal_uInt32 NOT_OVER_PAGE (0x00000000); + + +} // end of anonymous namespace + + +namespace sd { namespace slidesorter { namespace controller { + +class SelectionFunction::SubstitutionHandler +{ +public: + SubstitutionHandler (SlideSorter& rSlideSorter); + ~SubstitutionHandler (void); + + /** Create a substitution display of the currently selected pages and + use the given position as the anchor point. + */ + void Start (const Point& rMouseModelPosition); + + /** Move the substitution display by the distance the mouse has + travelled since the last call to this method or to + CreateSubstitution(). The given point becomes the new anchor. + */ + void UpdatePosition (const Point& rMouseModelPosition); + + /** Move the substitution display of the currently selected pages. + */ + void Process (void); + + void End (void); + + bool HasBeenMoved (void) const; + +private: + SlideSorter& mrSlideSorter; + + bool mbHasBeenMoved; + + /** Determine whether there is a) a substitution and b) its insertion at + the current position of the insertion marker would alter the + document. This would be the case when the substitution has been + moved or is not consecutive. + */ + bool IsSubstitutionInsertionNonTrivial (void) const; +}; + + +class SelectionFunction::InsertionIndicatorHandler +{ +public: + InsertionIndicatorHandler (SlideSorter& rSlideSorter); + ~InsertionIndicatorHandler (void); + + /** Show the insertion marker at the given coordinates. + */ + void Start (const Point& rMouseModelPosition); + + void UpdatePosition (const Point& rMouseModelPosition); + + /** Hide the insertion marker. + */ + void End (void); + +private: + SlideSorter& mrSlideSorter; +}; + +class SelectionFunction::EventDescriptor +{ +public: + + Point maMousePosition; + Point maMouseModelPosition; + ::boost::weak_ptr<model::PageDescriptor> mpHitDescriptor; + SdrPage* mpHitPage; + sal_uInt32 mnEventCode; + + EventDescriptor ( + sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter); + EventDescriptor ( + const KeyEvent& rEvent, + SlideSorter& rSlideSorter); +}; + + +TYPEINIT1(SelectionFunction, FuPoor); + + +SelectionFunction::SelectionFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest) + : SlideFunction (rSlideSorter, rRequest), + mrSlideSorter(rSlideSorter), + mrController(mrSlideSorter.GetController()), + mbDragSelection(false), + maInsertionMarkerBox(), + mbProcessingMouseButtonDown(false), + mpSubstitutionHandler(new SubstitutionHandler(mrSlideSorter)), + mpInsertionIndicatorHandler(new InsertionIndicatorHandler(mrSlideSorter)) +{ + //af aDelayToScrollTimer.SetTimeout(50); + aDragTimer.SetTimeoutHdl( LINK( this, SelectionFunction, DragSlideHdl ) ); +} + +SelectionFunction::~SelectionFunction (void) +{ + aDragTimer.Stop(); +} + + + + +FunctionReference SelectionFunction::Create( + SlideSorter& rSlideSorter, + SfxRequest& rRequest) +{ + FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) ); + return xFunc; +} + + + + +BOOL SelectionFunction::MouseButtonDown (const MouseEvent& rEvent) +{ + // #95491# remember button state for creation of own MouseEvents + SetMouseButtonCode (rEvent.GetButtons()); + mbProcessingMouseButtonDown = true; + + mpWindow->CaptureMouse(); + + ProcessMouseEvent(BUTTON_DOWN, rEvent); + + return TRUE; +} + + + + +BOOL SelectionFunction::MouseMove (const MouseEvent& rEvent) +{ + Point aMousePosition (rEvent.GetPosPixel()); + + // Determine page under mouse and show the mouse over effect. + model::SharedPageDescriptor pHitDescriptor (mrController.GetPageAt(aMousePosition)); + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + rOverlay.GetMouseOverIndicatorOverlay().SetSlideUnderMouse( + rEvent.IsLeaveWindow() ? model::SharedPageDescriptor() : pHitDescriptor); + if (pHitDescriptor.get() != NULL) + rOverlay.GetMouseOverIndicatorOverlay().setVisible(true); + else + rOverlay.GetMouseOverIndicatorOverlay().setVisible(false); + + // Allow one mouse move before the drag timer is disabled. + if (aDragTimer.IsActive()) + { + if (bFirstMouseMove) + bFirstMouseMove = FALSE; + else + aDragTimer.Stop(); + } + + Rectangle aRectangle (Point(0,0),mpWindow->GetOutputSizePixel()); + if ( ! aRectangle.IsInside(aMousePosition) + && rOverlay.GetSubstitutionOverlay().isVisible()) + { + // Mouse left the window with pressed left button. Make it a drag. + StartDrag(); + } + else + { + // Call ProcessMouseEvent() only when one of the buttons is + // pressed. This prevents calling the method on every motion. + if (rEvent.GetButtons() != 0 + && mbProcessingMouseButtonDown) + { + ProcessMouseEvent(MOUSE_MOTION, rEvent); + } + } + + return TRUE; +} + + + + +BOOL SelectionFunction::MouseButtonUp (const MouseEvent& rEvent) +{ + mrController.GetScrollBarManager().StopAutoScroll (); + + // #95491# remember button state for creation of own MouseEvents + SetMouseButtonCode (rEvent.GetButtons()); + + if (aDragTimer.IsActive()) + aDragTimer.Stop(); + + ProcessMouseEvent(BUTTON_UP, rEvent); + + mbProcessingMouseButtonDown = false; + mpWindow->ReleaseMouse(); + + return TRUE; +} + + + + +BOOL SelectionFunction::KeyInput (const KeyEvent& rEvent) +{ + FocusManager& rFocusManager (mrController.GetFocusManager()); + BOOL bResult = FALSE; + + switch (rEvent.GetKeyCode().GetCode()) + { + case KEY_RETURN: + if (rFocusManager.HasFocus()) + { + model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); + if (pDescriptor.get() != NULL) + { + SetCurrentPage(pDescriptor); + SwitchView(pDescriptor); + } + bResult = TRUE; + } + break; + + case KEY_TAB: + if ( ! rFocusManager.IsFocusShowing()) + rFocusManager.ShowFocus(); + else + if (rEvent.GetKeyCode().IsShift()) + rFocusManager.MoveFocus (FocusManager::FMD_LEFT); + else + rFocusManager.MoveFocus (FocusManager::FMD_RIGHT); + bResult = TRUE; + break; + + case KEY_ESCAPE: + rFocusManager.SetFocusToToolBox(); + bResult = TRUE; + break; + + case KEY_SPACE: + { + // Toggle the selection state. + model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); + if (pDescriptor.get() != NULL) + { + // Doing a multi selection by default. Can we ask the event + // for the state of the shift key? + if (pDescriptor->IsSelected()) + mrController.GetPageSelector().DeselectPage(pDescriptor); + else + mrController.GetPageSelector().SelectPage(pDescriptor); + } + bResult = TRUE; + } + break; + + + // Move the focus indicator left. + case KEY_LEFT: + rFocusManager.MoveFocus (FocusManager::FMD_LEFT); + bResult = TRUE; + break; + + // Move the focus indicator right. + case KEY_RIGHT: + rFocusManager.MoveFocus (FocusManager::FMD_RIGHT); + bResult = TRUE; + break; + + // Move the focus indicator up. + case KEY_UP: + rFocusManager.MoveFocus (FocusManager::FMD_UP); + bResult = TRUE; + break; + + // Move the focus indicator down. + case KEY_DOWN: + rFocusManager.MoveFocus (FocusManager::FMD_DOWN); + bResult = TRUE; + break; + + // Go to previous page. No wrap around. + case KEY_PAGEUP: + GotoNextPage(-1); + bResult = TRUE; + break; + + // Go to next page. No wrap around.. + case KEY_PAGEDOWN: + GotoNextPage(+1); + bResult = TRUE; + break; + + case KEY_DELETE: + case KEY_BACKSPACE: + { + if (mrController.GetProperties()->IsUIReadOnly()) + break; + + int nSelectedPagesCount = 0; + + // Count the selected pages and look if there any objects on any + // of the selected pages so that we can warn the user and + // prevent an accidental deletion. + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + nSelectedPagesCount++; + aSelectedPages.GetNextElement(); + } + + if (nSelectedPagesCount > 0) + mrController.GetSelectionManager()->DeleteSelectedPages(); + + bResult = TRUE; + } + break; + + case KEY_F10: + if (rEvent.GetKeyCode().IsShift()) + ProcessKeyEvent(rEvent); + break; + + default: + break; + } + + if ( ! bResult) + bResult = SlideFunction::KeyInput (rEvent); + + return bResult; +} + + + + +void SelectionFunction::Activate() +{ + FuPoor::Activate(); +} + + + + +void SelectionFunction::Deactivate() +{ + FuPoor::Deactivate(); +} + + + +void SelectionFunction::ScrollStart (void) +{ +} + + + + +void SelectionFunction::ScrollEnd (void) +{ +} + + + + +void SelectionFunction::DoCut (void) +{ + if ( ! mrController.GetProperties()->IsUIReadOnly()) + { + mrController.GetClipboard().DoCut(); + } +} + + + + +void SelectionFunction::DoCopy (void) +{ + mrController.GetClipboard().DoCopy(); +} + + + + +void SelectionFunction::DoPaste (void) +{ + if ( ! mrController.GetProperties()->IsUIReadOnly()) + { + mrController.GetClipboard().DoPaste(); + } +} + + + + +void SelectionFunction::Paint (const Rectangle&, ::sd::Window* ) +{ +} + + + + +IMPL_LINK( SelectionFunction, DragSlideHdl, Timer*, EMPTYARG ) +{ + StartDrag(); + return 0; +} + + + + +void SelectionFunction::StartDrag (void) +{ + if (mbPageHit + && ! mrController.GetProperties()->IsUIReadOnly()) + { + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + mpSubstitutionHandler->Start(rOverlay.GetSubstitutionOverlay().GetPosition()); + mbPageHit = false; + mpWindow->ReleaseMouse(); + + if (mrSlideSorter.GetViewShell() != NULL) + { + SlideSorterViewShell* pSlideSorterViewShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + pSlideSorterViewShell->StartDrag ( + rOverlay.GetSubstitutionOverlay().GetPosition(), + mpWindow); + } + } +} + + + + +bool SelectionFunction::cancel (void) +{ + mrController.GetFocusManager().ToggleFocus(); + return true; +} + + + + +void SelectionFunction::SelectHitPage (const model::SharedPageDescriptor& rpDescriptor) +{ + mrController.GetPageSelector().SelectPage(rpDescriptor); +} + + + + +void SelectionFunction::DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor) +{ + mrController.GetPageSelector().DeselectPage(rpDescriptor); +} + + + + +void SelectionFunction::DeselectAllPages (void) +{ + mrController.GetPageSelector().DeselectAllPages(); +} + + + + +void SelectionFunction::StartRectangleSelection (const Point& rMouseModelPosition) +{ + if (mrController.GetProperties()->IsShowSelection()) + { + mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Start( + rMouseModelPosition); + } +} + + + + +void SelectionFunction::UpdateRectangleSelection (const Point& rMouseModelPosition) +{ + if (mrController.GetProperties()->IsShowSelection()) + { + mrSlideSorter.GetView().GetOverlay().GetSelectionRectangleOverlay().Update( + rMouseModelPosition); + } +} + + + + +void SelectionFunction::ProcessRectangleSelection (bool bToggleSelection) +{ + if ( ! mrController.GetProperties()->IsShowSelection()) + return; + + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + if (rOverlay.GetSelectionRectangleOverlay().isVisible()) + { + PageSelector& rSelector (mrController.GetPageSelector()); + + rOverlay.GetSelectionRectangleOverlay().setVisible(false); + + // Select all pages whose page object lies completly inside the drag + // rectangle. + const Rectangle& rSelectionRectangle ( + rOverlay.GetSelectionRectangleOverlay().GetSelectionRectangle()); + model::PageEnumeration aPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration( + mrSlideSorter.GetModel())); + while (aPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + Rectangle aPageBox (mrSlideSorter.GetView().GetPageBoundingBox( + pDescriptor, + view::SlideSorterView::CS_MODEL, + view::SlideSorterView::BBT_SHAPE)); + if (rSelectionRectangle.IsOver(aPageBox)) + { + // When we are extending the selection (shift key is + // pressed) then toggle the selection state of the page. + // Otherwise select it: this results in the previously + // selected pages becoming deslected. + if (bToggleSelection && pDescriptor->IsSelected()) + rSelector.DeselectPage(pDescriptor); + else + rSelector.SelectPage(pDescriptor); + } + } + } +} + + + + +void SelectionFunction::PrepareMouseMotion (const Point& ) +{ + if ( ! mrController.GetProperties()->IsUIReadOnly()) + { + bFirstMouseMove = TRUE; + aDragTimer.Start(); + } +} + + + + +void SelectionFunction::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) +{ + PageSelector& rSelector (mrController.GetPageSelector()); + + model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor()); + DeselectAllPages(); + + if (pAnchor.get() != NULL) + { + // Select all pages between the anchor and the given one, including + // the two. + USHORT nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2); + USHORT nOtherIndex ((rpDescriptor->GetPage()->GetPageNum()-1) / 2); + + // Iterate over all pages in the range. Start with the anchor + // page. This way the PageSelector will recognize it again as + // anchor (the first selected page after a DeselectAllPages() + // becomes the anchor.) + USHORT nStep = (nAnchorIndex < nOtherIndex) ? +1 : -1; + USHORT nIndex = nAnchorIndex; + while (true) + { + rSelector.SelectPage(nIndex); + if (nIndex == nOtherIndex) + break; + nIndex = nIndex + nStep; + } + } +} + + + + +void SelectionFunction::GotoNextPage (int nOffset) +{ + model::SharedPageDescriptor pDescriptor + = mrController.GetCurrentSlideManager()->GetCurrentSlide(); + if (pDescriptor.get() != NULL) + { + SdPage* pPage = pDescriptor->GetPage(); + OSL_ASSERT(pPage!=NULL); + sal_Int32 nIndex = (pPage->GetPageNum()-1) / 2; + nIndex += nOffset; + USHORT nPageCount = (USHORT)mrSlideSorter.GetModel().GetPageCount(); + + if (nIndex >= nPageCount) + nIndex = nPageCount - 1; + if (nIndex < 0) + nIndex = 0; + + mrController.GetFocusManager().SetFocusedPage(nIndex); + model::SharedPageDescriptor pNextPageDescriptor ( + mrSlideSorter.GetModel().GetPageDescriptor (nIndex)); + if (pNextPageDescriptor.get() != NULL) + SetCurrentPage(pNextPageDescriptor); + else + { + OSL_ASSERT(pNextPageDescriptor.get() != NULL); + } + } +} + + + + +void SelectionFunction::ClearOverlays (void) +{ + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + + rOverlay.GetSubstitutionOverlay().setVisible(false); + rOverlay.GetSubstitutionOverlay().Clear(); + + mpInsertionIndicatorHandler->End(); + rOverlay.GetMouseOverIndicatorOverlay().SetSlideUnderMouse(model::SharedPageDescriptor()); +} + + + + +void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) +{ + // #95491# remember button state for creation of own MouseEvents + SetMouseButtonCode (rEvent.GetButtons()); + + // 1. Compute some frequently used values relating to the event. + ::std::auto_ptr<EventDescriptor> pEventDescriptor ( + new EventDescriptor(nEventType, rEvent, mrSlideSorter)); + + // 2. Compute a numerical code that describes the event and that is used + // for fast look-up of the associated reaction. + pEventDescriptor->mnEventCode = EncodeMouseEvent(*pEventDescriptor, rEvent); + + // 3. Process the event. + EventPreprocessing(*pEventDescriptor); + if ( ! EventProcessing(*pEventDescriptor)) + { + OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode); + } + EventPostprocessing(*pEventDescriptor); + + if (nEventType == BUTTON_UP) + mbPageHit = false; +} + + + + +sal_uInt32 SelectionFunction::EncodeMouseEvent ( + const EventDescriptor& rDescriptor, + const MouseEvent& rEvent) const +{ + // Initialize with the type of mouse event. + sal_uInt32 nEventCode (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION)); + + // Detect the affected button. + switch (rEvent.GetButtons()) + { + case MOUSE_LEFT: nEventCode |= LEFT_BUTTON; break; + case MOUSE_RIGHT: nEventCode |= RIGHT_BUTTON; break; + case MOUSE_MIDDLE: nEventCode |= MIDDLE_BUTTON; break; + } + + // Detect the number of clicks. + switch (rEvent.GetClicks()) + { + case 1: nEventCode |= SINGLE_CLICK; break; + case 2: nEventCode |= DOUBLE_CLICK; break; + } + + // Detect whether the event has happened over a page object. + if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired()) + { + model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor); + if (pHitDescriptor->IsSelected()) + nEventCode |= OVER_SELECTED_PAGE; + else + nEventCode |= OVER_UNSELECTED_PAGE; + } + + // Detect pressed modifier keys. + if (rEvent.IsShift()) + nEventCode |= SHIFT_MODIFIER; + if (rEvent.IsMod1()) + nEventCode |= CONTROL_MODIFIER; + + // Detect whether we are dragging pages or dragging a selection rectangle. + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + if (rOverlay.GetSubstitutionOverlay().isVisible()) + nEventCode |= SUBSTITUTION_VISIBLE; + if (rOverlay.GetSelectionRectangleOverlay().isVisible()) + nEventCode |= RECTANGLE_VISIBLE; + + return nEventCode; +} + + + + +void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) +{ + // 1. Compute some frequently used values relating to the event. + ::std::auto_ptr<EventDescriptor> pEventDescriptor ( + new EventDescriptor(rEvent, mrSlideSorter)); + + // 2. Encode the event. + pEventDescriptor->mnEventCode = EncodeKeyEvent(*pEventDescriptor, rEvent); + + // 3. Process the event. + EventPreprocessing(*pEventDescriptor); + if ( ! EventProcessing(*pEventDescriptor)) + OSL_TRACE ("can not handle event code %x", pEventDescriptor->mnEventCode); + EventPostprocessing(*pEventDescriptor); +} + + + + +sal_uInt32 SelectionFunction::EncodeKeyEvent ( + const EventDescriptor& rDescriptor, + const KeyEvent& rEvent) const +{ + // Initialize as key event. + sal_uInt32 nEventCode (KEY_EVENT); + + // Add the actual key code in the lower 16 bit. + nEventCode |= rEvent.GetKeyCode().GetCode(); + + // Detect pressed modifier keys. + if (rEvent.GetKeyCode().IsShift()) + nEventCode |= SHIFT_MODIFIER; + if (rEvent.GetKeyCode().IsMod1()) + nEventCode |= CONTROL_MODIFIER; + + // Detect whether the event has happened over a page object. + if (rDescriptor.mpHitPage != NULL && ! rDescriptor.mpHitDescriptor.expired()) + { + model::SharedPageDescriptor pHitDescriptor (rDescriptor.mpHitDescriptor); + if (pHitDescriptor->IsSelected()) + nEventCode |= OVER_SELECTED_PAGE; + else + nEventCode |= OVER_UNSELECTED_PAGE; + } + + // Detect whether we are dragging pages or dragging a selection rectangle. + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + if (rOverlay.GetSubstitutionOverlay().isVisible()) + nEventCode |= SUBSTITUTION_VISIBLE; + if (rOverlay.GetSelectionRectangleOverlay().isVisible()) + nEventCode |= RECTANGLE_VISIBLE; + + return nEventCode; +} + + + +void SelectionFunction::EventPreprocessing (const EventDescriptor& rDescriptor) +{ + // Some general processing that is not specific to the exact event code. + if (rDescriptor.mnEventCode & BUTTON_DOWN) + mbPageHit = (rDescriptor.mpHitPage!=NULL); + + // Set the focus to the slide under the mouse. + if (rDescriptor.mpHitPage != NULL) + mrController.GetFocusManager().FocusPage((rDescriptor.mpHitPage->GetPageNum()-1)/2); +} + + + + +bool SelectionFunction::EventProcessing (const EventDescriptor& rDescriptor) +{ + // Define some macros to make the following switch statement more readable. +#define ANY_MODIFIER(code) \ + code|NO_MODIFIER: \ + case code|SHIFT_MODIFIER: \ + case code|CONTROL_MODIFIER +#define ANY_PAGE(code) \ + code|NOT_OVER_PAGE: \ + case code|OVER_UNSELECTED_PAGE: \ + case code|OVER_SELECTED_PAGE +#define ANY_PAGE_AND_MODIFIER(code) \ + ANY_PAGE(code|NO_MODIFIER): \ + case ANY_PAGE(code|SHIFT_MODIFIER): \ + case ANY_PAGE(code|CONTROL_MODIFIER) + + + bool bResult (true); + bool bMakeSelectionVisible (true); + + mrController.GetPageSelector().DisableBroadcasting(); + + // 2b. With the event code determine the type of operation with which to + // react to the event. + + // Acquire a shared_ptr to the hit page descriptor. + model::SharedPageDescriptor pHitDescriptor; + if ( ! rDescriptor.mpHitDescriptor.expired()) + pHitDescriptor = model::SharedPageDescriptor(rDescriptor.mpHitDescriptor); + + switch (rDescriptor.mnEventCode) + { + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE: + SetCurrentPage(pHitDescriptor); + PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); + mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition); + break; + + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + SetCurrentPage(pHitDescriptor); + mpSubstitutionHandler->End(); + break; + + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); + mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition); + break; + + case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_SELECTED_PAGE: + case BUTTON_DOWN | LEFT_BUTTON | DOUBLE_CLICK | OVER_UNSELECTED_PAGE: + // A double click allways shows the selected slide in the center + // pane in an edit view. + SetCurrentPage(pHitDescriptor); + SwitchView(pHitDescriptor); + break; + + // Multi selection with the control modifier. + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER: + DeselectHitPage(pHitDescriptor); + PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); + break; + + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER: + SelectHitPage(pHitDescriptor); + PrepareMouseMotion(mpWindow->PixelToLogic(rDescriptor.maMousePosition)); + + break; + + // Range selection with the shift modifier. + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER: + RangeSelect(pHitDescriptor); + break; + + // Was: Preview of the page transition effect. + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_FADE_INDICATOR: + // No action. + break; + + // Right button for context menu. + case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE: + case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | OVER_UNSELECTED_PAGE: + // Single right click and shift+F10 select as preparation to + // show the context menu. Change the selection only when the + // page under the mouse is not selected. In this case the + // selection is set to this single page. Otherwise the + // selection is not modified. + DeselectAllPages(); + SelectHitPage(pHitDescriptor); + SetCurrentPage(pHitDescriptor); + bMakeSelectionVisible = false; + break; + + case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + case KEY_EVENT | KEY_F10 | OVER_SELECTED_PAGE | SHIFT_MODIFIER: + // Do not change the selection. Just adjust the insertion indicator. + bMakeSelectionVisible = false; + break; + + case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: + // The Shift+F10 key event is here just for completeness. It should + // not be possible to really receive this (not being over a page.) + case KEY_EVENT | KEY_F10 | SHIFT_MODIFIER | NOT_OVER_PAGE: + DeselectAllPages(); + bMakeSelectionVisible = false; + break; + + // A mouse motion without visible substitution starts that. + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE): + mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition); + mpSubstitutionHandler->Start(rDescriptor.maMouseModelPosition); + break; + + // Move substitution. + case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE): + if ((rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0) + StartDrag(); + mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition); + mpSubstitutionHandler->UpdatePosition(rDescriptor.maMouseModelPosition); + break; + + // Place substitution. + case ANY_PAGE_AND_MODIFIER(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | SUBSTITUTION_VISIBLE): + // When the substitution has not been moved the button up event + // is taken to be part of a single click. The selected pages + // are therefore not moved (which technically would be necessary + // for unconsecutive multi selections). Instead the page under + // the mouse becomes the only selected page. + if (mpSubstitutionHandler->HasBeenMoved()) + { + // The following Process() call may lead to the desctruction + // of pHitDescriptor so release our reference to it. + pHitDescriptor.reset(); + mpSubstitutionHandler->Process(); + } + else + if (pHitDescriptor != NULL) + SetCurrentPage(pHitDescriptor); + mpSubstitutionHandler->End(); + break; + + // Rectangle selection. + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | NO_MODIFIER: + DeselectAllPages(); + StartRectangleSelection(rDescriptor.maMouseModelPosition); + break; + + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | SHIFT_MODIFIER: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE | CONTROL_MODIFIER: + StartRectangleSelection(rDescriptor.maMouseModelPosition); + break; + + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE): + case ANY_PAGE_AND_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE): + mrController.GetScrollBarManager().AutoScroll(rDescriptor.maMousePosition); + UpdateRectangleSelection(rDescriptor.maMouseModelPosition); + break; + + case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | NO_MODIFIER): + ProcessRectangleSelection(false); + break; + + case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | SHIFT_MODIFIER): + case ANY_PAGE(BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | RECTANGLE_VISIBLE | CONTROL_MODIFIER): + ProcessRectangleSelection(true); + break; + + default: + bResult = false; + break; + } + mrController.GetPageSelector().EnableBroadcasting(bMakeSelectionVisible); + + return bResult; +} + + + + +void SelectionFunction::EventPostprocessing (const EventDescriptor& rDescriptor) +{ + if (rDescriptor.mnEventCode & BUTTON_UP) + { + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + + mpWindow->ReleaseMouse(); + + // The overlays should not be visible anymore. Warn when one of + // them still is. An exception is th insertion indicator in the + // case that the context menu is visible. + DBG_ASSERT( + mrController.IsContextMenuOpen() + || !rOverlay.GetInsertionIndicatorOverlay().isVisible(), + "slidesorter::SelectionFunction: insertion indicator still visible"); + DBG_ASSERT( + !rOverlay.GetSubstitutionOverlay().isVisible(), + "slidesorter::SelectionFunction: substitution still visible"); + DBG_ASSERT( + !rOverlay.GetSelectionRectangleOverlay().isVisible(), + "slidesorter::SelectionFunction: selection rectangle still visible"); + + // Now turn them off. + if ( ! mrController.IsContextMenuOpen()) + rOverlay.GetInsertionIndicatorOverlay().setVisible(false); + rOverlay.GetSubstitutionOverlay().setVisible(false); + rOverlay.GetSelectionRectangleOverlay().setVisible(false); + } +} + + + + +void SelectionFunction::SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor) +{ + PageSelector& rSelector (mrController.GetPageSelector()); + rSelector.DeselectAllPages (); + rSelector.SelectPage(rpDescriptor); + + mrController.GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor); +} + + + + +void SelectionFunction::SwitchView (const model::SharedPageDescriptor& rpDescriptor) +{ + // Switch to the draw view. This is done only when the current + // view is the main view. + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell!=NULL && pViewShell->IsMainViewShell()) + { + if (rpDescriptor.get()!=NULL && rpDescriptor->GetPage()!=NULL) + { + mrSlideSorter.GetModel().GetDocument()->SetSelected(rpDescriptor->GetPage(), TRUE); + mpViewShell->GetFrameView()->SetSelectedPage( + (rpDescriptor->GetPage()->GetPageNum()-1)/2); + } + if (mrSlideSorter.GetViewShellBase() != NULL) + framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView( + framework::FrameworkHelper::msImpressViewURL, + framework::FrameworkHelper::msCenterPaneURL); + } +} + + + + +//===== EventDescriptor ======================================================= + +SelectionFunction::EventDescriptor::EventDescriptor ( + sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter) + : maMousePosition(), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(nEventType) +{ + ::Window* pWindow = rSlideSorter.GetActiveWindow(); + + maMousePosition = rEvent.GetPosPixel(); + maMouseModelPosition = pWindow->PixelToLogic(maMousePosition); + model::SharedPageDescriptor pHitDescriptor ( + rSlideSorter.GetController().GetPageAt(maMousePosition)); + if (pHitDescriptor.get() != NULL) + { + mpHitDescriptor = pHitDescriptor; + mpHitPage = pHitDescriptor->GetPage(); + } +} + + + + + +SelectionFunction::EventDescriptor::EventDescriptor ( + const KeyEvent&, + SlideSorter& rSlideSorter) + : maMousePosition(), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(0) +{ + mpHitDescriptor = rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor(); + model::SharedPageDescriptor pHitDescriptor ( + rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); + if (pHitDescriptor.get() != NULL) + { + mpHitPage = pHitDescriptor->GetPage(); + mpHitDescriptor = pHitDescriptor; + } +} + + + + + +//===== SubstitutionHandler =================================================== + +SelectionFunction::SubstitutionHandler::SubstitutionHandler (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mbHasBeenMoved(false) +{ +} + + + + +SelectionFunction::SubstitutionHandler::~SubstitutionHandler (void) +{ + if (mrSlideSorter.IsValid()) + { + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + rOverlay.GetSubstitutionOverlay().setVisible(false); + rOverlay.GetSubstitutionOverlay().Clear(); + } +} + + + + +void SelectionFunction::SubstitutionHandler::Start (const Point& rMouseModelPosition) +{ + // No Drag-and-Drop for master pages. + if (mrSlideSorter.GetModel().GetEditMode() != EM_PAGE) + return; + + if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) + return; + + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + + if ( ! rOverlay.GetSubstitutionOverlay().isVisible()) + { + // Show a new substitution for the selected page objects. + model::PageEnumeration aSelectedPages( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + rOverlay.GetSubstitutionOverlay().Create(aSelectedPages, rMouseModelPosition); + rOverlay.GetSubstitutionOverlay().setVisible(true); + mbHasBeenMoved = false; + } + else + UpdatePosition(rMouseModelPosition); +} + + + + +void SelectionFunction::SubstitutionHandler::UpdatePosition (const Point& rMouseModelPosition) +{ + if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) + return; + + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + + // Move the existing substitution to the new position. + rOverlay.GetSubstitutionOverlay().SetPosition(rMouseModelPosition); + + rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition); + rOverlay.GetInsertionIndicatorOverlay().setVisible(true); + + mbHasBeenMoved = true; +} + + + + +void SelectionFunction::SubstitutionHandler::Process (void) +{ + if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) + return; + + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + + if (IsSubstitutionInsertionNonTrivial()) + { + // Tell the model to move the selected pages behind the one with the + // index mnInsertionIndex which first has to transformed into an index + // understandable by the document. + sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex(); + if (nInsertionIndex >= 0) + { + USHORT nDocumentIndex = (USHORT)nInsertionIndex-1; + mrSlideSorter.GetController().GetSelectionManager()->MoveSelectedPages(nDocumentIndex); + } + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL) + pViewShell->GetViewFrame()->GetBindings().Invalidate(SID_STATUS_PAGE); + } +} + + + + +void SelectionFunction::SubstitutionHandler::End (void) +{ + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + rOverlay.GetSubstitutionOverlay().setVisible(false); + rOverlay.GetSubstitutionOverlay().Clear(); + rOverlay.GetInsertionIndicatorOverlay().setVisible(false); +} + + + + +bool SelectionFunction::SubstitutionHandler::HasBeenMoved (void) const +{ + return mbHasBeenMoved; +} + + + + +bool SelectionFunction::SubstitutionHandler::IsSubstitutionInsertionNonTrivial (void) const +{ + bool bIsNonTrivial = false; + + do + { + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + + // Make sure that the substitution and the insertion indicator are visible. + if ( ! rOverlay.GetSubstitutionOverlay().isVisible()) + break; + if ( ! rOverlay.GetInsertionIndicatorOverlay().isVisible()) + break; + + // Iterate over all selected pages and check whether there are + // holes. While we do this we remember the indices of the first and + // last selected page as preparation for the next step. + sal_Int32 nCurrentIndex = -1; + sal_Int32 nFirstIndex = -1; + sal_Int32 nLastIndex = -1; + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements() && ! bIsNonTrivial) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + SdPage* pPage = pDescriptor->GetPage(); + if (pPage != NULL) + { + // Get the page number and compare it to the last one. + sal_Int32 nPageNumber = (pPage->GetPageNum()-1)/2; + if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1)) + bIsNonTrivial = true; + else + nCurrentIndex = nPageNumber; + + // Remember indices of the first and last page of the selection. + if (nFirstIndex == -1) + nFirstIndex = nPageNumber; + nLastIndex = nPageNumber; + } + } + if (bIsNonTrivial) + break; + + // When we come here then the selection is consecutive. We still + // have to check that the insertion position is not directly in + // front or directly behind the selection and thus moving the + // selection there would not change the model. + sal_Int32 nInsertionIndex = rOverlay.GetInsertionIndicatorOverlay().GetInsertionPageIndex(); + if (nInsertionIndex<nFirstIndex || nInsertionIndex>(nLastIndex+1)) + bIsNonTrivial = true; + } + while (false); + + return bIsNonTrivial; +} + + + + +//===== InsertionIndicatorHandler ============================================= + +SelectionFunction::InsertionIndicatorHandler::InsertionIndicatorHandler ( + SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter) +{ +} + + + + +SelectionFunction::InsertionIndicatorHandler::~InsertionIndicatorHandler (void) +{ +} + + + + +void SelectionFunction::InsertionIndicatorHandler::Start (const Point& rMouseModelPosition) +{ + if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) + return; + + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition); + rOverlay.GetInsertionIndicatorOverlay().setVisible(true); +} + + + + +void SelectionFunction::InsertionIndicatorHandler::UpdatePosition (const Point& rMouseModelPosition) +{ + if (mrSlideSorter.GetController().GetProperties()->IsUIReadOnly()) + return; + + view::ViewOverlay& rOverlay (mrSlideSorter.GetView().GetOverlay()); + rOverlay.GetInsertionIndicatorOverlay().SetPosition(rMouseModelPosition); +} + + + + +void SelectionFunction::InsertionIndicatorHandler::End (void) +{ + mrSlideSorter.GetView().GetOverlay().GetInsertionIndicatorOverlay().setVisible(false); +} + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx new file mode 100644 index 000000000000..2eac8b757780 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx @@ -0,0 +1,665 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSelectionManager.cxx,v $ + * + * $Revision: 1.4 $ + * + * 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 "precompiled_sd.hxx" + +#include "controller/SlsSelectionManager.hxx" + +#include "SlideSorter.hxx" +#include "SlsSelectionCommand.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsAnimator.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsSlotManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "drawdoc.hxx" +#include "Window.hxx" +#include <svx/svxids.hrc> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> + +#include "res_bmp.hrc" +#include "sdresid.hxx" +#include "strings.hrc" +#include "app.hrc" +#include "glob.hrc" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::uno; +using namespace ::sd::slidesorter::model; +using namespace ::sd::slidesorter::view; +using namespace ::sd::slidesorter::controller; + +namespace sd { namespace slidesorter { namespace controller { + + +namespace { + class VerticalVisibleAreaScroller + { + public: + VerticalVisibleAreaScroller (SlideSorter& rSlideSorter, + const double nStart, const double nEnd); + void operator() (const double nValue); + private: + SlideSorter& mrSlideSorter; + double mnStart; + double mnEnd; + }; + class HorizontalVisibleAreaScroller + { + public: + HorizontalVisibleAreaScroller (SlideSorter& rSlideSorter, + const double nStart, const double nEnd); + void operator() (const double nValue); + private: + SlideSorter& mrSlideSorter; + double mnStart; + double mnEnd; + }; +} + + + + +SelectionManager::SelectionManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mrController(rSlideSorter.GetController()), + maSelectionBeforeSwitch(), + mbIsMakeSelectionVisiblePending(true) +{ +} + + + + +SelectionManager::~SelectionManager (void) +{ +} + + + + +void SelectionManager::DeleteSelectedPages (void) +{ + SlideSorterController::ModelChangeLock aLock (mrController); + + // Hide focus. + bool bIsFocusShowing = mrController.GetFocusManager().IsFocusShowing(); + if (bIsFocusShowing) + mrController.GetFocusManager().ToggleFocus(); + + // Store pointers to all selected page descriptors. This is necessary + // because the pages get deselected when the first one is deleted. + model::PageEnumeration aPageEnumeration ( + PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); + ::std::vector<SdPage*> aSelectedPages; + while (aPageEnumeration.HasMoreElements()) + aSelectedPages.push_back (aPageEnumeration.GetNextElement()->GetPage()); + + // The actual deletion of the selected pages is done in one of two + // helper functions. They are specialized for normal respectively for + // master pages. + mrSlideSorter.GetView().BegUndo (SdResId(STR_UNDO_DELETEPAGES)); + if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) + DeleteSelectedNormalPages(aSelectedPages); + else + DeleteSelectedMasterPages(aSelectedPages); + mrSlideSorter.GetView().EndUndo (); + + mrController.HandleModelChange(); + aLock.Release(); + + // Show focus and move it to next valid location. + if (bIsFocusShowing) + mrController.GetFocusManager().ToggleFocus (); + mrController.GetFocusManager().MoveFocus (FocusManager::FMD_NONE); +} + + + + +void SelectionManager::DeleteSelectedNormalPages (const ::std::vector<SdPage*>& rSelectedPages) +{ + // Prepare the deletion via the UNO API. + OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EM_PAGE); + + try + { + Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW ); + Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getDrawPages(), UNO_QUERY_THROW ); + + // Iterate over all pages that where seleted when this method was called + // and delete the draw page the notes page. The iteration is done in + // reverse order so that when one slide is not deleted (to avoid an + // empty document) the remaining slide is the first one. + ::std::vector<SdPage*>::const_reverse_iterator aI; + for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); aI++) + { + // Do not delete the last slide in the document. + if (xPages->getCount() <= 1) + break; + + USHORT nPage = ((*aI)->GetPageNum()-1) / 2; + + Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); + xPages->remove(xPage); + } + } + catch( Exception& ) + { + DBG_ERROR("SelectionManager::DeleteSelectedNormalPages(), exception caught!"); + } +} + + + + +void SelectionManager::DeleteSelectedMasterPages (const ::std::vector<SdPage*>& rSelectedPages) +{ + // Prepare the deletion via the UNO API. + OSL_ASSERT(mrSlideSorter.GetModel().GetEditMode() == EM_MASTERPAGE); + + try + { + Reference<drawing::XMasterPagesSupplier> xDrawPagesSupplier( mrSlideSorter.GetModel().GetDocument()->getUnoModel(), UNO_QUERY_THROW ); + Reference<drawing::XDrawPages> xPages( xDrawPagesSupplier->getMasterPages(), UNO_QUERY_THROW ); + + // Iterate over all pages that where seleted when this method was called + // and delete the draw page the notes page. The iteration is done in + // reverse order so that when one slide is not deleted (to avoid an + // empty document) the remaining slide is the first one. + ::std::vector<SdPage*>::const_reverse_iterator aI; + for (aI=rSelectedPages.rbegin(); aI!=rSelectedPages.rend(); aI++) + { + // Do not delete the last slide in the document. + if (xPages->getCount() <= 1) + break; + + USHORT nPage = ((*aI)->GetPageNum()-1) / 2; + + Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); + xPages->remove(xPage); + } + } + catch( Exception& ) + { + DBG_ERROR("SelectionManager::DeleteSelectedMasterPages(), exception caught!"); + } +} + + + + +bool SelectionManager::MoveSelectedPages (const sal_Int32 nTargetPageIndex) +{ + bool bMoved (false); + PageSelector& rSelector (mrController.GetPageSelector()); + + mrSlideSorter.GetView().LockRedraw (TRUE); + SlideSorterController::ModelChangeLock aLock (mrController); + + // Transfer selection of the slide sorter to the document. + mrSlideSorter.GetModel().SynchronizeDocumentSelection (); + + // Detect how many pages lie between document start and insertion + // position. + sal_Int32 nPageCountBeforeTarget (0); + ::boost::shared_ptr<PageSelector::PageSelection> pSelection (rSelector.GetPageSelection()); + PageSelector::PageSelection::const_iterator iSelectedPage (pSelection->begin()); + PageSelector::PageSelection::const_iterator iSelectionEnd (pSelection->end()); + for ( ; iSelectedPage!=iSelectionEnd; ++iSelectedPage) + { + if (*iSelectedPage==NULL) + continue; + if (((*iSelectedPage)->GetPageNum()-1)/2 <= nTargetPageIndex) + ++nPageCountBeforeTarget; + else + break; + } + + // Prepare to select the moved pages. + SelectionCommand* pCommand = new SelectionCommand( + rSelector,mrController.GetCurrentSlideManager(),mrSlideSorter.GetModel()); + sal_Int32 nSelectedPageCount (rSelector.GetSelectedPageCount()); + for (sal_Int32 nOffset=0; nOffset<nSelectedPageCount; ++nOffset) + pCommand->AddSlide(sal::static_int_cast<USHORT>( + nTargetPageIndex + nOffset - nPageCountBeforeTarget + 1)); + + // At the moment we can not move master pages. + if (nTargetPageIndex>=0) + { + if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) + bMoved = mrSlideSorter.GetModel().GetDocument()->MovePages( + sal::static_int_cast<sal_uInt16>(nTargetPageIndex)); + } + if (bMoved) + mrController.GetSlotManager()->ExecuteCommandAsynchronously( + ::std::auto_ptr<controller::Command>(pCommand)); + + mrSlideSorter.GetView().LockRedraw (FALSE); + + return bMoved; +} + + + + +void SelectionManager::SelectionHasChanged (const bool bMakeSelectionVisible) +{ + if (bMakeSelectionVisible) + mbIsMakeSelectionVisiblePending = true; + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL) + { + pViewShell->Invalidate (SID_EXPAND_PAGE); + pViewShell->Invalidate (SID_SUMMARY_PAGE); + pViewShell->Invalidate(SID_SHOW_SLIDE); + pViewShell->Invalidate(SID_HIDE_SLIDE); + pViewShell->Invalidate(SID_DELETE_PAGE); + pViewShell->Invalidate(SID_DELETE_MASTER_PAGE); + + // StatusBar + pViewShell->Invalidate (SID_STATUS_PAGE); + pViewShell->Invalidate (SID_STATUS_LAYOUT); + + OSL_ASSERT(mrController.GetCurrentSlideManager()); + SharedPageDescriptor pDescriptor(mrController.GetCurrentSlideManager()->GetCurrentSlide()); + if (pDescriptor.get() != NULL) + pViewShell->UpdatePreview(pDescriptor->GetPage()); + + // Tell the slection change listeners that the selection has changed. + ::std::vector<Link>::iterator iListener (maSelectionChangeListeners.begin()); + ::std::vector<Link>::iterator iEnd (maSelectionChangeListeners.end()); + for (; iListener!=iEnd; ++iListener) + { + iListener->Call(NULL); + } + + // Reset the insertion position: until set again it is calculated from + // the current selection. + mnInsertionPosition = -1; + } +} + + + + +bool SelectionManager::IsMakeSelectionVisiblePending (void) const +{ + return mbIsMakeSelectionVisiblePending; +} + + + + +/** We have to distinguish three cases: 1) the selection is empty, 2) the + selection fits completely into the visible area, 3) it does not. + 1) The visible area is not modified. + 2) When the selection fits completely into the visible area we have to + decide how to align it. It is done by scrolling it there and thus when + we scoll up the (towards the end of the document) the bottom of the + selection is aligned with the bottom of the window. When we scroll + down (towards the beginning of the document) the top of the selection is + aligned with the top of the window. + 3) We have to decide what part of the selection to make visible. Here + we use the eSelectionHint and concentrate on either the first, the last, + or the most recently selected page. We then again apply the algorithm + of a). + +*/ +Size SelectionManager::MakeSelectionVisible (const SelectionHint eSelectionHint) +{ + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + if (pWindow == NULL) + return Size(0,0); + + mbIsMakeSelectionVisiblePending = false; + + // Determine the descriptors of the first and last selected page and the + // bounding box that encloses their page objects. + model::SharedPageDescriptor pFirst; + model::SharedPageDescriptor pLast; + Rectangle aSelectionBox; + model::PageEnumeration aSelectedPages ( + PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + + if (pFirst.get() == NULL) + pFirst = pDescriptor; + pLast = pDescriptor; + + aSelectionBox.Union (mrSlideSorter.GetView().GetPageBoundingBox ( + pDescriptor, + view::SlideSorterView::CS_MODEL, + view::SlideSorterView::BBT_INFO)); + } + + if (pFirst != NULL) + { + // Determine scroll direction and the position in model coordinates + // that will be aligned with the top/left or bottom/right window + // border. + if (DoesSelectionExceedVisibleArea(aSelectionBox)) + { + // We can show only a part of the selection. + aSelectionBox = ResolveLargeSelection(pFirst,pLast, eSelectionHint); + } + + return MakeRectangleVisible(aSelectionBox); + } + + return Size(0,0); +} + + + + +Size SelectionManager::MakeRectangleVisible (const Rectangle& rBox) +{ + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + if (pWindow == NULL) + return Size(0,0); + + Rectangle aVisibleArea (pWindow->PixelToLogic( + Rectangle( + Point(0,0), + pWindow->GetOutputSizePixel()))); + + if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL) + { + // Scroll the visible area to make aSelectionBox visible. + sal_Int32 nNewTop (aVisibleArea.Top()); + if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection()) + { + nNewTop = rBox.Top() - (aVisibleArea.GetHeight() - rBox.GetHeight()) / 2; + } + else + { + if (rBox.Top() < aVisibleArea.Top()) + nNewTop = rBox.Top(); + else if (rBox.Bottom() > aVisibleArea.Bottom()) + nNewTop = rBox.Bottom() - aVisibleArea.GetHeight(); + // otherwise we do not modify the visible area. + } + + // Make some corrections of the new visible area. + Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); + if (nNewTop + aVisibleArea.GetHeight() > aModelArea.Bottom()) + nNewTop = aModelArea.GetHeight() - aVisibleArea.GetHeight(); + if (nNewTop < aModelArea.Top()) + nNewTop = aModelArea.Top(); + + // Scroll. + if (nNewTop != aVisibleArea.Top()) + { + mrController.GetAnimator()->AddAnimation( + VerticalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Top(), nNewTop), + mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ? + 1000 : 0 + ); + } + + return Size(0,aVisibleArea.Top() - nNewTop); + } + else + { + // Scroll the visible area to make aSelectionBox visible. + sal_Int32 nNewLeft (aVisibleArea.Left()); + if (mrSlideSorter.GetController().GetProperties()->IsCenterSelection()) + { + nNewLeft = rBox.Left() - (aVisibleArea.GetWidth() - rBox.GetWidth()) / 2; + } + else + { + if (rBox.Left() < aVisibleArea.Left()) + nNewLeft = rBox.Left(); + else if (rBox.Right() > aVisibleArea.Right()) + nNewLeft = rBox.Right() - aVisibleArea.GetWidth(); + // otherwise we do not modify the visible area. + } + + // Make some corrections of the new visible area. + Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); + if (nNewLeft + aVisibleArea.GetWidth() > aModelArea.Right()) + nNewLeft = aModelArea.GetWidth() - aVisibleArea.GetWidth(); + if (nNewLeft < aModelArea.Left()) + nNewLeft = aModelArea.Left(); + + // Scroll. + if (nNewLeft != aVisibleArea.Left()) + { + mrController.GetAnimator()->AddAnimation( + HorizontalVisibleAreaScroller(mrSlideSorter, aVisibleArea.Left(), nNewLeft), + mrSlideSorter.GetController().GetProperties()->IsSmoothSelectionScrolling() ? + 1000 : 0 + ); + } + + return Size(aVisibleArea.Left() - nNewLeft, 0); + } +} + + + + +void SelectionManager::AddSelectionChangeListener (const Link& rListener) +{ + if (::std::find ( + maSelectionChangeListeners.begin(), + maSelectionChangeListeners.end(), + rListener) == maSelectionChangeListeners.end()) + { + maSelectionChangeListeners.push_back (rListener); + } +} + + + + +void SelectionManager::RemoveSelectionChangeListener(const Link&rListener) +{ + maSelectionChangeListeners.erase ( + ::std::find ( + maSelectionChangeListeners.begin(), + maSelectionChangeListeners.end(), + rListener)); +} + + + + +bool SelectionManager::DoesSelectionExceedVisibleArea (const Rectangle& rSelectionBox) const +{ + ::sd::Window* pWindow = mrSlideSorter.GetActiveWindow(); + if (pWindow == NULL) + return true; + + Rectangle aVisibleArea (pWindow->PixelToLogic( + Rectangle( + Point(0,0), + pWindow->GetOutputSizePixel()))); + if (mrSlideSorter.GetView().GetOrientation() == SlideSorterView::VERTICAL) + return rSelectionBox.GetHeight() > aVisibleArea.GetHeight(); + else + return rSelectionBox.GetWidth() > aVisibleArea.GetWidth(); +} + + + + +Rectangle SelectionManager::ResolveLargeSelection ( + const SharedPageDescriptor& rpFirst, + const SharedPageDescriptor& rpLast, + const SelectionHint eSelectionHint) +{ + OSL_ASSERT(rpFirst.get()!=NULL); + OSL_ASSERT(rpLast.get()!=NULL); + + // The mose recently selected page is assumed to lie in the range + // between first and last selected page. Therefore the bounding box is + // not modified. + model::SharedPageDescriptor pRecent ( + mrController.GetPageSelector().GetMostRecentlySelectedPage()); + + // Get the bounding box of the page object on which to concentrate. + model::SharedPageDescriptor pRepresentative; + switch (eSelectionHint) + { + case SH_FIRST: + pRepresentative = rpFirst; + break; + + case SH_LAST: + pRepresentative = rpLast; + break; + + case SH_RECENT: + default: + if (pRecent.get() == NULL) + pRepresentative = rpFirst; + else + pRepresentative = pRecent; + break; + } + OSL_ASSERT(pRepresentative.get() != NULL); + + return mrSlideSorter.GetView().GetPageBoundingBox ( + pRepresentative, + view::SlideSorterView::CS_MODEL, + view::SlideSorterView::BBT_INFO); +} + + + + +sal_Int32 SelectionManager::GetInsertionPosition (void) const +{ + sal_Int32 nInsertionPosition (mnInsertionPosition); + if (nInsertionPosition < 0) + { + model::PageEnumeration aSelectedPages + (model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + // Initialize (for the case of an empty selection) with the position + // at the end of the document. + nInsertionPosition = mrSlideSorter.GetModel().GetPageCount(); + while (aSelectedPages.HasMoreElements()) + { + const sal_Int32 nPosition (aSelectedPages.GetNextElement()->GetPage()->GetPageNum()); + // Convert *2+1 index to straight index (n-1)/2 after the page + // (+1). + nInsertionPosition = (nPosition-1)/2 + 1; + } + + } + return nInsertionPosition; +} + + + + +void SelectionManager::SetInsertionPosition (const sal_Int32 nInsertionPosition) +{ + if (nInsertionPosition < 0) + mnInsertionPosition = -1; + else if (nInsertionPosition > mrSlideSorter.GetModel().GetPageCount()) + { + // Assert but then ignore invalid values. + OSL_ASSERT(nInsertionPosition<=mrSlideSorter.GetModel().GetPageCount()); + return; + } + else + mnInsertionPosition = nInsertionPosition; +} + + + + +//===== VerticalVisibleAreaScroller =========================================== + +namespace { + +VerticalVisibleAreaScroller::VerticalVisibleAreaScroller ( + SlideSorter& rSlideSorter, + const double nStart, + const double nEnd) + : mrSlideSorter(rSlideSorter), + mnStart(nStart), + mnEnd(nEnd) +{ +} + + + +void VerticalVisibleAreaScroller::operator() (const double nValue) +{ + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + mrSlideSorter.GetController().GetScrollBarManager().SetTop( + int(mnStart * (1.0 - nValue) + mnEnd * nValue)); +} + + + + +HorizontalVisibleAreaScroller::HorizontalVisibleAreaScroller ( + SlideSorter& rSlideSorter, + const double nStart, + const double nEnd) + : mrSlideSorter(rSlideSorter), + mnStart(nStart), + mnEnd(nEnd) +{ +} + + + + +void HorizontalVisibleAreaScroller::operator() (const double nValue) +{ + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + mrSlideSorter.GetController().GetScrollBarManager().SetLeft( + int(mnStart * (1.0 - nValue) + mnEnd * nValue)); +} + +} // end of anonymous namespace + +} } } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx new file mode 100644 index 000000000000..d12b485b8d87 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSlideFunction.cxx,v $ + * $Revision: 1.8 $ + * + * 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_sd.hxx" + +#include "controller/SlsSlideFunction.hxx" + +#include "SlideSorter.hxx" +#include "controller/SlideSorterController.hxx" +#include "view/SlideSorterView.hxx" +#include "model/SlideSorterModel.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +TYPEINIT1(SlideFunction, FuPoor); + + +SlideFunction::SlideFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest) + : FuPoor ( + rSlideSorter.GetViewShell(), + rSlideSorter.GetView().GetWindow(), + &rSlideSorter.GetView(), + rSlideSorter.GetModel().GetDocument(), + rRequest) +{ +} + +FunctionReference SlideFunction::Create( SlideSorter& rSlideSorter, SfxRequest& rRequest ) +{ + FunctionReference xFunc( new SlideFunction( rSlideSorter, rRequest ) ); + return xFunc; +} + +void SlideFunction::ScrollStart (void) +{ +} + +void SlideFunction::ScrollEnd (void) +{ +} + +BOOL SlideFunction::MouseMove(const MouseEvent& ) +{ + return FALSE; +} + +BOOL SlideFunction::MouseButtonUp(const MouseEvent& ) +{ + return FALSE; + +} + +BOOL SlideFunction::MouseButtonDown(const MouseEvent& ) +{ + return FALSE; +} + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx new file mode 100644 index 000000000000..4b48aa60678d --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx @@ -0,0 +1,1234 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSlotManager.cxx,v $ + * $Revision: 1.34.52.3 $ + * + * 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 "precompiled_sd.hxx" + +#include <com/sun/star/presentation/XPresentation2.hpp> + +#include "controller/SlsSlotManager.hxx" +#include "SlideSorter.hxx" +#include "SlideSorterViewShell.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsClipboard.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "SlsHideSlideFunction.hxx" +#include "SlsCommand.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsViewOverlay.hxx" +#include "framework/FrameworkHelper.hxx" +#include "Window.hxx" +#include "fupoor.hxx" +#include "fuzoom.hxx" +#include "fucushow.hxx" +#include "fusldlg.hxx" +#include "fuexpand.hxx" +#include "fusumry.hxx" +#include "fuscale.hxx" +#include "slideshow.hxx" +#include "app.hrc" +#include "strings.hrc" +#include "sdresid.hxx" +#include "drawdoc.hxx" +#include "DrawDocShell.hxx" +#include "ViewShellBase.hxx" +#include "ViewShellImplementation.hxx" +#include "sdattr.hxx" +#include "TaskPaneViewShell.hxx" +#include "FrameView.hxx" +#include "zoomlist.hxx" +#include "sdpage.hxx" +#include "sdxfer.hxx" +#include "helpids.h" +#include "glob.hrc" +#include "unmodpg.hxx" +#include "DrawViewShell.hxx" + +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/topfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svxids.hrc> +#include <svx/zoomitem.hxx> +#include <svx/svxdlg.hxx> +#include <svx/dialogs.hrc> +#include <vcl/msgbox.hxx> +#include <svtools/intitem.hxx> +#include <svtools/whiter.hxx> +#include <svtools/itempool.hxx> +#include <svtools/aeitem.hxx> +#include <com/sun/star/presentation/FadeEffect.hpp> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/drawing/XDrawPages.hpp> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::presentation; + +namespace sd { namespace slidesorter { namespace controller { + +SlotManager::SlotManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maCommandQueue() +{ +} + + + + +SlotManager::~SlotManager (void) +{ +} + + + + +void SlotManager::FuTemporary (SfxRequest& rRequest) +{ + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + + SlideSorterViewShell* pShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + if (pShell == NULL) + return; + + switch (rRequest.GetSlot()) + { + case SID_PRESENTATION: + case SID_REHEARSE_TIMINGS: + ShowSlideShow (rRequest); + pShell->Cancel(); + rRequest.Done(); + break; + + case SID_HIDE_SLIDE: + case SID_SHOW_SLIDE: + HideSlideFunction::Create(mrSlideSorter, rRequest); + break; + + case SID_PAGES_PER_ROW: + if (rRequest.GetArgs() != NULL) + { + SFX_REQUEST_ARG(rRequest, pPagesPerRow, SfxUInt16Item, + SID_PAGES_PER_ROW, FALSE); + if (pPagesPerRow != NULL) + { + sal_Int32 nColumnCount = pPagesPerRow->GetValue(); + // Force the given number of columns by setting the + // minimal and maximal number of columns to the same + // value. + mrSlideSorter.GetView().GetLayouter().SetColumnCount ( + nColumnCount, nColumnCount); + // Force a repaint and re-layout. + pShell->ArrangeGUIElements (); + // Rearrange the UI-elements controlled by the + // controller and force a rearrangement of the view. + mrSlideSorter.GetController().Rearrange(true); + } + } + rRequest.Done(); + break; + + case SID_SELECTALL: + mrSlideSorter.GetController().GetPageSelector().SelectAllPages(); + rRequest.Done(); + break; + + case SID_SLIDE_TRANSITIONS_PANEL: + { + // Make the slide transition panel visible (expand it) in the + // tool pane. + if (mrSlideSorter.GetViewShellBase() != NULL) + framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase()) + ->RequestTaskPanel(sd::framework::FrameworkHelper::msSlideTransitionTaskPanelURL); + rRequest.Ignore (); + break; + } + + case SID_PRESENTATION_DLG: + FuSlideShowDlg::Create ( + pShell, + mrSlideSorter.GetView().GetWindow(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_CUSTOMSHOW_DLG: + FuCustomShowDlg::Create ( + pShell, + mrSlideSorter.GetView().GetWindow(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_EXPAND_PAGE: + FuExpandPage::Create ( + pShell, + mrSlideSorter.GetView().GetWindow(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_SUMMARY_PAGE: + FuSummaryPage::Create ( + pShell, + mrSlideSorter.GetView().GetWindow(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_INSERTPAGE: + case SID_INSERT_MASTER_PAGE: + InsertSlide(rRequest); + rRequest.Done(); + break; + + case SID_DELETE_PAGE: + case SID_DELETE_MASTER_PAGE: + case SID_DELETE: // we need SID_CUT to handle the delete key + // (DEL -> accelerator -> SID_CUT). + if (mrSlideSorter.GetModel().GetPageCount() > 1) + { + mrSlideSorter.GetController().GetSelectionManager()->DeleteSelectedPages(); + } + + rRequest.Done(); + break; + + case SID_RENAMEPAGE: + case SID_RENAME_MASTER_PAGE: + RenameSlide (); + rRequest.Done (); + break; + + case SID_ASSIGN_LAYOUT: + { + SFX_REQUEST_ARG (rRequest, pWhatPage, SfxUInt32Item, ID_VAL_WHATPAGE, FALSE); + SFX_REQUEST_ARG (rRequest, pWhatLayout, SfxUInt32Item, ID_VAL_WHATLAYOUT, FALSE); + pShell->mpImpl->AssignLayout( + pDocument->GetSdPage((USHORT)pWhatPage->GetValue(), + mrSlideSorter.GetModel().GetPageType()), + (AutoLayout)pWhatLayout->GetValue()); + rRequest.Done (); + } + break; + + default: + break; + } +} + + + + +void SlotManager::FuPermanent (SfxRequest& rRequest) +{ + ViewShell* pShell = mrSlideSorter.GetViewShell(); + if (pShell == NULL) + return; + + if(pShell->GetCurrentFunction().is()) + { + FunctionReference xEmpty; + if (pShell->GetOldFunction() == pShell->GetCurrentFunction()) + pShell->SetOldFunction(xEmpty); + + pShell->GetCurrentFunction()->Deactivate(); + pShell->SetCurrentFunction(xEmpty); + } + + switch(rRequest.GetSlot()) + { + case SID_OBJECT_SELECT: + pShell->SetCurrentFunction( SelectionFunction::Create(mrSlideSorter, rRequest) ); + rRequest.Done(); + break; + + default: + break; + } + + if(pShell->GetOldFunction().is()) + { + pShell->GetOldFunction()->Deactivate(); + FunctionReference xEmpty; + pShell->SetOldFunction(xEmpty); + } + + if(pShell->GetCurrentFunction().is()) + { + pShell->GetCurrentFunction()->Activate(); + pShell->SetOldFunction(pShell->GetCurrentFunction()); + } + + //! das ist nur bis das ENUM-Slots sind + // Invalidate( SID_OBJECT_SELECT ); +} + +void SlotManager::FuSupport (SfxRequest& rRequest) +{ + switch (rRequest.GetSlot()) + { + case SID_STYLE_FAMILY: + if (rRequest.GetArgs() != NULL) + { + SdDrawDocument* pDocument + = mrSlideSorter.GetModel().GetDocument(); + if (pDocument != NULL) + { + const SfxPoolItem& rItem ( + rRequest.GetArgs()->Get(SID_STYLE_FAMILY)); + pDocument->GetDocSh()->SetStyleFamily( + static_cast<const SfxUInt16Item&>(rItem).GetValue()); + } + } + break; + + case SID_PASTE: + { + SdTransferable* pTransferClip = SD_MOD()->pTransferClip; + if( pTransferClip ) + { + SfxObjectShell* pTransferDocShell = pTransferClip->GetDocShell(); + + DrawDocShell* pDocShell = dynamic_cast<DrawDocShell*>(pTransferDocShell); + if (pDocShell && pDocShell->GetDoc()->GetPageCount() > 1) + { + mrSlideSorter.GetController().GetClipboard().HandleSlotCall(rRequest); + break; + } + } + ViewShellBase* pBase = mrSlideSorter.GetViewShellBase(); + if (pBase != NULL) + { + ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( + ::boost::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell())); + if (pDrawViewShell.get() != NULL) + pDrawViewShell->FuSupport(rRequest); + } + } + break; + + case SID_CUT: + case SID_COPY: + case SID_DELETE: + mrSlideSorter.GetController().GetClipboard().HandleSlotCall(rRequest); + break; + + case SID_DRAWINGMODE: + case SID_NOTESMODE: + case SID_HANDOUTMODE: + case SID_DIAMODE: + case SID_OUTLINEMODE: + { + ViewShellBase* pBase = mrSlideSorter.GetViewShellBase(); + if (pBase != NULL) + { + framework::FrameworkHelper::Instance(*pBase)->HandleModeChangeSlot( + rRequest.GetSlot(), rRequest); + rRequest.Done(); + } + break; + } + + case SID_UNDO : + { + SlideSorterViewShell* pViewShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + if (pViewShell != NULL) + pViewShell->ImpSidUndo (FALSE, rRequest); + break; + } + + case SID_REDO : + { + SlideSorterViewShell* pViewShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + if (pViewShell != NULL) + pViewShell->ImpSidRedo (FALSE, rRequest); + break; + } + + default: + break; + } +} + + + + +void SlotManager::ExecCtrl (SfxRequest& rRequest) +{ + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + USHORT nSlot = rRequest.GetSlot(); + switch (nSlot) + { + case SID_RELOAD: + { + // Undo-Manager leeren + mrSlideSorter.GetModel().GetDocument()->GetDocSh()->ClearUndoBuffer(); + + // Normale Weiterleitung an ViewFrame zur Ausfuehrung + if (pViewShell != NULL) + pViewShell->GetViewFrame()->ExecuteSlot(rRequest); + + // Muss sofort beendet werden + return; + } + + case SID_OUTPUT_QUALITY_COLOR: + case SID_OUTPUT_QUALITY_GRAYSCALE: + case SID_OUTPUT_QUALITY_BLACKWHITE: + case SID_OUTPUT_QUALITY_CONTRAST: + { + // flush page cache + if (pViewShell != NULL) + pViewShell->ExecReq (rRequest); + break; + } + + case SID_MAIL_SCROLLBODY_PAGEDOWN: + { + if (pViewShell != NULL) + pViewShell->ExecReq (rRequest); + break; + } + + case SID_OPT_LOCALE_CHANGED: + { + mrSlideSorter.GetController().UpdateAllPages(); + if (pViewShell != NULL) + pViewShell->UpdatePreview (pViewShell->GetActualPage()); + rRequest.Done(); + break; + } + + case SID_SEARCH_DLG: + // We have to handle the SID_SEARCH_DLG slot explicitly because + // in some cases (when the slide sorter is displayed in the + // center pane) we want to disable the search dialog. Therefore + // we have to handle the execution of that slot as well. + // We try to do that by forwarding the request to the view frame + // of the view shell. + if (pViewShell != NULL) + pViewShell->GetViewFrame()->ExecuteSlot(rRequest); + break; + + default: + break; + } +} + + + + +void SlotManager::GetAttrState (SfxItemSet& rSet) +{ + // Iteratate over all items. + SfxWhichIter aIter (rSet); + USHORT nWhich = aIter.FirstWhich(); + while (nWhich) + { + USHORT nSlotId (nWhich); + if (SfxItemPool::IsWhich(nWhich) && mrSlideSorter.GetViewShell()!=NULL) + nSlotId = mrSlideSorter.GetViewShell()->GetPool().GetSlotId(nWhich); + switch (nSlotId) + { + case SID_PAGES_PER_ROW: + rSet.Put ( + SfxUInt16Item ( + nSlotId, + (USHORT)mrSlideSorter.GetView().GetLayouter().GetColumnCount() + ) + ); + break; + } + nWhich = aIter.NextWhich(); + } +} + + + + +void SlotManager::GetCtrlState (SfxItemSet& rSet) +{ + if (rSet.GetItemState(SID_RELOAD) != SFX_ITEM_UNKNOWN) + { + // "Letzte Version" vom SFx en/disablen lassen + ViewShell* pShell = mrSlideSorter.GetViewShell(); + if (pShell != NULL) + { + SfxViewFrame* pSlideViewFrame = pShell->GetViewFrame(); + DBG_ASSERT(pSlideViewFrame!=NULL, + "SlideSorterController::GetCtrlState: ViewFrame not found"); + if (pSlideViewFrame->ISA(SfxTopViewFrame)) + { + pSlideViewFrame->GetSlotState (SID_RELOAD, NULL, &rSet); + } + else // MI sagt: kein MDIFrame --> disablen + { + rSet.DisableItem(SID_RELOAD); + } + } + } + + // Output quality. + if (rSet.GetItemState(SID_OUTPUT_QUALITY_COLOR)==SFX_ITEM_AVAILABLE + ||rSet.GetItemState(SID_OUTPUT_QUALITY_GRAYSCALE)==SFX_ITEM_AVAILABLE + ||rSet.GetItemState(SID_OUTPUT_QUALITY_BLACKWHITE)==SFX_ITEM_AVAILABLE + ||rSet.GetItemState(SID_OUTPUT_QUALITY_CONTRAST)==SFX_ITEM_AVAILABLE) + { + ULONG nMode = mrSlideSorter.GetView().GetWindow()->GetDrawMode(); + UINT16 nQuality = 0; + + switch (nMode) + { + case ::sd::ViewShell::OUTPUT_DRAWMODE_COLOR: + nQuality = 0; + break; + case ::sd::ViewShell::OUTPUT_DRAWMODE_GRAYSCALE: + nQuality = 1; + break; + case ::sd::ViewShell::OUTPUT_DRAWMODE_BLACKWHITE: + nQuality = 2; + break; + case ::sd::ViewShell::OUTPUT_DRAWMODE_CONTRAST: + nQuality = 3; + break; + } + + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_COLOR, + (BOOL)(nQuality==0))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_GRAYSCALE, + (BOOL)(nQuality==1))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_BLACKWHITE, + (BOOL)(nQuality==2))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_CONTRAST, + (BOOL)(nQuality==3))); + } + + if (rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) == SFX_ITEM_AVAILABLE) + { + rSet.Put (SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, TRUE)); + } +} + + + + +void SlotManager::GetMenuState ( SfxItemSet& rSet) +{ + EditMode eEditMode = mrSlideSorter.GetModel().GetEditMode(); + ViewShell* pShell = mrSlideSorter.GetViewShell(); + DrawDocShell* pDocShell = mrSlideSorter.GetModel().GetDocument()->GetDocSh(); + + if (pShell!=NULL && pShell->GetCurrentFunction().is()) + { + USHORT nSId = pShell->GetCurrentFunction()->GetSlotID(); + + rSet.Put( SfxBoolItem( nSId, TRUE ) ); + } + rSet.Put( SfxBoolItem( SID_DRAWINGMODE, FALSE ) ); + rSet.Put( SfxBoolItem( SID_DIAMODE, TRUE ) ); + rSet.Put( SfxBoolItem( SID_OUTLINEMODE, FALSE ) ); + rSet.Put( SfxBoolItem( SID_NOTESMODE, FALSE ) ); + rSet.Put( SfxBoolItem( SID_HANDOUTMODE, FALSE ) ); + + // Vorlagenkatalog darf nicht aufgerufen werden + rSet.DisableItem(SID_STYLE_CATALOG); + + if (pShell!=NULL && pShell->IsMainViewShell()) + { + rSet.DisableItem(SID_SPELL_DIALOG); + rSet.DisableItem(SID_SEARCH_DLG); + } + + if (SFX_ITEM_AVAILABLE == rSet.GetItemState(SID_EXPAND_PAGE)) + { + bool bDisable = true; + if (eEditMode == EM_PAGE) + { + // At least one of the selected pages has to contain an outline + // presentation objects in order to enable the expand page menu + // entry. + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + SdPage* pPage = aSelectedPages.GetNextElement()->GetPage(); + SdrObject* pObj = pPage->GetPresObj(PRESOBJ_OUTLINE); + if (pObj!=NULL && !pObj->IsEmptyPresObj()) + bDisable = false; + } + } + + if (bDisable) + rSet.DisableItem (SID_EXPAND_PAGE); + } + + if (SFX_ITEM_AVAILABLE == rSet.GetItemState(SID_SUMMARY_PAGE)) + { + bool bDisable = true; + if (eEditMode == EM_PAGE) + { + // At least one of the selected pages has to contain a title + // presentation objects in order to enable the summary page menu + // entry. + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + SdPage* pPage = aSelectedPages.GetNextElement()->GetPage(); + SdrObject* pObj = pPage->GetPresObj(PRESOBJ_TITLE); + + if (pObj!=NULL && !pObj->IsEmptyPresObj()) + bDisable = false; + } + } + if (bDisable) + rSet.DisableItem (SID_SUMMARY_PAGE); + } + + // Starten der Praesentation moeglich? + if( SFX_ITEM_AVAILABLE == rSet.GetItemState( SID_PRESENTATION ) || + SFX_ITEM_AVAILABLE == rSet.GetItemState( SID_REHEARSE_TIMINGS ) ) + { + BOOL bDisable = TRUE; + model::PageEnumeration aAllPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrSlideSorter.GetModel())); + while (aAllPages.HasMoreElements()) + { + SdPage* pPage = aAllPages.GetNextElement()->GetPage(); + + if( !pPage->IsExcluded() ) + bDisable = FALSE; + } + if( bDisable || pDocShell->IsPreview()) + { + rSet.DisableItem( SID_PRESENTATION ); + rSet.DisableItem( SID_REHEARSE_TIMINGS ); + } + } + + + // Disable the rename slots when there are no or more than one slides/master + // pages selected. + if (rSet.GetItemState(SID_RENAMEPAGE) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_RENAME_MASTER_PAGE) == SFX_ITEM_AVAILABLE) + { + if (mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount() != 1) + { + rSet.DisableItem(SID_RENAMEPAGE); + rSet.DisableItem(SID_RENAME_MASTER_PAGE); + } + } + + if (rSet.GetItemState(SID_HIDE_SLIDE) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_SHOW_SLIDE) == SFX_ITEM_AVAILABLE) + { + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + HideSlideFunction::ExclusionState eState ( + HideSlideFunction::GetExclusionState(aSelectedPages)); + switch (eState) + { + case HideSlideFunction::MIXED: + // Show both entries. + break; + + case HideSlideFunction::EXCLUDED: + rSet.DisableItem(SID_HIDE_SLIDE); + break; + + case HideSlideFunction::INCLUDED: + rSet.DisableItem(SID_SHOW_SLIDE); + break; + + case HideSlideFunction::UNDEFINED: + rSet.DisableItem(SID_HIDE_SLIDE); + rSet.DisableItem(SID_SHOW_SLIDE); + break; + } + } +} + + + + +void SlotManager::GetClipboardState ( SfxItemSet& rSet) +{ + SdTransferable* pTransferClip = SD_MOD()->pTransferClip; + + if (rSet.GetItemState(SID_PASTE) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_PASTE_SPECIAL) == SFX_ITEM_AVAILABLE) + { + // Keine eigenen Clipboard-Daten? + if ( !pTransferClip || !pTransferClip->GetDocShell() ) + { + rSet.DisableItem(SID_PASTE); + rSet.DisableItem(SID_PASTE_SPECIAL); + } + else + { + SfxObjectShell* pTransferDocShell = pTransferClip->GetDocShell(); + + if( !pTransferDocShell || ( (DrawDocShell*) pTransferDocShell)->GetDoc()->GetPageCount() <= 1 ) + { + bool bIsPastingSupported (false); + + // No or just one page. Check if there is anything that can be + // pasted via a DrawViewShell. + ViewShellBase* pBase = mrSlideSorter.GetViewShellBase(); + if (pBase != NULL) + { + ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( + ::boost::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell())); + if (pDrawViewShell.get() != NULL) + { + TransferableDataHelper aDataHelper ( + TransferableDataHelper::CreateFromSystemClipboard( + pDrawViewShell->GetActiveWindow())); + if (aDataHelper.GetFormatCount() > 0) + bIsPastingSupported = true; + } + } + + if ( ! bIsPastingSupported) + { + rSet.DisableItem(SID_PASTE); + rSet.DisableItem(SID_PASTE_SPECIAL); + } + } + } + } + + // Cut, copy and paste of master pages is not yet implemented properly + if (rSet.GetItemState(SID_COPY) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_PASTE) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_PASTE_SPECIAL) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_CUT) == SFX_ITEM_AVAILABLE) + { + if (mrSlideSorter.GetModel().GetEditMode() == EM_MASTERPAGE) + { + if (rSet.GetItemState(SID_CUT) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_CUT); + if (rSet.GetItemState(SID_COPY) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_COPY); + if (rSet.GetItemState(SID_PASTE) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_PASTE); + if (rSet.GetItemState(SID_PASTE_SPECIAL) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_PASTE_SPECIAL); + } + } + + // Cut, copy, and delete page are disabled when there is no selection. + if (rSet.GetItemState(SID_CUT) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_COPY) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_DELETE) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_DELETE_PAGE) == SFX_ITEM_AVAILABLE + || rSet.GetItemState(SID_DELETE_MASTER_PAGE) == SFX_ITEM_AVAILABLE) + { + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + + // For copy to work we have to have at least one selected page. + if ( ! aSelectedPages.HasMoreElements()) + rSet.DisableItem(SID_COPY); + + bool bDisable = false; + // The operations that lead to the deletion of a page are valid if + // a) there is at least one selected page + // b) deleting the selected pages leaves at least one page in the + // document + // c) selected master pages must not be used by slides. + + // Test a). + if ( ! aSelectedPages.HasMoreElements()) + bDisable = true; + // Test b): Count the number of selected pages. It has to be less + // than the number of all pages. + else if (mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount() + >= mrSlideSorter.GetController().GetPageSelector().GetPageCount()) + bDisable = true; + // Test c): Iterate over the selected pages and look for a master + // page that is used by at least one page. + else while (aSelectedPages.HasMoreElements()) + { + SdPage* pPage = aSelectedPages.GetNextElement()->GetPage(); + int nUseCount (mrSlideSorter.GetModel().GetDocument() + ->GetMasterPageUserCount(pPage)); + if (nUseCount > 0) + { + bDisable = true; + break; + } + } + + if (bDisable) + { + rSet.DisableItem(SID_CUT); + rSet.DisableItem(SID_DELETE_PAGE); + rSet.DisableItem(SID_DELETE_MASTER_PAGE); + } + } +} + + + + +void SlotManager::GetStatusBarState (SfxItemSet& rSet) +{ + // Seitenanzeige und Layout + /* + if( SFX_ITEM_AVAILABLE == rSet.GetItemState( SID_STATUS_PAGE ) || + SFX_ITEM_AVAILABLE == rSet.GetItemState( SID_STATUS_LAYOUT ) ) + */ + SdPage* pPage = NULL; + SdPage* pFirstPage = NULL; + USHORT nFirstPage; + USHORT nSelectedPages = (USHORT)mrSlideSorter.GetController().GetPageSelector().GetSelectedPageCount(); + String aPageStr; + String aLayoutStr; + + if (nSelectedPages > 0) + aPageStr = String(SdResId(STR_SD_PAGE)); + + if (nSelectedPages == 1) + { + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + pPage = aSelectedPages.GetNextElement()->GetPage(); + nFirstPage = pPage->GetPageNum()/2; + pFirstPage = pPage; + + aPageStr += sal_Unicode(' '); + aPageStr += String::CreateFromInt32( nFirstPage + 1 ); + aPageStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " / " )); + aPageStr += String::CreateFromInt32( + mrSlideSorter.GetModel().GetPageCount()); + + aLayoutStr = pFirstPage->GetLayoutName(); + aLayoutStr.Erase( aLayoutStr.SearchAscii( SD_LT_SEPARATOR ) ); + } + + rSet.Put( SfxStringItem( SID_STATUS_PAGE, aPageStr ) ); + rSet.Put( SfxStringItem( SID_STATUS_LAYOUT, aLayoutStr ) ); + + if( SFX_ITEM_AVAILABLE == rSet.GetItemState( SID_ATTR_ZOOMSLIDER ) ) + { + rSet.Put( SfxVoidItem( SID_ATTR_ZOOMSLIDER ) ); + } +} + +void SlotManager::ShowSlideShow( SfxRequest& rReq) +{ + Reference< XPresentation2 > xPresentation( mrSlideSorter.GetModel().GetDocument()->getPresentation() ); + if( xPresentation.is() ) + { + if( ( SID_REHEARSE_TIMINGS != rReq.GetSlot() ) ) + xPresentation->start(); + else + xPresentation->rehearseTimings(); + } +} + +void SlotManager::RenameSlide (void) +{ + PageKind ePageKind = mrSlideSorter.GetModel().GetPageType(); + View* pDrView = &mrSlideSorter.GetView(); + + if (ePageKind==PK_STANDARD || ePageKind==PK_NOTES) + { + if ( pDrView->IsTextEdit() ) + { + pDrView->SdrEndTextEdit(); + } + + SdPage* pSelectedPage = NULL; + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + if (aSelectedPages.HasMoreElements()) + pSelectedPage = aSelectedPages.GetNextElement()->GetPage(); + if (pSelectedPage != NULL) + { + String aTitle( SdResId( STR_TITLE_RENAMESLIDE ) ); + String aDescr( SdResId( STR_DESC_RENAMESLIDE ) ); + String aPageName = pSelectedPage->GetName(); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + DBG_ASSERT(pFact, "Dialogdiet fail!"); + AbstractSvxNameDialog* aNameDlg = pFact->CreateSvxNameDialog( + mrSlideSorter.GetActiveWindow(), + aPageName, aDescr, RID_SVXDLG_NAME); + DBG_ASSERT(aNameDlg, "Dialogdiet fail!"); + aNameDlg->SetText( aTitle ); + aNameDlg->SetCheckNameHdl( LINK( this, SlotManager, RenameSlideHdl ), true ); + aNameDlg->SetEditHelpId( HID_SD_NAMEDIALOG_PAGE ); + + if( aNameDlg->Execute() == RET_OK ) + { + String aNewName; + aNameDlg->GetName( aNewName ); + if( ! aNewName.Equals( aPageName ) ) + { +#ifdef DBG_UTIL + bool bResult = +#endif + RenameSlideFromDrawViewShell( + pSelectedPage->GetPageNum()/2, aNewName ); + DBG_ASSERT( bResult, "Couldn't rename slide" ); + } + } + delete aNameDlg; + + // Tell the slide sorter about the name change (necessary for + // accessibility.) + mrSlideSorter.GetController().PageNameHasChanged( + (pSelectedPage->GetPageNum()-1)/2, aPageName); + } + } +} + +IMPL_LINK(SlotManager, RenameSlideHdl, AbstractSvxNameDialog*, pDialog) +{ + if( ! pDialog ) + return 0; + + String aNewName; + pDialog->GetName( aNewName ); + + model::SharedPageDescriptor pDescriptor ( + mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); + SdPage* pCurrentPage = NULL; + if (pDescriptor.get() != NULL) + pCurrentPage = pDescriptor->GetPage(); + + return ( (pCurrentPage!=NULL && aNewName.Equals( pCurrentPage->GetName() )) + || (mrSlideSorter.GetViewShell() + && mrSlideSorter.GetViewShell()->GetDocSh()->IsNewPageNameValid( aNewName ) )); +} + +bool SlotManager::RenameSlideFromDrawViewShell( USHORT nPageId, const String & rName ) +{ + BOOL bOutDummy; + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if( pDocument->GetPageByName( rName, bOutDummy ) != SDRPAGE_NOTFOUND ) + return false; + + SdPage* pPageToRename = NULL; + PageKind ePageKind = mrSlideSorter.GetModel().GetPageType(); + + SfxUndoManager* pManager = pDocument->GetDocSh()->GetUndoManager(); + + if( mrSlideSorter.GetModel().GetEditMode() == EM_PAGE ) + { + model::SharedPageDescriptor pDescriptor ( + mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); + if (pDescriptor.get() != NULL) + pPageToRename = pDescriptor->GetPage(); + + if (pPageToRename != NULL) + { + // Undo + SdPage* pUndoPage = pPageToRename; + SdrLayerAdmin & rLayerAdmin = pDocument->GetLayerAdmin(); + BYTE nBackground = rLayerAdmin.GetLayerID( String( SdResId( STR_LAYER_BCKGRND )), FALSE ); + BYTE nBgObj = rLayerAdmin.GetLayerID( String( SdResId( STR_LAYER_BCKGRNDOBJ )), FALSE ); + SetOfByte aVisibleLayers = pPageToRename->TRG_GetMasterPageVisibleLayers(); + + // (#67720#) + ModifyPageUndoAction* pAction = new ModifyPageUndoAction( + pManager, pDocument, pUndoPage, rName, pUndoPage->GetAutoLayout(), + aVisibleLayers.IsSet( nBackground ), + aVisibleLayers.IsSet( nBgObj )); + pManager->AddUndoAction( pAction ); + + // rename + pPageToRename->SetName( rName ); + + if( ePageKind == PK_STANDARD ) + { + // also rename notes-page + SdPage* pNotesPage = pDocument->GetSdPage( nPageId, PK_NOTES ); + if (pNotesPage != NULL) + pNotesPage->SetName (rName); + } + } + } + else + { + // rename MasterPage -> rename LayoutTemplate + pPageToRename = pDocument->GetMasterSdPage( nPageId, ePageKind ); + if (pPageToRename != NULL) + { + const String aOldLayoutName( pPageToRename->GetLayoutName() ); + pManager->AddUndoAction( new RenameLayoutTemplateUndoAction( pDocument, aOldLayoutName, rName ) ); + pDocument->RenameLayoutTemplate( aOldLayoutName, rName ); + } + } + + bool bSuccess = pPageToRename!=NULL && ( FALSE != rName.Equals( pPageToRename->GetName())); + + if( bSuccess ) + { + // user edited page names may be changed by the page so update control + // aTabControl.SetPageText( nPageId, rName ); + + // set document to modified state + pDocument->SetChanged( TRUE ); + + // inform navigator about change + SfxBoolItem aItem( SID_NAVIGATOR_INIT, TRUE ); + if (mrSlideSorter.GetViewShell() != NULL) + mrSlideSorter.GetViewShell()->GetDispatcher()->Execute( + SID_NAVIGATOR_INIT, SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD, &aItem, 0L ); + } + + return bSuccess; +} + + + + +/** Insert a slide. The insertion position depends on a) the selection and + b) the mouse position when there is no selection. + + When there is a selection then insertion takes place after the last + slide of the selection. For this to work all but the last selected + slide are deselected first. + + Otherwise, when there is no selection but the insertion marker is visible + the slide is inserted at that position. The slide before that marker is + selected first. + + When both the selection and the insertion marker are not visible--can + that happen?--the new slide is inserted after the last slide. +*/ +void SlotManager::InsertSlide (SfxRequest& rRequest) +{ + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + // The fallback insertion position is after the last slide. + sal_Int32 nInsertionIndex (rSelector.GetPageCount() - 1); + if (rSelector.GetSelectedPageCount() > 0) + { + // Deselect all but the last selected slide. + bool bLastSelectedSlideSeen (false); + for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex) + { + if (rSelector.IsPageSelected(nIndex)) + { + if (bLastSelectedSlideSeen) + rSelector.DeselectPage (nIndex); + else + { + nInsertionIndex = nIndex; + bLastSelectedSlideSeen = true; + } + } + } + } + + // No selection. Is there an insertion indicator? + else if (mrSlideSorter.GetView().GetOverlay() + .GetInsertionIndicatorOverlay().isVisible()) + { + // Select the page before the insertion indicator. + nInsertionIndex = mrSlideSorter.GetView().GetOverlay() + .GetInsertionIndicatorOverlay().GetInsertionPageIndex(); + nInsertionIndex --; + rSelector.SelectPage (nInsertionIndex); + } + + // Is there a stored insertion position? + else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0) + { + nInsertionIndex + = mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1; + rSelector.SelectPage(nInsertionIndex); + } + + // Select the last page when there is at least one page. + else if (rSelector.GetPageCount() > 0) + { + nInsertionIndex = rSelector.GetPageCount() - 1; + rSelector.SelectPage (nInsertionIndex); + } + + // Hope for the best that CreateOrDuplicatePage() can cope with an empty + // selection. + else + { + nInsertionIndex = -1; + } + + USHORT nPageCount ((USHORT)mrSlideSorter.GetModel().GetPageCount()); + + rSelector.DisableBroadcasting(); + // In order for SlideSorterController::GetActualPage() to select the + // selected page as current page we have to turn off the focus + // temporarily. + { + FocusManager::FocusHider aTemporaryFocusHider ( + mrSlideSorter.GetController().GetFocusManager()); + + SdPage* pPreviousPage = NULL; + if (nInsertionIndex >= 0) + pPreviousPage = mrSlideSorter.GetModel() + .GetPageDescriptor(nInsertionIndex)->GetPage(); + + if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) + { + SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>( + mrSlideSorter.GetViewShell()); + if (pShell != NULL) + { + pShell->CreateOrDuplicatePage ( + rRequest, + mrSlideSorter.GetModel().GetPageType(), + pPreviousPage); + } + } + else + { + // Use the API to create a new page. + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + Reference<drawing::XMasterPagesSupplier> xMasterPagesSupplier ( + pDocument->getUnoModel(), UNO_QUERY); + if (xMasterPagesSupplier.is()) + { + Reference<drawing::XDrawPages> xMasterPages ( + xMasterPagesSupplier->getMasterPages()); + if (xMasterPages.is()) + { + xMasterPages->insertNewByIndex (nInsertionIndex+1); + + // Create shapes for the default layout. + SdPage* pMasterPage = pDocument->GetMasterSdPage( + (USHORT)(nInsertionIndex+1), PK_STANDARD); + pMasterPage->CreateTitleAndLayout (TRUE,TRUE); + } + } + } + } + + // When a new page has been inserted then select it and make it the + // current page. + mrSlideSorter.GetView().LockRedraw(TRUE); + if (mrSlideSorter.GetModel().GetPageCount() > nPageCount) + { + nInsertionIndex++; + model::SharedPageDescriptor pDescriptor = mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex); + if (pDescriptor.get() != NULL) + mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + } + rSelector.EnableBroadcasting(); + mrSlideSorter.GetView().LockRedraw(FALSE); +} + + + + +void SlotManager::AssignTransitionEffect (void) +{ + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + + // We have to manually select the pages in the document that are + // selected in the slide sorter. + rModel.SynchronizeDocumentSelection(); + + // #i34011#: Needs review, AF's bugfix is removed here + //rShell.AssignFromSlideChangeWindow(rModel.GetEditMode()); + + // We have to remove the selection of master pages to not confuse the + // model. + if (rModel.GetEditMode() == EM_MASTERPAGE) + { + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + USHORT nMasterPageCount = pDocument->GetMasterSdPageCount(PK_STANDARD); + for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++) + { + SdPage* pPage = pDocument->GetMasterSdPage(nIndex, PK_STANDARD); + if (pPage != NULL) + pPage->SetSelected (FALSE); + } + } +} + + + + +void SlotManager::ExecuteCommandAsynchronously (::std::auto_ptr<Command> pCommand) +{ + // Ownership of command is (implicitely) transferred to the queue. + maCommandQueue.push(pCommand.get()); + pCommand.release(); + Application::PostUserEvent(LINK(this,SlotManager,UserEventCallback)); +} + +IMPL_LINK(SlotManager, UserEventCallback, void*, EMPTYARG) +{ + if ( ! maCommandQueue.empty()) + { + Command* pCommand = maCommandQueue.front(); + maCommandQueue.pop(); + + if (pCommand != NULL) + { + // The queue ownes the command that has just been removed from + // it. Therefore it is deleted after it has been executed. + (*pCommand)(); + delete pCommand; + } + } + + return 1; +} + +} } } // end of namespace ::sd::slidesorter::controller + diff --git a/sd/source/ui/slidesorter/controller/SlsTransferable.cxx b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx new file mode 100644 index 000000000000..f072f6815285 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsTransferable.cxx,v $ + * $Revision: 1.6 $ + * + * 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_sd.hxx" + +#include "SlsTransferable.hxx" + +#include "SlideSorterViewShell.hxx" +#include "View.hxx" + +namespace sd { namespace slidesorter { namespace controller { + +Transferable::Transferable ( + SdDrawDocument* pSrcDoc, + ::sd::View* pWorkView, + BOOL bInitOnGetData, + SlideSorterViewShell* pViewShell) + : SdTransferable (pSrcDoc, pWorkView, bInitOnGetData), + mpViewShell(pViewShell) +{ + if (mpViewShell != NULL) + StartListening(*mpViewShell); +} + + + +Transferable::~Transferable (void) +{ + if (mpViewShell != NULL) + EndListening(*mpViewShell); +} + + + + +void Transferable::DragFinished (sal_Int8 nDropAction) +{ + if (mpViewShell != NULL) + mpViewShell->DragFinished(nDropAction); +} + + + + +void Transferable::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) +{ + if (rHint.ISA(SfxSimpleHint) && mpViewShell!=NULL) + { + SfxSimpleHint& rSimpleHint (*PTR_CAST(SfxSimpleHint, &rHint)); + if (rSimpleHint.GetId() == SFX_HINT_DYING) + { + // This hint may come either from the ViewShell or from the + // document (registered by SdTransferable). We do not know + // which but both are sufficient to disconnect from the + // ViewShell. + EndListening(*mpViewShell); + mpViewShell = NULL; + } + } + + SdTransferable::Notify(rBroadcaster, rHint); +} + + + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsTransferable.hxx b/sd/source/ui/slidesorter/controller/SlsTransferable.hxx new file mode 100644 index 000000000000..2dd02e068ade --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsTransferable.hxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsTransferable.hxx,v $ + * $Revision: 1.5 $ + * + * 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 SD_SLIDESORTER_TRANSFERABLE_HXX +#define SD_SLIDESORTER_TRANSFERABLE_HXX + +#include "sdxfer.hxx" + +class SdDrawDocument; +namespace sd +{ + class pWorkView; + namespace slidesorter + { + class SlideSorterViewShell; + } +} + +namespace sd { namespace slidesorter { namespace controller { + +/** This class exists to have DragFinished call the correct object: the + SlideSorterViewShell instead of the old SlideView. +*/ +class Transferable + : public SdTransferable +{ +public: + Transferable ( + SdDrawDocument* pSrcDoc, + ::sd::View* pWorkView, + BOOL bInitOnGetData, + SlideSorterViewShell* pViewShell); + + virtual ~Transferable (void); + + virtual void DragFinished (sal_Int8 nDropAction); + +private: + SlideSorterViewShell* mpViewShell; + + virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/controller/makefile.mk b/sd/source/ui/slidesorter/controller/makefile.mk new file mode 100644 index 000000000000..0eda7ccba22d --- /dev/null +++ b/sd/source/ui/slidesorter/controller/makefile.mk @@ -0,0 +1,75 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.9 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slscontroller +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/SlideSorterController.obj \ + $(SLO)$/SlsAnimator.obj \ + $(SLO)$/SlsClipboard.obj \ + $(SLO)$/SlsCurrentSlideManager.obj \ + $(SLO)$/SlsFocusManager.obj \ + $(SLO)$/SlsListener.obj \ + $(SLO)$/SlsPageObjectFactory.obj \ + $(SLO)$/SlsPageSelector.obj \ + $(SLO)$/SlsProperties.obj \ + $(SLO)$/SlsScrollBarManager.obj \ + $(SLO)$/SlsSelectionCommand.obj \ + $(SLO)$/SlsSelectionManager.obj \ + $(SLO)$/SlsSlotManager.obj \ + $(SLO)$/SlsTransferable.obj \ + \ + $(SLO)$/SlsHideSlideFunction.obj \ + $(SLO)$/SlsSelectionFunction.obj \ + $(SLO)$/SlsSlideFunction.obj + +EXCEPTIONSFILES= \ + $(SLO)$/SlideSorterController.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx b/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx new file mode 100644 index 000000000000..336fc48edd97 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx @@ -0,0 +1,110 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCacheContext.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_CACHE_CONTEXT_HXX +#define SD_SLIDESORTER_CACHE_CONTEXT_HXX + +#include <sal/types.h> +#include <com/sun/star/uno/XInterface.hpp> +#include <boost/shared_ptr.hpp> +#include <vector> + +class BitmapEx; +class SdrPage; + +namespace sd { namespace slidesorter { namespace cache { + +typedef const SdrPage* CacheKey; + +/** This interface allows the individualisation of different instances of + the PreviewCache. +*/ +class CacheContext +{ +public: + /** This method is called when the asynchronous creation of a preview + has been finished. + @param aKey + The key of the page for which the preview has been created. + @param aPreview + The newly created preview. + */ + virtual void NotifyPreviewCreation ( + CacheKey aKey, + const ::boost::shared_ptr<BitmapEx>& rPreview) = 0; + + /** Called to determine whether the system is idle and a preview can be + created without annoying the user. + */ + virtual bool IsIdle (void) = 0; + + /** This method is used to determine whether a page is currently visible + or not. It is called when the cache becomes to large and some + previews have to be released or scaled down. + */ + virtual bool IsVisible (CacheKey aKey) = 0; + + /** Return the page associdated with the given key. Note that different + keys may map to a single page (this may be the case with custom + slide shows.) + */ + virtual const SdrPage* GetPage (CacheKey aKey) = 0; + + /** This method is used when the request queue is filled. It asks for + the list of visible entries and maybe for the list of not visible + entries and creates preview creation requests for them. + @param bVisible + When this is <FALSE/> then the implementation can decide whether + to allow rendering of previews that are not visible (ahead of + time). When not then return an empty pointer or an empty vector. + */ + virtual ::boost::shared_ptr<std::vector<CacheKey> > GetEntryList (bool bVisible) = 0; + + /** Return the priority that defines the order in which previews are + created for different keys/pages. Typically the visible pages come + first, then top-down, left-to-right. + */ + virtual sal_Int32 GetPriority (CacheKey aKey) = 0; + + /** Return the model to which the pages belong for which the called + cache manages the previews. Different caches that belong to the + same model but have different preview sizes may acces previews of + each other in order to create fast previews of the previews. + */ + virtual ::com::sun::star::uno::Reference<com::sun::star::uno::XInterface> GetModel (void) = 0; +}; + +typedef ::boost::shared_ptr<CacheContext> SharedCacheContext; + +} } } // end of namespace ::sd::slidesorter::cache + +#endif + diff --git a/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx b/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx new file mode 100644 index 000000000000..8191a18df54e --- /dev/null +++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx @@ -0,0 +1,176 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageCache.hxx,v $ + * $Revision: 1.6 $ + * + * 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 SD_SLIDESORTER_PAGE_CACHE_HXX +#define SD_SLIDESORTER_PAGE_CACHE_HXX + +#include "cache/SlsCacheContext.hxx" +#include <sal/types.h> +#include <vcl/bitmapex.hxx> +#include <boost/function.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> + +namespace sd { namespace slidesorter { namespace view { +class PageObjectViewObjectContact; +} } } + +namespace sd { namespace slidesorter { namespace cache { + +class GenericPageCache; +class RequestData; + +/** The page cache is responsible for the creation and storage of preview + bitmaps of pages that are shown by the slide sorter. + + <p>Bitmaps for previews and a cache are used to speed up the display + (painting) of the slide sorter. But, of course, we have to limit this + time-space-tradeoff by limiting the amount of space that can be use to + store bitmaps.</p> + + <p>There are several strategies employed by this class to shorten the + perceived time that is used to paint the slide sorter: + <ul> + <li>Rendering pages ahead of time. Additionally to rendering the + visible slides we try to render part or all of the slides that are not + (yet) visible. This, of course, makes sense only when the computer is + ohterwise idle while doing that.</li> + <li>When the size of the slides on the screen changes we mark the + bitmaps as needing an update but use them while the new bitmap in the + correct size is not available.</li> + <li>Give the UI the chance to handle user events between the rendering + of differe slides.</li> + <li>Limit the amount of space that may be used for storing preview + bitmaps and throw.</li> + </p> + + <p>There are three somewhat similar methods for requesting new previews: + a) GetPreviewBitmap() schedules a re-rendering (when necessary) and + returns the preview what is currently available, either as a preview of + the preview or, when nothing has changed since the last call, as the + final thing. + b) RequestPreviewBitmap() schedules, like GetPreviewBitmap(), a + re-rendering when the currently available preview is not up-to-date. It + does not, however, return anything. Use this if you can wait for the + preview. + c) InvalidatePreviewBitmap() does not schedule a re-rendering, but + remembers that one is necessary when one of the other two methods is + called. + </p> +*/ +class PageCache +{ +public: + /** The page chache is created with a reference to the slide sorter so + that it has access to both the view and the model and so can fill + itself with requests for all or just the visible pages. + + It is the task of the PageCacheManager to create new objects of this + class. + */ + PageCache ( + const Size& rPreviewSize, + const SharedCacheContext& rpCacheContext); + + ~PageCache (void); + + void ChangeSize(const Size& rPreviewSize); + + /** Request a preview bitmap for the specified page object in the + specified size. The returned bitmap may be a preview of the + preview, i.e. either a scaled (up or down) version of a previous + preview (of the wrong size) or an empty bitmap. In this case a + request for the generation of a new preview is created and inserted + into the request queue. When the preview is available the page + shape will be told to paint itself again. When it then calls this + method again if receives the correctly sized preview bitmap. + @param rRequestData + This data is used to determine the preview. + @param rSize + The size of the requested preview bitmap. + @return + Returns a bitmap that is either empty, contains a scaled (up or + down) version or is the requested bitmap. + */ + BitmapEx GetPreviewBitmap ( + CacheKey aKey, + const Size& rSize); + + /** When the requested preview bitmap does not yet exist or is not + up-to-date then the rendering of one is scheduled. Otherwise this + method does nothing. + */ + void RequestPreviewBitmap ( + CacheKey aKey, + const Size& rSize); + + /** Tell the cache that the bitmap associated with the given request + data is not up-to-date anymore. Unlike the RequestPreviewBitmap() + method this does not trigger the rendering itself. It just + remembers to render it when the preview is requested the next time. + @param rRequestData + It is safe to pass a (barly) living object. It will called only + once to obtain its page object. + */ + void InvalidatePreviewBitmap (CacheKey aKey); + + /** Call this method when a view-object-contact object is being deleted + and does not need (a) its current bitmap in the cache and (b) a + requested new bitmap. + */ + void ReleasePreviewBitmap (CacheKey aKey); + + /** Call this method when all preview bitmaps have to be generated anew. + This is the case when the size of the page objects on the screen has + changed or when the model has changed. + @param bUpdateCache + When this flags is <TRUE/> then requests for updated previews + are created. When it is <FALSE/> the existing previews are only + marked as not being up-to-date anymore. + */ + void InvalidateCache (bool bUpdateCache = true); + + /** With the precious flag you can control whether a bitmap can be + removed or reduced in size to make room for other bitmaps or is so + precious that it will not touched. A typical use is to set the + precious flag for exactly the visible pages. + */ + void SetPreciousFlag (CacheKey aKey, bool bIsPrecious); + + void Pause (void); + void Resume (void); + +private: + ::boost::scoped_ptr<GenericPageCache> mpImplementation; +}; + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx b/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx new file mode 100644 index 000000000000..be1e6c811e1c --- /dev/null +++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageCacheManager.hxx,v $ + * $Revision: 1.7 $ + * + * 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 SD_PAGE_CACHE_MANAGER_HXX +#define SD_PAGE_CACHE_MANAGER_HXX + +#include <sal/types.h> +#include <com/sun/star/uno/XInterface.hpp> +#include <boost/shared_ptr.hpp> +#include <memory> +#include <vector> + +class Size; +class SdDrawDocument; +class SdrPage; + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +class PageObjectViewObjectContact; +} } } + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + +namespace sd { namespace slidesorter { namespace cache { + +namespace css = ::com::sun::star; + +class BitmapCache; + + +/** Provide and manage the preview bitmap caches for all slide sorter + instances. There is one cache per active slide sorter plus a small + number of caches that are no longer in use. The later are kept to speed + up the switching between views. +*/ +class PageCacheManager +{ +public: + typedef BitmapCache Cache; + typedef ::std::vector< ::std::pair<Size, ::boost::shared_ptr<BitmapCache> > > BestFittingPageCaches; + typedef css::uno::Reference<css::uno::XInterface> DocumentKey; + + /** Return the one instance of the PageCacheManager class. + */ + static ::boost::shared_ptr<PageCacheManager> Instance (void); + + /** Look up the cache for the given model in which the previews have the + specified size. If no such cache exists, then one is created. When + a new BitmapCache is created its Recycle() method is called with a + sorted list of existing caches from which the new one initialize its + previews. + @return + The returned cache lives as long as somebody keeps a shared + pointer and the ReleaseCache() method has not been called. + */ + ::boost::shared_ptr<Cache> GetCache ( + DocumentKey pDocument, + const Size& rPreviewSize); + + /** Tell the cache manager to release its own reference to the specified + cache. After that the cache will live as long as the caller (and + maybe others) holds its reference. + */ + void ReleaseCache (const ::boost::shared_ptr<Cache>& rpCache); + + /** This is an information to the cache manager that the size of preview + bitmaps in the specified cache has changed. + + */ + ::boost::shared_ptr<Cache> ChangeSize ( + const ::boost::shared_ptr<Cache>& rpCache, + const Size& rOldPreviewSize, + const Size& rNewPreviewSize); + + /** Invalidate the preview bitmap for one slide that belongs to the + specified document. The bitmaps for this slide in all caches are + marked as out-of-date and will be re-created when they are requested + the next time. + */ + void InvalidatePreviewBitmap ( + DocumentKey pDocument, + const SdrPage* pPage); + + /** Invalidate all the caches that are currently in use and destroy + those that are not. This is used for example when the high contrast + mode is turned on or off. + */ + void InvalidateAllCaches (void); + +private: + /** Singleton instance of the cache manager. Note that this is a weak + pointer. The (implementation class of) ViewShellBase holds a + shared_ptr so that the cache manager has the same life time as the + ViewShellBase. + */ + static ::boost::weak_ptr<PageCacheManager> mpInstance; + + /// List of active caches. + class PageCacheContainer; + ::std::auto_ptr<PageCacheContainer> mpPageCaches; + + /// List of inactive, recently used caches. + class RecentlyUsedPageCaches; + ::std::auto_ptr<RecentlyUsedPageCaches> mpRecentlyUsedPageCaches; + + /** The maximal number of recently used caches that are kept alive after + they have become inactive, i.e. after they are not used anymore by a + slide sorter. + */ + const sal_uInt32 mnMaximalRecentlyCacheCount; + + PageCacheManager (void); + ~PageCacheManager (void); + + class Deleter; + friend class Deleter; + + ::boost::shared_ptr<Cache> GetRecentlyUsedCache( + DocumentKey pDocument, + const Size& rSize); + + /** Add the given cache to the list of recently used caches for the + document. There is one such list per document. Each least has at + most mnMaximalRecentlyCacheCount members. + */ + void PutRecentlyUsedCache( + DocumentKey pDocument, + const Size& rPreviewSize, + const ::boost::shared_ptr<Cache>& rpCache); + + /** Return a sorted list of the available caches, both active caches and + those recently used, for the given document. The sort order is so + that an exact match of the preview size is at the front. Other + caches follow with the largest size first. + */ + BestFittingPageCaches GetBestFittingCaches ( + DocumentKey pDocument, + const Size& rPreviewSize); + + /** This method is used internally to initialize a newly created + BitmapCache with already exisiting previews. + */ + void Recycle ( + const ::boost::shared_ptr<Cache>& rpCache, + DocumentKey pDocument, + const Size& rPreviewSize); +}; + +} } } // end of namespace ::sd::slidesorter::cache + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx b/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx new file mode 100644 index 000000000000..06dc252f7b96 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx @@ -0,0 +1,358 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterController.hxx,v $ + * $Revision: 1.19 $ + * + * 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 SD_SLIDESORTER_SLIDE_SORTER_CONTROLLER_HXX +#define SD_SLIDESORTER_SLIDE_SORTER_CONTROLLER_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include "ViewShell.hxx" + +#include <com/sun/star/drawing/XDrawPages.hpp> + +#include <sfx2/shell.hxx> +#include <sfx2/viewfac.hxx> +#include <tools/link.hxx> +#include <tools/gen.hxx> +#include <memory> +#include <comphelper/implementationreference.hxx> + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +class HighlightObject; +} } } + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + +namespace css = ::com::sun::star; + +namespace sd { namespace slidesorter { namespace controller { + +class Animator; +class Clipboard; +class CurrentSlideManager; +class FocusManager; +class Listener; +class PageSelector; +class Properties; +class ScrollBarManager; +class SelectionManager; +class SlotManager; + +class SlideSorterController +{ +public: + /** Create a new controller for the slide sorter. + @param pParentWindow + The window that contains the controls of the new + controller. + */ + SlideSorterController (SlideSorter& rSlideSorter); + + /** Late initialization. Call this method once a new new object has been + created. + */ + virtual void Init (void); + + virtual ~SlideSorterController (void); + + /** Place and size the scroll bars and the browser window so that the + given rectangle is filled. + @return + The space occupied by the browser window is returned. + */ + Rectangle Resize (const Rectangle& rAvailableSpace); + + /** Determine which of the UI elements--the scroll bars, the scroll bar + filler, the actual slide sorter view--are visible and place them in + the area last passed to Resize(). + @param bForce + When <TRUE/> is given (<FALSE/> is the default) then the content + window and with it the SlideSorterView is resized event when its + size does not change (the size does change when the visibility + of scroll bars changes.) + @return + Returns the space occupied by the browser window. + */ + Rectangle Rearrange (bool bForce = false); + + SlideSorter& GetSlideSorter (void) const; + + /** Return the descriptor of the page that is rendered under the + given position. + @return + Returns a pointer to a page descriptor instead of a + reference because when no page is found at the position + then NULL is returned to indicate this. + */ + model::SharedPageDescriptor GetPageAt (const Point& rPixelPosition); + + /** Return the descriptor of the page that is associated to the page + visible fade symbol at the given position. + @return + When the given position is not over a visible page fade symbol + then NULL is returned. + */ + model::SharedPageDescriptor GetFadePageAt (const Point& rPixelPosition); + + PageSelector& GetPageSelector (void); + FocusManager& GetFocusManager (void); + controller::Clipboard& GetClipboard (void); + + /** Return the object that manages the scroll bars. + */ + ScrollBarManager& GetScrollBarManager (void); + + ::boost::shared_ptr<CurrentSlideManager> GetCurrentSlideManager (void) const; + ::boost::shared_ptr<SlotManager> GetSlotManager (void) const; + ::boost::shared_ptr<SelectionManager> GetSelectionManager (void) const; + + // forward VCLs PrePaint window event to DrawingLayer + void PrePaint(); + + /** This method forwards the call to the SlideSorterView and executes + pending operations like moving selected pages into the visible area. + */ + void Paint (const Rectangle& rRect, ::Window* pWin); + + void FuTemporary (SfxRequest& rRequest); + void FuPermanent (SfxRequest& rRequest); + void FuSupport (SfxRequest& rRequest); + bool Command ( + const CommandEvent& rEvent, + ::sd::Window* pWindow); + + void GetCtrlState (SfxItemSet &rSet); + void GetStatusBarState (SfxItemSet& rSet); + + void ExecCtrl (SfxRequest& rRequest); + void GetAttrState (SfxItemSet& rSet); + void ExecStatusBar (SfxRequest& rRequest); + + bool IsLocked (void) const; + + /** Create an object of this inner class to prevent updates due to model + changes. + */ + class ModelChangeLock + {public: + ModelChangeLock (SlideSorterController& rController); + ~ModelChangeLock (void); + void Release (void); + private: + SlideSorterController* mpController; + }; + friend class ModelChangeLock; + + + /** Handle a change of the model, that is, handle the removal and + insertion of whole pages or a change of the edit mode. + + This method is a convenience function that simply calls + PreModelChange() and then PostModelChange(). + */ + void HandleModelChange (void); + + DECL_LINK(WindowEventHandler, VclWindowEvent*); + + /** Update the display of all pages. This involves a redraw and + releasing previews and caches. + */ + void UpdateAllPages (void); + + /** Set the zoom factor. The given value is clipped against an upper + bound. + @param nZoom + An integer percent value, i.e. nZoom/100 is the actual zoom + factor. + */ + void SetZoom (long int nZoom); + + /** This factory method creates a selection function. + */ + virtual FunctionReference CreateSelectionFunction (SfxRequest& rRequest); + + /** Prepare for a change of the edit mode. Depending on the current + edit mode we may save the selection so that it can be restored when + later changing back to the current edit mode. + */ + void PrepareEditModeChange (void); + + /** Set a new edit mode and return whether the edit mode really + has been changed. For proper saving and restoring of the selection + this method should be called between calls to + PrepareEditModeChange() and FinishEditModeChange(). + @return + A return value of <TRUE/> indicates that the edit mode has + changed. + */ + bool ChangeEditMode (EditMode eEditMode); + + /** Finish the change of the edit mode. Here we may select a page or + restore a previously saved selection. + */ + void FinishEditModeChange (void); + + /** Call this method when the name of one of the pages has changed. + This is then notified to the accessibility object, when that exists. + @param nPageIndex + The index of the page whose name has been changed. + @param rsOldName + The old name of the page. The new name can be taken from the + page object. + */ + void PageNameHasChanged (int nPageIndex, const String& rsOldName); + + /** Return whether a context menu has been opened by the called + SlideSorterController object and is still open. + */ + bool IsContextMenuOpen (void) const; + + /** Return a collection of properties that are used througout the slide + sorter. + */ + ::boost::shared_ptr<Properties> GetProperties (void) const; + + /** Provide the set of pages to be displayed in the slide sorter. The + GetDocumentSlides() method can be found only in the SlideSorterModel. + */ + void SetDocumentSlides (const css::uno::Reference<css::container::XIndexAccess>& rxSlides); + + /** Return an Animator object. + */ + ::boost::shared_ptr<Animator> GetAnimator (void) const; + +private: + SlideSorter& mrSlideSorter; + model::SlideSorterModel& mrModel; + view::SlideSorterView& mrView; + ::std::auto_ptr<PageSelector> mpPageSelector; + ::std::auto_ptr<FocusManager> mpFocusManager; + ::boost::shared_ptr<SlotManager> mpSlotManager; + ::std::auto_ptr<controller::Clipboard> mpClipboard; + ::std::auto_ptr<ScrollBarManager> mpScrollBarManager; + mutable ::boost::shared_ptr<CurrentSlideManager> mpCurrentSlideManager; + ::boost::shared_ptr<SelectionManager> mpSelectionManager; + ::boost::shared_ptr<Animator> mpAnimator; + + // The listener listens to UNO events and thus is a UNO object. + // For proper life time management and at the same time free access to + // the implementation object we use the ImplementationReference class. + ::rtl::Reference<controller::Listener> mpListener; + + int mnModelChangeLockCount; + + bool mbPreModelChangeDone; + bool mbPostModelChangePending; + + ::std::vector<Link> maSelectionChangeListeners; + + /** This array stores the indices of the selected page descriptors at + the time when the edit mode is switched to EM_MASTERPAGE. With this + we can restore the selection when switching back to EM_PAGE mode. + */ + ::std::vector<SdPage*> maSelectionBeforeSwitch; + /// The current page before the edit mode is switched to EM_MASTERPAGE. + int mnCurrentPageBeforeSwitch; + + /** The master page to select after the edit mode is changed. This + member is used to pass the pointer from PrepareEditModeChange() to + FinishEditModeChange(). + */ + SdPage* mpEditModeChangeMasterPage; + + /** This rectangle in the parent window encloses scroll bars and slide + sorter window. It is set when Resize() is called. + */ + Rectangle maTotalWindowArea; + + /** This counter is used to avoid processing of reentrant calls to + Paint(). + */ + sal_Int32 mnPaintEntranceCount; + + /** Remember whether the context menu is open. + */ + bool mbIsContextMenuOpen; + + /** Some slide sorter wide properties that are used in different + classes. + */ + ::boost::shared_ptr<Properties> mpProperties; + + /** Delete the given list of normal pages. This method is a helper + function for DeleteSelectedPages(). + @param rSelectedNormalPages + A list of normal pages. Supplying master pages is an error. + */ + void DeleteSelectedNormalPages (const ::std::vector<SdPage*>& rSelectedNormalPages); + + /** Delete the given list of master pages. This method is a helper + function for DeleteSelectedPages(). + @param rSelectedMasterPages + A list of master pages. Supplying normal pages is an error. + */ + void DeleteSelectedMasterPages (const ::std::vector<SdPage*>& rSelectedMasterPages); + + /** Prepare for several model changes, i.e. prevent time-consuming and + non-critical operations like repaints until UnlockModelChange() is + called. Ciritcal operations like releasing references to pages that + do not exist anymore are executed. + */ + void LockModelChange (void); + + /** Further calls to HandleModelChange() will result in a full featured + update of model, view, and controller. When HandleModelChange() has + been called since the last LockModelChange() then this is done right + away to bring the view up-to-date. + */ + void UnlockModelChange (void); + + /** Prepare for a model change. This method does all the things that + need to be done _before_ the model changes, e.g. because they need + access to the model data before the change. + */ + void PreModelChange (void); + + /** Complete a model change. This includes the recreation of data + structures that depend on the model and the request for a repaint to + show the changes. + */ + void PostModelChange (void); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx b/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx new file mode 100644 index 000000000000..d96d200d2476 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsAnimator.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_CONTROLLER_ANIMATOR_HXX +#define SD_SLIDESORTER_CONTROLLER_ANIMATOR_HXX + +#include "SlideSorter.hxx" +#include <vcl/timer.hxx> +#include <sal/types.h> +#include <vector> +#include <boost/function.hpp> +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> + + +namespace sd { namespace slidesorter { namespace controller { + +/** Experimental class for simple eye candy animations. +*/ +class Animator + : private ::boost::noncopyable +{ +public: + Animator (SlideSorter& rSlideSorter); + ~Animator (void); + + /** An animation object is called with values between 0 and 1 as single + argument to its operator() method. + */ + typedef ::boost::function1<void, double> AnimationFunction; + + /** Schedule a new animation for execution. The () operator of that + animation will be called with increasing values between 0 and 1 for + the specified duration. + @param rAnimation + The animation operation. + @param nDuration + The duration in milli seconds. + */ + void AddAnimation ( + const AnimationFunction& rAnimation, + const sal_Int32 nDuration); + +private: + SlideSorter& mrSlideSorter; + Timer maTimer; + + class Animation; + typedef ::std::vector<boost::shared_ptr<Animation> > AnimationList; + AnimationList maAnimations; + + class DrawLock; + ::boost::scoped_ptr<DrawLock> mpDrawLock; + + DECL_LINK(TimeoutHandler, Timer*); + + /** Execute one step of every active animation. + @return + When one or more animation has finished then <TRUE/> is + returned. Call CleanUpAnimationList() in this case. + */ + bool ServeAnimations (void); + + /** Remove animations that have expired. + */ + void CleanUpAnimationList (void); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx b/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx new file mode 100644 index 000000000000..f3b8af7f83a0 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx @@ -0,0 +1,219 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsClipboard.hxx,v $ + * $Revision: 1.10 $ + * + * 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 SD_SLIDESORTER_CLIPBOARD +#define SD_SLIDESORTER_CLIPBOARD + +#include "ViewClipboard.hxx" + +#include <sal/types.h> +#include <tools/solar.h> +#include <svx/svdpage.hxx> + +#include <set> + +class SfxRequest; +class Window; + +struct AcceptDropEvent; +class DropTargetHelper; +struct ExecuteDropEvent; +class Point; +class SdPage; +class Window; + +namespace sd { +class Window; +} + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace model { +class PageDescriptor; +} } } + +namespace sd { namespace slidesorter { namespace controller { + +class SlideSorterController; + +class Clipboard + : public ViewClipboard +{ +public: + Clipboard (SlideSorter& rSlideSorter); + ~Clipboard (void); + + void HandleSlotCall (SfxRequest& rRequest); + + void DoCut (::Window* pWindow = 0); + void DoCopy (::Window* pWindow = 0); + void DoPaste (::Window* pWindow = 0); + void DoDelete (::Window* pWindow = 0); + + void StartDrag ( + const Point& rDragPt, + ::Window* pWindow ); + + void DragFinished ( + sal_Int8 nDropAction); + + sal_Int8 AcceptDrop ( + const AcceptDropEvent& rEvt, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow = NULL, + USHORT nPage = SDRPAGE_NOTFOUND, + USHORT nLayer = SDRPAGE_NOTFOUND ); + + sal_Int8 ExecuteDrop ( + const ExecuteDropEvent& rEvt, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow = NULL, + USHORT nPage = SDRPAGE_NOTFOUND, + USHORT nLayer = SDRPAGE_NOTFOUND); + +protected: + virtual USHORT DetermineInsertPosition ( + const SdTransferable& rTransferable); + + virtual USHORT InsertSlides ( + const SdTransferable& rTransferable, + USHORT nInsertPosition); + +private: + SlideSorter& mrSlideSorter; + SlideSorterController& mrController; + + typedef ::std::vector<SdPage*> PageList; + /** Remember the pages that are dragged to another document or to + another place in the same document so that they can be removed after + a move operation. + */ + PageList maPagesToRemove; + + /** Remember the pages inserted from another document or another place + in the same document so that they can be selected after the + drag-and-drop operation is completed. + */ + PageList maPagesToSelect; + + /** When pages are moved or copied then the selection of the slide + sorter has to be updated. This flag is used to remember whether the + selection has to be updated or can stay as it is (FALSE). + */ + bool mbUpdateSelectionPending; + + void CreateSlideTransferable ( + ::Window* pWindow, + bool bDrag); + + /** Select the pages stored in the maPagesToSelect member. The list in + the member is cleared afterwards. + */ + void SelectPages (void); + + /** Determine the position of where to insert the pages in the current + transferable of the sd module. + @param pWindow + This window is used as parent for dialogs that have to be shown + to the user. + @return + The index in the range [0,n] (both inclusive) with n the number + of pages is returned. + */ + sal_Int32 GetInsertionPosition (::Window* pWindow); + + /** Paste the pages of the transferable of the sd module at the given + position. + @param nInsertPosition + The position at which to insert the pages. The valid range is + [0,n] (both inclusive) with n the number of pages in the + document. + @return + The number of inserted pages is returned. + */ + sal_Int32 PasteTransferable (sal_Int32 nInsertPosition); + + /** Select a range of pages of the model. Typicall usage is the + selection of newly inserted pages. + @param nFirstIndex + The index of the first page to select. + @param nPageCount + The number of pages to select. + */ + void SelectPageRange (sal_Int32 nFirstIndex, sal_Int32 nPageCount); + + /** Return <TRUE/> when the current transferable in the current state of + the slidesorter is acceptable to be pasted. For this the + transferable has to + a) exist, + b) contain one or more regular draw pages, no master pages. + When master pages are involved, either in the transferable or in the + slide sorter (by it displaying master pages) the drop of the + transferable is not accepted. The reason is the missing + implementation of proper handling master pages copy-and-paste. + */ + enum DropType { DT_PAGE, DT_SHAPE, DT_NONE }; + DropType IsDropAccepted (void) const; + + /** This method contains the code for AcceptDrop() and ExecuteDrop() shapes. + There are only minor differences for the two cases at this level. + @param eCommand + This parameter specifies whether to do a AcceptDrop() or + ExecuteDrop(). + @param rPosition + Since the event is given as void pointer we can not take the + mouse position from it. The caller has to supply it in this + parameter. + @param pDropEvent + Event though the AcceptDropEvent and ExecuteDropEvent are very + similar they do not have a common base class. Because of that + we have to use a void* to pase these structs. + @param nPage + When the page number is given as 0xffff then it is replaced by + the number of the page at the mouse position. If the mouse is + not over a page then neither AcceptDrop() nor ExecuteDrop() are + executed. + */ + enum DropCommand { DC_ACCEPT, DC_EXECUTE }; + sal_Int8 ExecuteOrAcceptShapeDrop ( + DropCommand eCommand, + const Point& rPosition, + const void* pDropEvent , + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow, + USHORT nPage, + USHORT nLayer); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + diff --git a/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx new file mode 100644 index 000000000000..f5e4ddd71ee2 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsCurrentSlideManager.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_CURRENT_SLIDE_MANAGER_HXX +#define SD_SLIDESORTER_CURRENT_SLIDE_MANAGER_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include <com/sun/star/drawing/XDrawPage.hpp> + +class SdPage; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace controller { + +/** Manage the current slide. This includes setting the according flags at + the PageDescriptor objects and setting the current slide at the main + view shell. +*/ +class CurrentSlideManager +{ +public: + /** Create a new CurrentSlideManager object that manages the current + slide for the given SlideSorter. + */ + CurrentSlideManager (SlideSorter& rSlideSorter); + + ~CurrentSlideManager (void); + + /** Call this when the current page of the main view shell has been + switched. Use SwitchCurrentSlide() to initiate such a switch. + */ + void CurrentSlideHasChanged (const sal_Int32 nSlideIndex); + + /** Call this method to switch the current page of the main view shell + to the given slide. Use CurrentSlideHasChanged() when the current + slide change has been initiated by someone else. + */ + void SwitchCurrentSlide (const sal_Int32 nSlideIndex); + void SwitchCurrentSlide (const model::SharedPageDescriptor& rpSlide); + + /** Return the page descriptor for the current slide. Note, that when + there is no current slide then the returned pointer is empty. + */ + model::SharedPageDescriptor GetCurrentSlide (void); + + /** Release all references to model data. + */ + void PrepareModelChange (void); + + /** Modify inner state in reaction to a change of the SlideSorterModel. + */ + void HandleModelChange (void); + +private: + SlideSorter& mrSlideSorter; + sal_Int32 mnCurrentSlideIndex; + model::SharedPageDescriptor mpCurrentSlide; + + bool IsCurrentSlideIsValid (void); + void SetCurrentSlideAtViewShellBase (const model::SharedPageDescriptor& rpSlide); + void SetCurrentSlideAtXController (const model::SharedPageDescriptor& rpSlide); + + /** When switching from one slide to a new current slide then this + method releases all ties to the old slide. + */ + void ReleaseCurrentSlide (void); + + /** When switching from one slide to a new current slide then this + method connects to the new current slide. + */ + void AcquireCurrentSlide (const sal_Int32 nSlideIndex); +}; + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx new file mode 100644 index 000000000000..00678c83058d --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx @@ -0,0 +1,231 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsFocusManager.hxx,v $ + * $Revision: 1.10 $ + * + * 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 SD_SLIDESORTER_FOCUS_MANAGER_HXX +#define SD_SLIDESORTER_FOCUS_MANAGER_HXX + +#include <model/SlsSharedPageDescriptor.hxx> + +#include <sal/types.h> +#include <tools/link.hxx> +#include <vector> + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace controller { + +/** This class manages the focus of the slide sorter. There is the focus + page which is or is not focused. Initialized to point to the first page + it can be set to other pages by using the MoveFocus() method. The + focused state of the focus page can be toggled with the ToggleFocus() + method. +*/ +class FocusManager +{ +public: + /** Create a new focus manager that operates on the pages of the model + associated with the given controller. The focus page is set to the + first page. Focused state is off. + */ + FocusManager (SlideSorter& rSlideSorter); + + ~FocusManager (void); + + enum FocusMoveDirection + { + FMD_NONE, + FMD_LEFT, + FMD_RIGHT, + FMD_UP, + FMD_DOWN + }; + + /** Move the focus from the currently focused page to one that is + displayed adjacent to it, either vertically or horizontally. + @param eDirection + Direction in which to move the focus. Wrap arround is done + differently when moving vertically or horizontally. Vertical + wrap arround takes place in the same column, i.e. when you are + in the top row and move up you come out in the bottom row in the + same column. Horizontal wrap arround moves to the next + (FMD_RIGHT) or previous (FMD_LEFT) page. Moving to the right + from the last page goes to the first page and vice versa. + When FMD_NONE is given, the current page index is checked for + being valid. If it is not, then it is set to the nearest valid + page index. + */ + void MoveFocus (FocusMoveDirection eDirection); + + /** Show the focus indicator of the current slide. + */ + void ShowFocus (void); + + /** Hide the focus indicator. + */ + void HideFocus (void); + + /** Toggle the focused state of the current slide. + @return + Returns the focused state of the focus page after the call. + */ + bool ToggleFocus (void); + + /** Return whether the window managed by the called focus manager has + the input focus of the application. + */ + bool HasFocus (void) const; + + /** Return the descriptor of the page that currently has the focus. + @return + When there is no page that currently has the focus then NULL is + returned. + */ + model::SharedPageDescriptor GetFocusedPageDescriptor (void) const; + + /** Return the index of the page that currently has the focus as it is + accepted by the slide sorter model. + @return + When there is no page that currently has the focus then -1 is + returned. + */ + sal_Int32 GetFocusedPageIndex (void) const; + + /** DEPRECATED. (Use equivalent SetFocusedPage(sal_Int32) instead. + + Set the focus to the page with the given index. This does not make + the focus visible. + @param nPageIndex + Index of a page as it is accepted by the slide sorter model. + The index is not checked for validity. + */ + void FocusPage (sal_Int32 nPageIndex); + + /** Set the focused page to the one described by the given page + descriptor. The visibility of the focus indicator is not modified. + @param rDescriptor + One of the page descriptors that are currently managed by the + SlideSorterModel. + */ + void SetFocusedPage (const model::SharedPageDescriptor& rDescriptor); + + /** Set the focused page to the one described by the given page + index. The visibility of the focus indicator is not modified. + @param nPageIndex + A valid page index that is understood by the SlideSorterModel. + */ + void SetFocusedPage (sal_Int32 nPageIndex); + + /** Return <TRUE/> when the focus inidcator is currently shown. A + prerequisite is that the window managed by this focus manager has + the input focus as indicated by a <TRUE/> return value of + HasFocus(). It is not necessary that the focus indicator is + visible. It may have been scrolled outside the visible area. + */ + bool IsFocusShowing (void) const; + + /** Add a listener that is called when the focus is shown or hidden or + set to another page object. + @param rListener + When this method is called multiple times for the same listener + the second and all following calls are ignored. Each listener + is added only once. + */ + void AddFocusChangeListener (const Link& rListener); + + /** Remove a focus change listener. + @param rListener + It is save to pass a listener that was not added are has been + removed previously. Such calls are ignored. + */ + void RemoveFocusChangeListener (const Link& rListener); + + /** Move focus to sibling outside the actual slide sorter. This is + typically the tool bar with the close button. + */ + void SetFocusToToolBox (void); + + /** Create an instance of this class to temporarily hide the focus + indicator. It is restored to its former visibility state when the + FocusHider is destroyed. + */ + class FocusHider + { + public: + FocusHider (FocusManager&); + ~FocusHider (void); + private: + bool mbFocusVisible; + FocusManager& mrManager; + }; + +private: + SlideSorter& mrSlideSorter; + + /** Index of the page that may be focused. It is -1 when the model + contains no page. + */ + sal_Int32 mnPageIndex; + + /** This flag indicates whether the page pointed to by mpFocusDescriptor + has the focus. + */ + bool mbPageIsFocused; + + ::std::vector<Link> maFocusChangeListeners; + + /** Reset the focus state of the given descriptor and request a repaint + so that the focus indicator is hidden. + @param pDescriptor + When NULL is given then the call is ignored. + */ + void HideFocusIndicator (const model::SharedPageDescriptor& rpDescriptor); + + /** Set the focus state of the given descriptor, scroll it into the + visible area and request a repaint so that the focus indicator is + made visible. + @param pDescriptor + When NULL is given then the call is ignored. + */ + void ShowFocusIndicator (const model::SharedPageDescriptor& rpDescriptor); + + /** Call all currently registered listeners that a focus change has + happended. The focus may be hidden or shown or moved from one page + object to another. + */ + void NotifyFocusChangeListeners (void) const; +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + diff --git a/sd/source/ui/slidesorter/inc/controller/SlsPageObjectFactory.hxx b/sd/source/ui/slidesorter/inc/controller/SlsPageObjectFactory.hxx new file mode 100644 index 000000000000..3522eb78a99a --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsPageObjectFactory.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObjectFactory.hxx,v $ + * $Revision: 1.6 $ + * + * 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 SD_SLIDESORTER_PAGE_OBJECT_FACTORY_HEADER +#define SD_SLIDESORTER_PAGE_OBJECT_FACTORY_HEADER + +#include <boost/shared_ptr.hpp> +#include "model/SlsSharedPageDescriptor.hxx" + +class SdPage; + +namespace sdr { namespace contact { +class ObjectContact; +class ViewContact; +class ViewObjectContact; +} } + +namespace sd { namespace slidesorter { namespace view { +class PageObject; +} } } + +namespace sd { namespace slidesorter { namespace cache { +class PageCache; +} } } + + +namespace sd { namespace slidesorter { namespace controller { + +class Properties; + +/** This class is a factory for the creation of objects that represent page + objects (shapes). This includes the contact objects of the drawing + layer. + + <p>The factory methods are called by the model::PageDescriptor and the + standard implementations of the contact objects.</p> + + <p>The factory forwars the preview cache and Properties object to page + objects and contact objects.</p> +*/ +class PageObjectFactory +{ +public: + /** Create a new PageObjectFactory object that has references to the + given cache and properties. + */ + PageObjectFactory ( + const ::boost::shared_ptr<cache::PageCache>& rpCache, + const ::boost::shared_ptr<controller::Properties>& rpProperties); + PageObjectFactory (const ::boost::shared_ptr<cache::PageCache>& rpCache); + virtual ~PageObjectFactory (void); + + virtual view::PageObject* CreatePageObject ( + SdPage* pPage, + const model::SharedPageDescriptor& rpDescriptor) const; + + virtual ::sdr::contact::ViewContact* CreateViewContact ( + view::PageObject* pPageObject, + const model::SharedPageDescriptor& rpDescriptor) const; + + virtual ::sdr::contact::ViewObjectContact* CreateViewObjectContact ( + ::sdr::contact::ObjectContact& rObjectContact, + ::sdr::contact::ViewContact& rViewContact) const; + +private: + ::boost::shared_ptr<cache::PageCache> mpPageCache; + ::boost::shared_ptr<controller::Properties> mpProperties; +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + diff --git a/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx b/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx new file mode 100644 index 000000000000..7c6616674328 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx @@ -0,0 +1,185 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageSelector.hxx,v $ + * $Revision: 1.9 $ + * + * 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 SD_SLIDESORTER_PAGE_SELECTOR_HXX +#define SD_SLIDESORTER_PAGE_SELECTOR_HXX + +#include "model/SlsSharedPageDescriptor.hxx" + +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <vector> +#include <memory> + +class SdPage; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + +namespace sd { namespace slidesorter { namespace controller { + +class SlideSorterController; + + +/** A sub-controller that handles page selection of the slide browser. + Selecting a page does not make it the current page (of the main view) + automatically as this would not be desired in a multi selection. This + has to be done explicitly by calling the + CurrentSlideManager::SetCurrentSlide() method. + + Indices of pages relate allways to the number of all pages in the model + (as returned by GetPageCount()) not just the selected pages. +*/ +class PageSelector +{ +public: + PageSelector (SlideSorter& rSlideSorter); + + void SelectAllPages (void); + void DeselectAllPages (void); + /** Update the selection state of all page descriptors to be the same as + that of the pages of the SdDrawDocument they describe and issue + redraw requests where necessary. + */ + void UpdateAllPages (void); + + void SelectPage (int nPageIndex); + /** Select the descriptor that is associated with the given page. + */ + void SelectPage (const SdPage* pPage); + void SelectPage (const model::SharedPageDescriptor& rpDescriptor); + + /** Return whether the specified page is selected. This convenience + method is a subsitute for + SlideSorterModel::GetPageDescriptor(i)->IsSelected() is included + here to make this class more self contained. + */ + bool IsPageSelected (int nPageIndex); + + /** Deselect the descriptor that is associated with the given page. + */ + void DeselectPage (int nPageIndex); + void DeselectPage (const SdPage* pPage); + void DeselectPage (const model::SharedPageDescriptor& rpDescriptor); + + /** This convenience method returns the same number of pages that + SlideSorterModel.GetPageCount() returns. It is included here so + that it is self contained for iterating over all pages to select or + deselect them. + */ + int GetPageCount (void) const; + int GetSelectedPageCount (void) const; + + void PrepareModelChange (void); + void HandleModelChange (void); + + /** Enable the broadcasting of selection change events. This calls the + SlideSorterController::SelectionHasChanged() method to do the actual + work. When EnableBroadcasting has been called as many times as + DisableBroadcasting() was called before and the selection has been + changed in the mean time, this change will be broadcasted. + */ + void EnableBroadcasting (bool bMakeSelectionVisible = true); + + /** Disable the broadcasting o selectio change events. Subsequent + changes of the selection will set a flag that triggers the sending + of events when EnableBroadcasting() is called. + */ + void DisableBroadcasting (void); + + /** Return the descriptor of the most recently selected page. This + works only when the page has not been de-selected in the mean time. + This method helps the view when it scrolls the selection into the + visible area. + @return + When the selection is empty or when the most recently selected + page has been deselected already (but other pages are still + selected) then NULL is returned, even when a selection did exist + but has been cleared. + */ + model::SharedPageDescriptor GetMostRecentlySelectedPage (void) const; + + /** Return the anchor for a range selection. This usually is the first + selected page after all pages have been deselected. + @return + The returned anchor may be NULL. + */ + model::SharedPageDescriptor GetSelectionAnchor (void) const; + + + typedef ::std::vector<SdPage*> PageSelection; + + /** Return an object that describes the current selection. The caller + can use that object to later restore the selection. + @return + The object returned describes the selection via indices. So + even if pages are exchanged a later call to SetPageSelection() + is valid. + */ + ::boost::shared_ptr<PageSelection> GetPageSelection (void) const; + + /** Restore a page selection according to the given selection object. + @param rSelection + Typically obtained by calling GetPageSelection() this object + is used to restore the selection. If pages were exchanged since + the last call to GetPageSelection() it is still valid to call + this method with the selection. When pages have been inserted + or removed the result may be unexpected. + */ + void SetPageSelection (const ::boost::shared_ptr<PageSelection>& rSelection); + + void UpdateCurrentPage (const model::SharedPageDescriptor& rCurrentPageDescriptor); + +private: + model::SlideSorterModel& mrModel; + SlideSorter& mrSlideSorter; + SlideSorterController& mrController; + int mnSelectedPageCount; + int mnBroadcastDisableLevel; + bool mbSelectionChangeBroadcastPending; + model::SharedPageDescriptor mpMostRecentlySelectedPage; + /// Anchor for a range selection. + model::SharedPageDescriptor mpSelectionAnchor; + model::SharedPageDescriptor mpCurrentPage; + + void CountSelectedPages (void); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx b/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx new file mode 100644 index 000000000000..53a72a5ec6cf --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsProperties.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_PROPERTIES_HEADER +#define SD_SLIDESORTER_PROPERTIES_HEADER + +#include <tools/color.hxx> + +namespace sd { namespace slidesorter { namespace controller { + +/** An extensible set of properties used throughout the slide sorter. +*/ +class Properties +{ +public: + Properties (void); + ~Properties (void); + + /** When this method returns <TRUE/> then the current slide is + highlighted in the view. The default value is <FALSE/>. + */ + bool IsHighlightCurrentSlide (void) const; + void SetHighlightCurrentSlide (const bool bIsHighlightCurrentSlide); + + /** When this method returns <TRUE/> then the selection is indicated in + the view (typically by drawing rectangles around the selected + slides.) The default value is <TRUE/>. + */ + bool IsShowSelection (void) const; + void SetShowSelection (const bool bIsShowSelection); + + /** When this method returns <TRUE/> then the focusdselection is indicated in + the view (typically by drawing dotted rectangles around the selected + slides.) The default value is <TRUE/>. + */ + bool IsShowFocus (void) const; + void SetShowFocus (const bool bIsShowFocus); + + /** When this method returns <TRUE/> then on a selection change the + visible area is adapted so that the selected slides are shown + centered in the view. This can be used to center the current slide + by selecting only the current slide. The default value is <FALSE/>. + */ + bool IsCenterSelection (void) const; + void SetCenterSelection (const bool bIsCenterSelection); + + /** When this mehod returns <TRUE/> then the view may try to change the + visible area by scrolling it smoothly on the screen. Experimental. + Default value is <FALSE/>. + */ + bool IsSmoothSelectionScrolling (void) const; + void SetSmoothSelectionScrolling (const bool bIsSmoothSelectionScrolling); + + /** When this method returns <TRUE/> then during a full screen + presentation the previews in a slide sorter are not updated. + Default value is <TRUE/>. + */ + bool IsSuspendPreviewUpdatesDuringFullScreenPresentation (void) const; + void SetSuspendPreviewUpdatesDuringFullScreenPresentation (const bool bFlag); + + /** Return the background color. + */ + Color GetBackgroundColor (void) const; + void SetBackgroundColor (const Color& rColor); + + /** Return the text color. + */ + Color GetTextColor (void) const; + void SetTextColor (const Color& rColor); + + /** Return the color in which selections are to be painted. + */ + Color GetSelectionColor (void) const; + void SetSelectionColor (const Color& rColor); + + /** Return the color used for highlighting e.g. the current slide. + */ + Color GetHighlightColor (void) const; + void SetHighlightColor (const Color& rColor); + + /** The UI can be set to be read only indepently from the model status. + Used for instance in the presenter view. + */ + bool IsUIReadOnly (void) const; + void SetUIReadOnly (const bool bIsUIReadOnly); + +private: + bool mbIsHighlightCurrentSlide; + bool mbIsShowSelection; + bool mbIsShowFocus; + bool mbIsCenterSelection; + bool mbIsSmoothSelectionScrolling; + bool mbIsSuspendPreviewUpdatesDuringFullScreenPresentation; + Color maBackgroundColor; + Color maTextColor; + Color maSelectionColor; + Color maHighlightColor; + bool mbIsUIReadOnly; +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + diff --git a/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx new file mode 100644 index 000000000000..e3ae4ef60175 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx @@ -0,0 +1,259 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsScrollBarManager.hxx,v $ + * $Revision: 1.8 $ + * + * 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 SD_SLIDESORTER_SLIDE_SORTER_SCROLL_BAR_MANAGER_HXX +#define SD_SLIDESORTER_SLIDE_SORTER_SCROLL_BAR_MANAGER_HXX + +#include <tools/link.hxx> +#include <tools/gen.hxx> +#include <vcl/timer.hxx> +#include <boost/shared_ptr.hpp> + +class Point; +class Rectangle; +class ScrollBar; +class ScrollBarBox; +class Window; + +namespace sd { +class Window; +} + +namespace sd { namespace slidesorter { + class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace controller { + +/** Manage the horizontal and vertical scroll bars. Listen for events, set + their sizes, place them in the window, determine their visibilities. + + <p>Handle auto scrolling, i.e. the scrolling of the window when the + mouse comes near the window border while dragging a selection.</p> + + <p>In order to make the slide sorter be used in the task pane with its + own vertical scrollbars the vertical scrollbar of the use of the slide + sorter is optional. When using it the available area in a window is + used and the vertical scrollbar is displayed when that area is not large + enough. When the vertical scrollbar is not used then the available area + is assumed to be modifiable. In that case the PlaceScrollBars() method + may return an area larger than the one given.<p> +*/ +class ScrollBarManager +{ +public: + /** Create a new scroll bar manager that manages three controls: the + horizontal scroll bar, the vertical scroll bar, and the little + window that fills the gap at the bottom right corner that is left + between the two scroll bars. Call LateInitialization() after + constructing a new object. + */ + ScrollBarManager (SlideSorter& rSlideSorter); + + ~ScrollBarManager (void); + + /** Call this method after constructing a new object of this class. + */ + void LateInitialization (void); + + /** Register listeners at the scroll bars. This method is called after + startup of a new slide sorter object or after a reactivation of a + slide sorter that for example is taken from a cache. + */ + void Connect (void); + + /** Remove listeners from the scroll bars. This method is called whent + the slide sorter is destroyed or when it is suspended, e.g. put + into a cache for later reuse. + */ + void Disconnect (void); + + /** Set up the scroll bar, i.e. thumb size and position. Call this + method when the content of the browser window changed, i.e. pages + were inserted or deleted, the layout or the zoom factor has + changed. + @param bResetThumbPosition + When <TRUE/> then set the thumb position to position 0. This is + done when e.g. switching between master page mode and draw mode. + @param bScrollToCurrentPosition + When <TRUE/> then scroll the window to the new offset that is + defined by the scroll bars. Otherwise the new offset is simply + set and the whole window is repainted. + */ + void UpdateScrollBars ( + bool bResetThumbPosition = false, + bool bScrollToCurrentPosition = true); + + /** Place the scroll bars inside the given area. When the available + area is not large enough for the content to display the resulting + behaviour depends on the mbUseVerticalScrollBar flag. When it is + set to true then a vertical scroll bar is shown. Otherwise the + height of the returned area is enlarged so that the content fits + into it. + @param rAvailableArea + The scroll bars will be placed inside this rectangle. It is + expected to be given in pixel relative to its parent. + @return + Returns the space that remains after the scroll bars are + placed. When the mbUseVerticalScrollBar flag is false then the + returned rectangle may be larger than the given one. + */ + Rectangle PlaceScrollBars (const Rectangle& rAvailableArea); + + /** Update the vertical scroll bar so that the visible area has the + given top value. + */ + void SetTop (const sal_Int32 nTop); + + /** Update the horizontal scroll bar so that the visible area has the + given left value. + */ + void SetLeft (const sal_Int32 nLeft); + + /** Return the width of the vertical scroll bar, which--when + shown--should be fixed in contrast to its height. + @return + Returns 0 when the vertical scroll bar is not shown or does not + exist, otherwise its width in pixel is returned. + */ + int GetVerticalScrollBarWidth (void) const; + + /** Return the height of the horizontal scroll bar, which--when + shown--should be fixed in contrast to its width. + @return + Returns 0 when the vertical scroll bar is not shown or does not + exist, otherwise its height in pixel is returned. + */ + int GetHorizontalScrollBarHeight (void) const; + + /** Call this method to scroll a window while the mouse is in dragging a + selection. If the mouse is near the window border or is outside the + window then scroll the window accordingly. + @return + When the window is scrolled then this method returns <TRUE/>. + When the window is not changed then <FALSE/> is returned. + */ + bool AutoScroll (const Point& rMouseWindowPosition); + + void StopAutoScroll (void); + +private: + SlideSorter& mrSlideSorter; + + /** The horizontal scroll bar. Note that is used but not owned by + objects of this class. It is given to the constructor. + */ + ::boost::shared_ptr<ScrollBar> mpHorizontalScrollBar; + + /** The vertical scroll bar. Note that is used but not owned by + objects of this class. It is given to the constructor. + */ + ::boost::shared_ptr<ScrollBar> mpVerticalScrollBar; + + /// Relative horizontal position of the visible area in the view. + double mnHorizontalPosition; + /// Relative vertical position of the visible area in the view. + double mnVerticalPosition; + /** The width and height of the border at the inside of the window which + when entered while in drag mode leads to a scrolling of the window. + */ + Size maScrollBorder; + double mnHorizontalScrollFactor; + double mnVerticalScrollFactor; + /** The only task of this little window is to paint the little square at + the bottom right corner left by the two scroll bars (when both are + visible). + */ + ::boost::shared_ptr<ScrollBarBox> mpScrollBarFiller; + + /** The auto scroll timer is used for keep scrolling the window when the + mouse reaches its border while dragging a selection. When the mouse + is not moved the timer issues events to keep scrolling. + */ + Timer maAutoScrollTimer; + Size maAutoScrollOffset; + + /** The content window is the one whose view port is controlled by the + scroll bars. + */ + ::boost::shared_ptr<sd::Window> mpContentWindow; + + void SetWindowOrigin ( + double nHorizontalPosition, + double nVerticalPosition); + + /** Determine the visibility of the scroll bars so that the window + content is not clipped in any dimension without showing a scroll + bar. + @param rAvailableArea + The area in which the scroll bars, the scroll bar filler, and + the SlideSorterView will be placed. + @return + The area that is enclosed by the scroll bars is returned. It + will be filled with the SlideSorterView. + */ + Rectangle DetermineScrollBarVisibilities (const Rectangle& rAvailableArea); + + /** Typically called by DetermineScrollBarVisibilities() this method + tests a specific configuration of the two scroll bars being visible + or hidden. + @return + When the window content can be shown with only being clipped in + an orientation where the scroll bar would be shown then <TRUE/> + is returned. + */ + bool TestScrollBarVisibilities ( + bool bHorizontalScrollBarVisible, + bool bVerticalScrollBarVisible, + const Rectangle& rAvailableArea); + + void CalcAutoScrollOffset (const Point& rMouseWindowPosition); + bool RepeatAutoScroll (void); + + DECL_LINK(HorizontalScrollBarHandler, ScrollBar*); + DECL_LINK(VerticalScrollBarHandler, ScrollBar*); + DECL_LINK(AutoScrollTimeoutHandler, Timer*); + + void PlaceHorizontalScrollBar (const Rectangle& aArea); + void PlaceVerticalScrollBar (const Rectangle& aArea); + void PlaceFiller (const Rectangle& aArea); + + /** Make the height of the content window larger or smaller, so that the + + content size fits exactly in. This is achieved by changing the size + of the parent window and rely on the resulting resize. + */ + void AdaptWindowSize (const Rectangle& rArea); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx new file mode 100644 index 000000000000..4646726ed9ff --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx @@ -0,0 +1,215 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSelectionFunction.hxx,v $ + * $Revision: 1.14 $ + * + * 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 SD_SLIDESORTER_SELECTION_FUNCTION_HXX +#define SD_SLIDESORTER_SELECTION_FUNCTION_HXX + +#include "controller/SlsSlideFunction.hxx" +#include "model/SlsSharedPageDescriptor.hxx" +#include <tools/list.hxx> +#include <memory> + +class SdSlideViewShell; +class SdWindow; +class SdSlideView; +class SdDrawDocument; +class Sound; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace controller { + +class SlideSorterController; + +class SelectionFunction + : public SlideFunction +{ +public: + TYPEINFO(); + + static FunctionReference Create( SlideSorter& rSlideSorter, SfxRequest& rRequest ); + + // Mouse- & Key-Events + virtual BOOL KeyInput(const KeyEvent& rKEvt); + virtual BOOL MouseMove(const MouseEvent& rMEvt); + virtual BOOL MouseButtonUp(const MouseEvent& rMEvt); + virtual BOOL MouseButtonDown(const MouseEvent& rMEvt); + virtual void Paint(const Rectangle&, ::sd::Window* ); + + virtual void Activate(); // Function aktivieren + virtual void Deactivate(); // Function deaktivieren + + virtual void ScrollStart(); + virtual void ScrollEnd(); + + /// Forward to the clipboard manager. + virtual void DoCut (void); + + /// Forward to the clipboard manager. + virtual void DoCopy (void); + + /// Forward to the clipboard manager. + virtual void DoPaste (void); + + /** is called when the current function should be aborted. <p> + This is used when a function gets a KEY_ESCAPE but can also + be called directly. + + @returns + true if a active function was aborted + */ + virtual bool cancel(); + +protected: + SlideSorter& mrSlideSorter; + SlideSorterController& mrController; + + SelectionFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest); + + virtual ~SelectionFunction(); + +private: + class SubstitutionHandler; + class EventDescriptor; + class InsertionIndicatorHandler; + + /// Set in MouseButtonDown this flag indicates that a page has been hit. + bool mbPageHit; + + /// The rectangle of the mouse drag selection. + Rectangle maDragSelectionRectangle; + bool mbDragSelection; + + /// Box of the insert marker in model coordinates. + Rectangle maInsertionMarkerBox; + + /** We use this flag to filter out the cases where MouseMotion() is called + with a pressed mouse button but without a prior MouseButtonDown() + call. This is an indication that the mouse button was pressed over + another control, e.g. the view tab bar, and that a re-layout of the + controls moved the slide sorter under the mouse. + */ + bool mbProcessingMouseButtonDown; + + ::std::auto_ptr<SubstitutionHandler> mpSubstitutionHandler; + + ::std::auto_ptr<InsertionIndicatorHandler> mpInsertionIndicatorHandler; + + DECL_LINK( DragSlideHdl, Timer* ); + void StartDrag (void); + + /** Set the selection to exactly the specified page and also set it as + the current page. + */ + void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor); + + /** When the view on which this selection function is working is the + main view then the view is switched to the regular editing view. + */ + void SwitchView (const model::SharedPageDescriptor& rpDescriptor); + + /** Make the slide nOffset slides away of the current one the new + current slide. When the new index is outside the range of valid + page numbers it is clipped to that range. + @param nOffset + When nOffset is negative then go back. When nOffset if positive go + forward. When it is zero then ignore the call. + */ + void GotoNextPage (int nOffset); + + void ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent); + void ProcessKeyEvent (const KeyEvent& rEvent); + + // What follows are a couple of helper methods that are used by + // ProcessMouseEvent(). + + /// Select the specified page and set the selection anchor. + void SelectHitPage (const model::SharedPageDescriptor& rpDescriptor); + /// Deselect the specified page. + void DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor); + /// Deselect all pages. + void DeselectAllPages (void); + + /** for a possibly following mouse motion by starting the drag timer + that after a short time of pressed but un-moved mouse starts a drag + operation. + */ + void PrepareMouseMotion (const Point& aMouseModelPosition); + + /** Select all pages between and including the selection anchor and the + specified page. + */ + void RangeSelect (const model::SharedPageDescriptor& rpDescriptor); + + /** Start a rectangle selection at the given position. + */ + void StartRectangleSelection (const Point& aMouseModelPosition); + + /** Update the rectangle selection so that the given position becomes + the new second point of the selection rectangle. + */ + void UpdateRectangleSelection (const Point& aMouseModelPosition); + + /** Select all pages that lie completly in the selection rectangle. + */ + void ProcessRectangleSelection (bool bToggleSelection); + + /** Hide and clear the insertion indiciator, substitution display and + selection rectangle. + */ + void ClearOverlays (void); + + /** Compute a numerical code that describes a mouse event and that can + be used for fast look up of the appropriate reaction. + */ + sal_uInt32 EncodeMouseEvent ( + const EventDescriptor& rDescriptor, + const MouseEvent& rEvent) const; + + /** Compute a numerical code that describes a key event and that can + be used for fast look up of the appropriate reaction. + */ + sal_uInt32 EncodeKeyEvent ( + const EventDescriptor& rDescriptor, + const KeyEvent& rEvent) const; + + void EventPreprocessing (const EventDescriptor& rEvent); + bool EventProcessing (const EventDescriptor& rEvent); + void EventPostprocessing (const EventDescriptor& rEvent); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx new file mode 100644 index 000000000000..10b3167af563 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx @@ -0,0 +1,215 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSelectionManager.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_CONTROLLER_SELECTION_MANAGER_HXX +#define SD_SLIDESORTER_CONTROLLER_SELECTION_MANAGER_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include <sal/types.h> +#include <tools/gen.hxx> +#include <vector> + +class Link; +class SdPage; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace controller { + +class SlideSorterController; + +/** This class is a part of the controller and handles the selection of + slides. + <p>It has methods to modify the selected slides (delete them or + move them to other places in the document), change the visible area so + to make the selected slides visble, tell listeners when the selection + changes.</p> +*/ +class SelectionManager +{ +public: + /** Create a new SelectionManger for the given slide sorter. + */ + SelectionManager (SlideSorter& rSlideSorter); + + ~SelectionManager (void); + + /** Delete the currently selected slides. When this method returns the + selection is empty. + */ + void DeleteSelectedPages (void); + + /** Move the maked pages to a position directly after the specified page. + */ + bool MoveSelectedPages (const sal_Int32 nTargetPage); + + /** Call this method after the selection has changed (possible several + calls to the PageSelector) to invalidate the relevant slots and send + appropriate events. + */ + void SelectionHasChanged (const bool bMakeSelectionVisible = true); + + /** Return <TRUE/> when the selection has changed but has not yet been + moved to the visible area of the slide sorter view. + */ + bool IsMakeSelectionVisiblePending (void) const; + + enum SelectionHint { SH_FIRST, SH_LAST, SH_RECENT }; + + /** Try to make all currently selected page objects visible, i.e. set + the origin so that the page objects lie inside the visible area. + When the selection is empty then the visible area is not modified. + + <p>This method, and the ones is calls, look into the Properties + object of the SlideSorter in order to determine whether the current + selection is to be displayed centered.</p> + @param eSelectionHint + This is an advice on which selected page object to handle with + the highest priority when the whole selection does not fit into + the visible area. + @return + Returns the vertical translation of the visible area. It is 0 + when no update of the visible area was done. + */ + Size MakeSelectionVisible ( + const SelectionHint eSelectionHint = SH_RECENT); + + /** Modify the origin of the visible area so that the given rectangle + comes into view. This is done with the smallest change: no + scrolling takes place when the given rectangle already lies in the + visible area. Otherwise either the top or the bottom of the given + rectangle is aligned with the top or the bottom of the visible area. + @return + Returns the vertical translation of the visible area. It is 0 + when no update of the visible area was done. + */ + Size MakeRectangleVisible (const Rectangle& rBox); + + /** Add a listener that is called when the selection of the slide sorter + changes. + @param rListener + When this method is called multiple times for the same listener + the second and all following calls are ignored. Each listener + is added only once. + */ + void AddSelectionChangeListener (const Link& rListener); + + /** Remove a listener that was called when the selection of the slide + sorter changes. + @param rListener + It is save to pass a listener that was not added are has been + removed previously. Such calls are ignored. + */ + void RemoveSelectionChangeListener (const Link& rListener); + + /** Return the position where to insert pasted slides based on the + current selection. When there is a selection then the insert + position is behind the last slide. When the selection is empty then + most of the time the insert position is at the end of the document. + There is an exception right after the display of a popup-menu. The + position of the associated insertion marker is stored here and reset + the next time the selection changes. + */ + sal_Int32 GetInsertionPosition (void) const; + + /** Store an insertion position temporarily. It is reset when the + selection changes the next time. + */ + void SetInsertionPosition (const sal_Int32 nInsertionPosition); + +private: + SlideSorter& mrSlideSorter; + SlideSorterController& mrController; + + ::std::vector<Link> maSelectionChangeListeners; + + /** This array stores the indices of the selected page descriptors at + the time when the edit mode is switched to EM_MASTERPAGE. With this + we can restore the selection when switching back to EM_PAGE mode. + */ + ::std::vector<SdPage*> maSelectionBeforeSwitch; + + /** When this flag is set then on the next call to Paint() the selection + is moved into the visible area. + */ + bool mbIsMakeSelectionVisiblePending; + + /** The insertion position is only temporarily valid. Negative values + indicate that the explicit insertion position is not valid. In this + case GetInsertionPosition() calculates it from the current selection. + */ + sal_Int32 mnInsertionPosition; + + /** Delete the given list of normal pages. This method is a helper + function for DeleteSelectedPages(). + @param rSelectedNormalPages + A list of normal pages. Supplying master pages is an error. + */ + void DeleteSelectedNormalPages (const ::std::vector<SdPage*>& rSelectedNormalPages); + + /** Delete the given list of master pages. This method is a helper + function for DeleteSelectedPages(). + @param rSelectedMasterPages + A list of master pages. Supplying normal pages is an error. + */ + void DeleteSelectedMasterPages (const ::std::vector<SdPage*>& rSelectedMasterPages); + + /** Return <TRUE/> when the given rectangle, that typically is the + bounding box of all currently selected slides, does not fit entirely + into the visible area of the slide sorter view. + */ + bool DoesSelectionExceedVisibleArea (const Rectangle& rSelectionBox) const; + + /** When not all currently selected slides fit into the visible area of + the slide sorter view, and thus DoesSelectionExceedVisibleArea() + would return <TRUE/>, then it is the task of this method to + determine which part of the selection to move into the visible area. + @param rpFirst + The first selected slide. Must not be an empty pointer. + @param rpLast + The last selected slide. Must not be an empty pointer. + @param eSelectionHint + This hint tells the method on which slide to concentrate, + i.e. which slide has to be inside the returned visible area. + @return + Returns the new visible area. + */ + Rectangle ResolveLargeSelection ( + const model::SharedPageDescriptor& rpFirst, + const model::SharedPageDescriptor& rpLast, + const SelectionHint eSelectionHint); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSlideFunction.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSlideFunction.hxx new file mode 100644 index 000000000000..ec175f8e7c7b --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSlideFunction.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSlideFunction.hxx,v $ + * $Revision: 1.6 $ + * + * 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 SD_SLIDESORTER_SLIDE_FUNCTION_HXX +#define SD_SLIDESORTER_SLIDE_FUNCTION_HXX + +#include "fupoor.hxx" + +class SdDrawDocument; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace controller { + +class SlideSorterController; + + +/** Base class for functions of the slide sorter. +*/ +class SlideFunction + : public FuPoor +{ +public: + TYPEINFO(); + + static FunctionReference Create( SlideSorter& rSlideSorter, SfxRequest& rRequest ); + + virtual BOOL MouseMove (const MouseEvent& rMEvt); + virtual BOOL MouseButtonUp (const MouseEvent& rMEvt); + virtual BOOL MouseButtonDown (const MouseEvent& rMEvt); + + /** Called from ForceScroll() before the actual scrolling. + */ + virtual void ScrollStart (void); + + /** Called from ForceScroll() after the actual scrolling. + */ + virtual void ScrollEnd (void); + +protected: + SlideFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx new file mode 100644 index 000000000000..06e16c604500 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx @@ -0,0 +1,108 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSlotManager.hxx,v $ + * $Revision: 1.2 $ + * + * 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 SD_SLIDESORTER_SLOT_MANAGER_HXX +#define SD_SLIDESORTER_SLOT_MANAGER_HXX + +#include <tools/link.hxx> +#include <memory> +#include <queue> + +class AbstractSvxNameDialog; +class SfxItemSet; +class SfxRequest; +class String; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace controller { + +class Command; + +/** This manager takes over the work of handling slot calls from the + controller of the slide sorter. +*/ +class SlotManager +{ +public: + /** Create a new slot manager that handles slot calls for the controller + of a slide sorter. + @param rController + The controller for which to handle the slot calls. + */ + SlotManager (SlideSorter& rSlideSorter); + + ~SlotManager (void); + + void FuTemporary (SfxRequest& rRequest); + void FuPermanent (SfxRequest& rRequest); + void FuSupport (SfxRequest& rRequest); + void GetCtrlState (SfxItemSet &rSet); + void GetMenuState (SfxItemSet &rSet); + void GetClipboardState (SfxItemSet &rSet); + void GetStatusBarState (SfxItemSet& rSet); + void ExecCtrl (SfxRequest& rRequest); + void GetAttrState (SfxItemSet& rSet); + + void ExecuteCommandAsynchronously (::std::auto_ptr<Command> pCommand); + +private: + /// The controller for which we manage the slot calls. + SlideSorter& mrSlideSorter; + + typedef ::std::queue<Command*> CommandQueue; + CommandQueue maCommandQueue; + + /** Called by FuTemporary to show the slide show. + */ + void ShowSlideShow (SfxRequest& rRequest); + + /** The implementation is a copy of the code for SID_RENAMEPAGE in + drviews2.cxx. + */ + void RenameSlide (void); + DECL_LINK(RenameSlideHdl, AbstractSvxNameDialog*); + bool RenameSlideFromDrawViewShell( USHORT nPageId, const String& rName); + + /** Handle SID_INSERTPAGE slot calls. + */ + void InsertSlide (SfxRequest& rRequest); + + void AssignTransitionEffect (void); + + DECL_LINK(UserEventCallback, void*); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + diff --git a/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx b/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx new file mode 100644 index 000000000000..9922787c42bc --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx @@ -0,0 +1,211 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterModel.hxx,v $ + * $Revision: 1.7 $ + * + * 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 SD_SLIDESORTER_SLIDE_SORTER_MODEL_HXX +#define SD_SLIDESORTER_SLIDE_SORTER_MODEL_HXX + +class SdDrawDocument; + +#include "model/SlsPageEnumeration.hxx" +#include "model/SlsSharedPageDescriptor.hxx" + +#include "pres.hxx" +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <osl/mutex.hxx> + +#include <memory> +#include <vector> +#include <functional> + +namespace css = ::com::sun::star; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace controller { +class PageObjectFactory; +} } } + +namespace sd { namespace slidesorter { namespace model { + +class DocumentPageContainer; + +/** The model of the slide sorter gives access to the slides that are to be + displayed in the slide sorter view. Via the SetDocumentSlides() method + this set of slides can be modified (but do not call it directly, use + SlideSorterController::SetDocumentSlides() instead.) +*/ +class SlideSorterModel +{ +public: + SlideSorterModel (SlideSorter& rSlideSorter); + + virtual ~SlideSorterModel (void); + + /** This method is present to let the view create a ShowView for + displaying slides. + */ + SdDrawDocument* GetDocument (void); + + /** Set a new edit mode and return whether the edit mode really + has been changed. When the edit mode is changed then the + previous page descriptor list is replaced by a new one which + has to be repainted. + @return + A return value of <TRUE/> indicates that the edit mode has + changed and thus the page descriptor list has been set up + to reflect that change. A repaint is necessary. + */ + bool SetEditMode (EditMode eEditMode); + + /** Set the edit mode to that currently used by the controller. + */ + bool SetEditModeFromController (void); + EditMode GetEditMode (void) const; + PageKind GetPageType (void) const; + + /** Return the number of slides in the document regardless of whether + they are visible or not or whether they are hidden or not. + The number of slides depends on the set of slides available through + the XIndexAccess given to SetDocumentSlides(). + */ + sal_Int32 GetPageCount (void) const; + + /** Return a page descriptor for the page with the specified index. + Page descriptors are created on demand. The page descriptor is + found (or not found) in constant time. + @param nPageIndex + The index of the requested slide. The valid values + are 0 to GetPageCount()-1. + @param bCreate + When <TRUE/> and the requested page descriptor is missing then + it is created. When <FALSE/> then an empty reference is + returned for missing descriptors. + @return + When the given index is not valid, i.e. lower then zero or + larger than or equal to the number of pages then an empty + reference is returned. Note that the page count may change + between calls to GetPageCount() and GetPageDescriptor(). + */ + SharedPageDescriptor GetPageDescriptor ( + const sal_Int32 nPageIndex, + const bool bCreate = true) const; + + /** Return a page descriptor for the given XDrawPage. Page descriptors + are created on demand. The page descriptor is found (or not found) + in (at most) linear time. Note that all page descriptors in front of + the one associated with the given XDrawPage are created when not yet + present. When the XDrawPage is not found then all descriptors are + created. + @return + Returns the index to the requested page descriptor or -1 when + there is no such page descriptor. + */ + sal_Int32 GetIndex ( + const ::com::sun::star::uno::Reference<com::sun::star::drawing::XDrawPage>& rxSlide) const; + + /** Call this method after the document has changed its structure. This + will get the model in sync with the SdDrawDocument. This method + tries not to throw away to much information already gathered. This + is especially important for previews of complex pages that take some + time to create. + */ + void Resync (void); + + /** Delete all descriptors that currently are in the container. The size + of the container, however, is not altered. Use the AdaptSize + method for that. + */ + void ClearDescriptorList (void); + + /** Set the selection of the document to exactly that of the called model. + */ + void SynchronizeDocumentSelection (void); + + /** Set the selection of the called model to exactly that of the document. + */ + void SynchronizeModelSelection (void); + + /** Replace the factory for the creation of the page objects and + contacts with the given object. The old factory is destroyed. + */ + void SetPageObjectFactory( + ::std::auto_ptr<controller::PageObjectFactory> pPageObjectFactory); + + /** Return the page object factory. It none has been set so far or it + has been reset, then a new one is created. + */ + const controller::PageObjectFactory& GetPageObjectFactory (void) const; + + /** Return the mutex so that the caller can lock it and then safely + access the model. + */ + ::osl::Mutex& GetMutex (void); + + /** Set the XIndexAccess from which the called SlideSorterModel takes + its pages. + @param rxSlides + The set of slides accessible through this XIndexAccess are not + necessarily the same as the ones of the XModel of the + XController (although it typically is a subset). + */ + void SetDocumentSlides (const css::uno::Reference<css::container::XIndexAccess>& rxSlides); + + /** Return the set of pages that is currently displayed by the slide sorter. + */ + css::uno::Reference<css::container::XIndexAccess> GetDocumentSlides (void) const; + + /** This method is called when the edit mode has changed. It calls + SetDocumentSlides() with the set of slides or master pages obtained + from the model of the XController. + */ + void UpdatePageList (void); + +private: + mutable ::osl::Mutex maMutex; + SlideSorter& mrSlideSorter; + ::com::sun::star::uno::Reference<com::sun::star::container::XIndexAccess> mxSlides; + PageKind mePageKind; + EditMode meEditMode; + typedef ::std::vector<SharedPageDescriptor> DescriptorContainer; + mutable DescriptorContainer maPageDescriptors; + mutable ::std::auto_ptr<controller::PageObjectFactory> mpPageObjectFactory; + + /** Resize the descriptor container according to current values of + page kind and edit mode. + */ + void AdaptSize (void); + +}; + +} } } // end of namespace ::sd::slidesorter::model + +#endif diff --git a/sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx b/sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx new file mode 100644 index 000000000000..34be7ca8beac --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx @@ -0,0 +1,56 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsEnumeration.hxx,v $ + * $Revision: 1.5 $ + * + * 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 SD_SLIDESORTER_ENUMERATION_HXX +#define SD_SLIDESORTER_ENUMERATION_HXX + +#include <memory> + +namespace sd { namespace slidesorter { namespace model { + + +/** Interface to generic enumerations. Designed to operate on shared + pointers. Therefore GetNextElement() returns T and not T&. +*/ +template <class T> +class Enumeration +{ +public: + virtual bool HasMoreElements (void) const = 0; + /** Returns T instead of T& so that it can handle shared pointers. + */ + virtual T GetNextElement (void) = 0; + virtual void Rewind (void) = 0; + virtual ::std::auto_ptr<Enumeration<T> > Clone (void) = 0; +}; + +} } } // end of namespace ::sd::slidesorter::model + +#endif diff --git a/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx b/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx new file mode 100644 index 000000000000..e04e5c6e6afb --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx @@ -0,0 +1,229 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageDescriptor.hxx,v $ + * $Revision: 1.8 $ + * + * 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 SD_SLIDESORTER_PAGE_DESCRIPTOR_HXX +#define SD_SLIDESORTER_PAGE_DESCRIPTOR_HXX + +#include <com/sun/star/drawing/XDrawPage.hpp> +#include <tools/gen.hxx> +#include <tools/link.hxx> +#include <vcl/bitmap.hxx> +#include <sfx2/viewfrm.hxx> + +#include <memory> +#include <boost/enable_shared_from_this.hpp> + +class SdPage; + +namespace sdr { namespace contact { +class ObjectContact; +} } + +namespace sd { namespace slidesorter { namespace view { +class PageObject; +class PageObjectViewObjectContact; +} } } + +namespace sd { namespace slidesorter { namespace controller { +class PageObjectFactory; +} } } + +namespace sd { namespace slidesorter { namespace model { + +class SlideRenderer; + +namespace css = ::com::sun::star; + +/** Each PageDescriptor object represents the preview of one draw page, + slide, or master page of a Draw or Impress document as they are displayed + in the slide sorter. This class gives access to some associated + information like prerendered preview or position on the screen. + + <p>Bounding boxes of page objects come in four varieties: + Model and screen/pixel coordinates and the bounding boxes of the actual + page objects and the larger bounding boxes that include page names and + fade symbol.</p> +*/ +class PageDescriptor + : public ::boost::enable_shared_from_this<PageDescriptor> +{ +public: + /** Create a PageDescriptor for the given SdPage object. + @param rxPage + The page that is represented by the new PageDescriptor object. + @param pPage + The page pointer can in some situations not be detected from + rxPage, e.g. after undo of page deletion. Therefore supply it + seperately. + @param nIndex + This index is displayed in the view as page number. It is not + necessaryily the page index (not even when you add or subtract 1 + or use (x-1)/2 magic). + */ + PageDescriptor ( + const css::uno::Reference<css::drawing::XDrawPage>& rxPage, + SdPage* pPage, + const sal_Int32 nIndex, + const controller::PageObjectFactory& rPageObjectFactory); + + ~PageDescriptor (void); + + /** Return the page that is represented by the descriptor as SdPage pointer . + */ + SdPage* GetPage (void) const; + + /** Return the page that is represented by the descriptor as XDrawPage reference. + */ + css::uno::Reference<css::drawing::XDrawPage> GetXDrawPage (void) const; + + /** Returns the index of the page as it is displayed in the view as page + number. The value may differ from the index returned by the + XDrawPage when there are hidden slides and the XIndexAccess used to + access the model filters them out. + */ + sal_Int32 GetPageIndex (void) const; + + /** Return the page shape that is used for visualizing the page. + */ + view::PageObject* GetPageObject (void); + void ReleasePageObject (void); + + /** Return <TRUE/> when the page object is fully or parially visible. */ + bool IsVisible (void) const; + + /** Set the visible state that is returned by the IsVisible() method. + This method is typically called by the view who renders the object + onto the screen. + */ + void SetVisible (bool bVisible); + + /** Make sure that the page is selected and return whether the + selection state changed. + */ + bool Select (void); + /** Make sure that the page is not selected and return whether the + selection state changed. + */ + bool Deselect (void); + + /** Return whether the page is selected (and thus bypasses the internal + mbIsSelected flag. + */ + bool IsSelected (void) const; + + /** Set the internal mbIsSelected flag to the selection state of the + page. Use this method to synchronize a page descriptor with the + page it describes and determine whether a redraw to update the + selection indicator is necessary. + @return + When the two selection states were different <TRUE/> is + returned. When they were the same this method returns + <FALSE/>. + */ + bool UpdateSelection (void); + + bool IsFocused (void) const; + void SetFocus (void); + void RemoveFocus (void); + + view::PageObjectViewObjectContact* GetViewObjectContact (void) const; + + void SetViewObjectContact ( + view::PageObjectViewObjectContact* pViewObjectContact); + + /** Return the currently used page object factory. + */ + const controller::PageObjectFactory& GetPageObjectFactory (void) const; + + /** Replace the current page object factory by the given one. + */ + void SetPageObjectFactory (const controller::PageObjectFactory& rFactory); + + void SetModelBorder (const SvBorder& rBorder); + SvBorder GetModelBorder (void) const; + + /** The size of the area in which the page number is displayed is + calculated by the SlideSorterView and then stored in the page + descriptors so that the contact objects can access them. The + contact objects can not calculate them on demand because the total + number of slides is needed to do that and this number is not known + to the contact objects. + */ + void SetPageNumberAreaModelSize (const Size& rSize); + Size GetPageNumberAreaModelSize (void) const; + + /** Returns <TRUE/> when the slide is the current slide. + */ + bool IsCurrentPage (void) const; + + /** Set or revoke the state of this slide being the current slide. + */ + void SetIsCurrentPage (const bool bIsCurrent); + +private: + SdPage* mpPage; + css::uno::Reference<css::drawing::XDrawPage> mxPage; + /** This index is displayed as page number in the view. It may or may + not be actual page index. + */ + const sal_Int32 mnIndex; + + /// The factory that is used to create PageObject objects. + const controller::PageObjectFactory* mpPageObjectFactory; + + /** The page object will be destroyed by the page into which it has + been inserted. + */ + view::PageObject* mpPageObject; + + bool mbIsSelected; + bool mbIsVisible; + bool mbIsFocused; + bool mbIsCurrent; + + view::PageObjectViewObjectContact* mpViewObjectContact; + + /// The borders in model coordinates arround the page object. + SvBorder maModelBorder; + + /// The size of the page number area in model coordinates. + Size maPageNumberAreaModelSize; + + // Do not use the copy constructor operator. It is not implemented. + PageDescriptor (const PageDescriptor& rDescriptor); + + // Do not use the assignment operator. It is not implemented + // (mrPage can not be assigned). + PageDescriptor& operator= (const PageDescriptor& rDescriptor); +}; + +} } } // end of namespace ::sd::slidesorter::model + +#endif diff --git a/sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx b/sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx new file mode 100644 index 000000000000..072b93589ab5 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx @@ -0,0 +1,130 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageEnumeration.hxx,v $ + * $Revision: 1.7 $ + * + * 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 SD_SLIDESORTER_PAGE_ENUMERATION_HXX +#define SD_SLIDESORTER_PAGE_ENUMERATION_HXX + +#include "pres.hxx" + + +#include "model/SlsEnumeration.hxx" +#include "model/SlsSharedPageDescriptor.hxx" + +#include <boost/function.hpp> +#include <memory> + +namespace sd { namespace slidesorter { namespace model { + +class SlideSorterModel; + + +/** Public class of page enumerations that delegates its calls to an + implementation object that can filter pages by using a given predicate. + + @see PageEnumerationProvider + The PageEnumerationProvider has methods for creating different types + of page enumerations. +*/ +class PageEnumeration + : public Enumeration<SharedPageDescriptor> +{ +public: + /** Create a new page enumeration that enumerates a subset of the pages + of the given model. + @param rModel + The new page enumeration enumerates the pages of this model. + @param rPredicate + This predicate determines which pages to include in the + enumeration. Pages for which rPredicate returns <FALSE/> are + exclude. + */ + typedef ::boost::function<bool(const SharedPageDescriptor&)> PagePredicate; + static PageEnumeration Create ( + const SlideSorterModel& rModel, + const PagePredicate& rPredicate); + + /** This copy constructor creates a copy of the given enumeration. + */ + PageEnumeration (const PageEnumeration& rEnumeration); + + virtual ~PageEnumeration(); + + /** Create a new enumeration object. The ownership of the + implementation object goes to the new object. Use this copy + constructor only when you know what you are doing. When in doubt, + use the one argument version. + @param bCloneImpl + When <TRUE/> is given this constructor behaves exactly like its + one argument version. When <FALSE/> is given then the + implementation object is not copied but moved from the given + enumeration to the newly created one. The given enumeration + thus becomes empty. + */ + PageEnumeration (PageEnumeration& rEnumeration, bool bCloneImpl); + + /** Create and return an exact copy of the called object. + */ + virtual ::std::auto_ptr<Enumeration<SharedPageDescriptor> > Clone (void); + + PageEnumeration& operator= (const PageEnumeration& rEnumeration); + + /** Return <TRUE/> when the enumeration has more elements, i.e. it is + save to call GetNextElement() at least one more time. + */ + virtual bool HasMoreElements (void) const; + + /** Return the next element of the enumeration. Call the + HasMoreElements() before to make sure that there exists at least one + more element. Calling this method with HasMoreElements() returning + <FALSE/> is an error. + */ + virtual SharedPageDescriptor GetNextElement (void); + + /** Rewind the enumeration so that the next call to GetNextElement() + will return its first element. + */ + virtual void Rewind (void); + +private: + /// Implementation object. + ::std::auto_ptr<Enumeration<SharedPageDescriptor> > mpImpl; + + /** This constructor expects an implementation object that holds + the predicate that filters the pages. + */ + PageEnumeration (::std::auto_ptr<Enumeration<SharedPageDescriptor> > pImpl); + + // Default constructor not implemented. + PageEnumeration (void); +}; + +} } } // end of namespace ::sd::slidesorter::model + +#endif diff --git a/sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx b/sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx new file mode 100644 index 000000000000..d1576801f366 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageEnumerationProvider.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_PAGE_ENUMERATION_PROVIDER_HXX +#define SD_SLIDESORTER_PAGE_ENUMERATION_PROVIDER_HXX + +#include "model/SlsPageEnumeration.hxx" + +namespace sd { namespace slidesorter { namespace model { + +class SlideSorterModel; + +/** Collection of methods that create enumeration of slides. +*/ +class PageEnumerationProvider +{ +public: + /** The returned enumeration of slides iterates over all slides of the + given model. + */ + static PageEnumeration CreateAllPagesEnumeration (const SlideSorterModel& rModel); + + /** The returned enumeration of slides iterates over the currently + selected slides of the given model. + */ + static PageEnumeration CreateSelectedPagesEnumeration (const SlideSorterModel& rModel); + + /** The returned enumeration of slides iterates over the slides + (partially) inside the visible area. + */ + static PageEnumeration CreateVisiblePagesEnumeration (const SlideSorterModel& rModel); +}; + +} } } // end of namespace ::sd::slidesorter::model + +#endif diff --git a/sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx b/sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx new file mode 100644 index 000000000000..9e6e635e2a4b --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx @@ -0,0 +1,44 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsSharedPageDescriptor.hxx,v $ + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_SHARED_PAGE_DESCRIPTOR_HXX +#define SD_SLIDESORTER_SHARED_PAGE_DESCRIPTOR_HXX + +#include <boost/shared_ptr.hpp> + +namespace sd { namespace slidesorter { namespace model { + +class PageDescriptor; + +typedef ::boost::shared_ptr<PageDescriptor> SharedPageDescriptor; + +} } } // end of namespace ::sd::slidesorter::model + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx b/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx new file mode 100644 index 000000000000..360ecaba703c --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx @@ -0,0 +1,306 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterView.hxx,v $ + * $Revision: 1.15 $ + * + * 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 SD_SLIDESORTER_SLIDE_SORTER_VIEW_HXX +#define SD_SLIDESORTER_SLIDE_SORTER_VIEW_HXX + +#include "View.hxx" + +#include "model/SlsSharedPageDescriptor.hxx" + +#include <sfx2/viewfrm.hxx> +#include "pres.hxx" +#include <tools/gen.hxx> +#include <memory> +#include <boost/shared_ptr.hpp> + +class Point; + +namespace sdr { namespace contact { +class ObjectContact; +} } + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace controller { +class SlideSorterController; +} } } + +namespace sd { namespace slidesorter { namespace cache { +class PageCache; +} } } + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class Layouter; +class ViewOverlay; + + +class SlideSorterView + : public View +{ +public: + TYPEINFO(); + + /** Create a new view for the slide sorter. + @param rViewShell + This reference is simply passed to the base class and not used + by this class. + + */ + SlideSorterView (SlideSorter& rSlideSorter); + + virtual ~SlideSorterView (void); + + enum Orientation { HORIZONTAL, VERTICAL }; + void SetOrientation (const Orientation eOrientation); + Orientation GetOrientation (void) const; + + void RequestRepaint (void); + void RequestRepaint (const model::SharedPageDescriptor& rDescriptor); + + Rectangle GetModelArea (void); + + enum CoordinateSystem { CS_SCREEN, CS_MODEL }; + enum BoundingBoxType { BBT_SHAPE, BBT_INFO }; + + /** Return the rectangle that bounds the page object represented by the + given page descriptor. + @param rDescriptor + The descriptor of the page for which to return the bounding box. + @param eCoordinateSystem + Specifies whether to return the screen or model coordinates. + @param eBoundingBoxType + Specifies whether to return the bounding box of only the page + object or the one that additionally includes other displayed + information like page name and fader symbol. + */ + Rectangle GetPageBoundingBox ( + const model::SharedPageDescriptor& rpDescriptor, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const; + + /** Return the rectangle that bounds the page object represented by the + given page index . + @param nIndex + The index of the page for which to return the bounding box. + @param eCoordinateSystem + Specifies whether to return the screen or model coordinates. + @param eBoundingBoxType + Specifies whether to return the bounding box of only the page + object or the one that additionally includes other displayed + information like page name and fader symbol. + */ + Rectangle GetPageBoundingBox ( + sal_Int32 nIndex, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const; + + /** Return the index of the page that is rendered at the given position. + @param rPosition + The position is expected to be in pixel coordinates. + @return + The returned index is -1 when there is no page object at the + given position. + */ + sal_Int32 GetPageIndexAtPoint (const Point& rPosition) const; + sal_Int32 GetFadePageIndexAtPoint (const Point& rPosition) const; + + view::Layouter& GetLayouter (void); + + virtual void ModelHasChanged (void); + + void LocalModelHasChanged(void); + + /** This method is typically called before a model change takes place. + All references to model data are released. PostModelChange() has to + be called to complete the handling of the model change. When the + calls to Pre- and PostModelChange() are very close to each other you + may call HandleModelChange() instead. + */ + void PreModelChange (void); + + /** This method is typically called after a model change took place. + References to model data are re-allocated. Call this method only + after PreModelChange() has been called. + */ + void PostModelChange (void); + + /** This method is a convenience function that simply calls + PreModelChange() and then PostModelChange(). + */ + void HandleModelChange (void); + + void HandleDrawModeChange (void); + + virtual void Resize (void); + virtual void CompleteRedraw (OutputDevice* pDevice, const Region& rPaintArea, sdr::contact::ViewObjectContactRedirector* pRedirector = 0L); + virtual void InvalidateOneWin ( + ::Window& rWindow); + virtual void InvalidateOneWin ( + ::Window& rWindow, + const Rectangle& rPaintArea ); + + void Layout (void); + /** This tells the view that it has to re-determine the visibility of + the page objects before painting them the next time. + */ + void InvalidatePageObjectVisibilities (void); + + /** Return the window to which this view renders its output. + */ + ::sd::Window* GetWindow (void) const; + + + ::boost::shared_ptr<cache::PageCache> GetPreviewCache (void); + + view::ViewOverlay& GetOverlay (void); + + /** Set the bounding box of the insertion marker in model coordinates. + + It will be painted as a dark rectangle that fills the given box. + */ + void SetInsertionMarker (const Rectangle& rBBox); + + /** Specify whether the insertion marker will be painted or not. + */ + void SetInsertionMarkerVisibility (bool bVisible); + + /** Set the size and position of the selection rectangle. + + It will be painted as a dashed rectangle. + */ + void SetSelectionRectangle (const Rectangle& rBox); + + /** Specify whether the selection rectangle will be painted or not. + */ + void SetSelectionRectangleVisibility (bool bVisible); + + ::sdr::contact::ObjectContact& GetObjectContact (void) const; + + typedef ::std::pair<sal_Int32,sal_Int32> PageRange; + /** Return the range of currently visible page objects including the + first and last one in that range. + @return + The returned pair of page object indices is empty when the + second index is lower than the first. + */ + PageRange GetVisiblePageRange (void); + + /** Return the size of the area where the page numbers are displayed. + @return + The returned size is given in model coordinates. + */ + Size GetPageNumberAreaModelSize (void) const; + + /** Return the size of the border around the original SdrPageObj. + */ + SvBorder GetModelBorder (void) const; + + /** Add a shape to the page. Typically used from inside + PostModelChange(). + */ + void AddSdrObject (SdrObject& rObject); + +protected: + virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); + +private: + SlideSorter& mrSlideSorter; + model::SlideSorterModel& mrModel; + /// This model is used for the maPage object and for the page visualizers + /// (SdrPageObj) + SdrModel maPageModel; + /** This page acts as container for the page objects that represent the + pages of the document that is represented by the SlideSorterModel. + */ + SdrPage* mpPage; + ::std::auto_ptr<Layouter> mpLayouter; + bool mbPageObjectVisibilitiesValid; + ::boost::shared_ptr<cache::PageCache> mpPreviewCache; + ::std::auto_ptr<ViewOverlay> mpViewOverlay; + + int mnFirstVisiblePageIndex; + int mnLastVisiblePageIndex; + + SvBorder maPagePixelBorder; + + bool mbModelChangedWhileModifyEnabled; + + Size maPreviewSize; + + bool mbPreciousFlagUpdatePending; + + Size maPageNumberAreaModelSize; + SvBorder maModelBorder; + + Orientation meOrientation; + + /** Adapt the coordinates of the given bounding box according to the + other parameters. + @param rModelPageObjectBoundingBox + Bounding box given in model coordinates that bounds only the + page object. + @param eCoordinateSystem + When CS_SCREEN is given then the bounding box is converted into + screen coordinates. + @param eBoundingBoxType + When BBT_INFO is given then the bounding box is made larger so + that it encloses all relevant displayed information. + */ + void AdaptBoundingBox ( + Rectangle& rModelPageObjectBoundingBox, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const; + + /** Determine the visibility of all page objects. + */ + void DeterminePageObjectVisibilities (void); + + /** Update the page borders used by the layouter by using those returned + by the first page. Call this function when the model changes, + especially when the number of pages changes, or when the window is + resized as the borders may be device dependent. + */ + void UpdatePageBorders (void); + + void UpdatePreciousFlags (void); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsFontProvider.hxx b/sd/source/ui/slidesorter/inc/view/SlsFontProvider.hxx new file mode 100644 index 000000000000..4202ef581b64 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsFontProvider.hxx @@ -0,0 +1,97 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsFontProvider.hxx,v $ + * $Revision: 1.4 $ + * + * 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 SD_SLIDESORTER_VIEW_FONT_PROVIDER_HXX +#define SD_SLIDESORTER_VIEW_FONT_PROVIDER_HXX + +#include "tools/SdGlobalResourceContainer.hxx" + +#include <boost/shared_ptr.hpp> +#include <vcl/mapmod.hxx> + +class Font; +class OutputDevice; +class VclWindowEvent; + +namespace sd { namespace slidesorter { namespace view { + +/** This simple singleton class provides fonts that are scaled so that they + have a fixed height on the given device regardless of its map mode. +*/ +class FontProvider + : public SdGlobalResource +{ +public: + typedef ::boost::shared_ptr<Font> SharedFontPointer; + + /** Return the single instance of this class. Throws a RuntimeException + when no instance can be created. + */ + static FontProvider& Instance (void); + + /** Return a font that is scaled according to the current map mode of + the given device. Repeated calls with a device, not necessarily the + same device, with the same map mode will return the same font. The + first call with a different map mode will release the old font and + create a new one that is correctly scaled. + */ + SharedFontPointer GetFont (const OutputDevice& rDevice); + + /** Call this method to tell an object to release its currently used + font. The next call to GetFont() will then create a new one. + Typically called after a DataChange event when for instance a system + font has been modified. + */ + void Invalidate (void); + +private: + static FontProvider* mpInstance; + + /** The font that was created by a previous call to GetFont(). It is + replaced by another one only when GetFont() is called with a device + with a different map mode or by a call to Invalidate(). + */ + SharedFontPointer maFont; + /** The mape mode for which maFont was created. + */ + MapMode maMapMode; + + FontProvider (void); + virtual ~FontProvider (void); + + // Copy constructor is not implemented. + FontProvider (const FontProvider&); + // Assignment operator is not implemented. + FontProvider& operator= (const FontProvider&); +}; + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx b/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx new file mode 100644 index 000000000000..194f83680f06 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx @@ -0,0 +1,408 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsLayouter.hxx,v $ + * $Revision: 1.8 $ + * + * 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 SD_SLIDESORTER_VIEW_LAYOUTER_HXX +#define SD_SLIDESORTER_VIEW_LAYOUTER_HXX + +#include <sal/types.h> +#include <tools/fract.hxx> +#include <vcl/mapmod.hxx> +#include <vector> +#include <utility> + +class MapMode; +class OutputDevice; +class Size; + +namespace sd { namespace slidesorter { namespace view { + +/** Calculate the size and position of page objects displayed by a slide + sorter. The layouter takes into account various input values: + 1.) Size of the window in which the slide sorter is displayed. + 2.) Desired and minimal and maximal widths of page objects. + 3.) Minimal and maximal number of columns. + 4.) Vertical and horizontal gaps between objects in adjacent columns. + 5.) Borders arround every page object. + 6.) Vertical and horizontal borders between enclosing page and outer + page objects. + From these it calculates various output values: + 1.) The width of page objects. + 2.) The number of columns. + 3.) The size of the enclosing page. + + <p>Sizes and lengths are all in pixel except where explicitly stated + otherwise.</p> + + <p>The GetIndex... methods may return indices that are larger than or + equal to (zero based) the number of pages. This is so because the + number of pages is not known to the class instances. Indices are + calculated with reference to the general grid layout of page + objects.</p> +*/ +class Layouter +{ +public: + Layouter (void); + ~Layouter (void); + + /** Set the minimal, the maximal, and the desired width of the page + objects. The three parameters have to fullfill the constraint + nMinimalWidth <= nPreferredWidth <= nMaximalWidth or the call is + ignored. + */ + void SetObjectWidth (sal_Int32 nMinimalWidth, sal_Int32 nMaximalWidth, + sal_Int32 nPreferredWidth); + + /** Set the horizontal and vertical borders in pixel coordinates between + the enclosing window and page objects. The borders may be painted + larger then the given values when the space for the insertion marker + is not sufficient. + @param nLeftBorder + Use a negative value to indicate that the left border size + shall not be modified. A value of 10 is the default. + @param nRightBorder + Use a negative value to indicate that the right border size + shall not be modified. A value of 10 is the default. + @param nTopBorder + Use a negative value to indicate that the top border size + shall not be modified. A value of 10 is the default. + @param nBottomBorder + Use a negative value to indicate that the bottom border size + shall not be modified. A value of 10 is the default. + */ + void SetBorders (sal_Int32 nLeftBorder, sal_Int32 nRightBorder, + sal_Int32 nTopBorder, sal_Int32 nBottomBorder); + + /** Set the borders arround every page object. + @param nLeftBorder + A negative value indicates that the left border shall not be + modified. A value of 0 is the default. + @param nRightBorder + A negative value indicates that the left border shall not be + modified. A value of 0 is the default. + @param nTopBorder + A negative value indicates that the left border shall not be + modified. A value of 0 is the default. + @param nBottomBorder + A negative value indicates that the left border shall not be + modified. A value of 0 is the default. + */ + void SetPageBorders (sal_Int32 nLeftBorder, sal_Int32 nRightBorder, + sal_Int32 nTopBorder, sal_Int32 nBottomBorder); + + /** Set the horizontal and vertical gaps between adjacent page objects. + These gaps are only relevant when there is more than one column or + more than one row. Negative values indicate that the respective gap + is not set. + */ + void SetGaps (sal_Int32 nHorizontalGap, sal_Int32 nVerticalGap); + + /** Set the interval of valid column counts. When nMinimalColumnCount + <= nMaximalColumnCount is not fullfilled then the call is ignored. + @param nMinimalColumnCount + The default value is 1. The question whether higher values make + any sense is left to the caller. + @param nMaximalColumnCount + The default value is 5. + */ + void SetColumnCount (sal_Int32 nMinimalColumnCount, + sal_Int32 nMaximalColumnCount); + + /** Central method of this class. It takes the input values and + calculates the output values. Both given sizes must not be 0 in any + dimension or the call is ignored. + @param rWindowSize + The size of the window in pixels that the slide sorter is + displayed in. + @param rPageObjectSize + Size of each page in model coordinates. + @param pDevice + The map mode of this output device is adapted to the new layout + of the page objects. + @return + The return value indicates whether the Get... methods can be + used to obtain valid values (<TRUE/>). + */ + bool RearrangeHorizontal ( + const Size& rWindowSize, + const Size& rPageObjectSize, + OutputDevice* pDevice, + const sal_uInt32 nPageCount); + bool RearrangeVertical ( + const Size& rWindowSize, + const Size& rPageObjectSize, + OutputDevice* pDevice); + + /** Change the zoom factor. This does not change the general layout + (number of columns). + */ + void SetZoom (double nZoomFactor, OutputDevice* pDevice); + void SetZoom (Fraction nZoomFactor, OutputDevice* pDevice); + + /** Return the number of columns. + */ + sal_Int32 GetColumnCount (void) const; + + /** Returns whether the column count is fixed (<TRUE/>) or variable + (<FALSE/>). It is fixed if SetColumnCount() was called with the + same value for minimal and maximal column count. + */ + bool IsColumnCountFixed (void) const; + + /** Return the scale factor that can be set at the map mode of the + output window. + */ + Fraction GetScaleFactor (void) const; + + Size GetPageObjectSize (void) const; + + /** Return the bounding box in model coordinates of the nIndex-th page + object. + */ + Rectangle GetPageObjectBox (sal_Int32 nIndex) const; + + /** Return the bounding box in model coordinates of the page that + contains the given amount of page objects. + */ + Rectangle GetPageBox (sal_Int32 nObjectCount) const; + + /** Return the rectangle that bounds the insertion marker that is + specified by the parameters. + @param nIndex + Index of the page object from which the position of the marker + will be calculated. + @param bVertical + When <TRUE/> then the insertion marker will be calculated with a + vertical orientation positioned to the left or right of the + specified page object. A horizontal orientation is indicated by + <FALSE/>. In this case the marker will be positioned above or + below the page object. + @param bLeftOrTop + This flag indicates whether the insertion marker will be + positioned above or to the left (<TRUE/>) the page object. When + <FALSE/> is given then the marker will be positioned below or to + the right of the page object. + */ + Rectangle GetInsertionMarkerBox ( + sal_Int32 nIndex, + bool bVertical, + bool bLeftOrTop) const; + + /** Return the index of the first fully or partially visible page + object. This takes into account only the vertical dimension. + */ + sal_Int32 GetIndexOfFirstVisiblePageObject ( + const Rectangle& rVisibleArea) const; + + /** Return the index of the last fully or partially visible page + object. This takes into account only the vertical dimension. + @return + The returned index may be larger than the number of existing + page objects. + */ + sal_Int32 GetIndexOfLastVisiblePageObject ( + const Rectangle& rVisibleArea) const; + + /** Return the index of the page object that is rendered at the given + point. + @param rPosition + The position is expected to be in model coordinates relative to + the page origin. + @param bIncludePageBorders + When <TRUE/> then include the page borders into the calculation, + i.e. when a point lies in the border of a page object but not on + the actual page area the index of that page is returned; + otherwise -1 would be returned to indicate that no page object + has been hit. + @return + The returned index may be larger than the number of existing + page objects. + */ + sal_Int32 GetIndexAtPoint ( + const Point& rModelPosition, + bool bIncludePageBorders = false) const; + + /** Return the page index of where to do an insert operation when the + user would release the the mouse button at the given position after + a drag operation. + @param rPosition + The position in the model coordinate system for which to + determine the insertion page index. The position does not have + to be over a page object to return a valid value. + @param bAllowVerticalPosition + When this flag is <TRUE/> then the vertical gaps between rows + may be taken into account for calculating the insertion index as + well as the horizontal gaps between columns. This will happen + only when there is only one column. + (better name, anyone?) + @return + Returns the page index, as accepted by the slide sorter model, + of the page after which an insertion would take place. An index + of 0 means that insertion will take place before the first page, + An index equal to or greater than the page count means to insert + after the last page. + A value of -1 indicates that no valid insertion index exists for + the given point. + */ + sal_Int32 GetInsertionIndex ( + const Point& rModelPosition, + bool bAllowVerticalPosition) const; + + typedef ::std::pair<double,double> DoublePoint; + /** Transform a point given in model coordinates in to layouter + coordinates. Layouter coordinates are floating point numbers where + the integer part denotes a row or a column and the part after the + decimal point is a relative position in that row or column. + */ + DoublePoint ConvertModelToLayouterCoordinates ( + const Point& rModelPoint) const; + + /** Transform a point given in layouter coordinates to model + coordinates. See ConvertModelToLayouterCoordinates for a + description of layouter coordinates. + */ + Point ConvertLayouterToModelCoordinates ( + const DoublePoint&rLayouterPoint) const; + + typedef ::std::vector<Rectangle> BackgroundRectangleList; + const BackgroundRectangleList& GetBackgroundRectangleList (void) const; + +private: + class ScreenAndModelValue {public: + sal_Int32 mnScreen,mnModel; + explicit ScreenAndModelValue (sal_Int32 nScreen, sal_Int32 nModel = 0) + : mnScreen(nScreen),mnModel(nModel) {} + }; + ScreenAndModelValue mnRequestedLeftBorder; + ScreenAndModelValue mnRequestedRightBorder; + ScreenAndModelValue mnRequestedTopBorder; + ScreenAndModelValue mnRequestedBottomBorder; + ScreenAndModelValue mnLeftBorder; + ScreenAndModelValue mnRightBorder; + ScreenAndModelValue mnTopBorder; + ScreenAndModelValue mnBottomBorder; + ScreenAndModelValue mnLeftPageBorder; + ScreenAndModelValue mnRightPageBorder; + ScreenAndModelValue mnTopPageBorder; + ScreenAndModelValue mnBottomPageBorder; + ScreenAndModelValue mnVerticalGap; + ScreenAndModelValue mnHorizontalGap; + ScreenAndModelValue mnInsertionMarkerThickness; + ScreenAndModelValue mnTotalVerticalGap; + ScreenAndModelValue mnTotalHorizontalGap; + sal_Int32 mnMinimalWidth; + sal_Int32 mnPreferredWidth; + sal_Int32 mnMaximalWidth; + sal_Int32 mnMinimalColumnCount; + sal_Int32 mnMaximalColumnCount; + sal_Int32 mnColumnCount; + Size maPageObjectModelSize; + Size maPageObjectPixelSize; + + BackgroundRectangleList maBackgroundRectangleList; + + enum GapMembership { GM_NONE, GM_PREVIOUS, GM_BOTH, GM_NEXT, + GM_PAGE_BORDER}; + + /** Calculate the row that the point with the given vertical coordinate + is over. The horizontal component is ignored. + @param nYPosition + Vertical position in model coordinates. + @param bIncludeBordersAndGaps + When this flag is <TRUE/> then the area of borders and gaps are + interpreted as belonging to one of the rows. + @param eGapMembership + Specifies to what row the gap areas belong. Here GM_NONE + corresponds to bIncludeBordersAndGaps being <FALSE/>. When + GM_BOTH is given then the upper half is associated to the row + above and the lower half to the row below. Values of + GM_PREVIOUS and GM_NEXT associate the whole gap area with the + row above or below respectively. + */ + sal_Int32 GetRowAtPosition ( + sal_Int32 nYPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership = GM_NONE) const; + + /** Calculate the column that the point with the given horizontal + coordinate is over. The verical component is ignored. + @param nXPosition + Horizontal position in model coordinates. + @param bIncludeBordersAndGaps + When this flag is <TRUE/> then the area of borders and gaps are + interpreted as belonging to one of the columns. + @param eGapMembership + Specifies to what column the gap areas belong. Here GM_NONE + corresponds to bIncludeBordersAndGaps being <FALSE/>. When + GM_BOTH is given then the left half is associated with the + column at the left and the right half with the column to the + right. Values of GM_PREVIOUS and GM_NEXT associate the whole + gap area with the column to the left or right respectively. + */ + sal_Int32 GetColumnAtPosition ( + sal_Int32 nXPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership = GM_NONE) const; + + /** This method is typically called from GetRowAtPosition() and + GetColumnAtPosition() to handle a position that lies inside the gap + between two adjacent rows or columns. + @param nDistanceIntoGap + Vertical distance from the bottom of the upper row down into the + gap or or horizontal distance from the right edge right into the + gap. + @param eGapMemberhship + This value decides what areas in the gap belong to which (or no) + row or column. + @param nIndex + The row index of the upper row or the column index of the left + column. + @param nLeftOrTopPageBorder + Width in model coordinates of the border the the right of or + below a page. + @param nGap + Width or height of the gap in model coordiantes between the + page borders. + @return + Returns either the index of the upper row (as given as nRow), the + index of the lower row (nRow+1) or -1 to indicate that the + position belongs to no row. + */ + sal_Int32 ResolvePositionInGap ( + sal_Int32 nDistanceIntoGap, + GapMembership eGapMembership, + sal_Int32 nIndex, + sal_Int32 nLeftOrTopPageBorder, + sal_Int32 nGap) const; +}; + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObject.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObject.hxx new file mode 100644 index 000000000000..9769731ab52c --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObject.hxx @@ -0,0 +1,67 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObject.hxx,v $ + * $Revision: 1.5 $ + * + * 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 SD_SLIDESORTER_PAGE_OBJECT_HXX +#define SD_SLIDESORTER_PAGE_OBJECT_HXX + +#include "model/SlsSharedPageDescriptor.hxx" + +#include <svx/svdopage.hxx> + +namespace sd { namespace slidesorter { namespace view { + + +/** This sub class of the SdrPageObject exists to create the view contact + and indirectly to create view-object-contact objects. +*/ +class PageObject + : public SdrPageObj +{ +public: + PageObject ( + const Rectangle& rRect, + SdrPage* pPage, + const model::SharedPageDescriptor& rpDescriptor); + + virtual ~PageObject (void); + + model::SharedPageDescriptor GetDescriptor (void) const; + +private: + model::SharedPageDescriptor mpDescriptor; + + virtual sdr::contact::ViewContact* CreateObjectSpecificViewContact (void); +}; + + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewContact.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewContact.hxx new file mode 100644 index 000000000000..2ac7eeb69055 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewContact.hxx @@ -0,0 +1,94 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObjectViewContact.hxx,v $ + * $Revision: 1.9 $ + * + * 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 SD_SLIDESORTER_PAGE_OBJECT_VIEW_CONTACT_HXX +#define SD_SLIDESORTER_PAGE_OBJECT_VIEW_CONTACT_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include <svx/sdtakitm.hxx> +#include <svx/sdr/contact/viewcontactofpageobj.hxx> + +class SdrPageObj; + +namespace sdr {namespace contact { +class ViewObjectContact; +class ObjectContact; +} } + +namespace sd { namespace slidesorter { namespace view { + +/** Details: + This class has to provide the bounding box but can not determine it + fully because it has no access to the output device. It therefore + retrieves some of the necessary data, the border, from the + PageDescriptor which acts here as persistent storage. +*/ +class PageObjectViewContact + : public ::sdr::contact::ViewContactOfPageObj +{ +public: + PageObjectViewContact ( + SdrPageObj& rPageObj, + const model::SharedPageDescriptor& rpDescriptor); + ~PageObjectViewContact (void); + + /** Create a ViewObjectContact object that buffers its output in a + bitmap. + @return + Ownership of the new object passes to the caller. + */ + virtual ::sdr::contact::ViewObjectContact& + CreateObjectSpecificViewObjectContact( + ::sdr::contact::ObjectContact& rObjectContact); + + const SdrPage* GetPage (void) const; + + SdrPageObj& GetPageObject (void) const; + + Rectangle GetPageObjectBoundingBox (void) const; + + virtual void ActionChanged (void); + +protected: + // create graphical visualisation data + virtual drawinglayer::primitive2d::Primitive2DSequence createViewIndependentPrimitive2DSequence() const; + +private: + /** This flag is set to <TRUE/> when the destructor is called to + indicate that further calls made to it must not call outside. + */ + bool mbInDestructor; + + model::SharedPageDescriptor mpDescriptor; +}; + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewObjectContact.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewObjectContact.hxx new file mode 100644 index 000000000000..9351ab72dcd6 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewObjectContact.hxx @@ -0,0 +1,228 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObjectViewObjectContact.hxx,v $ + * $Revision: 1.14 $ + * + * 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 SD_SLIDESORTER_PAGE_OBJECT_VIEW_OBJECT_CONTACT_HXX +#define SD_SLIDESORTER_PAGE_OBJECT_VIEW_OBJECT_CONTACT_HXX + +#include <svx/sdr/contact/viewobjectcontactofpageobj.hxx> +#include "model/SlsSharedPageDescriptor.hxx" +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/image.hxx> +#include <sfx2/viewfrm.hxx> +#include <memory> +#include <boost/shared_ptr.hpp> + +class SdrPage; + +namespace sdr { namespace contact { +class DisplayInfo; +} } + +namespace sd { namespace slidesorter { namespace cache { +class PageCache; +} } } + +namespace sd { namespace slidesorter { namespace controller { +class Properties; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class SlideSorterView; + +/** This object-view-contact of page objects maintains a preview bitmap for + the page to speed up redraws of the same. It does so by colaborating + with a cache of bitmaps (see ../cache). +*/ + +// needs to be derived from ViewObjectContactOfPageObj, else the calls to parent implementations +// would use ViewObjectContact and thus not enable e.g. the correct primitive creation +// for view-independent printer output +// changed: ViewObjectContact -> ViewObjectContactOfPageObj + +class PageObjectViewObjectContact : public ::sdr::contact::ViewObjectContactOfPageObj +{ +public: + /** Create a new view-object-contact object for the given contact + objects of both model and view. + @param pCache + The caller should provide a pointer to a preview cache, if + available. If given then the cache is used to control when to + create a preview and to store it. If NULL is given then the + preview is created every time when requested. + */ + PageObjectViewObjectContact ( + ::sdr::contact::ObjectContact& rObjectContact, + ::sdr::contact::ViewContact& rViewContact, + const ::boost::shared_ptr<cache::PageCache>& rpCache, + const ::boost::shared_ptr<controller::Properties>& rpProperties); + virtual ~PageObjectViewObjectContact (void); + + /** This method is primarily for releasing the current preview cache (by + providing a NULL pointer.) + */ + void SetCache (const ::boost::shared_ptr<cache::PageCache>& rpCache); + + /** Return the page that is painted by this object. + */ + const SdrPage* GetPage (void) const; + + /** This fallback method is called when no preview cache is available. + It creates a preview for the page. + */ + BitmapEx CreatePreview (const sdr::contact::DisplayInfo& rDisplayInfo); + + /** Return the page descriptor of the slide sorter model that is + associated with the same page object as this contact object is. + */ + model::SharedPageDescriptor GetPageDescriptor (void) const; + + /** Return the border widths in the screen coordinate system of the + border arround the page object. The border contains frames for + selection, focus, the page name and number, and the indicator for + the page transition. + @param pDevice + The output device is used to convert pixel coordinates into + model coordinates. When NULL is given then the device dependent + part is not re-calculated but taken from an earlier calculation + or from the default values. + @param nPageCount + The total number of pages is used to determine the width of the + box that contains the page number. + */ + static SvBorder CalculatePageModelBorder ( + OutputDevice* pDevice, + int nPageCount); + + /** Calculate the size of the page number area so that all page numbers + including the given number fit in. Because this is device dependent + we need the device as parameter. The result is returned and stored + in maPageNumberAreaPixelSize so that it can be used later without + access to the device or page count. + */ + static Size CalculatePageNumberAreaModelSize ( + OutputDevice* pDevice, + int nPageCount); + + /** Paint a mouse over effect. + @param bVisible + When bVisible is <FALSE/> then paint the area of the mouse over + effect in the background color, i.e. erase it. + */ + drawinglayer::primitive2d::Primitive2DSequence createMouseOverEffectPrimitive2DSequence(); + + enum BoundingBoxType { + // This is the outer bounding box that includes the preview, page + // number, title. + PageObjectBoundingBox, + // Bounding box of the actual preview. + PreviewBoundingBox, + // Bounding box of the mouse indicator indicator frame. + MouseOverIndicatorBoundingBox, + // Bounding box of the focus indicator frame. + FocusIndicatorBoundingBox, + // Bounding box of the selection indicator frame. + SelectionIndicatorBoundingBox, + // Bounding box of the page number. + PageNumberBoundingBox, + // Bounding box of the pane name. + NameBoundingBox, + FadeEffectIndicatorBoundingBox + }; + enum CoordinateSystem { ModelCoordinateSystem, PixelCoordinateSystem }; + + /** Return the bounding box of the page object or one of its graphical + parts. + @param rDevice + This device is used to translate between model and window + coordinates. + @param eType + The part of the page object for which to return the bounding + box. + @param eCoodinateSystem + The bounding box can be returned in model and in pixel + (window) coordinates. + */ + Rectangle GetBoundingBox ( + OutputDevice& rDevice, + BoundingBoxType eType, + CoordinateSystem eCoordinateSystem) const; + + // create the graphical visualisation data + virtual drawinglayer::primitive2d::Primitive2DSequence createPrimitive2DSequence(const sdr::contact::DisplayInfo& rDisplayInfo) const; + + // access to the current page content primitive vector which may be used for visualisation + const drawinglayer::primitive2d::Primitive2DSequence& getCurrentPageContents() const { return mxCurrentPageContents; } + + virtual void ActionChanged (void); + +private: + /// Gap between border of page object and inside of selection rectangle. + static const sal_Int32 mnSelectionIndicatorOffset; + /// Thickness of the selection rectangle. + static const sal_Int32 mnSelectionIndicatorThickness; + /// Gap between border of page object and inside of focus rectangle. + static const sal_Int32 mnFocusIndicatorOffset; + /// Size of width and height of the fade effect indicator in pixels. + static const sal_Int32 mnFadeEffectIndicatorSize; + static const sal_Int32 mnFadeEffectIndicatorOffset; + /// Gap between border of page object and number rectangle. + static const sal_Int32 mnPageNumberOffset; + /// Offset and thickness of the mouse over effect rectangle. + static const sal_Int32 mnMouseOverEffectOffset; + static const sal_Int32 mnMouseOverEffectThickness; + + /** This flag is set to <TRUE/> when the destructor is called to + indicate that further calls made to it must not call outside. + */ + bool mbInDestructor; + + /// The primitive sequence of the page contents, completely scaled + /// and prepared for painiting + drawinglayer::primitive2d::Primitive2DSequence mxCurrentPageContents; + + ::boost::shared_ptr<cache::PageCache> mpCache; + + ::boost::shared_ptr<controller::Properties> mpProperties; + + BitmapEx GetPreview ( + const sdr::contact::DisplayInfo& rDisplayInfo, + const Rectangle& rNewSizePixel); + + /** Return the bounding box of where the page number is painted (when it + is painted). + */ + Rectangle GetPageNumberArea (OutputDevice& rDevice) const; +}; + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsViewOverlay.hxx b/sd/source/ui/slidesorter/inc/view/SlsViewOverlay.hxx new file mode 100644 index 000000000000..1d99584bec4b --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsViewOverlay.hxx @@ -0,0 +1,273 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsViewOverlay.hxx,v $ + * $Revision: 1.10 $ + * + * 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 SD_SLIDESORTER_VIEW_OVERLAY_HXX +#define SD_SLIDESORTER_VIEW_OVERLAY_HXX + +#include "model/SlsSharedPageDescriptor.hxx" + +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <osl/mutex.hxx> +#include <svx/sdr/overlay/overlayobject.hxx> +#include <tools/gen.hxx> +#include <vector> +#include <boost/weak_ptr.hpp> +#include <boost/noncopyable.hpp> + +class OutputDevice; +class Region; + + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace model { +class PageEnumeration; +} } } + +namespace sd { namespace slidesorter { namespace controller { +class SlideSorterController; +} } } + +namespace sdr { namespace overlay { +class OverlayManager; +} } + +namespace sd { namespace slidesorter { namespace view { + + +class InsertionIndicatorOverlay; +class PageObjectViewObjectContact; +class SelectionRectangleOverlay; +class SubstitutionOverlay; +class ViewOverlay; + +/** This base class of slide sorter overlays uses the drawing layer overlay + support for the display. +*/ +class OverlayBase + : public sdr::overlay::OverlayObject +{ +public: + OverlayBase (ViewOverlay& rViewOverlay); + virtual ~OverlayBase (void); + +protected: + ::osl::Mutex maMutex; + + ViewOverlay& mrViewOverlay; + + /** Make sure that the overlay object is registered at the + OverlayManager. This registration is done on demand. + */ + void EnsureRegistration (void); +}; + + + + +/** During internal drag and drop the outlines of the selected slides are + painted at the mouse position in dashed lines. +*/ +class SubstitutionOverlay + : public OverlayBase +{ +public: + SubstitutionOverlay (ViewOverlay& rViewOverlay); + virtual ~SubstitutionOverlay (void); + + /** Setup the substitution display of the given set of selected pages. + The given mouse position is remembered so that it later can be + returned by GetPosition(). This is a convenience feature. + */ + void Create ( + model::PageEnumeration& rSelection, + const Point& rPosition); + + /** Clear the substitution display. Until the next call of Create() no + substution is painted. + */ + void Clear (void); + + /** Move the substitution display by the given amount of pixels. + */ + void Move (const Point& rOffset); + void SetPosition (const Point& rPosition); + Point GetPosition (void) const; + + // react on stripe definition change + virtual void stripeDefinitionHasChanged(); + +protected: + // geometry creation for OverlayObject + virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); + +private: + Point maPosition; + basegfx::B2DPolyPolygon maShapes; +}; + + + + +/** Slides can be selected by drawing a selection rectangle in the slide + sorter. When the left mouse button is released all slides that are at + least partially in the rectangle are selected. +*/ +class SelectionRectangleOverlay + : public OverlayBase +{ +public: + SelectionRectangleOverlay (ViewOverlay& rViewOverlay); + + void Start (const Point& rAnchor); + void Update (const Point& rSecondCorner); + + Rectangle GetSelectionRectangle (void); + + // react on stripe definition change + virtual void stripeDefinitionHasChanged(); + +protected: + // geometry creation for OverlayObject + virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); + +private: + Point maAnchor; + Point maSecondCorner; +}; + + + + +/** The insertion indicator is painted as a vertical or horizonal bar + in the space between slides. +*/ +class InsertionIndicatorOverlay + : public OverlayBase +{ +public: + InsertionIndicatorOverlay (ViewOverlay& rViewOverlay); + + /** Given a position in model coordinates this method calculates the + insertion marker both as an index in the document and as a rectangle + used for drawing the insertion indicator. + */ + void SetPosition (const Point& rPosition); + + sal_Int32 GetInsertionPageIndex (void) const; + +protected: + // geometry creation for OverlayObject + virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); + +private: + sal_Int32 mnInsertionIndex; + Rectangle maBoundingBox; + + void SetPositionAndSize (const Rectangle& rBoundingBox); +}; + + + + +/** Paint a frame around the slide preview under the mouse. The actual + painting is done by the PageObjectViewObjectContact of the slidesorter. +*/ +class MouseOverIndicatorOverlay + : public OverlayBase +{ +public: + MouseOverIndicatorOverlay (ViewOverlay& rViewOverlay); + virtual ~MouseOverIndicatorOverlay (void); + + /** Set the page object for which to paint a mouse over indicator. + @param pContact + A value of <NULL/> indicates to not paint the mouse over indicator. + */ + void SetSlideUnderMouse (const model::SharedPageDescriptor& rpDescriptor); + +protected: + // geometry creation for OverlayObject + virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); + +private: + /** The page under the mouse is stored as weak shared pointer so that + model changes can be handled without having the SlideSorterModel + inform this class explicitly. + */ + ::boost::weak_ptr<model::PageDescriptor> mpPageUnderMouse; + + view::PageObjectViewObjectContact* GetViewObjectContact (void) const; +}; + + + + +/** The view overlay manages and paints some indicators that are painted on + top of the regular view content (the page objects). It is separated + from the view to allow the indicators to be altered in position and size + without repainting the whole view content (inside that the bounding box + of the indicator). This is achieved by using the drawing layer overlay + support. + + The view overlay itself simply gives access to the more specialized + classes that handle individual indicators. + +*/ +class ViewOverlay +{ +public: + ViewOverlay (SlideSorter& rSlideSorter); + ~ViewOverlay (void); + + SelectionRectangleOverlay& GetSelectionRectangleOverlay (void); + MouseOverIndicatorOverlay& GetMouseOverIndicatorOverlay (void); + InsertionIndicatorOverlay& GetInsertionIndicatorOverlay (void); + SubstitutionOverlay& GetSubstitutionOverlay (void); + + SlideSorter& GetSlideSorter (void) const; + + sdr::overlay::OverlayManager* GetOverlayManager (void) const; + +private: + SlideSorter& mrSlideSorter; + SelectionRectangleOverlay maSelectionRectangleOverlay; + MouseOverIndicatorOverlay maMouseOverIndicatorOverlay; + InsertionIndicatorOverlay maInsertionIndicatorOverlay; + SubstitutionOverlay maSubstitutionOverlay; +}; + + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/makefile.mk b/sd/source/ui/slidesorter/makefile.mk new file mode 100644 index 000000000000..c0b2829912be --- /dev/null +++ b/sd/source/ui/slidesorter/makefile.mk @@ -0,0 +1,62 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.4 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slidesorter +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/SlideSorter.obj \ + $(SLO)$/SlideSorterChildWindow.obj \ + $(SLO)$/SlideSorterViewShell.obj + +EXCEPTIONSFILES= + +SRS2NAME = slidesorter +SRC2FILES = SlsChildWindow.src + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sd/source/ui/slidesorter/model/SlideSorterModel.cxx b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx new file mode 100644 index 000000000000..4f21e48cce93 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx @@ -0,0 +1,492 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterModel.cxx,v $ + * $Revision: 1.11 $ + * + * 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 "precompiled_sd.hxx" + +#include "model/SlideSorterModel.hxx" + +#include "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsPageObjectFactory.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "view/SlideSorterView.hxx" +#include "taskpane/SlideSorterCacheDisplay.hxx" +#include <com/sun/star/drawing/XDrawPagesSupplier.hpp> +#include <com/sun/star/drawing/XMasterPagesSupplier.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> + +#include "ViewShellBase.hxx" +#include "DrawViewShell.hxx" +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "FrameView.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace sd { namespace slidesorter { namespace model { + +namespace { + class CompareToXDrawPage + { + public: + CompareToXDrawPage (const Reference<drawing::XDrawPage>& rxSlide) : mxSlide(rxSlide) {} + bool operator() (const SharedPageDescriptor& rpDescriptor) + { return rpDescriptor.get()!=NULL && rpDescriptor->GetXDrawPage()==mxSlide; } + private: + Reference<drawing::XDrawPage> mxSlide; + }; +} + + + + +SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter) + : maMutex(), + mrSlideSorter(rSlideSorter), + mxSlides(), + mePageKind(PK_STANDARD), + meEditMode(EM_PAGE), + maPageDescriptors(0), + mpPageObjectFactory(NULL) +{ +} + + + + +SlideSorterModel::~SlideSorterModel (void) +{ + ClearDescriptorList (); +} + + + + +SdDrawDocument* SlideSorterModel::GetDocument (void) +{ + if (mrSlideSorter.GetViewShellBase() != NULL) + return mrSlideSorter.GetViewShellBase()->GetDocument(); + else + return NULL; +} + + + + +bool SlideSorterModel::SetEditMode (EditMode eEditMode) +{ + bool bEditModeChanged = false; + if (meEditMode != eEditMode) + { + meEditMode = eEditMode; + UpdatePageList(); + ClearDescriptorList(); + bEditModeChanged = true; + } + return bEditModeChanged; +} + + + + +bool SlideSorterModel::SetEditModeFromController (void) +{ + bool bIsMasterPageMode = false; + // Get the edit mode from the controller. + try + { + Reference<beans::XPropertySet> xSet (mrSlideSorter.GetXController(), UNO_QUERY_THROW); + Any aValue (xSet->getPropertyValue( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IsMasterPageMode")))); + aValue >>= bIsMasterPageMode; + } + catch (RuntimeException&) + { + // When the property is not supported then the master + // page mode is not supported, too. + bIsMasterPageMode = false; + } + + return SetEditMode(bIsMasterPageMode ? EM_MASTERPAGE : EM_PAGE); +} + + + + +EditMode SlideSorterModel::GetEditMode (void) const +{ + return meEditMode; +} + + + + +PageKind SlideSorterModel::GetPageType (void) const +{ + return mePageKind; +} + + + + +sal_Int32 SlideSorterModel::GetPageCount (void) const +{ + return maPageDescriptors.size(); +} + + + + +SharedPageDescriptor SlideSorterModel::GetPageDescriptor ( + const sal_Int32 nPageIndex, + const bool bCreate) const +{ + ::osl::MutexGuard aGuard (maMutex); + + SharedPageDescriptor pDescriptor; + + if (nPageIndex>=0 && nPageIndex<GetPageCount()) + { + pDescriptor = maPageDescriptors[nPageIndex]; + if (pDescriptor == NULL && bCreate && mxSlides.is()) + { + SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument(); + SdPage* pPage = NULL; + if (pModel != NULL) + { + if (meEditMode == EM_PAGE) + pPage = pModel->GetSdPage ((USHORT)nPageIndex, mePageKind); + else + pPage = pModel->GetMasterSdPage ((USHORT)nPageIndex, mePageKind); + } + pDescriptor.reset(new PageDescriptor ( + Reference<drawing::XDrawPage>(mxSlides->getByIndex(nPageIndex),UNO_QUERY), + pPage, + nPageIndex, + GetPageObjectFactory())); + maPageDescriptors[nPageIndex] = pDescriptor; + } + } + + return pDescriptor; +} + + + + +sal_Int32 SlideSorterModel::GetIndex (const Reference<drawing::XDrawPage>& rxSlide) const +{ + ::osl::MutexGuard aGuard (maMutex); + + // First try to guess the right index. + Reference<beans::XPropertySet> xSet (rxSlide, UNO_QUERY); + if (xSet.is()) + { + try + { + const Any aNumber (xSet->getPropertyValue(::rtl::OUString::createFromAscii("Number"))); + sal_Int16 nNumber (-1); + aNumber >>= nNumber; + nNumber -= 1; + SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false)); + if (pDescriptor.get() != NULL + && pDescriptor->GetXDrawPage() == rxSlide) + { + return nNumber; + } + } + catch (beans::UnknownPropertyException&) + { + OSL_ASSERT(false); + } + catch (lang::DisposedException&) + { + OSL_ASSERT(false); + } + } + + // Guess was wrong, iterate over all slides and search for the right + // one. + const sal_Int32 nCount (maPageDescriptors.size()); + for (sal_Int32 nIndex=0; nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (maPageDescriptors[nIndex]); + + // Make sure that the descriptor exists. Without it the given slide + // can not be found. + if (pDescriptor.get() == NULL) + { + // Call GetPageDescriptor() to create the missing descriptor. + pDescriptor = GetPageDescriptor(nIndex,true); + } + + if (pDescriptor->GetXDrawPage() == rxSlide) + return nIndex; + } + + return -1; +} + + + + +/** For now this method uses a trivial algorithm: throw away all descriptors + and create them anew (on demand). The main problem that we are facing + when designing a better algorithm is that we can not compare pointers to + pages stored in the PageDescriptor objects and those obtained from the + document: pages may have been deleted and others may have been created + at the exact same memory locations. +*/ +void SlideSorterModel::Resync (void) +{ + ::osl::MutexGuard aGuard (maMutex); + ClearDescriptorList (); + AdaptSize(); +} + + + + +void SlideSorterModel::ClearDescriptorList (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Clear the cache of page descriptors. + DescriptorContainer::iterator I; + for (I=maPageDescriptors.begin(); I!=maPageDescriptors.end(); I++) + { + if (I->get() != NULL) + { + if ( ! I->unique()) + { + OSL_TRACE("SlideSorterModel::ClearDescriptorList: trying to delete page descriptor that is still used with count %d", I->use_count()); + // No assertion here because that can hang the office when + // opening a dialog from here. + } + I->reset(); + } + } +} + + + + +void SlideSorterModel::SynchronizeDocumentSelection (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->GetPage()->SetSelected (pDescriptor->IsSelected()); + } +} + + + + +void SlideSorterModel::SynchronizeModelSelection (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + if (pDescriptor->GetPage()->IsSelected()) + pDescriptor->Select (); + else + pDescriptor->Deselect (); + } +} + + + + +void SlideSorterModel::SetPageObjectFactory( + ::std::auto_ptr<controller::PageObjectFactory> pPageObjectFactory) +{ + ::osl::MutexGuard aGuard (maMutex); + + mpPageObjectFactory = pPageObjectFactory; + // When a NULL pointer was given then create a default factory. + const controller::PageObjectFactory& rFactory (GetPageObjectFactory()); + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->SetPageObjectFactory(rFactory); + } +} + + + + +const controller::PageObjectFactory& + SlideSorterModel::GetPageObjectFactory (void) const +{ + ::osl::MutexGuard aGuard (maMutex); + + if (mpPageObjectFactory.get() == NULL) + { + // We have to create a new factory. The pointer is mutable so we + // are alowed to do so. + mpPageObjectFactory = ::std::auto_ptr<controller::PageObjectFactory> ( + new controller::PageObjectFactory( + mrSlideSorter.GetView().GetPreviewCache(), + mrSlideSorter.GetController().GetProperties())); + } + return *mpPageObjectFactory.get(); +} + + + + +::osl::Mutex& SlideSorterModel::GetMutex (void) +{ + return maMutex; +} + + + + +void SlideSorterModel::SetDocumentSlides ( + const Reference<container::XIndexAccess>& rxSlides) +{ + ::osl::MutexGuard aGuard (maMutex); + + // Reset the current page so to cause everbody to release references to it. + mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged(-1); + + mxSlides = rxSlides; + Resync(); + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL) + { + SdPage* pPage = pViewShell->getCurrentPage(); + if (pPage != NULL) + mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged( + GetIndex(Reference<drawing::XDrawPage>(pPage->getUnoPage(), UNO_QUERY))); + else + { + // No current page. This can only be when the slide sorter is + // the main view shell. Get current slide form frame view. + const FrameView* pFrameView = pViewShell->GetFrameView(); + if (pFrameView != NULL) + mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged( + pFrameView->GetSelectedPage()); + else + { + // No frame view. As a last resort use the first slide as + // current slide. + mrSlideSorter.GetController().GetCurrentSlideManager()->CurrentSlideHasChanged(0); + } + } + } +} + + + + +Reference<container::XIndexAccess> SlideSorterModel::GetDocumentSlides (void) const +{ + ::osl::MutexGuard aGuard (maMutex); + return mxSlides; +} + + + + +void SlideSorterModel::UpdatePageList (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + Reference<container::XIndexAccess> xPages; + + // Get the list of pages according to the edit mode. + Reference<frame::XController> xController (mrSlideSorter.GetXController()); + if (xController.is()) + { + switch (meEditMode) + { + case EM_MASTERPAGE: + { + Reference<drawing::XMasterPagesSupplier> xSupplier ( + xController->getModel(), UNO_QUERY); + if (xSupplier.is()) + { + xPages = Reference<container::XIndexAccess>( + xSupplier->getMasterPages(), UNO_QUERY); + } + } + break; + + case EM_PAGE: + { + Reference<drawing::XDrawPagesSupplier> xSupplier ( + xController->getModel(), UNO_QUERY); + if (xSupplier.is()) + { + xPages = Reference<container::XIndexAccess>( + xSupplier->getDrawPages(), UNO_QUERY); + } + } + break; + + default: + // We should never get here. + OSL_ASSERT(false); + break; + } + } + + mrSlideSorter.GetController().SetDocumentSlides(xPages); +} + + + + +void SlideSorterModel::AdaptSize (void) +{ + if (mxSlides.is()) + maPageDescriptors.resize(mxSlides->getCount()); + else + maPageDescriptors.resize(0); +} + +} } } // end of namespace ::sd::slidesorter::model diff --git a/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx new file mode 100644 index 000000000000..5061d44a88a4 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx @@ -0,0 +1,300 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageDescriptor.cxx,v $ + * $Revision: 1.8 $ + * + * 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_sd.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "view/SlsPageObject.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "controller/SlsPageObjectFactory.hxx" + +#include "sdpage.hxx" +#include "drawdoc.hxx" + +#include <svx/svdopage.hxx> +#include <svx/svdpagv.hxx> +#include <svx/sdr/contact/viewcontact.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +namespace sd { namespace slidesorter { namespace model { + +PageDescriptor::PageDescriptor ( + const Reference<drawing::XDrawPage>& rxPage, + SdPage* pPage, + const sal_Int32 nIndex, + const controller::PageObjectFactory& rPageObjectFactory) + : mpPage(pPage), + mxPage(rxPage), + mnIndex(nIndex), + mpPageObjectFactory(&rPageObjectFactory), + mpPageObject(NULL), + mbIsSelected(false), + mbIsVisible(false), + mbIsFocused(false), + mbIsCurrent(false), + mpViewObjectContact(NULL), + maModelBorder(0,0,0,0), + maPageNumberAreaModelSize(0,0) +{ + OSL_ASSERT(mpPage == SdPage::getImplementation(rxPage)); +} + + + + +PageDescriptor::~PageDescriptor (void) +{ +} + + + + +SdPage* PageDescriptor::GetPage (void) const +{ + return mpPage; +} + + + + +Reference<drawing::XDrawPage> PageDescriptor::GetXDrawPage (void) const +{ + return mxPage; +} + + + + +sal_Int32 PageDescriptor::GetPageIndex (void) const +{ + return mnIndex; +} + + + + +view::PageObject* PageDescriptor::GetPageObject (void) +{ + if (mpPageObject==NULL && mpPageObjectFactory!=NULL && mpPage != NULL) + { + mpPageObject = mpPageObjectFactory->CreatePageObject(mpPage, shared_from_this()); + } + + return mpPageObject; +} + + + + +void PageDescriptor::ReleasePageObject (void) +{ + mpPageObject = NULL; +} + + + + +bool PageDescriptor::IsVisible (void) const +{ + return mbIsVisible; +} + + + + +void PageDescriptor::SetVisible (bool bIsVisible) +{ + mbIsVisible = bIsVisible; +} + + + + +bool PageDescriptor::Select (void) +{ + if ( ! IsSelected()) + { + mbIsSelected = true; + return true; + } + else + return false; +} + + + + +bool PageDescriptor::Deselect (void) +{ + if (IsSelected()) + { + mbIsSelected = false; + return true; + } + else + return false; +} + + + + +bool PageDescriptor::IsSelected (void) const +{ + return mbIsSelected; +} + + + + +bool PageDescriptor::UpdateSelection (void) +{ + if (mpPage!=NULL && (mpPage->IsSelected()==TRUE) != mbIsSelected) + { + mbIsSelected = ! mbIsSelected; + return true; + } + else + return false; +} + + + + +bool PageDescriptor::IsFocused (void) const +{ + return mbIsFocused; +} + + + + +void PageDescriptor::SetFocus (void) +{ + mbIsFocused = true; +} + + + + +void PageDescriptor::RemoveFocus (void) +{ + mbIsFocused = false; +} + + + + +view::PageObjectViewObjectContact* + PageDescriptor::GetViewObjectContact (void) const +{ + return mpViewObjectContact; +} + + + + +void PageDescriptor::SetViewObjectContact ( + view::PageObjectViewObjectContact* pViewObjectContact) +{ + mpViewObjectContact = pViewObjectContact; +} + + + + +const controller::PageObjectFactory& + PageDescriptor::GetPageObjectFactory (void) const +{ + return *mpPageObjectFactory; +} + + + + +void PageDescriptor::SetPageObjectFactory ( + const controller::PageObjectFactory& rFactory) +{ + mpPageObjectFactory = &rFactory; +} + + + + +void PageDescriptor::SetModelBorder (const SvBorder& rBorder) +{ + maModelBorder = rBorder; +} + + + + +SvBorder PageDescriptor::GetModelBorder (void) const +{ + return maModelBorder; +} + + + + +void PageDescriptor::SetPageNumberAreaModelSize (const Size& rSize) +{ + maPageNumberAreaModelSize = rSize; +} + + + + +Size PageDescriptor::GetPageNumberAreaModelSize (void) const +{ + return maPageNumberAreaModelSize; +} + + + + +bool PageDescriptor::IsCurrentPage (void) const +{ + return mbIsCurrent; +} + + + + +void PageDescriptor::SetIsCurrentPage (const bool bIsCurrent) +{ + mbIsCurrent = bIsCurrent; +} + + + +} } } // end of namespace ::sd::slidesorter::model diff --git a/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx b/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx new file mode 100644 index 000000000000..7fd80549cdb2 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx @@ -0,0 +1,287 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageEnumeration.cxx,v $ + * $Revision: 1.8 $ + * + * 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 "precompiled_sd.hxx" + +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" + +using namespace ::sd::slidesorter; +using namespace ::sd::slidesorter::model; + +namespace { + +class PageEnumerationImpl + : public Enumeration<SharedPageDescriptor> +{ +public: + inline PageEnumerationImpl ( + const SlideSorterModel& rModel, + const PageEnumeration::PagePredicate& rPredicate); + virtual ~PageEnumerationImpl (void); + /** Create a copy of the called enumeration object. + */ + virtual inline ::std::auto_ptr<Enumeration<SharedPageDescriptor> > Clone (void); + + virtual inline bool HasMoreElements (void) const; + virtual inline SharedPageDescriptor GetNextElement (void); + virtual inline void Rewind (void); + +private: + const SlideSorterModel& mrModel; + const PageEnumeration::PagePredicate maPredicate; + int mnIndex; + + /** This constructor sets the internal page index to the given value. + It does not call AdvanceToNextValidElement() to skip elements that + do not fullfill Predicate. + */ + inline PageEnumerationImpl ( + const SlideSorterModel& rModel, + const PageEnumeration::PagePredicate& rPredicate, + int nIndex); + + /** Skip all elements that do not fullfill Predicate starting with the + one pointed to by mnIndex. + */ + inline void AdvanceToNextValidElement (void); + + // Default constructor not implemented. + PageEnumerationImpl (void); + // Assignment operator not implemented. + PageEnumerationImpl& operator= (const PageEnumerationImpl&); +}; + +} // end of anonymouse namespace + + + + +namespace sd { namespace slidesorter { namespace model { + + +PageEnumeration PageEnumeration::Create ( + const SlideSorterModel& rModel, + const PagePredicate& rPredicate) +{ + return PageEnumeration(::std::auto_ptr<Enumeration<SharedPageDescriptor> >( + new PageEnumerationImpl(rModel, rPredicate))); +} + + + + +PageEnumeration::PageEnumeration ( + ::std::auto_ptr<Enumeration<SharedPageDescriptor> > pImpl) + : mpImpl(pImpl) +{ +} + + + + +PageEnumeration::PageEnumeration ( + PageEnumeration& rEnumeration, + bool bCloneImpl) +{ + + if( bCloneImpl ) + { + mpImpl = rEnumeration.mpImpl->Clone(); + } + else + { + mpImpl = rEnumeration.mpImpl; + } +} + + + + +PageEnumeration::PageEnumeration (const PageEnumeration& rEnumeration ) +: sd::slidesorter::model::Enumeration<sd::slidesorter::model::SharedPageDescriptor>() +{ + mpImpl = rEnumeration.mpImpl->Clone(); +} + + + + +PageEnumeration::~PageEnumeration (void) +{ +} + + + + +PageEnumeration& PageEnumeration::operator= ( + const PageEnumeration& rEnumeration) +{ + mpImpl = rEnumeration.mpImpl->Clone(); + return *this; +} + + + + +::std::auto_ptr<Enumeration<SharedPageDescriptor> > PageEnumeration::Clone (void) +{ + return ::std::auto_ptr<Enumeration<SharedPageDescriptor> >( + new PageEnumeration (*this, true)); +} + + + + +bool PageEnumeration::HasMoreElements (void) const +{ + return mpImpl->HasMoreElements(); +} + + + +SharedPageDescriptor PageEnumeration::GetNextElement (void) +{ + return mpImpl->GetNextElement(); +} + + + + +void PageEnumeration::Rewind (void) +{ + return mpImpl->Rewind(); +} + +} } } // end of namespace ::sd::slidesorter::model + + + + +namespace { + +PageEnumerationImpl::PageEnumerationImpl ( + const SlideSorterModel& rModel, + const PageEnumeration::PagePredicate& rPredicate) + : mrModel(rModel), + maPredicate(rPredicate), + mnIndex(0) +{ + Rewind(); +} + + + + +PageEnumerationImpl::PageEnumerationImpl ( + const SlideSorterModel& rModel, + const PageEnumeration::PagePredicate& rPredicate, + int nIndex) + : mrModel(rModel), + maPredicate(rPredicate), + mnIndex(nIndex) +{ +} + + + + +PageEnumerationImpl::~PageEnumerationImpl (void) +{ +} + + + + +::std::auto_ptr<Enumeration<SharedPageDescriptor> > + PageEnumerationImpl::Clone (void) +{ + return ::std::auto_ptr<Enumeration<SharedPageDescriptor> >( + new PageEnumerationImpl(mrModel,maPredicate,mnIndex)); +} + + + + +bool PageEnumerationImpl::HasMoreElements (void) const +{ + return (mnIndex < mrModel.GetPageCount()); +} + + + + +SharedPageDescriptor PageEnumerationImpl::GetNextElement (void) +{ + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(mnIndex)); + + // Go to the following valid element. + mnIndex += 1; + AdvanceToNextValidElement(); + + return pDescriptor; +} + + + + +void PageEnumerationImpl::Rewind (void) +{ + // Go to first valid element. + mnIndex = 0; + AdvanceToNextValidElement(); +} + + + + + +void PageEnumerationImpl::AdvanceToNextValidElement (void) +{ + while (mnIndex < mrModel.GetPageCount()) + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(mnIndex)); + + // Test for the predicate being fullfilled. + if (pDescriptor.get()!=NULL && maPredicate(pDescriptor)) + { + // This predicate is valid. + break; + } + else + { + // Advance to next predicate. + mnIndex += 1; + } + } +} + +} // end of anonymous namespace + diff --git a/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx new file mode 100644 index 000000000000..e6e3b89b12d5 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx @@ -0,0 +1,114 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageEnumerationProvider.cxx,v $ + * + * $Revision: 1.3 $ + * + * 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 "precompiled_sd.hxx" + +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageEnumeration.hxx" +#include "model/SlsPageDescriptor.hxx" +#include <boost/function.hpp> + +namespace sd { namespace slidesorter { namespace model { + + +namespace { + +class AllPagesPredicate +{ +public: + bool operator() (const SharedPageDescriptor& rpDescriptor) + { + (void)rpDescriptor; + return true; + } +}; + + + + + +class SelectedPagesPredicate +{ +public: + bool operator() (const SharedPageDescriptor& rpDescriptor) + { + return rpDescriptor->IsSelected(); + } +}; + + + + +class VisiblePagesPredicate +{ +public: + bool operator() (const SharedPageDescriptor& rpDescriptor) + { + return rpDescriptor->IsVisible(); + } +}; + +} + + + + +PageEnumeration PageEnumerationProvider::CreateAllPagesEnumeration ( + const SlideSorterModel& rModel) +{ +// AllPagesPredicate aPredicate; // spurious warning on unxsoli4 debug=t + return PageEnumeration::Create(rModel, AllPagesPredicate()); +} + + + + +PageEnumeration PageEnumerationProvider::CreateSelectedPagesEnumeration ( + const SlideSorterModel& rModel) +{ + return PageEnumeration::Create( + rModel, + SelectedPagesPredicate()); +} + + + + +PageEnumeration PageEnumerationProvider::CreateVisiblePagesEnumeration ( + const SlideSorterModel& rModel) +{ + return PageEnumeration::Create( + rModel, + VisiblePagesPredicate()); +} + + +} } } // end of namespace ::sd::slidesorter::model diff --git a/sd/source/ui/slidesorter/model/makefile.mk b/sd/source/ui/slidesorter/model/makefile.mk new file mode 100644 index 000000000000..653e437be91b --- /dev/null +++ b/sd/source/ui/slidesorter/model/makefile.mk @@ -0,0 +1,60 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.6 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slsmodel +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/SlsPageDescriptor.obj \ + $(SLO)$/SlsPageEnumeration.obj \ + $(SLO)$/SlsPageEnumerationProvider.obj \ + $(SLO)$/SlideSorterModel.obj + +EXCEPTIONSFILES= + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sd/source/ui/slidesorter/shell/SlideSorter.cxx b/sd/source/ui/slidesorter/shell/SlideSorter.cxx new file mode 100644 index 000000000000..9d0dbae862fa --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorter.cxx @@ -0,0 +1,654 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorter.cxx,v $ + * $Revision: 1.6 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlideSorter.hxx" + +#include "SlideSorterChildWindow.hrc" +#include "SlideSorterViewShell.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "view/SlideSorterView.hxx" +#include "model/SlideSorterModel.hxx" + +#include "glob.hrc" +#include "DrawController.hxx" +#include "ViewShellBase.hxx" +#include "ViewShellManager.hxx" +#include "Window.hxx" + +#include <vcl/scrbar.hxx> +#include <vcl/svapp.hxx> + +#include <sfx2/dispatch.hxx> +#include "sdresid.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + + +namespace sd { namespace slidesorter { + +namespace { +class ContentWindow : public ::sd::Window +{ +public: + ContentWindow(::Window& rParent, SlideSorter& rSlideSorter); + ~ContentWindow (void); + void SetCurrentFunction (const FunctionReference& rpFunction); + virtual void Paint(const Rectangle& rRect); + virtual void KeyInput (const KeyEvent& rEvent); + virtual void MouseMove (const MouseEvent& rEvent); + virtual void MouseButtonUp (const MouseEvent& rEvent); + virtual void MouseButtonDown (const MouseEvent& rEvent); + virtual void Command (const CommandEvent& rEvent); + virtual long Notify (NotifyEvent& rEvent); + +private: + SlideSorter& mrSlideSorter; + FunctionReference mpCurrentFunction; +}; +} + + + + +//===== SlideSorter =========================================================== + +::boost::shared_ptr<SlideSorter> SlideSorter::CreateSlideSorter( + ViewShell& rViewShell, + const ::boost::shared_ptr<sd::Window>& rpContentWindow, + const ::boost::shared_ptr<ScrollBar>& rpHorizontalScrollBar, + const ::boost::shared_ptr<ScrollBar>& rpVerticalScrollBar, + const ::boost::shared_ptr<ScrollBarBox>& rpScrollBarBox) +{ + ::boost::shared_ptr<SlideSorter> pSlideSorter( + new SlideSorter( + rViewShell, + rpContentWindow, + rpHorizontalScrollBar, + rpVerticalScrollBar, + rpScrollBarBox)); + pSlideSorter->Init(); + return pSlideSorter; +} + + + + +::boost::shared_ptr<SlideSorter> SlideSorter::CreateSlideSorter ( + ViewShellBase& rBase, + ViewShell* pViewShell, + ::Window& rParentWindow) +{ + ::boost::shared_ptr<SlideSorter> pSlideSorter( + new SlideSorter( + rBase, + pViewShell, + rParentWindow)); + pSlideSorter->Init(); + return pSlideSorter; +} + + + + +SlideSorter::SlideSorter ( + ViewShell& rViewShell, + const ::boost::shared_ptr<sd::Window>& rpContentWindow, + const ::boost::shared_ptr<ScrollBar>& rpHorizontalScrollBar, + const ::boost::shared_ptr<ScrollBar>& rpVerticalScrollBar, + const ::boost::shared_ptr<ScrollBarBox>& rpScrollBarBox) + : mbIsValid(false), + mpSlideSorterController(), + mpSlideSorterModel(), + mpSlideSorterView(), + mxControllerWeak(), + mpViewShell(&rViewShell), + mpViewShellBase(&rViewShell.GetViewShellBase()), + mpContentWindow(rpContentWindow), + mpHorizontalScrollBar(rpHorizontalScrollBar), + mpVerticalScrollBar(rpVerticalScrollBar), + mpScrollBarBox(rpScrollBarBox), + mbLayoutPending(true) +{ +} + + + + +SlideSorter::SlideSorter ( + ViewShellBase& rBase, + ViewShell* pViewShell, + ::Window& rParentWindow) + : mbIsValid(false), + mpSlideSorterController(), + mpSlideSorterModel(), + mpSlideSorterView(), + mxControllerWeak(), + mpViewShell(pViewShell), + mpViewShellBase(&rBase), + mpContentWindow(new ContentWindow(rParentWindow,*this )), + mpHorizontalScrollBar(new ScrollBar(&rParentWindow,WinBits(WB_HSCROLL | WB_DRAG))), + mpVerticalScrollBar(new ScrollBar(&rParentWindow,WinBits(WB_VSCROLL | WB_DRAG))), + mpScrollBarBox(new ScrollBarBox(&rParentWindow)), + mbLayoutPending(true) +{ +} + + + + +void SlideSorter::Init (void) +{ + if (mpViewShellBase != NULL) + mxControllerWeak = mpViewShellBase->GetController(); + + CreateModelViewController (); + + SetupListeners (); + + // Initialize the window. + ::sd::Window* pWindow = GetActiveWindow(); + if (pWindow != NULL) + { + ::Window* pParentWindow = pWindow->GetParent(); + if (pParentWindow != NULL) + pParentWindow->SetBackground(Wallpaper()); + pWindow->SetBackground(Wallpaper()); + pWindow->SetViewOrigin (Point(0,0)); + // We do our own scrolling while dragging a page selection. + pWindow->SetUseDropScroll (false); + // Change the winbits so that the active window accepts the focus. + pWindow->SetStyle ((pWindow->GetStyle() & ~WB_DIALOGCONTROL) | WB_TABSTOP); + pWindow->Hide(); + + // Set view pointer of base class. + SetupControls(pParentWindow); + + mbIsValid = true; + } +} + + + + +SlideSorter::~SlideSorter (void) +{ + mbIsValid = false; + + ReleaseListeners(); + + // Reset the auto pointers explicitly to control the order of destruction. + mpSlideSorterController.reset(); + mpSlideSorterView.reset(); + mpSlideSorterModel.reset(); + + mpHorizontalScrollBar.reset(); + mpVerticalScrollBar.reset(); + mpScrollBarBox.reset(); + mpContentWindow.reset(); +} + + + + +bool SlideSorter::IsValid (void) const +{ + return mbIsValid; +} + + + + +::boost::shared_ptr<ScrollBar> SlideSorter::GetVerticalScrollBar (void) const +{ + return mpVerticalScrollBar; +} + + + + + +::boost::shared_ptr<ScrollBar> SlideSorter::GetHorizontalScrollBar (void) const +{ + return mpHorizontalScrollBar; +} + + + + +::boost::shared_ptr<ScrollBarBox> SlideSorter::GetScrollBarFiller (void) const +{ + return mpScrollBarBox; +} + + + + +model::SlideSorterModel& SlideSorter::GetModel (void) const +{ + OSL_ASSERT(mpSlideSorterModel.get()!=NULL); + return *mpSlideSorterModel; +} + + + + +view::SlideSorterView& SlideSorter::GetView (void) const +{ + OSL_ASSERT(mpSlideSorterView.get()!=NULL); + return *mpSlideSorterView; +} + + + + +controller::SlideSorterController& SlideSorter::GetController (void) const +{ + OSL_ASSERT(mpSlideSorterController.get()!=NULL); + return *mpSlideSorterController; +} + + + + +Reference<frame::XController> SlideSorter::GetXController (void) const +{ + Reference<frame::XController> xController(mxControllerWeak); + return xController; +} + + + + +void SlideSorter::Paint (const Rectangle& rRepaintArea) +{ + GetController().Paint( + rRepaintArea, + GetContentWindow().get()); +} + + + + +::boost::shared_ptr<sd::Window> SlideSorter::GetContentWindow (void) const +{ + return mpContentWindow; +} + + + + +::sd::Window* SlideSorter::GetActiveWindow (void) const +{ + if (mpViewShell != NULL) + return mpViewShell->GetActiveWindow(); + else + return mpContentWindow.get(); +} + + + + +ViewShellBase* SlideSorter::GetViewShellBase (void) const +{ + return mpViewShellBase; +} + + + + +ViewShell* SlideSorter::GetViewShell (void) const +{ + return mpViewShell; +} + + + + +void SlideSorter::SetupControls (::Window* ) +{ + GetVerticalScrollBar()->Show(); + mpSlideSorterController->GetScrollBarManager().LateInitialization(); +} + + + + +void SlideSorter::SetupListeners (void) +{ + ::sd::Window* pWindow = GetActiveWindow(); + if (pWindow != NULL) + { + ::Window* pParentWindow = pWindow->GetParent(); + if (pParentWindow != NULL) + pParentWindow->AddEventListener( + LINK( + mpSlideSorterController.get(), + controller::SlideSorterController, + WindowEventHandler)); + pWindow->AddEventListener( + LINK( + mpSlideSorterController.get(), + controller::SlideSorterController, + WindowEventHandler)); + } + Application::AddEventListener( + LINK( + mpSlideSorterController.get(), + controller::SlideSorterController, + WindowEventHandler)); + + mpSlideSorterController->GetScrollBarManager().Connect(); +} + + + + +void SlideSorter::ReleaseListeners (void) +{ + mpSlideSorterController->GetScrollBarManager().Disconnect(); + + ::sd::Window* pWindow = GetActiveWindow(); + if (pWindow != NULL) + { + + pWindow->RemoveEventListener( + LINK(mpSlideSorterController.get(), + controller::SlideSorterController, + WindowEventHandler)); + + ::Window* pParentWindow = pWindow->GetParent(); + if (pParentWindow != NULL) + pParentWindow->RemoveEventListener( + LINK(mpSlideSorterController.get(), + controller::SlideSorterController, + WindowEventHandler)); + } + Application::RemoveEventListener( + LINK(mpSlideSorterController.get(), + controller::SlideSorterController, + WindowEventHandler)); +} + + + + +void SlideSorter::CreateModelViewController (void) +{ + mpSlideSorterModel.reset(CreateModel()); + DBG_ASSERT (mpSlideSorterModel.get()!=NULL, + "Can not create model for slide browser"); + + mpSlideSorterView.reset(CreateView()); + DBG_ASSERT (mpSlideSorterView.get()!=NULL, + "Can not create view for slide browser"); + + mpSlideSorterController.reset(CreateController()); + DBG_ASSERT (mpSlideSorterController.get()!=NULL, + "Can not create controller for slide browser"); + mpSlideSorterController->Init(); +} + + + + +model::SlideSorterModel* SlideSorter::CreateModel (void) +{ + // Get pointers to the document. + ViewShellBase* pViewShellBase = GetViewShellBase(); + if (pViewShellBase != NULL) + { + OSL_ASSERT (pViewShellBase->GetDocument() != NULL); + + return new model::SlideSorterModel(*this); + } + else + return NULL; +} + + + + +view::SlideSorterView* SlideSorter::CreateView (void) +{ + return new view::SlideSorterView (*this); +} + + + + +controller::SlideSorterController* SlideSorter::CreateController (void) +{ + controller::SlideSorterController* pController + = new controller::SlideSorterController (*this); + return pController; +} + + + + +void SlideSorter::ArrangeGUIElements ( + const Point& rOffset, + const Size& rSize) +{ + Point aOrigin (rOffset); + + if (rSize.Width()!=0 && rSize.Height()!=0) + { + // Prevent untimely redraws while the view is not yet correctly + // resized. + mpSlideSorterView->LockRedraw (TRUE); + if (GetActiveWindow() != NULL) + GetActiveWindow()->EnablePaint (FALSE); + + // maAllWindowRectangle = + mpSlideSorterController->Resize (Rectangle(aOrigin, rSize)); + + if (GetActiveWindow() != NULL) + GetActiveWindow()->EnablePaint (TRUE); + + mbLayoutPending = false; + mpSlideSorterView->LockRedraw (FALSE); + } + else + { + // maAllWindowRectangle = Rectangle(); + } +} + + + + +SvBorder SlideSorter::GetBorder (void) +{ + SvBorder aBorder; + + ::boost::shared_ptr<ScrollBar> pScrollBar = GetVerticalScrollBar(); + if (pScrollBar.get() != NULL && pScrollBar->IsVisible()) + aBorder.Right() = pScrollBar->GetOutputSizePixel().Width(); + + pScrollBar = GetHorizontalScrollBar(); + if (pScrollBar.get() != NULL && pScrollBar->IsVisible()) + aBorder.Bottom() = pScrollBar->GetOutputSizePixel().Height(); + + return aBorder; +} + + + + +bool SlideSorter::RelocateToWindow (::Window* pParentWindow) +{ + ReleaseListeners(); + + if (mpViewShell != NULL) + mpViewShell->ViewShell::RelocateToParentWindow(pParentWindow); + + SetupControls(mpViewShell->GetParentWindow()); + SetupListeners(); + + // For accessibility we have to shortly hide the content window. This + // triggers the construction of a new accessibility object for the new + // view shell. (One is created earlier while the construtor of the base + // class is executed. At that time the correct accessibility object can + // not be constructed.) + if (mpContentWindow.get() !=NULL) + { + mpContentWindow->Hide(); + mpContentWindow->Show(); + } + + return true; +} + + + + +void SlideSorter::SetCurrentFunction (const FunctionReference& rpFunction) +{ + if (GetViewShell() != NULL) + { + GetViewShell()->SetCurrentFunction(rpFunction); + GetViewShell()->SetOldFunction(rpFunction); + } + else + { + ::boost::shared_ptr<ContentWindow> pWindow + = ::boost::dynamic_pointer_cast<ContentWindow>(GetContentWindow()); + if (pWindow.get() != NULL) + pWindow->SetCurrentFunction(rpFunction); + } +} + + + + +//===== ContentWindow ========================================================= + +namespace { + +ContentWindow::ContentWindow( + ::Window& rParent, + SlideSorter& rSlideSorter) + : ::sd::Window(&rParent), + mrSlideSorter(rSlideSorter), + mpCurrentFunction() +{ + SetDialogControlFlags(GetDialogControlFlags() & ~WINDOW_DLGCTRL_WANTFOCUS); + SetStyle(GetStyle() | WB_NOPOINTERFOCUS); +} + + + + +ContentWindow::~ContentWindow (void) +{ +} + + + + +void ContentWindow::SetCurrentFunction (const FunctionReference& rpFunction) +{ + mpCurrentFunction = rpFunction; +} + + + + +void ContentWindow::Paint (const Rectangle& rRect) +{ + mrSlideSorter.Paint(rRect); +} + + + + +void ContentWindow::KeyInput (const KeyEvent& rEvent) +{ + if (mpCurrentFunction.is()) + mpCurrentFunction->KeyInput(rEvent); +} + + + + +void ContentWindow::MouseMove (const MouseEvent& rEvent) +{ + if (mpCurrentFunction.is()) + mpCurrentFunction->MouseMove(rEvent); +} + + + + +void ContentWindow::MouseButtonUp(const MouseEvent& rEvent) +{ + if (mpCurrentFunction.is()) + mpCurrentFunction->MouseButtonUp(rEvent); +} + + + + +void ContentWindow::MouseButtonDown(const MouseEvent& rEvent) +{ + if (mpCurrentFunction.is()) + mpCurrentFunction->MouseButtonDown(rEvent); +} + + + + +void ContentWindow::Command(const CommandEvent& rEvent) +{ + if (mpCurrentFunction.is()) + mpCurrentFunction->Command(rEvent); +} + + + + +long ContentWindow::Notify (NotifyEvent& rEvent) +{ + (void)rEvent; + return 0; +} + + + + +} // end of anonymous namespace + + +} } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.cxx b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.cxx new file mode 100644 index 000000000000..66eb0530f566 --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.cxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterChildWindow.cxx,v $ + * $Revision: 1.5 $ + * + * 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_sd.hxx" + +#include "SlideSorterChildWindow.hxx" + +#include "app.hrc" +#include "sfx2/app.hxx" +#include <sfx2/dockwin.hxx> + +#include "SlideSorter.hxx" + +namespace sd { namespace slidesorter { + +SlideSorterChildWindow::SlideSorterChildWindow ( + ::Window* pParentWindow, + USHORT nId, + SfxBindings* pBindings, + SfxChildWinInfo* pInfo) + : SfxChildWindow (pParentWindow, nId) +{ + pWindow = new SlideSorter ( + pBindings, + this, + pParentWindow); + eChildAlignment = SFX_ALIGN_LEFT; + static_cast<SfxDockingWindow*>(pWindow)->Initialize (pInfo); + // SetHideNotDelete (TRUE); +} + + + + +SlideSorterChildWindow::~SlideSorterChildWindow (void) +{} + + +SFX_IMPL_DOCKINGWINDOW(SlideSorterChildWindow, SID_SLIDE_BROWSER) + +} } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.src b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.src new file mode 100644 index 000000000000..fac755dd9251 --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.src @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterChildWindow.src,v $ + * $Revision: 1.5 $ + * + * 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 "app.hrc" +#include "SlideSorterChildWindow.hrc" + +DockingWindow FLT_WIN_SLIDE_BROWSER +{ + HelpID = SID_SLIDE_BROWSER; + Border = TRUE ; + Hide = FALSE ; + SVLook = TRUE ; + Sizeable = TRUE ; + Moveable = TRUE ; + Closeable = TRUE ; + Zoomable = TRUE ; + Dockable = TRUE ; + EnableResizing = TRUE ; + Size = MAP_APPFONT ( 140 , 120 ) ; + Text = "Slide Browser" ; + + Control TOOLPANEL + { + Pos = MAP_APPFONT ( 0 , 0 ) ; + Size = MAP_APPFONT ( 69, 150 ) ; + Border = FALSE; + }; +}; diff --git a/sd/source/ui/slidesorter/shell/SlideSorterService.cxx b/sd/source/ui/slidesorter/shell/SlideSorterService.cxx new file mode 100644 index 000000000000..75b7d23db43f --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterService.cxx @@ -0,0 +1,664 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterService.cxx,v $ + * + * $Revision: 1.3 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlideSorterService.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "DrawController.hxx" +#include <toolkit/helper/vclunohelper.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <cppuhelper/proptypehlp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; +using ::rtl::OUString; +using ::sd::slidesorter::view::SlideSorterView; + +namespace sd { namespace slidesorter { + +namespace { + enum Properties + { + PropertyDocumentSlides, + PropertyHighlightCurrentSlide, + PropertyShowSelection, + PropertyCenterSelection, + PropertySuspendPreviewUpdatesDuringFullScreenPresentation, + PropertyOrientationVertical + }; +} + + + + +//===== Service =============================================================== + +Reference<XInterface> SAL_CALL SlideSorterService_createInstance ( + const Reference<XComponentContext>& rxContext) +{ + return Reference<XInterface>(static_cast<drawing::XDrawView*>(new SlideSorterService(rxContext))); +} + + + + +::rtl::OUString SlideSorterService_getImplementationName (void) throw(RuntimeException) +{ + return OUString::createFromAscii("com.sun.star.comp.Draw.SlideSorter"); +} + + + + +Sequence<rtl::OUString> SAL_CALL SlideSorterService_getSupportedServiceNames (void) + throw (RuntimeException) +{ + static const ::rtl::OUString sServiceName( + ::rtl::OUString::createFromAscii("com.sun.star.drawing.SlideSorter")); + return Sequence<rtl::OUString>(&sServiceName, 1); +} + + + + +//===== SlideSorterService ========================================================== + +SlideSorterService::SlideSorterService (const Reference<XComponentContext>& rxContext) + : SlideSorterServiceInterfaceBase(m_aMutex), + mpSlideSorter(), + mxParentWindow() +{ + (void)rxContext; +} + + + + +SlideSorterService::~SlideSorterService (void) +{ +} + + + + +void SAL_CALL SlideSorterService::disposing (void) +{ + mpSlideSorter.reset(); + + if (mxParentWindow.is()) + { + mxParentWindow->removeWindowListener(this); + } +} + + + + +//----- XInitialization ------------------------------------------------------- + +void SAL_CALL SlideSorterService::initialize (const Sequence<Any>& rArguments) + throw (Exception, RuntimeException) +{ + ThrowIfDisposed(); + + if (rArguments.getLength() == 3) + { + try + { + mxViewId = Reference<XResourceId>(rArguments[0], UNO_QUERY_THROW); + + // Get the XController. + Reference<frame::XController> xController (rArguments[1], UNO_QUERY_THROW); + + // Tunnel through the controller to obtain a ViewShellBase. + ViewShellBase* pBase = NULL; + Reference<lang::XUnoTunnel> xTunnel (xController, UNO_QUERY_THROW); + ::sd::DrawController* pController = reinterpret_cast<sd::DrawController*>( + xTunnel->getSomething(sd::DrawController::getUnoTunnelId())); + if (pController != NULL) + pBase = pController->GetViewShellBase(); + + // Get the parent window. + mxParentWindow = Reference<awt::XWindow>(rArguments[2], UNO_QUERY_THROW); + ::Window* pParentWindow = VCLUnoHelper::GetWindow(mxParentWindow); + + mxParentWindow->addWindowListener(this); + + if (pBase != NULL && pParentWindow!=NULL) + mpSlideSorter = SlideSorter::CreateSlideSorter( + *pBase, + NULL, + *pParentWindow); + + Resize(); + } + catch (RuntimeException&) + { + throw; + } + } + else + { + throw RuntimeException( + OUString::createFromAscii("SlideSorterService: invalid number of arguments"), + static_cast<drawing::XDrawView*>(this)); + } +} + + + + +//----- XView ----------------------------------------------------------------- + +Reference<XResourceId> SAL_CALL SlideSorterService::getResourceId (void) + throw (RuntimeException) +{ + return mxViewId; +} + + + + +sal_Bool SAL_CALL SlideSorterService::isAnchorOnly (void) + throw (RuntimeException) +{ + return sal_False; +} + + + + +//----- XWindowListener ------------------------------------------------------- + +void SAL_CALL SlideSorterService::windowResized (const awt::WindowEvent& rEvent) + throw (RuntimeException) +{ + (void)rEvent; + ThrowIfDisposed(); + + Resize(); +} + + + + + +void SAL_CALL SlideSorterService::windowMoved (const awt::WindowEvent& rEvent) + throw (RuntimeException) +{ + (void)rEvent; +} + + + + +void SAL_CALL SlideSorterService::windowShown (const lang::EventObject& rEvent) + throw (RuntimeException) +{ + (void)rEvent; + ThrowIfDisposed(); + Resize(); +} + + + + +void SAL_CALL SlideSorterService::windowHidden (const lang::EventObject& rEvent) + throw (RuntimeException) +{ + (void)rEvent; + ThrowIfDisposed(); +} + + + + +//----- lang::XEventListener -------------------------------------------------- + +void SAL_CALL SlideSorterService::disposing (const lang::EventObject& rEvent) + throw (RuntimeException) +{ + if (rEvent.Source == mxParentWindow) + mxParentWindow = NULL; +} + + + + +//----- XDrawView ------------------------------------------------------------- + +void SAL_CALL SlideSorterService::setCurrentPage(const Reference<drawing::XDrawPage>& rxSlide) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL) + mpSlideSorter->GetController().GetCurrentSlideManager()->CurrentSlideHasChanged( + mpSlideSorter->GetModel().GetIndex(rxSlide)); +} + + + + +Reference<drawing::XDrawPage> SAL_CALL SlideSorterService::getCurrentPage (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL) + return mpSlideSorter->GetController().GetCurrentSlideManager()->GetCurrentSlide()->GetXDrawPage(); + else + return NULL; +} + + + + +//----- attributes ------------------------------------------------------------ + + +Reference<container::XIndexAccess> SAL_CALL SlideSorterService::getDocumentSlides (void) + throw (RuntimeException) +{ + return mpSlideSorter->GetModel().GetDocumentSlides(); +} + + + + +void SAL_CALL SlideSorterService::setDocumentSlides ( + const Reference<container::XIndexAccess >& rxSlides) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().SetDocumentSlides(rxSlides); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsHighlightCurrentSlide (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetController().GetProperties()->IsHighlightCurrentSlide(); +} + + + + +void SAL_CALL SlideSorterService::setIsHighlightCurrentSlide (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + { + mpSlideSorter->GetController().GetProperties()->SetHighlightCurrentSlide(bValue); + controller::SlideSorterController::ModelChangeLock aLock (mpSlideSorter->GetController()); + mpSlideSorter->GetController().HandleModelChange(); + } +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsShowSelection (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetController().GetProperties()->IsShowSelection(); +} + + + + +void SAL_CALL SlideSorterService::setIsShowSelection (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetShowSelection(bValue); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsShowFocus (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetController().GetProperties()->IsShowFocus(); +} + + + + +void SAL_CALL SlideSorterService::setIsShowFocus (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetShowFocus(bValue); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsCenterSelection (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetController().GetProperties()->IsCenterSelection(); +} + + + + +void SAL_CALL SlideSorterService::setIsCenterSelection (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetCenterSelection(bValue); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsSuspendPreviewUpdatesDuringFullScreenPresentation (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return true; + else + return mpSlideSorter->GetController().GetProperties() + ->IsSuspendPreviewUpdatesDuringFullScreenPresentation(); +} + + + + +void SAL_CALL SlideSorterService::setIsSuspendPreviewUpdatesDuringFullScreenPresentation ( + sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties() + ->SetSuspendPreviewUpdatesDuringFullScreenPresentation(bValue); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsOrientationVertical (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return true; + else + return mpSlideSorter->GetView().GetOrientation() == SlideSorterView::VERTICAL; +} + + + + +void SAL_CALL SlideSorterService::setIsOrientationVertical (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetView().SetOrientation(bValue + ? SlideSorterView::VERTICAL + : SlideSorterView::HORIZONTAL); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsSmoothScrolling (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetController().GetProperties()->IsSmoothSelectionScrolling(); +} + + + + +void SAL_CALL SlideSorterService::setIsSmoothScrolling (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetSmoothSelectionScrolling(bValue); +} + + + + +util::Color SAL_CALL SlideSorterService::getBackgroundColor (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return util::Color(); + else + return util::Color( + mpSlideSorter->GetController().GetProperties()->GetBackgroundColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setBackgroundColor (util::Color aBackgroundColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetBackgroundColor( + Color(aBackgroundColor)); +} + + + + +util::Color SAL_CALL SlideSorterService::getTextColor (void) + throw (css::uno::RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return util::Color(); + else + return util::Color( + mpSlideSorter->GetController().GetProperties()->GetTextColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setTextColor (util::Color aTextColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetTextColor( + Color(aTextColor)); +} + + + + +util::Color SAL_CALL SlideSorterService::getSelectionColor (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return util::Color(); + else + return util::Color( + mpSlideSorter->GetController().GetProperties()->GetSelectionColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setSelectionColor (util::Color aSelectionColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetSelectionColor( + Color(aSelectionColor)); +} + + + + +util::Color SAL_CALL SlideSorterService::getHighlightColor (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return util::Color(); + else + return util::Color( + mpSlideSorter->GetController().GetProperties()->GetHighlightColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setHighlightColor (util::Color aHighlightColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetHighlightColor( + Color(aHighlightColor)); +} + + + +sal_Bool SAL_CALL SlideSorterService::getIsUIReadOnly (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return true; + else + return mpSlideSorter->GetController().GetProperties()->IsUIReadOnly(); +} + + + + +void SAL_CALL SlideSorterService::setIsUIReadOnly (sal_Bool bIsUIReadOnly) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetController().GetProperties()->SetUIReadOnly( + bIsUIReadOnly); +} + + + + +//----------------------------------------------------------------------------- + +void SlideSorterService::Resize (void) +{ + if (mxParentWindow.is()) + { + awt::Rectangle aWindowBox = mxParentWindow->getPosSize(); + mpSlideSorter->ArrangeGUIElements( + Point(0,0), + Size(aWindowBox.Width, aWindowBox.Height)); + } +} + + + + +void SlideSorterService::Rearrange (void) +{ + if (mxParentWindow.is()) + { + awt::Rectangle aWindowBox = mxParentWindow->getPosSize(); + mpSlideSorter->GetController().Rearrange(); + } +} + + + + +void SlideSorterService::ThrowIfDisposed (void) + throw (::com::sun::star::lang::DisposedException) +{ + if (SlideSorterServiceInterfaceBase::rBHelper.bDisposed || SlideSorterServiceInterfaceBase::rBHelper.bInDispose) + { + throw lang::DisposedException ( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( + "SlideSorterService object has already been disposed")), + static_cast<drawing::XDrawView*>(this)); + } +} + + +} } // end of namespace ::sd::presenter + diff --git a/sd/source/ui/slidesorter/shell/SlideSorterService.hxx b/sd/source/ui/slidesorter/shell/SlideSorterService.hxx new file mode 100644 index 000000000000..1b8e88036a00 --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterService.hxx @@ -0,0 +1,221 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterService.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_SLIDE_SORTER_SERVICE_HXX +#define SD_SLIDESORTER_SLIDE_SORTER_SERVICE_HXX + +#include "SlideSorter.hxx" + +#include "tools/PropertySet.hxx" +#include <com/sun/star/awt/XWindowListener.hpp> +#include <com/sun/star/drawing/SlideSorter.hpp> +#include <com/sun/star/drawing/XDrawView.hpp> +#include <com/sun/star/drawing/framework/XView.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase3.hxx> +#include <cppuhelper/propshlp.hxx> +#include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/scoped_ptr.hpp> + +namespace css = ::com::sun::star; + +namespace sd { namespace slidesorter { + +namespace { + typedef ::cppu::WeakComponentImplHelper3 < + css::drawing::XSlideSorterBase, + css::lang::XInitialization, + css::awt::XWindowListener + > SlideSorterServiceInterfaceBase; +} + + +/** Implementation of the com.sun.star.drawing.SlideSorter service. +*/ +class SlideSorterService + : private ::boost::noncopyable, + protected ::cppu::BaseMutex, + public SlideSorterServiceInterfaceBase +{ +public: + explicit SlideSorterService ( + const css::uno::Reference<css::uno::XComponentContext>& rxContext); + virtual ~SlideSorterService (void); + virtual void SAL_CALL disposing (void); + + + // XInitialization + + virtual void SAL_CALL initialize (const css::uno::Sequence<css::uno::Any>& rArguments) + throw (css::uno::Exception, css::uno::RuntimeException); + + + // XResourceId + + css::uno::Reference<css::drawing::framework::XResourceId> SAL_CALL getResourceId (void) + throw (css::uno::RuntimeException); + + sal_Bool SAL_CALL isAnchorOnly (void) + throw (css::uno::RuntimeException); + + + // XWindowListener + + virtual void SAL_CALL windowResized (const css::awt::WindowEvent& rEvent) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL windowMoved (const css::awt::WindowEvent& rEvent) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL windowShown (const css::lang::EventObject& rEvent) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL windowHidden (const css::lang::EventObject& rEvent) + throw (css::uno::RuntimeException); + + + // lang::XEventListener + virtual void SAL_CALL disposing (const css::lang::EventObject& rEvent) + throw (css::uno::RuntimeException); + + + // XDrawView + + virtual void SAL_CALL setCurrentPage( + const css::uno::Reference<css::drawing::XDrawPage>& rxSlide) + throw (css::uno::RuntimeException); + + virtual css::uno::Reference<css::drawing::XDrawPage> SAL_CALL getCurrentPage (void) + throw (css::uno::RuntimeException); + + + // Attributes + + virtual css::uno::Reference<css::container::XIndexAccess> SAL_CALL getDocumentSlides (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setDocumentSlides ( + const css::uno::Reference<css::container::XIndexAccess >& rxSlides) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsHighlightCurrentSlide (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsHighlightCurrentSlide (::sal_Bool bIsHighlightCurrentSlide) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsShowSelection (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsShowSelection (sal_Bool bIsShowSelection) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsCenterSelection (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsCenterSelection (sal_Bool bIsCenterSelection) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsSuspendPreviewUpdatesDuringFullScreenPresentation (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsSuspendPreviewUpdatesDuringFullScreenPresentation ( + sal_Bool bIsSuspendPreviewUpdatesDuringFullScreenPresentation) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsOrientationVertical (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsOrientationVertical (sal_Bool bIsOrientationVertical) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsSmoothScrolling (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsSmoothScrolling (sal_Bool bIsOrientationVertical) + throw (css::uno::RuntimeException); + + virtual css::util::Color SAL_CALL getBackgroundColor (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setBackgroundColor (css::util::Color aBackgroundColor) + throw (css::uno::RuntimeException); + + virtual css::util::Color SAL_CALL getTextColor (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setTextColor (css::util::Color aTextColor) + throw (css::uno::RuntimeException); + + virtual css::util::Color SAL_CALL getSelectionColor (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setSelectionColor (css::util::Color aSelectionColor) + throw (css::uno::RuntimeException); + + virtual css::util::Color SAL_CALL getHighlightColor (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setHighlightColor (css::util::Color aHighlightColor) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsUIReadOnly (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsUIReadOnly (sal_Bool bIsUIReadOnly) + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL getIsShowFocus (void) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL setIsShowFocus (sal_Bool bIsShowFocus) + throw (css::uno::RuntimeException); + +private: + ::boost::shared_ptr<SlideSorter> mpSlideSorter; + css::uno::Reference<css::drawing::framework::XResourceId> mxViewId; + css::uno::Reference<css::awt::XWindow> mxParentWindow; + ::boost::scoped_ptr<cppu::IPropertyArrayHelper> mpPropertyArrayHelper; + + void Resize (void); + void Rearrange (void); + + /** This method throws a DisposedException when the object has already been + disposed. + */ + void ThrowIfDisposed (void) throw (css::lang::DisposedException); +}; + +} } // end of namespace ::sd::slidesorter + +#endif diff --git a/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx new file mode 100644 index 000000000000..0a04a236511c --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx @@ -0,0 +1,797 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterViewShell.cxx,v $ + * $Revision: 1.32.70.3 $ + * + * 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 "precompiled_sd.hxx" + +#include "SlideSorterViewShell.hxx" +#include "ViewShellImplementation.hxx" + +#include "SlideSorter.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsClipboard.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumeration.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "framework/FrameworkHelper.hxx" +#include "ViewShellBase.hxx" +#include "drawdoc.hxx" +#include "app.hrc" +#include "glob.hrc" +#include "sdattr.hrc" +#include "sdresid.hxx" +#include "AccessibleSlideSorterView.hxx" +#include "DrawDocShell.hxx" +#include "FrameView.hxx" +#include "SdUnoSlideView.hxx" +#include "ViewShellManager.hxx" +#include "Window.hxx" +#include <sfx2/app.hxx> +#include <sfx2/msg.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/request.hxx> +#include <svx/svxids.hrc> +#include <com/sun/star/drawing/framework/XControllerManager.hpp> +#include <com/sun/star/drawing/framework/ResourceId.hpp> +#include <cppuhelper/bootstrap.hxx> +#include <comphelper/processfactory.hxx> + +using namespace ::sd::slidesorter; +#define SlideSorterViewShell +#include "sdslots.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing::framework; + +using ::sd::framework::FrameworkHelper; + +namespace sd { namespace slidesorter { + + +SFX_IMPL_INTERFACE(SlideSorterViewShell, SfxShell, SdResId(STR_SLIDESORTERVIEWSHELL)) +{ +} + + + +TYPEINIT1(SlideSorterViewShell, ViewShell); + + + +::boost::shared_ptr<SlideSorterViewShell> SlideSorterViewShell::Create ( + SfxViewFrame* pFrame, + ViewShellBase& rViewShellBase, + ::Window* pParentWindow, + FrameView* pFrameViewArgument) +{ + ::boost::shared_ptr<SlideSorterViewShell> pViewShell; + try + { + pViewShell.reset( + new SlideSorterViewShell(pFrame,rViewShellBase,pParentWindow,pFrameViewArgument)); + pViewShell->Initialize(); + if (pViewShell->mpSlideSorter.get() == NULL) + pViewShell.reset(); + } + catch(Exception&) + { + pViewShell.reset(); + } + return pViewShell; +} + + + + +SlideSorterViewShell::SlideSorterViewShell ( + SfxViewFrame* pFrame, + ViewShellBase& rViewShellBase, + ::Window* pParentWindow, + FrameView* pFrameViewArgument) + : ViewShell (pFrame, pParentWindow, rViewShellBase), + mpSlideSorter() +{ + meShellType = ST_SLIDE_SORTER; + + SetPool( &GetDoc()->GetPool() ); + SetUndoManager( GetDoc()->GetDocSh()->GetUndoManager() ); + + if (pFrameViewArgument != NULL) + mpFrameView = pFrameViewArgument; + else + mpFrameView = new FrameView(GetDoc()); + GetFrameView()->Connect(); + + SetName (String (RTL_CONSTASCII_USTRINGPARAM("SlideSorterViewShell"))); + + pParentWindow->SetStyle(pParentWindow->GetStyle() | WB_DIALOGCONTROL); +} + + + + +SlideSorterViewShell::~SlideSorterViewShell (void) +{ + DisposeFunctions(); + + try + { + ::sd::Window* pWindow = GetActiveWindow(); + if (pWindow!=NULL) + { + ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XComponent> xComponent ( + pWindow->GetAccessible(false), + ::com::sun::star::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); + } + } + catch( ::com::sun::star::uno::Exception& e ) + { + (void)e; + DBG_ERROR("sd::SlideSorterViewShell::~SlideSorterViewShell(), exception caught!" ); + } +} + + + + + +void SlideSorterViewShell::Initialize (void) +{ + mpSlideSorter = SlideSorter::CreateSlideSorter( + *this, + mpContentWindow, + mpHorizontalScrollBar, + mpVerticalScrollBar, + mpScrollBarBox); + mpView = &mpSlideSorter->GetView(); + + // For accessibility we have to shortly hide the content window. + // This triggers the construction of a new accessibility object for + // the new view shell. (One is created earlier while the construtor + // of the base class is executed. At that time the correct + // accessibility object can not be constructed.) + ::Window* pWindow = mpSlideSorter->GetActiveWindow(); + if (pWindow != NULL) + { + pWindow->Hide(); + pWindow->Show(); + } +} + + + + +void SlideSorterViewShell::Init (bool bIsMainViewShell) +{ + ViewShell::Init(bIsMainViewShell); + + mpSlideSorter->GetModel().UpdatePageList(); + + if (mpContentWindow.get() != NULL) + mpContentWindow->SetViewShell(this); +} + + + + +SlideSorterViewShell* SlideSorterViewShell::GetSlideSorter (ViewShellBase& rBase) +{ + SlideSorterViewShell* pViewShell = NULL; + + // Test the center, left, and then the right pane for showing a slide sorter. + ::rtl::OUString aPaneURLs[] = { + FrameworkHelper::msCenterPaneURL, + FrameworkHelper::msFullScreenPaneURL, + FrameworkHelper::msLeftImpressPaneURL, + FrameworkHelper::msRightPaneURL, + ::rtl::OUString()}; + + try + { + ::boost::shared_ptr<FrameworkHelper> pFrameworkHelper (FrameworkHelper::Instance(rBase)); + if (pFrameworkHelper->IsValid()) + for (int i=0; pViewShell==NULL && aPaneURLs[i].getLength()>0; ++i) + { + pViewShell = dynamic_cast<SlideSorterViewShell*>( + pFrameworkHelper->GetViewShell(aPaneURLs[i]).get()); + } + } + catch (RuntimeException&) + {} + + return pViewShell; +} + + + + +Reference<drawing::XDrawSubController> SlideSorterViewShell::CreateSubController (void) +{ + Reference<drawing::XDrawSubController> xSubController; + + if (IsMainViewShell()) + { + // Create uno controller for the main view shell. + xSubController = Reference<drawing::XDrawSubController>( + new SdUnoSlideView ( + GetViewShellBase().GetDrawController(), + *mpSlideSorter, + *GetView())); + } + + return xSubController; +} + + + + +/** If there is a valid controller then create a new instance of + <type>AccessibleSlideSorterView</type>. Otherwise delegate this call + to the base class to return a default object (probably an empty + reference). +*/ +::com::sun::star::uno::Reference< + ::com::sun::star::accessibility::XAccessible> + SlideSorterViewShell::CreateAccessibleDocumentView (::sd::Window* pWindow) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + + // When the view is not set then the initialization is not yet complete + // and we can not yet provide an accessibility object. + if (mpView == NULL) + return NULL; + + return new ::accessibility::AccessibleSlideSorterView ( + *mpSlideSorter.get(), + pWindow->GetAccessibleParentWindow()->GetAccessible(), + pWindow); +} + + + + +SlideSorter& SlideSorterViewShell::GetSlideSorter (void) const +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + return *mpSlideSorter; +} + + + + +bool SlideSorterViewShell::RelocateToParentWindow (::Window* pParentWindow) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + return mpSlideSorter->RelocateToWindow(pParentWindow); +} + + + + +SfxUndoManager* SlideSorterViewShell::ImpGetUndoManager (void) const +{ + SfxShell* pObjectBar = GetViewShellBase().GetViewShellManager()->GetTopShell(); + if (pObjectBar != NULL) + { + // When it exists then return the undo manager of the currently + // active object bar. The object bar is missing when the + // SlideSorterViewShell is not the main view shell. + return pObjectBar->GetUndoManager(); + } + else + { + // Return the undo manager of this shell when there is no object or + // tool bar. + return const_cast<SlideSorterViewShell*>(this)->GetUndoManager(); + } +} + + + + +SfxShell* SlideSorterViewShell::CreateInstance ( + sal_Int32, + SfxShell*, + void* pUserData, + ViewShellBase& rBase) +{ + return new SlideSorterViewShell ( + rBase.GetViewFrame(), + rBase, + static_cast< ::Window*>(pUserData), + NULL); +} + + + + +void SlideSorterViewShell::GetFocus (void) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetFocusManager().ShowFocus(); +} + + + + +void SlideSorterViewShell::LoseFocus (void) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetFocusManager().HideFocus(); +} + + + + +SdPage* SlideSorterViewShell::getCurrentPage(void) const +{ + // since SlideSorterViewShell::GetActualPage() currently also + // returns master pages, which is a wrong behaviour for GetActualPage(), + // we can just use that for now + return const_cast<SlideSorterViewShell*>(this)->GetActualPage(); +} + + + + +SdPage* SlideSorterViewShell::GetActualPage (void) +{ + SdPage* pCurrentPage = NULL; + + // 1. Try to get the current page from the view shell in the center pane + // (if we are that not ourself). + if ( ! IsMainViewShell()) + { + ::boost::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell(); + if (pMainViewShell.get() != NULL) + pCurrentPage = pMainViewShell->GetActualPage(); + } + + if (pCurrentPage == NULL) + { + model::SharedPageDescriptor pDescriptor ( + mpSlideSorter->GetController().GetCurrentSlideManager()->GetCurrentSlide()); + if (pDescriptor.get() != NULL) + pCurrentPage = pDescriptor->GetPage(); + } + + return pCurrentPage; +} + + + + +void SlideSorterViewShell::GetMenuState ( SfxItemSet& rSet) +{ + ViewShell::GetMenuState(rSet); + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetSlotManager()->GetMenuState(rSet); +} + + + + +void SlideSorterViewShell::GetClipboardState ( SfxItemSet& rSet) +{ + ViewShell::GetMenuState(rSet); + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetSlotManager()->GetClipboardState(rSet); +} + + + + +void SlideSorterViewShell::ExecCtrl (SfxRequest& rRequest) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().ExecCtrl(rRequest); +} + + + + +void SlideSorterViewShell::GetCtrlState (SfxItemSet& rSet) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetCtrlState(rSet); +} + + + + +void SlideSorterViewShell::FuSupport (SfxRequest& rRequest) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().FuSupport(rRequest); +} + + + + +/** We have to handle those slot calls here that need to have access to + private or protected members and methods of this class. +*/ +void SlideSorterViewShell::FuTemporary (SfxRequest& rRequest) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + switch (rRequest.GetSlot()) + { + case SID_MODIFYPAGE: + { + SdPage* pCurrentPage = GetActualPage(); + if (pCurrentPage != NULL) + mpImpl->ProcessModifyPageSlot ( + rRequest, + pCurrentPage, + mpSlideSorter->GetModel().GetPageType()); + Cancel(); + rRequest.Done (); + } + break; + + default: + mpSlideSorter->GetController().FuTemporary(rRequest); + break; + } +} + + + + +void SlideSorterViewShell::GetStatusBarState (SfxItemSet& rSet) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetStatusBarState(rSet); +} + + + + +void SlideSorterViewShell::FuPermanent (SfxRequest& rRequest) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().FuPermanent(rRequest); +} + + + + +void SlideSorterViewShell::GetAttrState (SfxItemSet& rSet) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetAttrState(rSet); +} + + + + +void SlideSorterViewShell::ExecStatusBar (SfxRequest& rRequest) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().ExecStatusBar(rRequest); +} + + + + +void SlideSorterViewShell::PrePaint() +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + if (mpSlideSorter.get() != NULL) + mpSlideSorter->GetController().PrePaint(); +} + + + + +void SlideSorterViewShell::Paint ( + const Rectangle& rBBox, + ::sd::Window* pWindow) +{ + SetActiveWindow (pWindow); + OSL_ASSERT(mpSlideSorter.get()!=NULL); + if (mpSlideSorter.get() != NULL) + mpSlideSorter->GetController().Paint(rBBox,pWindow); +} + + + + +void SlideSorterViewShell::ArrangeGUIElements (void) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->ArrangeGUIElements( + maViewPos, + maViewSize); +} + + + + +SvBorder SlideSorterViewShell::GetBorder (bool ) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + return mpSlideSorter->GetBorder(); +} + + + + +void SlideSorterViewShell::Command ( + const CommandEvent& rEvent, + ::sd::Window* pWindow) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + if ( ! mpSlideSorter->GetController().Command (rEvent, pWindow)) + ViewShell::Command (rEvent, pWindow); +} + + + + +void SlideSorterViewShell::ReadFrameViewData (FrameView* pFrameView) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + if (pFrameView != NULL) + { + view::SlideSorterView& rView (mpSlideSorter->GetView()); + + USHORT nSlidesPerRow (pFrameView->GetSlidesPerRow()); + if (nSlidesPerRow == 0 || ! IsMainViewShell()) + { + // When a value of 0 (automatic) is given or the the slide + // sorter is displayed in a side pane then we ignore the value + // of the frame view and adapt the number of columns + // automatically to the window width. + rView.GetLayouter().SetColumnCount(1,5); + } + else + rView.GetLayouter().SetColumnCount(nSlidesPerRow,nSlidesPerRow); + mpSlideSorter->GetController().Rearrange(true); + + // DrawMode for 'main' window + if (GetActiveWindow()->GetDrawMode() != pFrameView->GetDrawMode() ) + GetActiveWindow()->SetDrawMode( pFrameView->GetDrawMode() ); + } +} + + + + +void SlideSorterViewShell::WriteFrameViewData() +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + if (mpFrameView != NULL) + { + view::SlideSorterView& rView (mpSlideSorter->GetView()); + mpFrameView->SetSlidesPerRow((USHORT)rView.GetLayouter().GetColumnCount()); + + // DrawMode for 'main' window + if( mpFrameView->GetDrawMode() != GetActiveWindow()->GetDrawMode() ) + mpFrameView->SetDrawMode( GetActiveWindow()->GetDrawMode() ); + + SdPage* pActualPage = GetActualPage(); + if (pActualPage != NULL) + { + // The slide sorter is not expected to switch the current page + // other then by double clicks. That is handled seperatly. + // mpFrameView->SetSelectedPage((pActualPage->GetPageNum()- 1) / 2); + } + else + { + // We have no current page to set but at least we can make sure + // that the index of the frame view has a legal value. + if (mpFrameView->GetSelectedPage() >= mpSlideSorter->GetModel().GetPageCount()) + mpFrameView->SetSelectedPage((USHORT)mpSlideSorter->GetModel().GetPageCount()-1); + } + } +} + + + + +void SlideSorterViewShell::SetZoom (long int ) +{ + // Ignored. + // The zoom scale is adapted internally to fit a number of columns in + // the window. +} + +void SlideSorterViewShell::SetZoomRect (const Rectangle& rZoomRect) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + Size aPageSize (mpSlideSorter->GetView().GetPageBoundingBox( + 0, + view::SlideSorterView::CS_MODEL, + view::SlideSorterView::BBT_SHAPE).GetSize()); + + Rectangle aRect(rZoomRect); + + if (aRect.GetWidth() < aPageSize.Width()) + { + long nWidthDiff = (aPageSize.Width() - aRect.GetWidth()) / 2; + + aRect.Left() -= nWidthDiff; + aRect.Right() += nWidthDiff; + + if (aRect.Left() < 0) + { + aRect.SetPos(Point(0, aRect.Top())); + } + } + + if (aRect.GetHeight() < aPageSize.Height()) + { + long nHeightDiff = (aPageSize.Height() - aRect.GetHeight()) / 2; + + aRect.Top() -= nHeightDiff; + aRect.Bottom() += nHeightDiff; + + if (aRect.Top() < 0) + { + aRect.SetPos(Point(aRect.Left(), 0)); + } + } + + ViewShell::SetZoomRect(aRect); + + // #106268# + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM ); + GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER ); +} + + + + +void SlideSorterViewShell::UpdateScrollBars (void) +{ + // Do not call the overwritten method of the base class: We do all the + // scroll bar setup by ourselves. + mpSlideSorter->GetController().GetScrollBarManager().UpdateScrollBars (false); +} + + + + +void SlideSorterViewShell::StartDrag ( + const Point& rDragPt, + ::Window* pWindow ) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetClipboard().StartDrag ( + rDragPt, + pWindow); +} + + + + +void SlideSorterViewShell::DragFinished ( + sal_Int8 nDropAction) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetClipboard().DragFinished (nDropAction); +} + + + + +sal_Int8 SlideSorterViewShell::AcceptDrop ( + const AcceptDropEvent& rEvt, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow, + USHORT nPage, + USHORT nLayer) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + return mpSlideSorter->GetController().GetClipboard().AcceptDrop ( + rEvt, + rTargetHelper, + pTargetWindow, + nPage, + nLayer); +} + + + + +sal_Int8 SlideSorterViewShell::ExecuteDrop ( + const ExecuteDropEvent& rEvt, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow, + USHORT nPage, + USHORT nLayer) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + return mpSlideSorter->GetController().GetClipboard().ExecuteDrop ( + rEvt, + rTargetHelper, + pTargetWindow, + nPage, + nLayer); +} + + + + +::boost::shared_ptr<SlideSorterViewShell::PageSelection> + SlideSorterViewShell::GetPageSelection (void) const +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + return mpSlideSorter->GetController().GetPageSelector().GetPageSelection(); +} + + + + +void SlideSorterViewShell::SetPageSelection ( + const ::boost::shared_ptr<PageSelection>& rSelection) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetPageSelector().SetPageSelection(rSelection); +} + + + + +void SlideSorterViewShell::AddSelectionChangeListener ( + const Link& rCallback) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetSelectionManager()->AddSelectionChangeListener(rCallback); +} + + + + +void SlideSorterViewShell::RemoveSelectionChangeListener ( + const Link& rCallback) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->GetController().GetSelectionManager()->RemoveSelectionChangeListener(rCallback); +} + + + +} } // end of namespace ::sd::slidesorter diff --git a/sd/source/ui/slidesorter/shell/makefile.mk b/sd/source/ui/slidesorter/shell/makefile.mk new file mode 100644 index 000000000000..95e159985b01 --- /dev/null +++ b/sd/source/ui/slidesorter/shell/makefile.mk @@ -0,0 +1,59 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.6 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slsshell +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/SlideSorter.obj \ + $(SLO)$/SlideSorterService.obj \ + $(SLO)$/SlideSorterViewShell.obj + +EXCEPTIONSFILES= + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/sd/source/ui/slidesorter/view/SlideSorterView.cxx b/sd/source/ui/slidesorter/view/SlideSorterView.cxx new file mode 100644 index 000000000000..3cd696e4bb26 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlideSorterView.cxx @@ -0,0 +1,849 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlideSorterView.cxx,v $ + * $Revision: 1.29 $ + * + * 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 "precompiled_sd.hxx" + +#include "view/SlideSorterView.hxx" + +#include "ViewShellBase.hxx" +#include "SlideSorter.hxx" +#include "SlideSorterViewShell.hxx" +#include "ViewShell.hxx" +#include "SlsViewCacheContext.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsViewOverlay.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsPageObjectFactory.hxx" +#include "controller/SlsProperties.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "cache/SlsPageCache.hxx" +#include "cache/SlsPageCacheManager.hxx" +#include "cache/SlsCacheContext.hxx" +#include "view/SlsPageObject.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "taskpane/SlideSorterCacheDisplay.hxx" +#include "DrawDocShell.hxx" + +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "Window.hxx" +#include "sdresid.hxx" +#include "glob.hrc" + +#include <svtools/itempool.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdopage.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnclit.hxx> +#include <com/sun/star/presentation/FadeEffect.hpp> +#include <vcl/svapp.hxx> +#include <tools/poly.hxx> +#include <vcl/lineinfo.hxx> +#include <algorithm> +#include <svx/sdr/contact/objectcontact.hxx> +#include <svx/sdrpagewindow.hxx> +#include <svtools/itempool.hxx> + +#ifndef _SFXITEMPOOL_HXX +#include <svtools/itempool.hxx> +#endif + +using namespace std; +using namespace ::sd::slidesorter::model; + +namespace sd { namespace slidesorter { namespace view { + +TYPEINIT1(SlideSorterView, ::sd::View); + + +SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter) + : ::sd::View ( + rSlideSorter.GetModel().GetDocument(), + NULL, + rSlideSorter.GetViewShell()), + mrSlideSorter(rSlideSorter), + mrModel(rSlideSorter.GetModel()), + maPageModel(), + mpPage(new SdrPage(maPageModel)), + mpLayouter (new Layouter ()), + mbPageObjectVisibilitiesValid (false), + mpPreviewCache(), + mpViewOverlay (new ViewOverlay(rSlideSorter)), + mnFirstVisiblePageIndex(0), + mnLastVisiblePageIndex(-1), + mbModelChangedWhileModifyEnabled(true), + maPreviewSize(0,0), + mbPreciousFlagUpdatePending(true), + maPageNumberAreaModelSize(0,0), + maModelBorder(), + meOrientation(VERTICAL) +{ + // Hide the page that contains the page objects. + SetPageVisible (FALSE); + + // call FreezeIdRanges() at the pool from the newly constructed SdrModel, + // else creating SfxItemSets on it will complain + maPageModel.GetItemPool().FreezeIdRanges(); + + // add the page to the model (no, this is NOT done by the constructor :-( ) + maPageModel.InsertPage(mpPage); + + // show page + LocalModelHasChanged(); +} + + + + +SlideSorterView::~SlideSorterView (void) +{ + // Inform the contact objects to disconnect from the preview cache. + // Otherwise each dying contact object invalidates its preview. When + // the previews are kept for a later re-use than this invalidation is + // not wanted. + ::boost::shared_ptr<cache::PageCache> pEmptyCache; + model::PageEnumeration aPageEnumeration ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aPageEnumeration.HasMoreElements()) + { + view::PageObjectViewObjectContact* pContact + = aPageEnumeration.GetNextElement()->GetViewObjectContact(); + if (pContact != NULL) + pContact->SetCache(pEmptyCache); + } + mpPreviewCache.reset(); + + // hide the page to avoid problems in the view when deleting + // visualized objects + HideSdrPage(); + + // Deletion of the objects and the page will be done in SdrModel + // destructor (as long as objects and pages are added) +} + + + + +sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rPosition) const +{ + sal_Int32 nIndex (-1); + + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + nIndex = mpLayouter->GetIndexAtPoint (pWindow->PixelToLogic (rPosition)); + + // Clip the page index against the page count. + if (nIndex >= mrModel.GetPageCount()) + nIndex = -1; + } + + return nIndex; +} + + + + +sal_Int32 SlideSorterView::GetFadePageIndexAtPoint ( + const Point& rPosition) const +{ + sal_Int32 nIndex (-1); + + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + Point aModelPosition (pWindow->PixelToLogic (rPosition)); + nIndex = mpLayouter->GetIndexAtPoint( + aModelPosition, + true // Include page borders into hit test + ); + + // Clip the page index against the page count. + if (nIndex >= mrModel.GetPageCount()) + nIndex = -1; + + if (nIndex >= 0) + { + // Now test whether the given position is inside the area of the + // fade effect indicator. + view::PageObjectViewObjectContact* pContact + = mrModel.GetPageDescriptor(nIndex)->GetViewObjectContact(); + if (pContact != NULL) + { + if ( ! pContact->GetBoundingBox( + *pWindow, + PageObjectViewObjectContact::FadeEffectIndicatorBoundingBox, + PageObjectViewObjectContact::ModelCoordinateSystem).IsInside ( + aModelPosition)) + { + nIndex = -1; + } + } + else + nIndex = -1; + } + } + + return nIndex; +} + + + + +Layouter& SlideSorterView::GetLayouter (void) +{ + return *mpLayouter.get(); +} + + + + +void SlideSorterView::ModelHasChanged (void) +{ + if (mbModelChangedWhileModifyEnabled) + { + controller::SlideSorterController::ModelChangeLock alock( mrSlideSorter.GetController() ); + mrSlideSorter.GetController().HandleModelChange(); + LocalModelHasChanged(); + } +} + + + + +void SlideSorterView::LocalModelHasChanged(void) +{ + mbModelChangedWhileModifyEnabled = false; + + // First call our base class. + View::ModelHasChanged (); + + // Then re-set the page as current page that contains the page objects. + ShowSdrPage(mpPage); + + // Initialize everything that depends on a page view, now that we have + // one. + // SetApplicationDocumentColor( + // Application::GetSettings().GetStyleSettings().GetWindowColor()); + + UpdatePageBorders(); +} + + + + +void SlideSorterView::PreModelChange (void) +{ + // Reset the slide under the mouse. It will be set to the correct slide + // on the next mouse motion. + GetOverlay().GetMouseOverIndicatorOverlay().SetSlideUnderMouse(SharedPageDescriptor()); + + // Tell the page descriptors of the model that the page objects do not + // exist anymore. + model::PageEnumeration aPageEnumeration ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aPageEnumeration.HasMoreElements()) + aPageEnumeration.GetNextElement()->ReleasePageObject(); + + // Remove all page objects from the page. + mpPage->Clear(); +} + + + + +void SlideSorterView::PostModelChange (void) +{ + // In PreModelChange() the page objects have been released. Here we + // create new ones. + ::osl::MutexGuard aGuard (mrModel.GetMutex()); + + model::PageEnumeration aPageEnumeration ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + UpdatePageBorders(); + while (aPageEnumeration.HasMoreElements()) + { + SdrPageObj* pPageObject = aPageEnumeration.GetNextElement()->GetPageObject(); + if (pPageObject != NULL) + AddSdrObject(*pPageObject); + } + + // The new page objects have to be scaled and positioned. + Layout (); +} + + + + +/** At the moment for every model change all page objects are destroyed and + re-created again. This can be optimized by accepting hints that + describe the type of change so that existing page objects can be + reused. +*/ +void SlideSorterView::HandleModelChange (void) +{ + PreModelChange (); + PostModelChange(); +} + + + + +void SlideSorterView::HandleDrawModeChange (void) +{ + UpdatePageBorders(); + + // Replace the preview cache with a new and empty one. The + // PreviewRenderer that is used by the cache is replaced by this as + // well. + mpPreviewCache.reset(); + GetPreviewCache()->InvalidateCache(true); + mrModel.SetPageObjectFactory( + ::std::auto_ptr<controller::PageObjectFactory>( + new controller::PageObjectFactory( + GetPreviewCache(), + mrSlideSorter.GetController().GetProperties()))); + + RequestRepaint(); +} + + + + +void SlideSorterView::Resize (void) +{ + ::sd::Window* pWindow = GetWindow(); + if (mrModel.GetPageCount()>0 && pWindow != NULL) + { + UpdatePageBorders(); + bool bRearrangeSuccess (false); + if (meOrientation == HORIZONTAL) + { + bRearrangeSuccess = mpLayouter->RearrangeHorizontal ( + pWindow->GetSizePixel(), + mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), + pWindow, + mrModel.GetPageCount()); + } + else + { + bRearrangeSuccess = mpLayouter->RearrangeVertical ( + pWindow->GetSizePixel(), + mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), + pWindow); + } + + if (bRearrangeSuccess) + { + Layout(); + pWindow->Invalidate(); + } + } +} + + + + +void SlideSorterView::Layout () +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + // Set the model area, i.e. the smallest rectangle that includes all + // page objects. + Rectangle aViewBox (mpLayouter->GetPageBox(mrModel.GetPageCount())); + pWindow->SetViewOrigin (aViewBox.TopLeft()); + pWindow->SetViewSize (aViewBox.GetSize()); + + Size aPageObjectPixelSize (pWindow->LogicToPixel(mpLayouter->GetPageObjectSize())); + if (maPreviewSize != aPageObjectPixelSize && mpPreviewCache.get()!=NULL) + { + mpPreviewCache->ChangeSize(aPageObjectPixelSize); + maPreviewSize = aPageObjectPixelSize; + } + + // Iterate over all page objects and place them relative to the + // containing page. + model::PageEnumeration aPageEnumeration ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + int nIndex = 0; + while (aPageEnumeration.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + SdrPageObj* pPageObject = pDescriptor->GetPageObject(); + Rectangle aPageObjectBox (mpLayouter->GetPageObjectBox (nIndex)); + pPageObject->SetSnapRect(aPageObjectBox); + + nIndex += 1; + } + // Set the page so that it encloses all page objects. + mpPage->SetSize (aViewBox.GetSize()); + } + + InvalidatePageObjectVisibilities (); +} + + + + +void SlideSorterView::InvalidatePageObjectVisibilities (void) +{ + mbPageObjectVisibilitiesValid = false; +} + + + + +void SlideSorterView::DeterminePageObjectVisibilities (void) +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + // Set this flag to true here so that an invalidate during the + // visibility calculation can correctly invalidate it again. + mbPageObjectVisibilitiesValid = true; + + Rectangle aViewArea ( + Point(0,0), + pWindow->GetSizePixel()); + aViewArea = pWindow->PixelToLogic (aViewArea); + int nFirstIndex = + mpLayouter->GetIndexOfFirstVisiblePageObject (aViewArea); + int nLastIndex = + mpLayouter->GetIndexOfLastVisiblePageObject (aViewArea); + + // For page objects that just dropped off the visible area we + // decrease the priority of pending requests for preview bitmaps. + + int nMinIndex = ::std::min (mnFirstVisiblePageIndex, nFirstIndex); + int nMaxIndex = ::std::max (mnLastVisiblePageIndex, nLastIndex); + if (mnFirstVisiblePageIndex!=nFirstIndex || mnLastVisiblePageIndex!=nLastIndex) + mbPreciousFlagUpdatePending |= true; + model::SharedPageDescriptor pDescriptor; + view::PageObjectViewObjectContact* pContact; + for (int nIndex=nMinIndex; nIndex<=nMaxIndex; nIndex++) + { + // Determine the visibility before and after the change so that + // we can handle the page objects for which the visibility has + // changed. + bool bWasVisible = nIndex>=mnFirstVisiblePageIndex + && nIndex<=mnLastVisiblePageIndex; + bool bIsVisible = nIndex>=nFirstIndex && nIndex<=nLastIndex; + + // Get the view-object-contact. + if (bWasVisible != bIsVisible) + { + pContact = NULL; + pDescriptor = mrModel.GetPageDescriptor(nIndex); + if (pDescriptor.get() != NULL) + pContact = pDescriptor->GetViewObjectContact(); + + if (pDescriptor.get() != NULL) + pDescriptor->SetVisible (bIsVisible); + } + + } + mnFirstVisiblePageIndex = nFirstIndex; + mnLastVisiblePageIndex = nLastIndex; + } +} + + + + +void SlideSorterView::UpdatePreciousFlags (void) +{ + if (mbPreciousFlagUpdatePending) + { + mbPreciousFlagUpdatePending = false; + + model::SharedPageDescriptor pDescriptor; + ::boost::shared_ptr<cache::PageCache> pCache = GetPreviewCache(); + sal_Int32 nPageCount (mrModel.GetPageCount()); + + for (int nIndex=0; nIndex<=nPageCount; ++nIndex) + { + pDescriptor = mrModel.GetPageDescriptor(nIndex); + if (pDescriptor.get() != NULL) + { + pCache->SetPreciousFlag( + pDescriptor->GetPage(), + (nIndex>=mnFirstVisiblePageIndex && nIndex<=mnLastVisiblePageIndex)); + SSCD_SET_VISIBILITY(mrModel.GetDocument(), nIndex, + (nIndex>=mnFirstVisiblePageIndex && nIndex<=mnLastVisiblePageIndex)); + } + else + { + // At least one cache entry can not be updated. Remember to + // repeat the whole updating later and leave the loop now. + mbPreciousFlagUpdatePending = true; + break; + } + } + } +} + + + + +void SlideSorterView::SetOrientation (const Orientation eOrientation) +{ + meOrientation = eOrientation; + RequestRepaint(); +} + + + + +SlideSorterView::Orientation SlideSorterView::GetOrientation (void) const +{ + return meOrientation; +} + + + + +void SlideSorterView::RequestRepaint (void) +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + pWindow->Invalidate(); +} + + + + +void SlideSorterView::RequestRepaint (const model::SharedPageDescriptor& rpDescriptor) +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + pWindow->Invalidate( + GetPageBoundingBox ( + rpDescriptor, + CS_MODEL, + BBT_INFO)); +} + + + + +Rectangle SlideSorterView::GetModelArea (void) +{ + return Rectangle ( + Point (0,0), + Size (mpPage->GetSize().Width(),mpPage->GetSize().Height())); +} + + + + +Rectangle SlideSorterView::GetPageBoundingBox ( + const model::SharedPageDescriptor& rpDescriptor, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const +{ + Rectangle aBBox; + SdrObject* pPageObject = rpDescriptor->GetPageObject(); + if (pPageObject != NULL) + { + aBBox = pPageObject->GetCurrentBoundRect(); + AdaptBoundingBox (aBBox, eCoordinateSystem, eBoundingBoxType); + } + + return aBBox; +} + + + + +Rectangle SlideSorterView::GetPageBoundingBox ( + sal_Int32 nIndex, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const +{ + Rectangle aBBox; + if (nIndex >= 0 && nIndex<mrModel.GetPageCount()) + { + aBBox = mpLayouter->GetPageObjectBox(nIndex); + AdaptBoundingBox (aBBox, eCoordinateSystem, eBoundingBoxType); + } + + return aBBox; +} + + + + +void SlideSorterView::CompleteRedraw(OutputDevice* pDevice, const Region& rPaintArea, sdr::contact::ViewObjectContactRedirector* pRedirector) +{ + if (mnLockRedrawSmph == 0) + { + // Update the page visibilities when they have been invalidated. + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + + if (mbPreciousFlagUpdatePending) + UpdatePreciousFlags(); + + // Call the base class InitRedraw even when re-drawing is locked to + // let it remember the request for a redraw. + View::CompleteRedraw (pDevice, rPaintArea, pRedirector); + } + else + { + // In sd::View::CompleteRedraw() this call is recorded and given + // region is painted when the view is unlocked. + View::CompleteRedraw (pDevice, rPaintArea, pRedirector); + } +} + + + + +void SlideSorterView::InvalidateOneWin (::Window& rWindow) +{ + // if ( IsInvalidateAllowed() ) + View::InvalidateOneWin (rWindow); +} + + + + +void SlideSorterView::InvalidateOneWin ( + ::Window& rWindow, + const Rectangle& rPaintArea) +{ + // if( IsInvalidateAllowed() ) + View::InvalidateOneWin (rWindow, rPaintArea); +} + + + + +::sd::Window* SlideSorterView::GetWindow (void) const +{ + return static_cast< ::sd::Window*>(GetFirstOutputDevice()); +} + + + + +void SlideSorterView::AdaptBoundingBox ( + Rectangle& rModelPageObjectBoundingBox, + CoordinateSystem eCoordinateSystem, + BoundingBoxType eBoundingBoxType) const +{ + CoordinateSystem aCurrentCoordinateSystem = CS_MODEL; + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL) + { + if (eBoundingBoxType == BBT_INFO) + { + // Make the box larger so that it encloses all relevant + // displayed information. + if (aCurrentCoordinateSystem == CS_MODEL) + { + // The relevant offsets are given in pixel values. Therefore + // transform the box first into screen coordinates. + rModelPageObjectBoundingBox + = pWindow->LogicToPixel (rModelPageObjectBoundingBox); + aCurrentCoordinateSystem = CS_SCREEN; + } + rModelPageObjectBoundingBox.Left() -= maPagePixelBorder.Left(); + rModelPageObjectBoundingBox.Right() += maPagePixelBorder.Right(); + rModelPageObjectBoundingBox.Top() -= maPagePixelBorder.Top(); + rModelPageObjectBoundingBox.Bottom() += maPagePixelBorder.Bottom(); + } + + // Make sure that the bounding box is given in the correct coordinate + // system. + if (eCoordinateSystem != aCurrentCoordinateSystem) + { + if (eCoordinateSystem == CS_MODEL) + rModelPageObjectBoundingBox + = pWindow->PixelToLogic (rModelPageObjectBoundingBox); + else + rModelPageObjectBoundingBox + = pWindow->LogicToPixel (rModelPageObjectBoundingBox); + } + } +} + + + + +::boost::shared_ptr<cache::PageCache> SlideSorterView::GetPreviewCache (void) +{ + ::sd::Window* pWindow = GetWindow(); + if (pWindow != NULL && mpPreviewCache.get() == NULL) + { + maPreviewSize = pWindow->LogicToPixel(mpLayouter->GetPageObjectSize()); + mpPreviewCache.reset( + new cache::PageCache( + maPreviewSize, + cache::SharedCacheContext(new ViewCacheContext(mrSlideSorter.GetModel(), *this)))); + } + + return mpPreviewCache; +} + + + + +ViewOverlay& SlideSorterView::GetOverlay (void) +{ + return *mpViewOverlay.get(); +} + + + + +::sdr::contact::ObjectContact& SlideSorterView::GetObjectContact (void) const +{ + return GetSdrPageView()->GetPageWindow(0)->GetObjectContact(); +} + + + + +SlideSorterView::PageRange SlideSorterView::GetVisiblePageRange (void) +{ + const int nMaxPageIndex (mrModel.GetPageCount() - 1); + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + return PageRange( + ::std::min(mnFirstVisiblePageIndex,nMaxPageIndex), + ::std::min(mnLastVisiblePageIndex, nMaxPageIndex)); +} + + + + +void SlideSorterView::Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) +{ + ::sd::DrawDocShell* pDocShell = mrModel.GetDocument()->GetDocSh(); + if (pDocShell!=NULL && pDocShell->IsEnableSetModified()) + mbModelChangedWhileModifyEnabled = true; + + ::sd::View::Notify(rBroadcaster, rHint); +} + + + + +void SlideSorterView::UpdatePageBorders (void) +{ + maPagePixelBorder = SvBorder(); + ::sd::Window* pWindow = GetWindow(); + if (mrModel.GetPageCount()>0 && pWindow!=NULL) + { + // Calculate the border in model coordinates. + maPageNumberAreaModelSize = PageObjectViewObjectContact::CalculatePageNumberAreaModelSize ( + pWindow, + mrModel.GetPageCount()); + maModelBorder = PageObjectViewObjectContact::CalculatePageModelBorder ( + pWindow, + mrModel.GetPageCount()); + + // Depending on values in the global properties the border has to be + // extended a little bit. + ::boost::shared_ptr<controller::Properties> pProperties( + mrSlideSorter.GetController().GetProperties()); + if (pProperties.get()!=NULL && pProperties->IsHighlightCurrentSlide()) + { + Size aBorderSize (pWindow->PixelToLogic (Size(3,3))); + maModelBorder.Left() += aBorderSize.Width(); + maModelBorder.Right() += aBorderSize.Width(); + maModelBorder.Top() += aBorderSize.Height(); + maModelBorder.Bottom() += aBorderSize.Height(); + } + + // Set the border at all page descriptors so that the contact + // objects have access to them. + model::PageEnumeration aPageEnumeration ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aPageEnumeration.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + pDescriptor->SetModelBorder(maModelBorder); + pDescriptor->SetPageNumberAreaModelSize(maPageNumberAreaModelSize); + } + + // Convert the borders to pixel coordinates and store them for later + // use. + Size aTopLeftBorders(pWindow->LogicToPixel( + Size (maModelBorder.Left(), maModelBorder.Top()))); + Size aBottomRightBorders(pWindow->LogicToPixel( + Size (maModelBorder.Right(), maModelBorder.Bottom()))); + maPagePixelBorder = SvBorder ( + aTopLeftBorders.Width(), + aTopLeftBorders.Height(), + aBottomRightBorders.Width(), + aBottomRightBorders.Height()); + } + + // Finally tell the layouter about the borders. + mpLayouter->SetBorders (2,5,4,5); + mpLayouter->SetPageBorders ( + maPagePixelBorder.Left(), + maPagePixelBorder.Right(), + maPagePixelBorder.Top(), + maPagePixelBorder.Bottom()); +} + + + + +Size SlideSorterView::GetPageNumberAreaModelSize (void) const +{ + return maPageNumberAreaModelSize; +} + + + + +SvBorder SlideSorterView::GetModelBorder (void) const +{ + return maModelBorder; +} + + + + +void SlideSorterView::AddSdrObject (SdrObject& rObject) +{ + mpPage->InsertObject(&rObject); + rObject.SetModel(&maPageModel); +} + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsFontProvider.cxx b/sd/source/ui/slidesorter/view/SlsFontProvider.cxx new file mode 100644 index 000000000000..a422f4031eae --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsFontProvider.cxx @@ -0,0 +1,135 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsFontProvider.cxx,v $ + * $Revision: 1.8 $ + * + * 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_sd.hxx" + +#include "view/SlsFontProvider.hxx" + +#include "controller/SlideSorterController.hxx" + +#include <sfx2/app.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> + + +using namespace ::sd::slidesorter; + +namespace sd { namespace slidesorter { namespace view { + +FontProvider* FontProvider::mpInstance = NULL; + +FontProvider& FontProvider::Instance (void) +{ + if (mpInstance == NULL) + { + ::osl::GetGlobalMutex aMutexFunctor; + ::osl::MutexGuard aGuard (aMutexFunctor()); + if (mpInstance == NULL) + { + // Create an instance of the class and register it at the + // SdGlobalResourceContainer so that it is eventually released. + FontProvider* pInstance = new FontProvider(); + SdGlobalResourceContainer::Instance().AddResource ( + ::std::auto_ptr<SdGlobalResource>(pInstance)); + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + mpInstance = pInstance; + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + + // We throw an exception when for some strange reason no instance of + // this class exists. + if (mpInstance == NULL) + throw ::com::sun::star::uno::RuntimeException(::rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("com.sun.star.document.IndexedPropertyValues")), + NULL); + + return *mpInstance; +} + + + + +FontProvider::FontProvider (void) + : maFont(), + maMapMode() +{ +} + + + + +FontProvider::~FontProvider (void) +{ +} + + + + +void FontProvider::Invalidate (void) +{ + maFont.reset(); +} + + + + +FontProvider::SharedFontPointer FontProvider::GetFont (const OutputDevice& rDevice) +{ + // Reset the font when the map mode has changed since its creation. + if (maMapMode != rDevice.GetMapMode()) + maFont.reset(); + + if (maFont.get() == NULL) + { + // Initialize the font from the application style settings. + maFont.reset(new Font (Application::GetSettings().GetStyleSettings().GetAppFont())); + maFont->SetTransparent(TRUE); + maFont->SetWeight(WEIGHT_NORMAL); + + // Transform the point size to pixel size. + MapMode aFontMapMode (MAP_POINT); + Size aFontSize (rDevice.LogicToPixel(maFont->GetSize(), aFontMapMode)); + + // Transform the font size to the logical coordinates of the device. + maFont->SetSize (rDevice.PixelToLogic(aFontSize)); + + // Remember the map mode of the given device to detect different + // devices or modified zoom scales on future calls. + maMapMode = rDevice.GetMapMode(); + } + + return maFont; +} + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsLayouter.cxx b/sd/source/ui/slidesorter/view/SlsLayouter.cxx new file mode 100644 index 000000000000..f3d91fff96dd --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayouter.cxx @@ -0,0 +1,816 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsLayouter.cxx,v $ + * $Revision: 1.11 $ + * + * 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 "precompiled_sd.hxx" + +#include "view/SlsLayouter.hxx" + +#include <vcl/outdev.hxx> +#include <rtl/math.hxx> + +namespace sd { namespace slidesorter { namespace view { + +Layouter::Layouter (void) + : mnRequestedLeftBorder(10), + mnRequestedRightBorder(10), + mnRequestedTopBorder(10), + mnRequestedBottomBorder(10), + mnLeftBorder(10), + mnRightBorder(10), + mnTopBorder(10), + mnBottomBorder(10), + mnLeftPageBorder(0), + mnRightPageBorder(0), + mnTopPageBorder(0), + mnBottomPageBorder(0), + mnVerticalGap (20), + mnHorizontalGap (20), + mnInsertionMarkerThickness (4), + mnTotalVerticalGap(0), + mnTotalHorizontalGap(0), + mnMinimalWidth (100), + mnPreferredWidth (200), + mnMaximalWidth (300), + mnMinimalColumnCount (1), + mnMaximalColumnCount (5), + mnColumnCount (1), + maPageObjectModelSize (1,1), + maPageObjectPixelSize (1,1) +{ +} + + + + +Layouter::~Layouter (void) +{ +} + + +void Layouter::SetObjectWidth ( + sal_Int32 nMinimalWidth, + sal_Int32 nMaximalWidth, + sal_Int32 nPreferredWidth) +{ + if (nMinimalWidth <= nPreferredWidth && nPreferredWidth <= nMaximalWidth) + { + mnMinimalWidth = nMinimalWidth; + mnPreferredWidth = nMaximalWidth; + mnMaximalWidth = nPreferredWidth; + } +} + + + + +void Layouter::SetBorders ( + sal_Int32 nLeftBorder, + sal_Int32 nRightBorder, + sal_Int32 nTopBorder, + sal_Int32 nBottomBorder) +{ + if (nLeftBorder >= 0) + mnRequestedLeftBorder.mnScreen = nLeftBorder; + if (nRightBorder >= 0) + mnRequestedRightBorder.mnScreen = nRightBorder; + if (nTopBorder >= 0) + mnRequestedTopBorder.mnScreen = nTopBorder; + if (nBottomBorder >= 0) + mnRequestedBottomBorder.mnScreen = nBottomBorder; +} + + + + +void Layouter::SetPageBorders ( + sal_Int32 nLeftBorder, + sal_Int32 nRightBorder, + sal_Int32 nTopBorder, + sal_Int32 nBottomBorder) +{ + if (nLeftBorder >= 0) + mnLeftPageBorder.mnScreen = nLeftBorder; + if (nRightBorder >= 0) + mnRightPageBorder.mnScreen = nRightBorder; + if (nTopBorder >= 0) + mnTopPageBorder.mnScreen = nTopBorder; + if (nBottomBorder >= 0) + mnBottomPageBorder.mnScreen = nBottomBorder; +} + + + + +void Layouter::SetGaps ( + sal_Int32 nHorizontalGap, + sal_Int32 nVerticalGap) +{ + if (nHorizontalGap >= 0) + mnHorizontalGap.mnScreen = nHorizontalGap; + if (nVerticalGap >= 0) + mnVerticalGap.mnScreen = nVerticalGap; +} + + + + + +void Layouter::SetColumnCount ( + sal_Int32 nMinimalColumnCount, + sal_Int32 nMaximalColumnCount) +{ + if (nMinimalColumnCount <= nMaximalColumnCount) + { + mnMinimalColumnCount = nMinimalColumnCount; + mnMaximalColumnCount = nMaximalColumnCount; + } +} + + + + +bool Layouter::RearrangeHorizontal ( + const Size& rWindowSize, + const Size& rPageObjectSize, + OutputDevice* pDevice, + const sal_uInt32 nPageCount) +{ + if (rWindowSize.Width() > 0 + && rWindowSize.Height() > 0 + && rPageObjectSize.Width() > 0 + && rPageObjectSize.Height() > 0) + { + mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen + + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen; + mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen + + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen; + + // Calculate the column count. + mnColumnCount = nPageCount; + + // Update the border values. The insertion marker has to have space. + mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen; + mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen; + mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen; + mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen; + if (mnColumnCount > 1) + { + int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen + + mnHorizontalGap.mnScreen/2; + if (mnLeftBorder.mnScreen < nMinimumBorderWidth) + mnLeftBorder.mnScreen = nMinimumBorderWidth; + if (mnRightBorder.mnScreen < nMinimumBorderWidth) + mnRightBorder.mnScreen = nMinimumBorderWidth; + } + else + { + int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen + + mnVerticalGap.mnScreen/2; + if (mnTopBorder.mnScreen < nMinimumBorderHeight) + mnTopBorder.mnScreen = nMinimumBorderHeight; + if (mnBottomBorder.mnScreen < nMinimumBorderHeight) + mnBottomBorder.mnScreen = nMinimumBorderHeight; + } + + // Calculate the width of each page object. + sal_uInt32 nTargetHeight = 0; + sal_uInt32 nRowCount = 1; + if (mnColumnCount > 0) + nTargetHeight = (rWindowSize.Height() + - mnTopBorder.mnScreen + - mnBottomBorder.mnScreen + - nRowCount * (mnTopPageBorder.mnScreen + + mnBottomPageBorder.mnScreen) + - (nRowCount-1) * mnTotalVerticalGap.mnScreen + ) + / nRowCount; + sal_uInt32 nMinimalHeight ( + mnMinimalWidth * rPageObjectSize.Height() / rPageObjectSize.Width()); + sal_uInt32 nMaximalHeight ( + mnMaximalWidth * rPageObjectSize.Height() / rPageObjectSize.Width()); + if (nTargetHeight < nMinimalHeight) + nTargetHeight = nMinimalHeight; + if (nTargetHeight > nMaximalHeight) + nTargetHeight = nMaximalHeight; + + // Initialize the device with some arbitrary zoom factor just in + // case that the current zoom factor is numerically instable when + // used in a multiplication. + MapMode aMapMode (pDevice->GetMapMode()); + aMapMode.SetScaleX (Fraction(1,1)); + aMapMode.SetScaleY (Fraction(1,1)); + pDevice->SetMapMode (aMapMode); + + // Calculate the resulting scale factor and the page object size in + // pixels. + maPageObjectModelSize = rPageObjectSize; + int nPagePixelHeight (pDevice->LogicToPixel(maPageObjectModelSize).Height()); + + // Adapt the layout of the given output device to the new layout of + // page objects. The zoom factor is set so that the page objects in + // one column fill the screen. + Fraction aScaleFactor (nTargetHeight, nPagePixelHeight); + SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice); + + return true; + } + else + return false; +} + + + + +bool Layouter::RearrangeVertical ( + const Size& rWindowSize, + const Size& rPageObjectSize, + OutputDevice* pDevice) +{ + if (rWindowSize.Width() > 0 + && rWindowSize.Height() > 0 + && rPageObjectSize.Width() > 0 + && rPageObjectSize.Height() > 0) + { + mnTotalHorizontalGap.mnScreen = mnHorizontalGap.mnScreen + + mnRightPageBorder.mnScreen + mnLeftPageBorder.mnScreen; + mnTotalVerticalGap.mnScreen = mnVerticalGap.mnScreen + + mnTopPageBorder.mnScreen + mnBottomPageBorder.mnScreen; + + // Calculate the column count. + mnColumnCount = (rWindowSize.Width() + - mnRequestedLeftBorder.mnScreen - mnRequestedRightBorder.mnScreen) + / (mnPreferredWidth + mnTotalHorizontalGap.mnScreen); + if (mnColumnCount < mnMinimalColumnCount) + mnColumnCount = mnMinimalColumnCount; + if (mnColumnCount > mnMaximalColumnCount) + mnColumnCount = mnMaximalColumnCount; + + // Update the border values. The insertion marker has to have space. + mnLeftBorder.mnScreen = mnRequestedLeftBorder.mnScreen; + mnTopBorder.mnScreen = mnRequestedTopBorder.mnScreen; + mnRightBorder.mnScreen = mnRequestedRightBorder.mnScreen; + mnBottomBorder.mnScreen = mnRequestedBottomBorder.mnScreen; + if (mnColumnCount > 1) + { + int nMinimumBorderWidth = mnInsertionMarkerThickness.mnScreen + + mnHorizontalGap.mnScreen/2; + if (mnLeftBorder.mnScreen < nMinimumBorderWidth) + mnLeftBorder.mnScreen = nMinimumBorderWidth; + if (mnRightBorder.mnScreen < nMinimumBorderWidth) + mnRightBorder.mnScreen = nMinimumBorderWidth; + } + else + { + int nMinimumBorderHeight = mnInsertionMarkerThickness.mnScreen + + mnVerticalGap.mnScreen/2; + if (mnTopBorder.mnScreen < nMinimumBorderHeight) + mnTopBorder.mnScreen = nMinimumBorderHeight; + if (mnBottomBorder.mnScreen < nMinimumBorderHeight) + mnBottomBorder.mnScreen = nMinimumBorderHeight; + } + + // Calculate the width of each page object. + sal_Int32 nTargetWidth = 0; + if (mnColumnCount > 0) + nTargetWidth = (rWindowSize.Width() + - mnLeftBorder.mnScreen + - mnRightBorder.mnScreen + - mnColumnCount * (mnRightPageBorder.mnScreen + + mnLeftPageBorder.mnScreen) + - (mnColumnCount-1) * mnTotalHorizontalGap.mnScreen + ) + / mnColumnCount; + if (nTargetWidth < mnMinimalWidth) + nTargetWidth = mnMinimalWidth; + if (nTargetWidth > mnMaximalWidth) + nTargetWidth = mnMaximalWidth; + + // Initialize the device with some arbitrary zoom factor just in + // case that the current zoom factor is numerically instable when + // used in a multiplication. + MapMode aMapMode (pDevice->GetMapMode()); + aMapMode.SetScaleX (Fraction(1,1)); + aMapMode.SetScaleY (Fraction(1,1)); + pDevice->SetMapMode (aMapMode); + + // Calculate the resulting scale factor and the page object size in + // pixels. + maPageObjectModelSize = rPageObjectSize; + int nPagePixelWidth (pDevice->LogicToPixel (maPageObjectModelSize).Width()); + + // Adapt the layout of the given output device to the new layout of + // page objects. The zoom factor is set so that the page objects in + // one row fill the screen. + Fraction aScaleFactor (nTargetWidth, nPagePixelWidth); + SetZoom (aMapMode.GetScaleX() * aScaleFactor, pDevice); + + return true; + } + else + return false; +} + + + + +void Layouter::SetZoom (double nZoomFactor, OutputDevice* pDevice) +{ + SetZoom(Fraction(nZoomFactor), pDevice); +} + + + + +void Layouter::SetZoom (Fraction nZoomFactor, OutputDevice* pDevice) +{ + MapMode aMapMode (pDevice->GetMapMode()); + aMapMode.SetScaleX (nZoomFactor); + aMapMode.SetScaleY (nZoomFactor); + maPageObjectPixelSize = pDevice->LogicToPixel (maPageObjectModelSize); + pDevice->SetMapMode (aMapMode); + + // Transform frequently used values from pixel to model coordinates. + + Size aTotalGap (pDevice->PixelToLogic (Size ( + mnTotalHorizontalGap.mnScreen, + mnTotalVerticalGap.mnScreen))); + mnTotalHorizontalGap.mnModel = aTotalGap.Width(); + mnTotalVerticalGap.mnModel = aTotalGap.Height(); + + Size aGap (pDevice->PixelToLogic (Size ( + mnHorizontalGap.mnScreen, + mnVerticalGap.mnScreen))); + mnHorizontalGap.mnModel = aGap.Width(); + mnVerticalGap.mnModel = aGap.Height(); + + Size aTopLeftBorder (pDevice->PixelToLogic (Size ( + mnLeftBorder.mnScreen, + mnTopBorder.mnScreen))); + mnLeftBorder.mnModel = aTopLeftBorder.Width(); + mnTopBorder.mnModel = aTopLeftBorder.Height(); + + Size aBottomRightBorder (pDevice->PixelToLogic (Size ( + mnLeftBorder.mnScreen, + mnTopBorder.mnScreen))); + mnRightBorder.mnModel = aBottomRightBorder.Width(); + mnBottomBorder.mnModel = aBottomRightBorder.Height(); + + Size aTopLeftPageBorder (pDevice->PixelToLogic (Size ( + mnLeftPageBorder.mnScreen, + mnTopPageBorder.mnScreen))); + mnLeftPageBorder.mnModel = aTopLeftPageBorder.Width(); + mnTopPageBorder.mnModel = aTopLeftPageBorder.Height(); + + Size aBottomRightPageBorder (pDevice->PixelToLogic (Size ( + mnRightPageBorder.mnScreen, + mnBottomPageBorder.mnScreen))); + mnRightPageBorder.mnModel = aBottomRightPageBorder.Width(); + mnBottomPageBorder.mnModel = aBottomRightPageBorder.Height(); + + mnInsertionMarkerThickness.mnModel = pDevice->PixelToLogic ( + Size(mnInsertionMarkerThickness.mnScreen,0)).Width(); +} + + + + +sal_Int32 Layouter::GetColumnCount (void) const +{ + return mnColumnCount; +} + + + + +bool Layouter::IsColumnCountFixed (void) const +{ + return mnMinimalColumnCount == mnMaximalColumnCount; +} + + + + +Size Layouter::GetPageObjectSize (void) const +{ + return maPageObjectModelSize; +} + + + + +Rectangle Layouter::GetPageObjectBox (sal_Int32 nIndex) const +{ + int nColumn = nIndex % mnColumnCount; + int nRow = nIndex / mnColumnCount; + return Rectangle ( + Point (mnLeftBorder.mnModel + + nColumn * maPageObjectModelSize.Width() + + mnLeftPageBorder.mnModel + + (nColumn>0 ? nColumn : 0) * mnTotalHorizontalGap.mnModel, + mnTopBorder.mnModel + + nRow * maPageObjectModelSize.Height() + + mnTopPageBorder.mnModel + + (nRow>0 ? nRow : 0) * mnTotalVerticalGap.mnModel), + maPageObjectModelSize); +} + + + + +Rectangle Layouter::GetPageBox (sal_Int32 nObjectCount) const +{ + sal_Int32 nHorizontalSize = 0; + sal_Int32 nVerticalSize = 0; + if (mnColumnCount > 0) + { + sal_Int32 nRowCount = (nObjectCount+mnColumnCount-1) / mnColumnCount; + nHorizontalSize = + mnLeftBorder.mnModel + + mnRightBorder.mnModel + + mnColumnCount * maPageObjectModelSize.Width() + + mnLeftPageBorder.mnModel + mnRightPageBorder.mnModel; + if (mnColumnCount > 1) + nHorizontalSize + += (mnColumnCount-1) * mnTotalHorizontalGap.mnModel; + nVerticalSize = + mnTopBorder.mnModel + + mnBottomBorder.mnModel + + nRowCount * maPageObjectModelSize.Height() + + mnTopPageBorder.mnModel + mnBottomPageBorder.mnModel; + if (nRowCount > 1) + nVerticalSize += (nRowCount-1) * mnTotalVerticalGap.mnModel; + } + + return Rectangle ( + Point(0,0), + Size (nHorizontalSize, nVerticalSize) + ); +} + + + + +Rectangle Layouter::GetInsertionMarkerBox ( + sal_Int32 nIndex, + bool bVertical, + bool bLeftOrTop) const +{ + Rectangle aBox (GetPageObjectBox (nIndex)); + + if (bVertical) + { + sal_Int32 nHorizontalInsertionMarkerOffset + = (mnHorizontalGap.mnModel-mnInsertionMarkerThickness.mnModel) / 2; + if (bLeftOrTop) + { + // Left. + aBox.Left() -= mnLeftPageBorder.mnModel + + mnHorizontalGap.mnModel + - nHorizontalInsertionMarkerOffset; + } + else + { + // Right. + aBox.Left() = aBox.Right() + + mnRightPageBorder.mnModel + + nHorizontalInsertionMarkerOffset; + } + aBox.Right() = aBox.Left() + mnInsertionMarkerThickness.mnModel; + } + else + { + sal_Int32 nVerticalInsertionMarkerOffset + = (mnVerticalGap.mnModel - mnInsertionMarkerThickness.mnModel) / 2; + if (bLeftOrTop) + { + // Above. + aBox.Top() -= mnTopPageBorder.mnModel + + mnVerticalGap.mnModel + - nVerticalInsertionMarkerOffset; + } + else + { + // Below. + aBox.Top() = aBox.Bottom() + + mnBottomPageBorder.mnModel + + nVerticalInsertionMarkerOffset; + } + aBox.Bottom() = aBox.Top() + mnInsertionMarkerThickness.mnModel; + } + + return aBox; +} + + + + +sal_Int32 Layouter::GetIndexOfFirstVisiblePageObject ( + const Rectangle& aVisibleArea) const +{ + sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Top(), true, GM_BOTH); + return nRow * mnColumnCount; +} + + + + +sal_Int32 Layouter::GetIndexOfLastVisiblePageObject ( + const Rectangle& aVisibleArea) const +{ + sal_Int32 nRow = GetRowAtPosition (aVisibleArea.Bottom(), + true, GM_BOTH); + return (nRow+1) * mnColumnCount - 1; +} + + + + +sal_Int32 Layouter::GetIndexAtPoint ( + const Point& rPosition, + bool bIncludePageBorders) const +{ + sal_Int32 nRow = GetRowAtPosition (rPosition.Y(), + bIncludePageBorders, + bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE); + sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(), + bIncludePageBorders, + bIncludePageBorders ? GM_PAGE_BORDER : GM_NONE); + + if (nRow >= 0 && nColumn >= 0) + return nRow * mnColumnCount + nColumn; + else + return -1; +} + + + + +/** Calculation of the insertion index: + 1. Determine the row. rPoint has to be in the row between upper and + lower border. If it is in a horizontal gap or border an invalid + insertion index (-1, which is a valid return value) will be returned. + 2. Determine the column. Here both vertical borders and vertical gaps + will yield valid return values. The horizontal positions between the + center of page objects in column i and the center of page objects in + column i+1 will return column i+1 as insertion index. + + When there is only one column and bAllowVerticalPosition is true than + take the vertical areas between rows into account as well. +*/ +sal_Int32 Layouter::GetInsertionIndex ( + const Point& rPosition, + bool bAllowVerticalPosition) const +{ + sal_Int32 nIndex = -1; + + sal_Int32 nRow = GetRowAtPosition (rPosition.Y(), true, + (mnColumnCount==1 && bAllowVerticalPosition) ? GM_BOTH : GM_BOTH); + sal_Int32 nColumn = GetColumnAtPosition (rPosition.X(), true, GM_BOTH); + + if (nRow >= 0 && nColumn >= 0) + nIndex = nRow * mnColumnCount + nColumn; + + return nIndex; +} + + + + +Layouter::DoublePoint + Layouter::ConvertModelToLayouterCoordinates ( + const Point& rModelPoint) const +{ + sal_Int32 nColumn = GetColumnAtPosition (rModelPoint.X(), true, GM_BOTH); + sal_Int32 nColumnWidth + = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel; + sal_Int32 nDistanceIntoColumn = + rModelPoint.X() - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel + - nColumn * nColumnWidth; + + sal_Int32 nRow = GetRowAtPosition (rModelPoint.Y(), true, GM_BOTH); + sal_Int32 nRowHeight + = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel; + sal_Int32 nDistanceIntoRow = + rModelPoint.Y() - mnTopBorder.mnModel - mnTopPageBorder.mnModel + - nRow * nRowHeight; + + return DoublePoint ( + nColumn + double(nDistanceIntoColumn) / double(nColumnWidth), + nRow + double(nDistanceIntoRow) / double(nRowHeight)); +} + + + + +Point Layouter::ConvertLayouterToModelCoordinates ( + const DoublePoint & rLayouterPoint) const +{ + sal_Int32 nColumn = (sal_Int32) ::rtl::math::round(rLayouterPoint.first, + 0,rtl_math_RoundingMode_Floor); + sal_Int32 nColumnWidth + = maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel; + sal_Int32 nDistanceIntoColumn + = (sal_Int32)((rLayouterPoint.first - nColumn) * nColumnWidth); + + sal_Int32 nRow = (sal_Int32) ::rtl::math::round(rLayouterPoint.second, + 0,rtl_math_RoundingMode_Floor); + sal_Int32 nRowHeight + = maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel; + sal_Int32 nDistanceIntoRow + = (sal_Int32)((rLayouterPoint.second - nRow) * nRowHeight); + + return Point ( + mnLeftBorder.mnModel + mnLeftPageBorder.mnModel + + nColumn * nColumnWidth + nDistanceIntoColumn, + mnTopBorder.mnModel + mnTopPageBorder.mnModel + + nRow * nRowHeight + nDistanceIntoRow); +} + + + + +sal_Int32 Layouter::GetRowAtPosition ( + sal_Int32 nYPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership) const +{ + sal_Int32 nRow = -1; + + const sal_Int32 nY = nYPosition + - mnTopBorder.mnModel - mnTopPageBorder.mnModel; + if (nY >= 0) + { + // Vertical distance from one row to the next. + const sal_Int32 nRowOffset ( + maPageObjectModelSize.Height() + mnTotalVerticalGap.mnModel); + + // Calculate row consisting of page objects and gap below. + nRow = nY / nRowOffset; + + const sal_Int32 nDistanceIntoGap ( + (nY - nRow*nRowOffset) - maPageObjectModelSize.Height()); + // When inside the gap below then nYPosition is not over a page + // object. + if (nDistanceIntoGap > 0) + nRow = ResolvePositionInGap ( + nDistanceIntoGap, + eGapMembership, + nRow, + mnBottomPageBorder.mnModel, + mnVerticalGap.mnModel); + } + else if (bIncludeBordersAndGaps) + { + // We are in the top border area. Set nRow to the first row when + // the top border shall be considered to belong to the first row. + nRow = 0; + } + + return nRow; +} + + + + +sal_Int32 Layouter::GetColumnAtPosition ( + sal_Int32 nXPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership) const +{ + sal_Int32 nColumn = -1; + + sal_Int32 nX = nXPosition + - mnLeftBorder.mnModel - mnLeftPageBorder.mnModel; + if (nX >= 0) + { + // Horizontal distance from one column to the next. + const sal_Int32 nColumnOffset ( + maPageObjectModelSize.Width() + mnTotalHorizontalGap.mnModel); + + // Calculate row consisting of page objects and gap below. + nColumn = nX / nColumnOffset; + if (nColumn < 0) + nColumn = 0; + else if (nColumn >= mnColumnCount) + nColumn = mnColumnCount-1; + + const sal_Int32 nDistanceIntoGap ( + (nX - nColumn*nColumnOffset) - maPageObjectModelSize.Width()); + // When inside the gap at the right then nXPosition is not over a + // page object. + if (nDistanceIntoGap > 0) + nColumn = ResolvePositionInGap ( + nDistanceIntoGap, + eGapMembership, + nColumn, + mnRightPageBorder.mnModel, + mnHorizontalGap.mnModel); + } + else if (bIncludeBordersAndGaps) + { + // We are in the left border area. Set nColumn to the first column + // when the left border shall be considered to belong to the first + // column. + nColumn = 0; + } + return nColumn; +} + + + + +sal_Int32 Layouter::ResolvePositionInGap ( + sal_Int32 nDistanceIntoGap, + GapMembership eGapMembership, + sal_Int32 nIndex, + sal_Int32 nLeftOrTopPageBorder, + sal_Int32 nGap) const +{ + switch (eGapMembership) + { + case GM_NONE: + // The gap is no man's land. + nIndex = -1; + break; + + case GM_BOTH: + { + // The lower half of the gap belongs to the next row or column. + sal_Int32 nFirstHalfGapWidth = nLeftOrTopPageBorder + nGap / 2; + if (nDistanceIntoGap > nFirstHalfGapWidth) + nIndex ++; + break; + } + + case GM_PREVIOUS: + // Row or column already at correct value. + break; + + case GM_NEXT: + // The complete gap belongs to the next row or column. + nIndex ++; + break; + + case GM_PAGE_BORDER: + if (nDistanceIntoGap > nLeftOrTopPageBorder) + { + if (nDistanceIntoGap > nLeftOrTopPageBorder + nGap) + { + // Inside the border of the next row or column. + nIndex ++; + } + else + { + // Inside the gap between the page borders. + nIndex = -1; + } + } + break; + + default: + nIndex = -1; + } + + return nIndex; +} + + + + +const Layouter::BackgroundRectangleList& + Layouter::GetBackgroundRectangleList (void) const +{ + return maBackgroundRectangleList; +} + + + + +} } } // end of namespace ::sd::slidesorter::namespace diff --git a/sd/source/ui/slidesorter/view/SlsPageObject.cxx b/sd/source/ui/slidesorter/view/SlsPageObject.cxx new file mode 100644 index 000000000000..27bc2e131e9f --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObject.cxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObject.cxx,v $ + * $Revision: 1.7 $ + * + * 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_sd.hxx" + +#include "view/SlsPageObject.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "controller/SlsPageObjectFactory.hxx" + +using namespace ::sdr::contact; +using namespace ::sd::slidesorter::model; + + +namespace sd { namespace slidesorter { namespace view { + + +PageObject::PageObject ( + const Rectangle& rRectangle, + SdrPage* _pPage, + const SharedPageDescriptor& rpDescriptor) + : SdrPageObj(rRectangle, _pPage), + mpDescriptor(rpDescriptor) +{ +} + + + + +PageObject::~PageObject (void) +{ +} + + + + +SharedPageDescriptor PageObject::GetDescriptor (void) const +{ + return mpDescriptor; +} + + + + +sdr::contact::ViewContact* PageObject::CreateObjectSpecificViewContact (void) +{ + if (mpDescriptor.get() != NULL) + return mpDescriptor->GetPageObjectFactory().CreateViewContact(this, mpDescriptor); + else + return NULL; +} + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx new file mode 100644 index 000000000000..5849140f8327 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectViewContact.cxx @@ -0,0 +1,143 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObjectViewContact.cxx,v $ + * $Revision: 1.10 $ + * + * 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 "precompiled_sd.hxx" + +#include "view/SlsPageObjectViewContact.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "controller/SlsPageObjectFactory.hxx" + +#include <svx/svdopage.hxx> +#include <tools/debug.hxx> + +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> + +using namespace ::sdr::contact; + +namespace sd { namespace slidesorter { namespace view { + + +PageObjectViewContact::PageObjectViewContact ( + SdrPageObj& rPageObj, + const model::SharedPageDescriptor& rpDescriptor) + : ViewContactOfPageObj (rPageObj), + mbInDestructor(false), + mpDescriptor(rpDescriptor) +{ +} + +PageObjectViewContact::~PageObjectViewContact (void) +{ + // remember that this instance is in destruction + mbInDestructor = true; +} + + + +ViewObjectContact& + PageObjectViewContact::CreateObjectSpecificViewObjectContact( + ObjectContact& rObjectContact) +{ + OSL_ASSERT(mpDescriptor.get()!=NULL); + + ViewObjectContact* pResult + = mpDescriptor->GetPageObjectFactory().CreateViewObjectContact ( + rObjectContact, + *this); + DBG_ASSERT (pResult!=NULL, + "PageObjectViewContact::CreateObjectSpecificViewObjectContact() was not able to create object."); + return *pResult; +} + +const SdrPage* PageObjectViewContact::GetPage (void) const +{ + // when this instance itself is in destruction, do no longer + // provide the referenced page to VOC childs of this OC. This + // happens e.g. in destructor which destroys all child-VOCs which + // may in their implementation still reference their VC from + // their own destructor + if (!mbInDestructor) + return GetReferencedPage(); + else + return NULL; +} + +void PageObjectViewContact::ActionChanged (void) +{ + ViewContactOfPageObj::ActionChanged(); +} + +Rectangle PageObjectViewContact::GetPageObjectBoundingBox (void) const +{ + // use model data directly here + OSL_ASSERT(mpDescriptor.get()!=NULL); + Rectangle aRetval(GetPageObject().GetLastBoundRect()); + const SvBorder aPageDescriptorBorder(mpDescriptor->GetModelBorder()); + + aRetval.Left() -= aPageDescriptorBorder.Left(); + aRetval.Top() -= aPageDescriptorBorder.Top(); + aRetval.Right() += aPageDescriptorBorder.Right(); + aRetval.Bottom() += aPageDescriptorBorder.Bottom(); + + return aRetval; +} + +SdrPageObj& PageObjectViewContact::GetPageObject (void) const +{ + return ViewContactOfPageObj::GetPageObj(); +} + +drawinglayer::primitive2d::Primitive2DSequence PageObjectViewContact::createViewIndependentPrimitive2DSequence() const +{ + // ceate graphical visualisation data. Since this is the view-independent version which should not be used, + // create a replacement graphic visualisation here. Use GetLastBoundRect to access the model data directly + // which is aOutRect for SdrPageObj. + OSL_ASSERT(mpDescriptor.get()!=NULL); + Rectangle aModelRectangle(GetPageObj().GetLastBoundRect()); + const SvBorder aBorder(mpDescriptor->GetModelBorder()); + + aModelRectangle.Left() -= aBorder.Left(); + aModelRectangle.Right() += aBorder.Right(); + aModelRectangle.Top() -= aBorder.Top(); + aModelRectangle.Bottom() += aBorder.Bottom(); + + const basegfx::B2DRange aModelRange(aModelRectangle.Left(), aModelRectangle.Top(), aModelRectangle.Right(), aModelRectangle.Bottom()); + const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aModelRange)); + const basegfx::BColor aYellow(1.0, 1.0, 0.0); + const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow)); + + return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); +} + +} } } // end of namespace ::sd::slidesorter::view + +// eof diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx new file mode 100644 index 000000000000..3e0d61064bdf --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectViewObjectContact.cxx @@ -0,0 +1,1416 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsPageObjectViewObjectContact.cxx,v $ + * $Revision: 1.23 $ + * + * 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 "precompiled_sd.hxx" + +#include "view/SlsPageObjectViewObjectContact.hxx" + +#include "controller/SlsProperties.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectViewContact.hxx" +#include "view/SlsPageObject.hxx" +#include "view/SlsFontProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "cache/SlsPageCache.hxx" +#include "cache/SlsPageCacheManager.hxx" +#include "res_bmp.hrc" +#include "tools/IconCache.hxx" +#include "PreviewRenderer.hxx" + +#include "sdpage.hxx" +#include "sdresid.hxx" +#include "glob.hrc" +#include "drawdoc.hxx" +#include <svx/sdr/contact/displayinfo.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <svx/svdopage.hxx> +#include <svx/svdpagv.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnclit.hxx> +#include <svx/svdoutl.hxx> +#include <svx/sdrpagewindow.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/outdev.hxx> +#include <vcl/virdev.hxx> +#include <vcl/lineinfo.hxx> +#include <tools/color.hxx> +#include <boost/shared_ptr.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <vcl/svapp.hxx> + +using namespace ::sdr::contact; +using namespace ::sd::slidesorter::model; + +using drawinglayer::primitive2d::Primitive2DReference; +using drawinglayer::primitive2d::Primitive2DSequence; + +namespace sd { namespace slidesorter { namespace view { + + +const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorOffset = 2; +const sal_Int32 PageObjectViewObjectContact::mnSelectionIndicatorThickness = 3; +const sal_Int32 PageObjectViewObjectContact::mnFocusIndicatorOffset = 3; +const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorOffset = 9; +const sal_Int32 PageObjectViewObjectContact::mnFadeEffectIndicatorSize = 14; +const sal_Int32 PageObjectViewObjectContact::mnPageNumberOffset = 9; +const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectOffset = 3; +const sal_Int32 PageObjectViewObjectContact::mnMouseOverEffectThickness = 1; + +PageObjectViewObjectContact::PageObjectViewObjectContact ( + ObjectContact& rObjectContact, + ViewContact& rViewContact, + const ::boost::shared_ptr<cache::PageCache>& rpCache, + const ::boost::shared_ptr<controller::Properties>& rpProperties) + : ViewObjectContactOfPageObj(rObjectContact, rViewContact), + mbInDestructor(false), + mxCurrentPageContents(), + mpCache(rpCache), + mpProperties(rpProperties) +{ + SharedPageDescriptor pDescriptor (GetPageDescriptor()); + OSL_ASSERT(pDescriptor.get()!=NULL); + if (pDescriptor.get() != NULL) + pDescriptor->SetViewObjectContact(this); +} + + + + +PageObjectViewObjectContact::~PageObjectViewObjectContact (void) +{ + mbInDestructor = true; + + GetPageDescriptor()->SetViewObjectContact(NULL); + + if (mpCache.get() != NULL) + { + const SdrPage* pPage = GetPage(); + + if(pPage) + { + mpCache->ReleasePreviewBitmap(GetPage()); + } + } +} + + + + +void PageObjectViewObjectContact::SetCache (const ::boost::shared_ptr<cache::PageCache>& rpCache) +{ + mpCache = rpCache; +} + + + + +Rectangle PageObjectViewObjectContact::GetBoundingBox ( + OutputDevice& rDevice, + BoundingBoxType eType, + CoordinateSystem eCoordinateSystem) const +{ + // Most of the bounding boxes are based on the bounding box of the preview. + // SdrPageObj is a SdrObject, so use SdrObject::aOutRect as model data + const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact())); + Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect()); + + CoordinateSystem eCurrentCoordinateSystem (ModelCoordinateSystem); + switch(eType) + { + case PageObjectBoundingBox: + { + const SvBorder aPageDescriptorBorder(GetPageDescriptor()->GetModelBorder()); + aBoundingBox.Left() -= aPageDescriptorBorder.Left(); + aBoundingBox.Top() -= aPageDescriptorBorder.Top(); + aBoundingBox.Right() += aPageDescriptorBorder.Right(); + aBoundingBox.Bottom() += aPageDescriptorBorder.Bottom(); + break; + } + case PreviewBoundingBox: + { + // The aBoundingBox already has the right value. + break; + } + case MouseOverIndicatorBoundingBox: + { + const sal_Int32 nBorderWidth (mnMouseOverEffectOffset+mnMouseOverEffectThickness); + const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth))); + aBoundingBox.Left() -= aBorderSize.Width(); + aBoundingBox.Top() -= aBorderSize.Height(); + aBoundingBox.Right() += aBorderSize.Width(); + aBoundingBox.Bottom() += aBorderSize.Height(); + break; + } + case FocusIndicatorBoundingBox: + { + const sal_Int32 nBorderWidth (mnFocusIndicatorOffset+1); + const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth))); + aBoundingBox.Left() -= aBorderSize.Width(); + aBoundingBox.Top() -= aBorderSize.Height(); + aBoundingBox.Right() += aBorderSize.Width(); + aBoundingBox.Bottom() += aBorderSize.Height(); + break; + } + case SelectionIndicatorBoundingBox: + { + const sal_Int32 nBorderWidth(mnSelectionIndicatorOffset+mnSelectionIndicatorThickness); + const Size aBorderSize (rDevice.PixelToLogic(Size(nBorderWidth,nBorderWidth))); + aBoundingBox.Left() -= aBorderSize.Width(); + aBoundingBox.Top() -= aBorderSize.Height(); + aBoundingBox.Right() += aBorderSize.Width(); + aBoundingBox.Bottom() += aBorderSize.Height(); + break; + } + case PageNumberBoundingBox: + { + Size aModelOffset = rDevice.PixelToLogic(Size(mnPageNumberOffset,mnPageNumberOffset)); + Size aNumberSize (GetPageDescriptor()->GetPageNumberAreaModelSize()); + aBoundingBox = Rectangle ( + Point ( + aBoundingBox.Left() - aModelOffset.Width() - aNumberSize.Width(), + aBoundingBox.Top()), + aNumberSize); + break; + } + + case NameBoundingBox: + break; + + case FadeEffectIndicatorBoundingBox: + Size aModelOffset = rDevice.PixelToLogic(Size (0, mnFadeEffectIndicatorOffset)); + // Flush left just outside the selection rectangle. + aBoundingBox = Rectangle ( + Point ( + aBoundingBox.Left(), + aBoundingBox.Bottom() + aModelOffset.Height() + ), + rDevice.PixelToLogic ( + IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR).GetSizePixel()) + ); + break; + } + + // Make sure the bounding box uses the requested coordinate system. + if (eCurrentCoordinateSystem != eCoordinateSystem) + { + if (eCoordinateSystem == ModelCoordinateSystem) + aBoundingBox = Rectangle( + rDevice.PixelToLogic(aBoundingBox.TopLeft()), + rDevice.PixelToLogic(aBoundingBox.GetSize())); + else + aBoundingBox = Rectangle( + rDevice.LogicToPixel(aBoundingBox.TopLeft()), + rDevice.LogicToPixel(aBoundingBox.GetSize())); + } + return aBoundingBox; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// example implementation for primitive usage for PageObjectViewObjectContact + +} } } // end of namespace ::sd::slidesorter::view + +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <sd_primitivetypes2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/textlayoutdevice.hxx> +#include <drawinglayer/primitive2d/textprimitive2d.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <svx/sdr/contact/objectcontact.hxx> + +namespace sd { namespace slidesorter { namespace view { + +/////////////////////////////////////////////////////////////////////////////////////////////// +// All primitives for SdrPageObject visualisation are based on one range which describes +// the size of the inner rectangle for PagePreview visualisation. Use a common implementation +// class for all derived SdPageObjectPrimitives. The SdPageObjectBasePrimitive itself +// is pure virtual + +class SdPageObjectBasePrimitive : public drawinglayer::primitive2d::BasePrimitive2D +{ +private: + // the inner range of the SdPageObject visualisation + basegfx::B2DRange maRange; + +public: + // constructor and destructor + SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange); + virtual ~SdPageObjectBasePrimitive(); + + // data access + const basegfx::B2DRange& getPageObjectRange() const { return maRange; } + + // compare operator + virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; +}; + +SdPageObjectBasePrimitive::SdPageObjectBasePrimitive(const basegfx::B2DRange& rRange) +: drawinglayer::primitive2d::BasePrimitive2D(), + maRange(rRange) +{ +} + +SdPageObjectBasePrimitive::~SdPageObjectBasePrimitive() +{ +} + +bool SdPageObjectBasePrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const +{ + if(drawinglayer::primitive2d::BasePrimitive2D::operator==(rPrimitive)) + { + const SdPageObjectBasePrimitive& rCompare = static_cast< const SdPageObjectBasePrimitive& >(rPrimitive); + return (getPageObjectRange() == rCompare.getPageObjectRange()); + } + + return false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// SdPageObjectPrimitive for selected visualisation + +class SdPageObjectPageBitmapPrimitive : public SdPageObjectBasePrimitive +{ +private: + // the bitmap containing the PagePreview + BitmapEx maBitmapEx; + +protected: + // method which is to be used to implement the local decomposition of a 2D primitive. + virtual Primitive2DSequence createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; + +public: + // constructor and destructor + SdPageObjectPageBitmapPrimitive( + const basegfx::B2DRange& rRange, + const BitmapEx& rBitmapEx); + ~SdPageObjectPageBitmapPrimitive(); + + // data access + const BitmapEx& getBitmapEx() const { return maBitmapEx; } + + // compare operator + virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; + + // provide unique ID + DeclPrimitrive2DIDBlock() +}; + +Primitive2DSequence SdPageObjectPageBitmapPrimitive::createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const +{ + // add bitmap primitive + // to avoid scaling, use the Bitmap pixel size as primitive size + basegfx::B2DHomMatrix aBitmapTransform; + const Size aBitmapSize(getBitmapEx().GetSizePixel()); + const basegfx::B2DVector aBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() * + basegfx::B2DVector(aBitmapSize.getWidth() - 1, aBitmapSize.getHeight() - 1)); + + // short form for scale and translate transformation + aBitmapTransform.set(0L, 0L, aBitmapSizeLogic.getX()); + aBitmapTransform.set(1L, 1L, aBitmapSizeLogic.getY()); + aBitmapTransform.set(0L, 2L, getPageObjectRange().getMinX()); + aBitmapTransform.set(1L, 2L, getPageObjectRange().getMinY()); + + // add a BitmapPrimitive2D to the result + const Primitive2DReference xReference( + new drawinglayer::primitive2d::BitmapPrimitive2D(getBitmapEx(), aBitmapTransform)); + return Primitive2DSequence(&xReference, 1); +} + +SdPageObjectPageBitmapPrimitive::SdPageObjectPageBitmapPrimitive( + const basegfx::B2DRange& rRange, + const BitmapEx& rBitmapEx) +: SdPageObjectBasePrimitive(rRange), + maBitmapEx(rBitmapEx) +{ +} + +SdPageObjectPageBitmapPrimitive::~SdPageObjectPageBitmapPrimitive() +{ +} + +bool SdPageObjectPageBitmapPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const +{ + if(SdPageObjectBasePrimitive::operator==(rPrimitive)) + { + const SdPageObjectPageBitmapPrimitive& rCompare = static_cast< const SdPageObjectPageBitmapPrimitive& >(rPrimitive); + return (getBitmapEx() == rCompare.getBitmapEx()); + } + + return false; +} + +ImplPrimitrive2DIDBlock(SdPageObjectPageBitmapPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTPAGEBITMAPPRIMITIVE) + +/////////////////////////////////////////////////////////////////////////////////////////////// +// SdPageObjectPrimitive for selected visualisation + +class SdPageObjectSelectPrimitive : public SdPageObjectBasePrimitive +{ +private: + /// Gap between border of page object and inside of selection rectangle. + static const sal_Int32 mnSelectionIndicatorOffset; + + /// Thickness of the selection rectangle. + static const sal_Int32 mnSelectionIndicatorThickness; + +protected: + // method which is to be used to implement the local decomposition of a 2D primitive. + virtual Primitive2DSequence createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; + +public: + // constructor and destructor + SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange); + ~SdPageObjectSelectPrimitive(); + + // provide unique ID + DeclPrimitrive2DIDBlock() +}; + +const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorOffset(1); +const sal_Int32 SdPageObjectSelectPrimitive::mnSelectionIndicatorThickness(3); + +Primitive2DSequence SdPageObjectSelectPrimitive::createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const +{ + Primitive2DSequence xRetval(2); + + // since old Width/Height calculations always added a single pixel value, + // it is necessary to create a inner range which is one display unit less + // at the bottom right. + const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); + const basegfx::B2DRange aAdaptedInnerRange( + getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), + getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); + + // PaintSelectionIndicator replacement. Grow by offset first + basegfx::B2DRange aDiscreteOuterRange(aAdaptedInnerRange); + aDiscreteOuterRange.grow(mnSelectionIndicatorOffset * aDiscretePixel.getX()); + + // Remember inner border. Make it one bigger in top left since polygons + // do not paint their lower-right corners. Since this is the inner polygon, + // the top-left corders are the ones to grow here + const basegfx::B2DRange aDiscreteInnerRange( + aDiscreteOuterRange.getMinimum() + aDiscretePixel, + aDiscreteOuterRange.getMaximum() - aDiscretePixel); + + // grow by line width + aDiscreteOuterRange.grow((mnSelectionIndicatorThickness - 1) * aDiscretePixel.getX()); + + // create a PolyPolygon from those ranges. For the outer polygon, round edges by + // giving a relative radius to the polygon creator (use mnSelectionIndicatorThickness here, too) + const double fPixelFactor(aDiscretePixel.getX() * (mnSelectionIndicatorThickness + 2.5)); + const double fRelativeRadiusX(fPixelFactor / ::std::max(aDiscreteOuterRange.getWidth(), 1.0)); + const double fRelativeRadiusY(fPixelFactor / ::std::max(aDiscreteOuterRange.getHeight(), 1.0)); + basegfx::B2DPolyPolygon aFramePolyPolygon; + const basegfx::B2DPolygon aRoundedOuterPolygon(basegfx::tools::createPolygonFromRect(aDiscreteOuterRange, fRelativeRadiusX, fRelativeRadiusY)); + + aFramePolyPolygon.append(aRoundedOuterPolygon); + aFramePolyPolygon.append(basegfx::tools::createPolygonFromRect(aDiscreteInnerRange)); + + // add colored PolyPolygon + const svtools::ColorConfig aColorConfig; + static bool bTestWithBrightColors(false); + const basegfx::BColor aFrameColor(bTestWithBrightColors ? basegfx::BColor(0,1,0) : Application::GetSettings().GetStyleSettings().GetMenuHighlightColor().getBColor()); + + xRetval[0] = Primitive2DReference( + new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(aFramePolyPolygon, aFrameColor)); + + // add aRoundedOuterPolygon again as non-filled line polygon to get the roundungs + // painted correctly + xRetval[1] = Primitive2DReference( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aRoundedOuterPolygon, aFrameColor)); + + return xRetval; +} + +SdPageObjectSelectPrimitive::SdPageObjectSelectPrimitive(const basegfx::B2DRange& rRange) +: SdPageObjectBasePrimitive(rRange) +{ +} + +SdPageObjectSelectPrimitive::~SdPageObjectSelectPrimitive() +{ +} + +ImplPrimitrive2DIDBlock(SdPageObjectSelectPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTSELECTPRIMITIVE) + +/////////////////////////////////////////////////////////////////////////////////////////////// +// SdPageObjectPrimitive for border around bitmap visualisation + +class SdPageObjectBorderPrimitive : public SdPageObjectBasePrimitive +{ +protected: + // method which is to be used to implement the local decomposition of a 2D primitive. + virtual Primitive2DSequence createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; + +public: + // constructor and destructor + SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange); + ~SdPageObjectBorderPrimitive(); + + // provide unique ID + DeclPrimitrive2DIDBlock() +}; + +Primitive2DSequence SdPageObjectBorderPrimitive::createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const +{ + // since old Width/Height calculations always added a single pixel value, + // it is necessary to create a inner range which is one display unit less + // at the bottom right. + const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); + const basegfx::B2DRange aAdaptedInnerRange( + getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), + getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); + + // Paint_Border replacement. (use aBorderColor) + static bool bTestWithBrightColors(false); + const svtools::ColorConfig aColorConfig; + const basegfx::BColor aBorderColor(bTestWithBrightColors ? basegfx::BColor(1,0,0) : Color(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor).getBColor()); + + const Primitive2DReference xReference( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(basegfx::tools::createPolygonFromRect(aAdaptedInnerRange), aBorderColor)); + return Primitive2DSequence(&xReference, 1); +} + +SdPageObjectBorderPrimitive::SdPageObjectBorderPrimitive(const basegfx::B2DRange& rRange) +: SdPageObjectBasePrimitive(rRange) +{ +} + +SdPageObjectBorderPrimitive::~SdPageObjectBorderPrimitive() +{ +} + +ImplPrimitrive2DIDBlock(SdPageObjectBorderPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTBORDERPRIMITIVE) + +/////////////////////////////////////////////////////////////////////////////////////////////// +// SdPageObjectPrimitive for focus visualisation + +class SdPageObjectFocusPrimitive : public SdPageObjectBasePrimitive +{ +private: + /// Gap between border of page object and inside of focus rectangle. + static const sal_Int32 mnFocusIndicatorOffset; + const bool mbContrastToSelected; + +protected: + // method which is to be used to implement the local decomposition of a 2D primitive. + virtual Primitive2DSequence createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; + +public: + // constructor and destructor + SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange, const bool bContrast); + ~SdPageObjectFocusPrimitive(); + + // provide unique ID + DeclPrimitrive2DIDBlock() +}; + +const sal_Int32 SdPageObjectFocusPrimitive::mnFocusIndicatorOffset(2); + +Primitive2DSequence SdPageObjectFocusPrimitive::createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const +{ + Primitive2DSequence xRetval(2); + + // since old Width/Height calculations always added a single pixel value, + // it is necessary to create a inner range which is one display unit less + // at the bottom right. + const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); + const basegfx::B2DRange aAdaptedInnerRange( + getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), + getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); + + // Paint_FocusIndicator replacement. (black and white). + // imitate Paint_DottedRectangle: First paint a white rectangle and above it a black dotted one + basegfx::B2DRange aFocusIndicatorRange(aAdaptedInnerRange); + aFocusIndicatorRange.grow(mnFocusIndicatorOffset * aDiscretePixel.getX()); + + // create polygon + const basegfx::B2DPolygon aIndicatorPolygon(basegfx::tools::createPolygonFromRect(aFocusIndicatorRange)); + + const StyleSettings& rStyleSettings(Application::GetSettings().GetStyleSettings()); + + // "background" rectangle + const Color aBackgroundColor(mbContrastToSelected ? rStyleSettings.GetMenuHighlightColor() : rStyleSettings.GetWindowColor()); + xRetval[0] = Primitive2DReference( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aIndicatorPolygon, Color(COL_WHITE).getBColor())); + + // dotted black rectangle with same geometry + ::std::vector< double > aDotDashArray; + + const sal_Int32 nFocusIndicatorWidth (3); + aDotDashArray.push_back(nFocusIndicatorWidth *aDiscretePixel.getX()); + aDotDashArray.push_back(nFocusIndicatorWidth * aDiscretePixel.getX()); + + // prepare line and stroke attributes + const Color aLineColor(mbContrastToSelected ? rStyleSettings.GetMenuHighlightTextColor() : rStyleSettings.GetWindowTextColor()); + const drawinglayer::attribute::LineAttribute aLineAttribute(aLineColor.getBColor()); + const drawinglayer::attribute::StrokeAttribute aStrokeAttribute( + aDotDashArray, 2.0 * nFocusIndicatorWidth * aDiscretePixel.getX()); + + + xRetval[1] = Primitive2DReference( + new drawinglayer::primitive2d::PolygonStrokePrimitive2D(aIndicatorPolygon, aLineAttribute, aStrokeAttribute)); + + return xRetval; +} + +SdPageObjectFocusPrimitive::SdPageObjectFocusPrimitive(const basegfx::B2DRange& rRange, const bool bContrast) + : SdPageObjectBasePrimitive(rRange), + mbContrastToSelected(bContrast) +{ +} + +SdPageObjectFocusPrimitive::~SdPageObjectFocusPrimitive() +{ +} + +ImplPrimitrive2DIDBlock(SdPageObjectFocusPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFOCUSPRIMITIVE) + +/////////////////////////////////////////////////////////////////////////////////////////////// +// SdPageObjectPrimitive for fade effect visualisation + +class SdPageObjectFadeNameNumberPrimitive : public SdPageObjectBasePrimitive +{ +private: + /// Size of width and height of the fade effect indicator in pixels. + static const sal_Int32 mnFadeEffectIndicatorOffset; + + /// Size of width and height of the comments indicator in pixels. + static const sal_Int32 mnCommentsIndicatorOffset; + + /// Gap between border of page object and number rectangle. + static const sal_Int32 mnPageNumberOffset; + + /// the indicator bitmaps. Static since it is usable outside this primitive + /// for size comparisons + static BitmapEx* mpFadeEffectIconBitmap; + static BitmapEx* mpCommentsIconBitmap; + + /// page name, number and needed infos + String maPageName; + sal_uInt32 mnPageNumber; + Font maPageNameFont; + Size maPageNumberAreaModelSize; + + // bitfield + bool mbShowFadeEffectIcon : 1; + bool mbShowCommentsIcon : 1; + bool mbExcluded : 1; + + // private helpers + const BitmapEx& getFadeEffectIconBitmap() const; + const BitmapEx& getCommentsIconBitmap() const; + +protected: + // method which is to be used to implement the local decomposition of a 2D primitive. + virtual Primitive2DSequence createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; + +public: + // constructor and destructor + SdPageObjectFadeNameNumberPrimitive( + const basegfx::B2DRange& rRange, + const String& rPageName, + sal_uInt32 nPageNumber, + const Font& rPageNameFont, + const Size& rPageNumberAreaModelSize, + bool bShowFadeEffectIcon, + bool bShowCommentsIcon, + bool bExcluded); + ~SdPageObjectFadeNameNumberPrimitive(); + + // data access + const String& getPageName() const { return maPageName; } + sal_uInt32 getPageNumber() const { return mnPageNumber; } + const Font& getPageNameFont() const { return maPageNameFont; } + const Size& getPageNumberAreaModelSize() const { return maPageNumberAreaModelSize; } + bool getShowFadeEffectIcon() const { return mbShowFadeEffectIcon; } + bool getShowCommentsIcon() const { return mbShowCommentsIcon; } + bool getExcluded() const { return mbExcluded; } + + // compare operator + virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; + + // provide unique ID + DeclPrimitrive2DIDBlock() +}; + +const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnFadeEffectIndicatorOffset(9); +const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnPageNumberOffset(9); +BitmapEx* SdPageObjectFadeNameNumberPrimitive::mpFadeEffectIconBitmap = 0; + +const BitmapEx& SdPageObjectFadeNameNumberPrimitive::getFadeEffectIconBitmap() const +{ + if(mpFadeEffectIconBitmap == NULL) + { + // prepare FadeEffectIconBitmap on demand + const sal_uInt16 nIconId(Application::GetSettings().GetStyleSettings().GetHighContrastMode() + ? BMP_FADE_EFFECT_INDICATOR_H + : BMP_FADE_EFFECT_INDICATOR); + const BitmapEx aFadeEffectIconBitmap(IconCache::Instance().GetIcon(nIconId).GetBitmapEx()); + const_cast< SdPageObjectFadeNameNumberPrimitive* >(this)->mpFadeEffectIconBitmap = new BitmapEx(aFadeEffectIconBitmap); + } + + return *mpFadeEffectIconBitmap; +} + +const sal_Int32 SdPageObjectFadeNameNumberPrimitive::mnCommentsIndicatorOffset(9); +BitmapEx* SdPageObjectFadeNameNumberPrimitive::mpCommentsIconBitmap = 0; + +const BitmapEx& SdPageObjectFadeNameNumberPrimitive::getCommentsIconBitmap() const +{ + if(mpCommentsIconBitmap == NULL) + { + // prepare CommentsIconBitmap on demand + const sal_uInt16 nIconId(Application::GetSettings().GetStyleSettings().GetHighContrastMode() + ? BMP_COMMENTS_INDICATOR_H + : BMP_COMMENTS_INDICATOR); + const BitmapEx aCommentsIconBitmap(IconCache::Instance().GetIcon(nIconId).GetBitmapEx()); + const_cast< SdPageObjectFadeNameNumberPrimitive* >(this)->mpCommentsIconBitmap = new BitmapEx(aCommentsIconBitmap); + } + + return *mpCommentsIconBitmap; +} + +Primitive2DSequence SdPageObjectFadeNameNumberPrimitive::createLocalDecomposition(const drawinglayer::geometry::ViewInformation2D& rViewInformation) const +{ + const xub_StrLen nTextLength(getPageName().Len()); + const sal_uInt32 nCount( + (getShowFadeEffectIcon() ? 1 : 0) + // FadeEffect icon + (nTextLength ? 1 : 0) + // PageName + 1 + // PageNumber (always) + (getExcluded() ? 2 : 0) // PageNumber crossed out + ); + sal_uInt32 nInsert(0); + Primitive2DSequence xRetval(nCount); + + // since old Width/Height calculations always added a single pixel value, + // it is necessary to create a inner range which is one display unit less + // at the bottom right. + const basegfx::B2DVector aDiscretePixel(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0)); + const basegfx::B2DRange aAdaptedInnerRange( + getPageObjectRange().getMinX(), getPageObjectRange().getMinY(), + getPageObjectRange().getMaxX() - aDiscretePixel.getX(), getPageObjectRange().getMaxY() - aDiscretePixel.getY()); + + // preapre TextLayouter + drawinglayer::primitive2d::TextLayouterDevice aTextLayouter; + aTextLayouter.setFont(getPageNameFont()); + + // get font attributes + basegfx::B2DVector aTextSizeAttribute; + const drawinglayer::primitive2d::FontAttributes aFontAttributes( + drawinglayer::primitive2d::getFontAttributesFromVclFont( + aTextSizeAttribute, + getPageNameFont(), + false, + false)); + + // prepare locale; this may need some more information in the future + const ::com::sun::star::lang::Locale aLocale; + + // prepare font color from System + const basegfx::BColor aFontColor(Application::GetSettings().GetStyleSettings().GetFontColor().getBColor()); + + if(getShowFadeEffectIcon()) + { + // prepare fFadeEffect Sizes + const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() * + basegfx::B2DVector( + getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1, + getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1)); + + // Paint_FadeEffectIndicator replacement. + // create transformation. To avoid bitmap scaling, use bitmap size as size + basegfx::B2DHomMatrix aBitmapTransform; + + // short form for scale and translate transformation + aBitmapTransform.set(0L, 0L, aFadeEffectBitmapSizeLogic.getX()); + aBitmapTransform.set(1L, 1L, aFadeEffectBitmapSizeLogic.getY()); + aBitmapTransform.set(0L, 2L, aAdaptedInnerRange.getMinX()); + aBitmapTransform.set(1L, 2L, aAdaptedInnerRange.getMaxY() + ((mnFadeEffectIndicatorOffset + 1) * aDiscretePixel.getX())); + + xRetval[nInsert++] = Primitive2DReference( + new drawinglayer::primitive2d::BitmapPrimitive2D(getFadeEffectIconBitmap(), aBitmapTransform)); + } + + if(nTextLength) + { + // prepare fFadeEffect Sizes since it consumes from text size + const basegfx::B2DVector aFadeEffectBitmapSizeLogic(rViewInformation.getInverseObjectToViewTransformation() * + basegfx::B2DVector( + getFadeEffectIconBitmap().GetSizePixel().getWidth() - 1, + getFadeEffectIconBitmap().GetSizePixel().getHeight() - 1)); + + // Paint_PageName replacement. Get text size + const double fTextWidth(aTextLayouter.getTextWidth(getPageName(), 0, nTextLength)); + const double fTextHeight(getPageNameFont().GetHeight()); + const double fFadeEffectWidth(aFadeEffectBitmapSizeLogic.getX() * 2.0); + const double fFadeEffectTextGap(((mnFadeEffectIndicatorOffset + 2) * aDiscretePixel.getX())); + String aPageName(getPageName()); + + // calculate text start position + double fStartX( + aAdaptedInnerRange.getMaxX() + - fTextWidth + + (aDiscretePixel.getX() * 3.0)); + const double fStartY( + aAdaptedInnerRange.getMaxY() + + fTextHeight + + fFadeEffectTextGap); + const bool bNeedClipping(fStartX < aAdaptedInnerRange.getMinX() + fFadeEffectWidth); + + // if text is too big, clip it + if(bNeedClipping) + { + // new left start + fStartX = aAdaptedInnerRange.getMinX() + fFadeEffectWidth; + + // find out how many characters to use + const double fAvailableLength(aAdaptedInnerRange.getWidth() - fFadeEffectWidth); + static const String aThreePoints(String::CreateFromAscii("...")); + const double fWidthThreePoints(aTextLayouter.getTextWidth(aThreePoints, 0, aThreePoints.Len())); + xub_StrLen a(1); + + for(; a < (xub_StrLen)nTextLength; a++) + { + const double fSnippetLength(aTextLayouter.getTextWidth(aPageName, 0, a)); + + if(fSnippetLength + fWidthThreePoints > fAvailableLength) + { + break; + } + } + + // build new string + aPageName = String(aPageName, 0, a - 1); + aPageName += aThreePoints; + } + + // fill text matrix + basegfx::B2DHomMatrix aTextMatrix; + + aTextMatrix.set(0, 0, aTextSizeAttribute.getX()); + aTextMatrix.set(1, 1, aTextSizeAttribute.getY()); + aTextMatrix.set(0, 2, fStartX); + aTextMatrix.set(1, 2, fStartY); + + // prepare DXTextArray (can be empty one) + const ::std::vector< double > aDXArray; + + // create Text primitive and add to target + xRetval[nInsert++] = Primitive2DReference( + new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + aTextMatrix, + aPageName, + 0, + aPageName.Len(), + aDXArray, + aFontAttributes, + aLocale, + aFontColor)); + } + + { + // Paint_PageNumber replacement. Get the range where it shall be centered and prepare the string + const double fLeft(aAdaptedInnerRange.getMinX() - (mnPageNumberOffset * aDiscretePixel.getX()) - getPageNumberAreaModelSize().Width()); + const double fTop(aAdaptedInnerRange.getMinY()); + const basegfx::B2DRange aNumberRange(fLeft, fTop, + fLeft + getPageNumberAreaModelSize().Width(), fTop + getPageNumberAreaModelSize().Height()); + const String aPageNumber(String::CreateFromInt32(getPageNumber())); + const xub_StrLen nNumberLen(aPageNumber.Len()); + + // Get text size + const double fTextWidth(aTextLayouter.getTextWidth(aPageNumber, 0, nNumberLen)); + const double fTextHeight(getPageNameFont().GetHeight()); + + // get text start postion + const double fStartX(aNumberRange.getCenterX() - (fTextWidth / 2.0)); + const double fStartY(aNumberRange.getMinY() + fTextHeight + aDiscretePixel.getX()); + + // fill text matrix + basegfx::B2DHomMatrix aTextMatrix; + + aTextMatrix.set(0, 0, aTextSizeAttribute.getX()); + aTextMatrix.set(1, 1, aTextSizeAttribute.getY()); + aTextMatrix.set(0, 2, fStartX); + aTextMatrix.set(1, 2, fStartY); + + // prepare DXTextArray (can be empty one) + const ::std::vector< double > aDXArray; + + // create Text primitive + xRetval[nInsert++] = Primitive2DReference( + new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( + aTextMatrix, + aPageNumber, + 0, + nNumberLen, + aDXArray, + aFontAttributes, + aLocale, + aFontColor)); + + if(getExcluded()) + { + // create a box with strikethrough from top left to bottom right + const basegfx::BColor aActiveColor(Application::GetSettings().GetStyleSettings().GetActiveColor().getBColor()); + basegfx::B2DPolygon aStrikethrough; + + aStrikethrough.append(aNumberRange.getMinimum()); + aStrikethrough.append(aNumberRange.getMaximum()); + + xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( + basegfx::tools::createPolygonFromRect(aNumberRange), aActiveColor)); + + xRetval[nInsert++] = Primitive2DReference(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( + aStrikethrough, aActiveColor)); + } + } + + return xRetval; +} + +SdPageObjectFadeNameNumberPrimitive::SdPageObjectFadeNameNumberPrimitive( + const basegfx::B2DRange& rRange, + const String& rPageName, + sal_uInt32 nPageNumber, + const Font& rPageNameFont, + const Size& rPageNumberAreaModelSize, + bool bShowFadeEffectIcon, + bool bShowCommentsIcon, + bool bExcluded) +: SdPageObjectBasePrimitive(rRange), + maPageName(rPageName), + mnPageNumber(nPageNumber), + maPageNameFont(rPageNameFont), + maPageNumberAreaModelSize(rPageNumberAreaModelSize), + mbShowFadeEffectIcon(bShowFadeEffectIcon), + mbShowCommentsIcon(bShowCommentsIcon), + mbExcluded(bExcluded) +{ +} + +SdPageObjectFadeNameNumberPrimitive::~SdPageObjectFadeNameNumberPrimitive() +{ +} + +bool SdPageObjectFadeNameNumberPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const +{ + if(SdPageObjectBasePrimitive::operator==(rPrimitive)) + { + const SdPageObjectFadeNameNumberPrimitive& rCompare = static_cast< const SdPageObjectFadeNameNumberPrimitive& >(rPrimitive); + + return (getPageName() == rCompare.getPageName() + && getPageNumber() == rCompare.getPageNumber() + && getPageNameFont() == rCompare.getPageNameFont() + && getPageNumberAreaModelSize() == rCompare.getPageNumberAreaModelSize() + && getShowFadeEffectIcon() == rCompare.getShowFadeEffectIcon() + && getExcluded() == rCompare.getExcluded()); + } + + return false; +} + +ImplPrimitrive2DIDBlock(SdPageObjectFadeNameNumberPrimitive, PRIMITIVE2D_ID_SDPAGEOBJECTFADENAMENUMBERPRIMITIVE) + +/////////////////////////////////////////////////////////////////////////////////////////////// +// createPrimitive2DSequence +// +// This method will replace the whole painting mechanism. Task is no longer to paint stuff to an OutDev, +// but to provide the necessary geometrical information using primitives. + +Primitive2DSequence PageObjectViewObjectContact::createPrimitive2DSequence(const sdr::contact::DisplayInfo& rDisplayInfo) const +{ + // OutputDevice* pDevice = rDisplayInfo.GetDIOutputDevice(); + OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice(); + + // get primitive vector from parent class. Do remember the contents for later use; this + // is done to create the page content renderer (see PagePrimitiveExtractor in svx) at the + // original object and to setup the draw hierarchy there so that changes to VCs of displayed + // objects will lead to InvalidatePartOfView-calls which will be forwarded from the helper-OC + // to this VOC in calling a ActionChanged(). + // + // This already produces the displayable page content as a primitive sequence, complete with + // embedding in the page visualizer, clipping if needed and object and aspect ratio + // preparations. It would thus be the base for creating the cached visualisation, too, + // by just painting extactly this primitive sequence. + // + // Currently, this slows down PagePane display heavily. Reason is that the current mechanism + // to react on a SdrObject change in an edit view is to react on the ModelChange and to completely + // reset the PagePane (delete SdrPageObjs, re-create and layout them). This works, but kicks + // the complete sequence of primitive creation at VOCs and VCs and their buffering out of + // memory each time. So there are two choices: + // + // 1, disable getting the sequence of primtives + // -> invalidate uses ModelChange + // -> cache repaint uses complete view creation and repainting + // + // 2, create and use the sequence of primitives + // -> invalidate would not need ModelChange, no destroy/recreate of SdrObjects, no rearrange, + // the invalidate and the following repaint would exactly update the SdrPages involved and + // use the DrawingLayer provided ActionChanged() invalidations over the VOCs and VCs + // -> cache repaint could use the here offered sequence of primitives to re-create the bitmap + // (just hand over the local member to the cache) + // + // For the moment i will use (1) and disable primitive creation for SdrPageObj contents here + + // const_cast< PageObjectViewObjectContact* >(this)->mxCurrentPageContents = ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo); + + // assert when this call is issued indirectly from the destructor of + // this instance. This is not allowed and needs to be looked at +#ifdef DBG_UTIL + if(mbInDestructor) + { + OSL_ENSURE(false, "Higher call inside PageObjectViewObjectContact in destructor (!)"); + } +#endif + + // Check if buffering can and shall be done. + if (pDevice != NULL + && !GetObjectContact().isOutputToPrinter() + && !GetObjectContact().isOutputToRecordingMetaFile() + && !mbInDestructor) + { + // get inner and outer logic rectangles. Use model data directly for creation. Do NOT use getBoundRect()/ + // getSnapRect() functionality; these will use the sequence of primitives in the long run itself. SdrPageObj + // is a SdrObject, so use SdrObject::aOutRect as model data. Access using GetLastBoundRect() to not execute anything + PageObjectViewContact& rPaObVOC(static_cast< PageObjectViewContact& >(GetViewContact())); + const Rectangle aInnerLogic(rPaObVOC.GetPageObject().GetLastBoundRect()); + + // get BitmapEx from cache. Do exactly the same as Paint_Preview() to avoid a repaint loop + // caused by slightly different pixel sizes of what the cache sees as pixel size and what is + // calculated here in discrete coordinates. This includes to not use LogicToPiyel on the Rectangle, + // but to do the same as the GetBoundingBox() implementation + const Rectangle aInnerPixel(Rectangle(pDevice->LogicToPixel(aInnerLogic.TopLeft()), pDevice->LogicToPixel(aInnerLogic.GetSize()))); + BitmapEx aBitmapEx(const_cast< PageObjectViewObjectContact* >(this)->GetPreview(rDisplayInfo, aInnerPixel)); + + // prepare inner range + const basegfx::B2DRange aInnerRange(aInnerLogic.Left(), aInnerLogic.Top(), aInnerLogic.Right(), aInnerLogic.Bottom()); + + // provide default parameters + String aPageName; + Font aPageNameFont; + sal_uInt32 nPageNumber(0); + Size aPageNumberAreaModelSize; + bool bShowFadeEffectIcon(false); + bool bShowCommentsIcon(false); + bool bExcluded(false); + + if(GetPage()) + { + const SdPage* pPage = static_cast<const SdPage*>(GetPage()); + + // decide if fade effect indicator will be painted + if(pPage->getTransitionType() > 0) + { + bShowFadeEffectIcon = true; + } + + bShowCommentsIcon = !pPage->getAnnotations().empty(); + + // prepare PageName, PageNumber, font and AreaModelSize + aPageName = pPage->GetName(); + aPageNameFont = *FontProvider::Instance().GetFont(*pDevice); + nPageNumber = ((pPage->GetPageNum() - 1) / 2) + 1; + aPageNumberAreaModelSize = GetPageDescriptor()->GetPageNumberAreaModelSize(); + + if(!aPageName.Len()) + { + aPageName = String(SdResId(STR_PAGE)); + aPageName += String::CreateFromInt32(nPageNumber); + } + + // decide if page is excluded + bExcluded = pPage->IsExcluded(); + } + + // create specialized primitives for focus, select and PagePreview itself + const bool bCreateBitmap(!aBitmapEx.IsEmpty()); + const bool bCreateFocused(GetPageDescriptor()->IsFocused()); + const bool bCreateSelected(GetPageDescriptor()->IsSelected()); + + const sal_uInt32 nCount( + (bCreateBitmap ? 1 : 0) + // bitmap itself + 1 + // border around bitmap (always) + 1 + // FadeEffect, PageName and PageNumber visualisation (always) + (bCreateFocused ? 1 : 0) + // create focused + (bCreateSelected ? 1 : 0) // create selected + ); + sal_uInt32 nInsert(0); + Primitive2DSequence xRetval(nCount); + + if(bCreateBitmap) + { + // add selection indicator if used + xRetval[nInsert++] = Primitive2DReference(new SdPageObjectPageBitmapPrimitive(aInnerRange, aBitmapEx)); + } + + if(true) + { + // add border (always) + xRetval[nInsert++] = Primitive2DReference(new SdPageObjectBorderPrimitive(aInnerRange)); + } + + if(true) + { + // add fade effext, page name and number if used + xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFadeNameNumberPrimitive( + aInnerRange, + aPageName, + nPageNumber, + aPageNameFont, + aPageNumberAreaModelSize, + bShowFadeEffectIcon, + bShowCommentsIcon, + bExcluded)); + } + + if(bCreateSelected) + { + // add selection indicator if used + xRetval[nInsert++] = Primitive2DReference(new SdPageObjectSelectPrimitive(aInnerRange)); + } + + if(bCreateFocused) + { + // add focus indicator if used + xRetval[nInsert++] = Primitive2DReference(new SdPageObjectFocusPrimitive(aInnerRange, bCreateSelected)); + } + + return xRetval; + } + else + { + // Call parent. Output to printer or metafile will use vector data, not cached bitmaps + return ViewObjectContactOfPageObj::createPrimitive2DSequence(rDisplayInfo); + } +} + +BitmapEx PageObjectViewObjectContact::CreatePreview (const DisplayInfo& /*rDisplayInfo*/) +{ + const SdPage* pPage = static_cast<const SdPage*>(GetPage()); + OutputDevice* pDevice = GetObjectContact().TryToGetOutputDevice(); + + if(pDevice) + { + Rectangle aPreviewPixelBox (GetBoundingBox(*pDevice,PreviewBoundingBox,PixelCoordinateSystem)); + + PreviewRenderer aRenderer (pDevice); + Image aPreview (aRenderer.RenderPage( + pPage, + aPreviewPixelBox.GetSize(), + String())); + + return aPreview.GetBitmapEx(); + } + else + { + return BitmapEx(); + } +} + + + + +BitmapEx PageObjectViewObjectContact::GetPreview ( + const DisplayInfo& rDisplayInfo, + const Rectangle& rNewSizePixel) +{ + BitmapEx aBitmap; + + try + { + // assert when this call is issued indirectly from the destructor of + // this instance. This is not allowed and needs to be looked at + OSL_ENSURE(!mbInDestructor, "Higher call inside PageObjectViewObjectContact in destructor (!)"); + + if (!mbInDestructor) + { + if (mpCache != NULL) + { + aBitmap = mpCache->GetPreviewBitmap( + GetPage(), + rNewSizePixel.GetSize()); + mpCache->SetPreciousFlag(GetPage(), true); + } + else + aBitmap = CreatePreview(rDisplayInfo); + } + } + catch (const ::com::sun::star::uno::Exception&) + { + OSL_TRACE("PageObjectViewObjectContact::GetPreview: caught exception"); + } + + return aBitmap; +} + + + + +const SdrPage* PageObjectViewObjectContact::GetPage (void) const +{ + return static_cast<PageObjectViewContact&>(GetViewContact()).GetPage(); +} + + + + +void PageObjectViewObjectContact::ActionChanged (void) +{ + // Even when we are called from destructor we still have to invalide + // the preview bitmap in the cache. + const SdrPage* pPage = GetPage(); + SdDrawDocument* pDocument = dynamic_cast<SdDrawDocument*>(pPage->GetModel()); + if (mpCache!=NULL && pPage!=NULL && pDocument!=NULL) + { + cache::PageCacheManager::Instance()->InvalidatePreviewBitmap( + pDocument->getUnoModel(), + GetPage()); + } + + // call parent + ViewObjectContactOfPageObj::ActionChanged(); +} + +////////////////////////////////////////////////////////////////////////////// +// helper MouseOverEffectPrimitive +// +// Used to allow view-dependent primitive definition. For that purpose, the +// initially created primitive (here: in createMouseOverEffectPrimitive2DSequence()) +// always has to be view-independent, but the decomposition is made view-dependent. +// Very simple primitive which just remembers the discrete data and applies +// it at decomposition time. + +class MouseOverEffectPrimitive : public drawinglayer::primitive2d::BasePrimitive2D +{ +private: + basegfx::B2DRange maLogicRange; + sal_uInt32 mnDiscreteOffset; + sal_uInt32 mnDiscreteWidth; + basegfx::BColor maRGBColor; + +protected: + virtual drawinglayer::primitive2d::Primitive2DSequence createLocalDecomposition( + const drawinglayer::geometry::ViewInformation2D& rViewInformation) const; + +public: + MouseOverEffectPrimitive( + const basegfx::B2DRange& rLogicRange, + sal_uInt32 nDiscreteOffset, + sal_uInt32 nDiscreteWidth, + const basegfx::BColor& rRGBColor) + : drawinglayer::primitive2d::BasePrimitive2D(), + maLogicRange(rLogicRange), + mnDiscreteOffset(nDiscreteOffset), + mnDiscreteWidth(nDiscreteWidth), + maRGBColor(rRGBColor) + {} + + // data access + const basegfx::B2DRange& getLogicRange() const { return maLogicRange; } + sal_uInt32 getDiscreteOffset() const { return mnDiscreteOffset; } + sal_uInt32 getDiscreteWidth() const { return mnDiscreteWidth; } + const basegfx::BColor& getRGBColor() const { return maRGBColor; } + + virtual bool operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const; + + DeclPrimitrive2DIDBlock() +}; + +drawinglayer::primitive2d::Primitive2DSequence MouseOverEffectPrimitive::createLocalDecomposition( + const drawinglayer::geometry::ViewInformation2D& rViewInformation) const +{ + // get logic sizes in object coordinate system + const double fDiscreteWidth((rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 0.0)).getLength()); + const double fOffset(fDiscreteWidth * getDiscreteOffset()); + const double fWidth(fDiscreteWidth * getDiscreteWidth()); + + // create range (one pixel less to get a good fitting) + basegfx::B2DRange aRange( + getLogicRange().getMinimum(), + getLogicRange().getMaximum() - basegfx::B2DTuple(fDiscreteWidth, fDiscreteWidth)); + + // grow range + aRange.grow(fOffset - (fWidth * 0.5)); + + // create fat line with parameters. The formerly hand-painted edge + // roundings will now be done using rounded edges of this fat line + const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange)); + const drawinglayer::attribute::LineAttribute aLineAttribute(getRGBColor(), fWidth); + const drawinglayer::primitive2d::Primitive2DReference xReference( + new drawinglayer::primitive2d::PolygonStrokePrimitive2D( + aPolygon, + aLineAttribute)); + + return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); +} + +bool MouseOverEffectPrimitive::operator==( const drawinglayer::primitive2d::BasePrimitive2D& rPrimitive ) const +{ + if(drawinglayer::primitive2d::BasePrimitive2D::operator==(rPrimitive)) + { + const MouseOverEffectPrimitive& rCompare = static_cast< const MouseOverEffectPrimitive& >(rPrimitive); + + return (getLogicRange() == rCompare.getLogicRange() + && getDiscreteOffset() == rCompare.getDiscreteOffset() + && getDiscreteWidth() == rCompare.getDiscreteWidth() + && getRGBColor() == rCompare.getRGBColor()); + } + + return false; +} + +ImplPrimitrive2DIDBlock(MouseOverEffectPrimitive, PRIMITIVE2D_ID_SDMOUSEOVEREFFECTPRIMITIVE) + +////////////////////////////////////////////////////////////////////////////// + +drawinglayer::primitive2d::Primitive2DSequence PageObjectViewObjectContact::createMouseOverEffectPrimitive2DSequence() +{ + drawinglayer::primitive2d::Primitive2DSequence aRetval; + + if(GetPageDescriptor()->IsSelected() && mpProperties.get() && mpProperties->IsShowSelection()) + { + // When the selection frame is visualized the mouse over frame is not + // visible and does not have to be created. + } + else + { + const PageObjectViewContact& rPaObVOC(static_cast<PageObjectViewContact&>(GetViewContact())); + const Rectangle aBoundingBox(rPaObVOC.GetPageObject().GetLastBoundRect()); + const basegfx::B2DRange aLogicRange(aBoundingBox.Left(), aBoundingBox.Top(), aBoundingBox.Right(), aBoundingBox.Bottom()); + const basegfx::BColor aSelectionColor(mpProperties->GetSelectionColor().getBColor()); + const drawinglayer::primitive2d::Primitive2DReference aReference( + new MouseOverEffectPrimitive( + aLogicRange, + mnMouseOverEffectOffset, + mnMouseOverEffectThickness, + aSelectionColor)); + + aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1); + } + + return aRetval; +} + + + + +SvBorder PageObjectViewObjectContact::CalculatePageModelBorder ( + OutputDevice* pDevice, + int nPageCount) +{ + SvBorder aModelBorder; + + if (pDevice != NULL) + { + // 1. Initialize the border with the values that do not depend on + // the device. + Size aTopLeftBorders (pDevice->PixelToLogic (Size ( + mnPageNumberOffset+1, + mnSelectionIndicatorOffset + mnSelectionIndicatorThickness))); + Size aBottomRightBorders (pDevice->PixelToLogic (Size ( + mnSelectionIndicatorOffset + mnSelectionIndicatorThickness, + mnFadeEffectIndicatorOffset))); + aModelBorder = SvBorder ( + aTopLeftBorders.Width(), + aTopLeftBorders.Height(), + aBottomRightBorders.Width(), + aBottomRightBorders.Height()); + + + // 2. Add the device dependent values. + + // Calculate the area of the page number. + Size aPageNumberModelSize ( + CalculatePageNumberAreaModelSize (pDevice, nPageCount)); + + // Update the border. + aModelBorder.Left() += aPageNumberModelSize.Width(); + // The height of the page number area is the same as the height of + // the page name area. + aModelBorder.Bottom() += aPageNumberModelSize.Height(); + } + + return aModelBorder; +} + + + + +Size PageObjectViewObjectContact::CalculatePageNumberAreaModelSize ( + OutputDevice* pDevice, + int nPageCount) +{ + // Set the correct font. + Font aOriginalFont (pDevice->GetFont()); + pDevice->SetFont(*FontProvider::Instance().GetFont(*pDevice)); + + String sPageNumberTemplate; + if (nPageCount < 10) + sPageNumberTemplate = String::CreateFromAscii("9"); + else if (nPageCount < 100) + sPageNumberTemplate = String::CreateFromAscii("99"); + else if (nPageCount < 200) + // Just for the case that 1 is narrower than 9. + sPageNumberTemplate = String::CreateFromAscii("199"); + else if (nPageCount < 1000) + sPageNumberTemplate = String::CreateFromAscii("999"); + else + sPageNumberTemplate = String::CreateFromAscii("9999"); + // More then 9999 pages are not handled. + + Size aSize ( + pDevice->GetTextWidth (sPageNumberTemplate), + pDevice->GetTextHeight ()); + + pDevice->SetFont (aOriginalFont); + + return aSize; +} + + + + +model::SharedPageDescriptor + PageObjectViewObjectContact::GetPageDescriptor (void) const +{ + PageObjectViewContact& rViewContact ( + static_cast<PageObjectViewContact&>(GetViewContact())); + PageObject& rPageObject ( + static_cast<PageObject&>(rViewContact.GetPageObject())); + return rPageObject.GetDescriptor(); +} + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx new file mode 100644 index 000000000000..b2f4f5874a56 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx @@ -0,0 +1,171 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsViewCacheContext.cxx,v $ + * + * $Revision: 1.6 $ + * + * 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_sd.hxx" + +#include "precompiled_sd.hxx" + +#include "SlsViewCacheContext.hxx" + +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "sdpage.hxx" +#include "Window.hxx" +#include "drawdoc.hxx" +#include "tools/IdleDetection.hxx" +#include <svx/svdpage.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <vcl/window.hxx> +#include <svx/sdr/contact/objectcontact.hxx> + +namespace sd { namespace slidesorter { namespace view { + + +ViewCacheContext::ViewCacheContext ( + model::SlideSorterModel& rModel, + SlideSorterView& rView) + : mrModel(rModel), + mrView(rView) +{ +} + + + + +ViewCacheContext::~ViewCacheContext (void) +{ +} + + + + +void ViewCacheContext::NotifyPreviewCreation ( + cache::CacheKey aKey, + const ::boost::shared_ptr<BitmapEx>& rPreview) +{ + (void)rPreview; + const model::SharedPageDescriptor pDescriptor (GetDescriptor(aKey)); + if (pDescriptor.get() != NULL) + { + // Use direct view-invalidate here and no ActionChanged() at the VC + // since the VC is a PageObjectViewObjectContact and in its ActionChanged() + // implementation invalidates the cache entry again. + view::PageObjectViewObjectContact* pContact = pDescriptor->GetViewObjectContact(); + if (pContact != NULL) + pContact->GetObjectContact().InvalidatePartOfView(pContact->getObjectRange()); + } + else + { + OSL_ASSERT(pDescriptor.get() != NULL); + } +} + + + + +bool ViewCacheContext::IsIdle (void) +{ + sal_Int32 nIdleState (tools::IdleDetection::GetIdleState(mrView.GetWindow())); + if (nIdleState == tools::IdleDetection::IDET_IDLE) + return true; + else + return false; +} + + + + +bool ViewCacheContext::IsVisible (cache::CacheKey aKey) +{ + return GetDescriptor(aKey)->IsVisible(); +} + + + + +const SdrPage* ViewCacheContext::GetPage (cache::CacheKey aKey) +{ + return static_cast<const SdrPage*>(aKey); +} + + + + +::boost::shared_ptr<std::vector<cache::CacheKey> > ViewCacheContext::GetEntryList (bool bVisible) +{ + ::boost::shared_ptr<std::vector<cache::CacheKey> > pKeys (new std::vector<cache::CacheKey>()); + + model::PageEnumeration aPageEnumeration ( + bVisible + ? model::PageEnumerationProvider::CreateVisiblePagesEnumeration(mrModel) + : model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + + while (aPageEnumeration.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + pKeys->push_back(pDescriptor->GetPage()); + } + + return pKeys; +} + + + + +sal_Int32 ViewCacheContext::GetPriority (cache::CacheKey aKey) +{ + return - (static_cast<const SdrPage*>(aKey)->GetPageNum()-1) / 2; +} + + + + +model::SharedPageDescriptor ViewCacheContext::GetDescriptor (cache::CacheKey aKey) +{ + sal_uInt16 nPageIndex ((static_cast<const SdrPage*>(aKey)->GetPageNum() - 1) / 2); + return mrModel.GetPageDescriptor(nPageIndex); +} + + + + +::com::sun::star::uno::Reference<com::sun::star::uno::XInterface> ViewCacheContext::GetModel (void) +{ + if (mrModel.GetDocument() == NULL) + return NULL; + else + return mrModel.GetDocument()->getUnoModel(); +} + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx new file mode 100644 index 000000000000..f6dab2ec8d29 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsViewCacheContext.hxx,v $ + * + * $Revision: 1.3 $ + * + * 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 SD_SLIDESORTER_VIEW_VIEW_CACHE_CONTEXT_HXX +#define SD_SLIDESORTER_VIEW_VIEW_CACHE_CONTEXT_HXX + +#include "cache/SlsCacheContext.hxx" +#include "model/SlsSharedPageDescriptor.hxx" + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class SlideSorterView; + +/** The cache context for the SlideSorter as used by Draw and Impress. See + the base class for documentation of the individual methods. +*/ +class ViewCacheContext : public cache::CacheContext +{ +public: + ViewCacheContext ( + model::SlideSorterModel& rModel, + SlideSorterView& rView); + virtual ~ViewCacheContext (void); + virtual void NotifyPreviewCreation (cache::CacheKey aKey, const ::boost::shared_ptr<BitmapEx>& rPreview); + virtual bool IsIdle (void); + virtual bool IsVisible (cache::CacheKey aKey); + virtual const SdrPage* GetPage (cache::CacheKey aKey); + virtual ::boost::shared_ptr<std::vector<cache::CacheKey> > GetEntryList (bool bVisible); + virtual sal_Int32 GetPriority (cache::CacheKey aKey); + virtual ::com::sun::star::uno::Reference<com::sun::star::uno::XInterface> GetModel (void); + +private: + model::SlideSorterModel& mrModel; + SlideSorterView& mrView; + + model::SharedPageDescriptor GetDescriptor (cache::CacheKey aKey); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx b/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx new file mode 100644 index 000000000000..5e338480e236 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewOverlay.cxx @@ -0,0 +1,583 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SlsViewOverlay.cxx,v $ + * $Revision: 1.16 $ + * + * 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 "precompiled_sd.hxx" + +#include "view/SlsViewOverlay.hxx" + +#include "SlideSorter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumeration.hxx" +#include "view/SlideSorterView.hxx" +#include "SlideSorterViewShell.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsPageObject.hxx" +#include "view/SlsPageObjectViewObjectContact.hxx" +#include "ViewShell.hxx" +#include "ViewShellBase.hxx" +#include "UpdateLockManager.hxx" + +#include "Window.hxx" +#include "sdpage.hxx" + +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <svx/svdpagv.hxx> +#include <svx/sdrpagewindow.hxx> +#include <vcl/svapp.hxx> + +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> + +using namespace ::sdr::overlay; + +namespace { + const static sal_Int32 gnSubstitutionStripeLength (3); +} + +namespace sd { namespace slidesorter { namespace view { + +//===== ViewOverlay ========================================================= + +ViewOverlay::ViewOverlay (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maSelectionRectangleOverlay(*this), + maMouseOverIndicatorOverlay(*this), + maInsertionIndicatorOverlay(*this), + maSubstitutionOverlay(*this) +{ +} + + + + +ViewOverlay::~ViewOverlay (void) +{ +} + + + + +SelectionRectangleOverlay& ViewOverlay::GetSelectionRectangleOverlay (void) +{ + return maSelectionRectangleOverlay; +} + + + + +MouseOverIndicatorOverlay& ViewOverlay::GetMouseOverIndicatorOverlay (void) +{ + return maMouseOverIndicatorOverlay; +} + + + + +InsertionIndicatorOverlay& ViewOverlay::GetInsertionIndicatorOverlay (void) +{ + return maInsertionIndicatorOverlay; +} + + + + +SubstitutionOverlay& ViewOverlay::GetSubstitutionOverlay (void) +{ + return maSubstitutionOverlay; +} + + + + +SlideSorter& ViewOverlay::GetSlideSorter (void) const +{ + return mrSlideSorter; +} + + + + +OverlayManager* ViewOverlay::GetOverlayManager (void) const +{ + OverlayManager* pOverlayManager = NULL; + + SlideSorterView& rView (mrSlideSorter.GetView()); + SdrPageView* pPageView = rView.GetSdrPageView(); + if (pPageView != NULL && pPageView->PageWindowCount()>0) + { + SdrPageWindow* pPageWindow = pPageView->GetPageWindow(0); + if (pPageWindow != NULL) + pOverlayManager = pPageWindow->GetOverlayManager(); + } + + return pOverlayManager; +} + + + + +//===== OverlayBase ========================================================= + +OverlayBase::OverlayBase (ViewOverlay& rViewOverlay) + : OverlayObject(Color(0,0,0)), + mrViewOverlay(rViewOverlay) +{ + setVisible(false); +} + + + + +OverlayBase::~OverlayBase (void) +{ + OverlayManager* pOverlayManager = getOverlayManager(); + if (pOverlayManager != NULL) + pOverlayManager->remove(*this); +} + + + + +void OverlayBase::EnsureRegistration (void) +{ + if (getOverlayManager() == NULL) + { + OverlayManager* pOverlayManager = mrViewOverlay.GetOverlayManager(); + if (pOverlayManager != NULL) + pOverlayManager->add(*this); + } +} + + + + +//===== SubstitutionOverlay ================================================= + +SubstitutionOverlay::SubstitutionOverlay (ViewOverlay& rViewOverlay) + : OverlayBase(rViewOverlay), + maPosition(0,0), + maShapes() +{ +} + + + + +SubstitutionOverlay::~SubstitutionOverlay (void) +{ +} + + + + +void SubstitutionOverlay::Create ( + model::PageEnumeration& rSelection, + const Point& rPosition) +{ + EnsureRegistration(); + + maPosition = rPosition; + + maShapes.clear(); + while (rSelection.HasMoreElements()) + { + const Rectangle aBox (rSelection.GetNextElement()->GetPageObject()->GetCurrentBoundRect()); + basegfx::B2DRectangle aB2DBox( + aBox.Left(), + aBox.Top(), + aBox.Right(), + aBox.Bottom()); + maShapes.append(basegfx::tools::createPolygonFromRect(aB2DBox), 4); + } + + setVisible(maShapes.count() > 0); + // The selection indicator may have been visible already so call + // objectChange() to enforce an update. + objectChange(); +} + + + + +void SubstitutionOverlay::Clear (void) +{ + maShapes.clear(); + setVisible(false); +} + + + + +void SubstitutionOverlay::Move (const Point& rOffset) +{ + basegfx::B2DHomMatrix aTranslation; + aTranslation.translate(rOffset.X(), rOffset.Y()); + + maShapes.transform(aTranslation); + maPosition += rOffset; + + objectChange(); +} + + + + +void SubstitutionOverlay::SetPosition (const Point& rPosition) +{ + Move(rPosition - GetPosition()); +} + + + + +Point SubstitutionOverlay::GetPosition (void) const +{ + return maPosition; +} + + + + +drawinglayer::primitive2d::Primitive2DSequence SubstitutionOverlay::createOverlayObjectPrimitive2DSequence() +{ + drawinglayer::primitive2d::Primitive2DSequence aRetval; + const sal_uInt32 nCount(maShapes.count()); + + if(nCount && getOverlayManager()) + { + aRetval.realloc(nCount); + const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); + const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); + + for(sal_uInt32 a(0); a < nCount; a++) + { + aRetval[a] = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::PolygonMarkerPrimitive2D( + maShapes.getB2DPolygon(a), + aRGBColorA, + aRGBColorB, + gnSubstitutionStripeLength)); + } + } + + return aRetval; +} + +void SubstitutionOverlay::stripeDefinitionHasChanged() +{ + // react on OverlayManager's stripe definition change + objectChange(); +} + + +//===== SelectionRectangleOverlay =========================================== + +SelectionRectangleOverlay::SelectionRectangleOverlay (ViewOverlay& rViewOverlay) + : OverlayBase (rViewOverlay), + maAnchor(0,0), + maSecondCorner(0,0) +{ +} + + + + +Rectangle SelectionRectangleOverlay::GetSelectionRectangle (void) +{ + return Rectangle(maAnchor, maSecondCorner); +} + + + + +void SelectionRectangleOverlay::Start (const Point& rAnchor) +{ + EnsureRegistration(); + setVisible(false); + maAnchor = rAnchor; +} + + + + +void SelectionRectangleOverlay::Update (const Point& rSecondCorner) +{ + maSecondCorner = rSecondCorner; + setVisible(true); + // The selection rectangle may have been visible already so call + // objectChange() to enforce an update. + objectChange(); +} + + + + +drawinglayer::primitive2d::Primitive2DSequence SelectionRectangleOverlay::createOverlayObjectPrimitive2DSequence() +{ + drawinglayer::primitive2d::Primitive2DSequence aRetval; + const basegfx::B2DRange aRange(maAnchor.X(), maAnchor.Y(), maSecondCorner.X(), maSecondCorner.Y()); + const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange)); + + if(aPolygon.count()) + { + const basegfx::BColor aRGBColorA(getOverlayManager()->getStripeColorA().getBColor()); + const basegfx::BColor aRGBColorB(getOverlayManager()->getStripeColorB().getBColor()); + const drawinglayer::primitive2d::Primitive2DReference xReference( + new drawinglayer::primitive2d::PolygonMarkerPrimitive2D( + aPolygon, + aRGBColorA, + aRGBColorB, + gnSubstitutionStripeLength)); + + aRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); + } + + return aRetval; +} + +void SelectionRectangleOverlay::stripeDefinitionHasChanged() +{ + // react on OverlayManager's stripe definition change + objectChange(); +} + + + + +//===== InsertionIndicatorOverlay =========================================== + +InsertionIndicatorOverlay::InsertionIndicatorOverlay (ViewOverlay& rViewOverlay) + : OverlayBase (rViewOverlay), + mnInsertionIndex(-1), + maBoundingBox() +{ +} + + + + +void InsertionIndicatorOverlay::SetPositionAndSize (const Rectangle& aNewBoundingBox) +{ + EnsureRegistration(); + maBoundingBox = aNewBoundingBox; + setVisible( ! maBoundingBox.IsEmpty()); + // The insertion indicator may have been visible already so call + // objectChange() to enforce an update. + objectChange(); +} + + + + +void InsertionIndicatorOverlay::SetPosition (const Point& rPoint) +{ + static const bool bAllowHorizontalInsertMarker = true; + Layouter& rLayouter (mrViewOverlay.GetSlideSorter().GetView().GetLayouter()); + USHORT nPageCount + = (USHORT)mrViewOverlay.GetSlideSorter().GetModel().GetPageCount(); + + sal_Int32 nInsertionIndex = rLayouter.GetInsertionIndex (rPoint, + bAllowHorizontalInsertMarker); + if (nInsertionIndex >= nPageCount) + nInsertionIndex = nPageCount-1; + sal_Int32 nDrawIndex = nInsertionIndex; + + bool bVertical = false; + bool bLeftOrTop = false; + if (nInsertionIndex >= 0) + { + // Now that we know where to insert, we still have to determine + // where to draw the marker. There are two decisions to make: + // 1. Draw a vertical or a horizontal insert marker. + // The horizontal one may only be chosen when there is only one + // column. + // 2. The vertical (standard) insert marker may be painted left to + // the insert page or right of the previous one. When both pages + // are in the same row this makes no difference. Otherwise the + // posiotions are at the left and right ends of two rows. + + Point aPageCenter (rLayouter.GetPageObjectBox ( + nInsertionIndex).Center()); + + if (bAllowHorizontalInsertMarker + && rLayouter.GetColumnCount() == 1) + { + bVertical = false; + bLeftOrTop = (rPoint.Y() <= aPageCenter.Y()); + } + else + { + bVertical = true; + bLeftOrTop = (rPoint.X() <= aPageCenter.X()); + } + + // Add one when the mark was painted below or to the right of the + // page object. + if ( ! bLeftOrTop) + nInsertionIndex += 1; + } + + mnInsertionIndex = nInsertionIndex; + + Rectangle aBox; + if (mnInsertionIndex >= 0) + aBox = rLayouter.GetInsertionMarkerBox ( + nDrawIndex, + bVertical, + bLeftOrTop); + SetPositionAndSize (aBox); +} + + + + +sal_Int32 InsertionIndicatorOverlay::GetInsertionPageIndex (void) const +{ + return mnInsertionIndex; +} + + + + +drawinglayer::primitive2d::Primitive2DSequence InsertionIndicatorOverlay::createOverlayObjectPrimitive2DSequence() +{ + drawinglayer::primitive2d::Primitive2DSequence aRetval(2); + const basegfx::B2DRange aRange(maBoundingBox.Left(), maBoundingBox.Top(), maBoundingBox.Right(), maBoundingBox.Bottom()); + const basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange)); + const basegfx::BColor aRGBColor(Application::GetDefaultDevice()->GetSettings().GetStyleSettings().GetFontColor().getBColor()); + + aRetval[0] = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( + basegfx::B2DPolyPolygon(aPolygon), + aRGBColor)); + aRetval[1] = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::PolygonHairlinePrimitive2D( + aPolygon, + aRGBColor)); + + return aRetval; +} + + + + +//===== MouseOverIndicatorOverlay =========================================== + +MouseOverIndicatorOverlay::MouseOverIndicatorOverlay (ViewOverlay& rViewOverlay) + : OverlayBase (rViewOverlay), + mpPageUnderMouse() +{ +} + + + + +MouseOverIndicatorOverlay::~MouseOverIndicatorOverlay (void) +{ +} + + + + +void MouseOverIndicatorOverlay::SetSlideUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor) +{ + ViewShellBase* pBase = mrViewOverlay.GetSlideSorter().GetViewShellBase(); + if (pBase==NULL || ! pBase->GetUpdateLockManager()->IsLocked()) + { + model::SharedPageDescriptor pDescriptor; + if ( ! mpPageUnderMouse.expired()) + { + try + { + pDescriptor = model::SharedPageDescriptor(mpPageUnderMouse); + } + catch (::boost::bad_weak_ptr) + { + } + } + + if (pDescriptor != rpDescriptor) + { + // Switch to the new (possibly empty) descriptor. + mpPageUnderMouse = rpDescriptor; + + EnsureRegistration(); + + // Show the indicator when a valid page descriptor is given. + setVisible( ! mpPageUnderMouse.expired()); + // The mouse over indicator may have been visible already so call + // objectChange() to enforce an update. + objectChange(); + } + } +} + + + + +drawinglayer::primitive2d::Primitive2DSequence MouseOverIndicatorOverlay::createOverlayObjectPrimitive2DSequence() +{ + view::PageObjectViewObjectContact* pContact = GetViewObjectContact(); + + if(pContact) + { + return pContact->createMouseOverEffectPrimitive2DSequence(); + } + + return drawinglayer::primitive2d::Primitive2DSequence(); +} + + + + +view::PageObjectViewObjectContact* MouseOverIndicatorOverlay::GetViewObjectContact (void) const +{ + if ( ! mpPageUnderMouse.expired()) + { + model::SharedPageDescriptor pDescriptor (mpPageUnderMouse); + return pDescriptor->GetViewObjectContact(); + } + return NULL; +} + + + + +} } } // end of namespace ::sd::slidesorter::view + diff --git a/sd/source/ui/slidesorter/view/makefile.mk b/sd/source/ui/slidesorter/view/makefile.mk new file mode 100644 index 000000000000..ebde1e7fe02d --- /dev/null +++ b/sd/source/ui/slidesorter/view/makefile.mk @@ -0,0 +1,65 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.10 $ +# +# 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. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slsview +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/SlsFontProvider.obj \ + $(SLO)$/SlsPageObject.obj \ + $(SLO)$/SlsPageObjectViewContact.obj \ + $(SLO)$/SlsPageObjectViewObjectContact.obj \ + $(SLO)$/SlsLayouter.obj \ + $(SLO)$/SlideSorterView.obj \ + $(SLO)$/SlsViewCacheContext.obj \ + $(SLO)$/SlsViewOverlay.obj + +EXCEPTIONSFILES= \ + $(SLO)$/SlsPageObjectViewObjectContact.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + |