diff options
Diffstat (limited to 'sd/source/ui/slidesorter')
128 files changed, 36195 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..531b01e57cc4 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.cxx @@ -0,0 +1,706 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "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 Bitmap& rBitmap, 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; } + + Bitmap GetPreview (void) const { return maPreview; } + inline void SetPreview (const Bitmap& rPreview); + bool HasPreview (void) const; + + Bitmap GetMarkedPreview (void) const { return maMarkedPreview; } + inline void SetMarkedPreview (const Bitmap& rMarkePreview); + bool HasMarkedPreview (void) const; + + bool HasReplacement (void) const { return (mpReplacement.get() != NULL); } + inline bool HasLosslessReplacement (void) const; + void Clear (void) { maPreview.SetEmpty(); maMarkedPreview.SetEmpty(); + 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: + Bitmap maPreview; + Bitmap maMarkedPreview; + ::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 ::boost::unordered_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::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; +} + + + + +Bitmap 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, Bitmap(), false); + iEntry = mpBitmapContainer->find(rKey); + iEntry->second.SetUpToDate(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(); +} + + + + +Bitmap BitmapCache::GetMarkedBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + return iEntry->second.GetMarkedPreview(); + } + else + return Bitmap(); +} + + + + +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); + } +} + + + + +bool BitmapCache::InvalidateBitmap (const CacheKey& rKey) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + iEntry->second.SetUpToDate(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(); + UpdateCacheSize(iEntry->second, ADD); + } + return true; + } + else + return false; +} + + + + +void BitmapCache::InvalidateCache (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry; + for (iEntry=mpBitmapContainer->begin(); iEntry!=mpBitmapContainer->end(); ++iEntry) + { + iEntry->second.Invalidate(); + } + ReCalculateTotalCacheSize(); +} + + + + +void BitmapCache::SetBitmap ( + const CacheKey& rKey, + const Bitmap& rPreview, + bool bIsPrecious) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.SetPreview(rPreview); + iEntry->second.SetUpToDate(true); + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + } + else + { + iEntry = mpBitmapContainer->insert(CacheBitmapContainer::value_type ( + rKey, + CacheEntry(rPreview, mnCurrentAccessTime++, bIsPrecious)) + ).first; + } + + if (iEntry != mpBitmapContainer->end()) + UpdateCacheSize(iEntry->second, ADD); +} + + + + +void BitmapCache::SetMarkedBitmap ( + const CacheKey& rKey, + const Bitmap& rPreview) +{ + ::osl::MutexGuard aGuard (maMutex); + + CacheBitmapContainer::iterator iEntry (mpBitmapContainer->find(rKey)); + if (iEntry != mpBitmapContainer->end()) + { + UpdateCacheSize(iEntry->second, REMOVE); + iEntry->second.SetMarkedPreview(rPreview); + iEntry->second.SetAccessTime(mnCurrentAccessTime++); + UpdateCacheSize(iEntry->second, ADD); + } +} + + + + +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(Bitmap(), 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) + : maPreview(), + maMarkedPreview(), + mbIsUpToDate(true), + mnLastAccessTime(nLastAccessTime), + mbIsPrecious(bIsPrecious) +{ +} + + + + +BitmapCache::CacheEntry::CacheEntry( + const Bitmap& rPreview, + sal_Int32 nLastAccessTime, + bool bIsPrecious) + : maPreview(rPreview), + maMarkedPreview(), + mbIsUpToDate(true), + mnLastAccessTime(nLastAccessTime), + mbIsPrecious(bIsPrecious) +{ +} + + + + +inline void BitmapCache::CacheEntry::Recycle (const CacheEntry& rEntry) +{ + if ((rEntry.HasPreview() || rEntry.HasLosslessReplacement()) + && ! (HasPreview() || HasLosslessReplacement())) + { + maPreview = rEntry.maPreview; + maMarkedPreview = rEntry.maMarkedPreview; + mpReplacement = rEntry.mpReplacement; + mpCompressor = rEntry.mpCompressor; + mnLastAccessTime = rEntry.mnLastAccessTime; + mbIsUpToDate = rEntry.mbIsUpToDate; + } +} + + + + +inline sal_Int32 BitmapCache::CacheEntry::GetMemorySize (void) const +{ + sal_Int32 nSize (0); + nSize += maPreview.GetSizeBytes(); + nSize += maMarkedPreview.GetSizeBytes(); + if (mpReplacement.get() != NULL) + nSize += mpReplacement->GetMemorySize(); + return nSize; +} + + + + +void BitmapCache::CacheEntry::Compress (const ::boost::shared_ptr<BitmapCompressor>& rpCompressor) +{ + if ( ! maPreview.IsEmpty()) + { + if (mpReplacement.get() == NULL) + { + mpReplacement = rpCompressor->Compress(maPreview); + +#ifdef VERBOSE + sal_uInt32 nOldSize (maPreview.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; + } + + maPreview.SetEmpty(); + maMarkedPreview.SetEmpty(); + } +} + + + + +inline void BitmapCache::CacheEntry::Decompress (void) +{ + if (mpReplacement.get()!=NULL && mpCompressor.get()!=NULL && maPreview.IsEmpty()) + { + maPreview = mpCompressor->Decompress(*mpReplacement); + maMarkedPreview.SetEmpty(); + if ( ! mpCompressor->IsLossless()) + mbIsUpToDate = false; + } +} + + + +inline void BitmapCache::CacheEntry::SetPreview (const Bitmap& rPreview) +{ + maPreview = rPreview; + maMarkedPreview.SetEmpty(); + mpReplacement.reset(); + mpCompressor.reset(); +} + + + + +bool BitmapCache::CacheEntry::HasPreview (void) const +{ + return ! maPreview.IsEmpty(); +} + + + + +inline void BitmapCache::CacheEntry::SetMarkedPreview (const Bitmap& rMarkedPreview) +{ + maMarkedPreview = rMarkedPreview; +} + + + + +bool BitmapCache::CacheEntry::HasMarkedPreview (void) const +{ + return ! maMarkedPreview.IsEmpty(); +} + + + + +inline bool BitmapCache::CacheEntry::HasLosslessReplacement (void) const +{ + return mpReplacement.get()!=NULL + && mpCompressor.get()!=NULL + && mpCompressor->IsLossless(); +} + + +} } } // end of namespace ::sd::slidesorter::cache + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx new file mode 100644 index 000000000000..03610667c1be --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCache.hxx @@ -0,0 +1,238 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <boost/shared_ptr.hpp> +#include <boost/unordered_map.hpp> +#include <boost/scoped_ptr.hpp> + +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/without this 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. + + Additionally to the actual preview there is an optional marked preview. + This is used for slides excluded from the slide show which have a preview + that shows a mark (some sort of bitmap overlay) to that effect. +*/ +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); + + /** 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. + */ + Bitmap GetBitmap (const CacheKey& rKey); + + /** Return the marked preview bitmap for the given contact object. + */ + Bitmap GetMarkedBitmap (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. + @return + When the key references a page in the cache then + return <TRUE/>. When the key is not known then <FALSE/> + is returned. + */ + bool 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 Bitmap& rPreview, + bool bIsPrecious); + + /** Add or replace a marked bitmap for the given key. + */ + void SetMarkedBitmap ( + const CacheKey& rKey, + const Bitmap& rPreview); + + /** 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; + + ::boost::scoped_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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx new file mode 100644 index 000000000000..69cc8f0b377d --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.cxx @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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: + Bitmap maPreview; + Size maOriginalSize; + + DummyReplacement (const Bitmap& rPreview) : maPreview(rPreview) { } + virtual ~DummyReplacement(void) {} + virtual sal_Int32 GetMemorySize (void) const { return maPreview.GetSizeBytes(); } +}; + + + +::boost::shared_ptr<BitmapReplacement> NoBitmapCompression::Compress (const Bitmap& rBitmap) const +{ + return ::boost::shared_ptr<BitmapReplacement>(new DummyReplacement(rBitmap)); +} + +Bitmap NoBitmapCompression::Decompress (const BitmapReplacement& rBitmapData) const +{ + return dynamic_cast<const DummyReplacement&>(rBitmapData).maPreview; +} + + + + +bool NoBitmapCompression::IsLossless (void) const +{ + return true; +} + + + + +//===== CompressionByDeletion ================================================= + +::boost::shared_ptr<BitmapReplacement> CompressionByDeletion::Compress (const Bitmap& ) const +{ + return ::boost::shared_ptr<BitmapReplacement>(); +} + + + + +Bitmap CompressionByDeletion::Decompress (const BitmapReplacement& ) const +{ + // Return a NULL pointer. This will eventually lead to a request for + // the creation of a new one. + return Bitmap(); +} + + + + +bool CompressionByDeletion::IsLossless (void) const +{ + return false; +} + + + + +//===== ResolutionReduction =================================================== + +/** Store a scaled down bitmap together with the original size. +*/ +class ResolutionReduction::ResolutionReducedReplacement : public BitmapReplacement +{ +public: + Bitmap maPreview; + Size maOriginalSize; + + virtual ~ResolutionReducedReplacement(); + virtual sal_Int32 GetMemorySize (void) const; +}; + +ResolutionReduction::ResolutionReducedReplacement::~ResolutionReducedReplacement() +{ +} + +sal_Int32 ResolutionReduction::ResolutionReducedReplacement::GetMemorySize (void) const +{ + return maPreview.GetSizeBytes(); +} + +::boost::shared_ptr<BitmapReplacement> ResolutionReduction::Compress ( + const Bitmap& rBitmap) const +{ + ResolutionReducedReplacement* pResult = new ResolutionReducedReplacement(); + pResult->maPreview = rBitmap; + Size aSize (rBitmap.GetSizePixel()); + pResult->maOriginalSize = aSize; + if (aSize.Width()>0 && aSize.Width()<mnWidth) + { + int nHeight = aSize.Height() * mnWidth / aSize.Width() ; + pResult->maPreview.Scale(Size(mnWidth,nHeight)); + } + + return ::boost::shared_ptr<BitmapReplacement>(pResult); +} + + + + +Bitmap ResolutionReduction::Decompress (const BitmapReplacement& rBitmapData) const +{ + Bitmap aResult; + + const ResolutionReducedReplacement* pData ( + dynamic_cast<const ResolutionReducedReplacement*>(&rBitmapData)); + + if ( ! pData->maPreview.IsEmpty()) + { + aResult = pData->maPreview; + if (pData->maOriginalSize.Width() > mnWidth) + aResult.Scale(pData->maOriginalSize); + } + + return aResult; +} + + + + +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 Bitmap& rBitmap) const +{ + ::vcl::PNGWriter aWriter (rBitmap); + SvMemoryStream aStream (32768, 32768); + aWriter.Write(aStream); + + PngReplacement* pResult = new PngReplacement(); + pResult->maImageSize = rBitmap.GetSizePixel(); + pResult->mnDataSize = aStream.Tell(); + pResult->mpData = new char[pResult->mnDataSize]; + memcpy(pResult->mpData, aStream.GetData(), pResult->mnDataSize); + + return ::boost::shared_ptr<BitmapReplacement>(pResult); +} + + + + +Bitmap PngCompression::Decompress ( + const BitmapReplacement& rBitmapData) const +{ + Bitmap aResult; + const PngReplacement* pData (dynamic_cast<const PngReplacement*>(&rBitmapData)); + if (pData != NULL) + { + SvMemoryStream aStream (pData->mpData, pData->mnDataSize, STREAM_READ); + ::vcl::PNGReader aReader (aStream); + aResult = aReader.Read().GetBitmap(); + } + + return aResult; +} + + + + +bool PngCompression::IsLossless (void) const +{ + return true; +} + + + + +} } } // end of namespace ::sd::slidesorter::cache + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx new file mode 100644 index 000000000000..f978c013d0b3 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapCompressor.hxx @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 Bitmap; + +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 Bitmap& rBitmap) 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 Bitmap 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 Bitmap& rpBitmap) const; + virtual Bitmap 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 Bitmap& rBitmap) const; + virtual Bitmap 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 Bitmap& rpBitmap) const; + /** Scale the replacement bitmap up to the original size. + */ + virtual Bitmap 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 Bitmap& rBitmap) const; + virtual Bitmap Decompress (const BitmapReplacement& rBitmapData) const; + virtual bool IsLossless (void) const; +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx new file mode 100644 index 000000000000..56625d5d9f04 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.cxx @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsBitmapFactory.hxx" + +#include "PreviewRenderer.hxx" +#include "view/SlideSorterView.hxx" +#include "sdpage.hxx" +#include "Window.hxx" +#include <drawdoc.hxx> +#include "DrawDocShell.hxx" +#include <svx/svdtypes.hxx> +#include <svx/svdpage.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/pngwrite.hxx> + +const static sal_Int32 gnSuperSampleFactor (2); +const static bool gbAllowSuperSampling (false); + + +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) +{ +} + + + + +Bitmap BitmapFactory::CreateBitmap ( + const SdPage& rPage, + const Size& rPixelSize, + const bool bDoSuperSampling) +{ + Size aSize (rPixelSize); + if (bDoSuperSampling && gbAllowSuperSampling) + { + aSize.Width() *= gnSuperSampleFactor; + aSize.Height() *= gnSuperSampleFactor; + } + + Bitmap aPreview (maRenderer.RenderPage ( + &rPage, + aSize, + String(), + true, + false).GetBitmapEx().GetBitmap()); + if (bDoSuperSampling && gbAllowSuperSampling) + { + aPreview.Scale(rPixelSize, BMP_SCALE_INTERPOLATE); + } + + return aPreview; +} + + +} } } // end of namespace ::sd::slidesorter::cache + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx new file mode 100644 index 000000000000..0b858f98565c --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsBitmapFactory.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 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); + + Bitmap CreateBitmap ( + const SdPage& rPage, + const Size& rPixelSize, + const bool bDoSuperSampling); + +private: + PreviewRenderer maRenderer; +}; + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx new file mode 100644 index 000000000000..4e48d5ac2510 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.cxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx new file mode 100644 index 000000000000..90a2932ad501 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheCompactor.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx new file mode 100644 index 000000000000..2ea515126c3b --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.cxx @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <osl/mutex.hxx> +#include <vcl/svapp.hxx> + +#include <comphelper/processfactory.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> + +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) +{ + SolarMutexGuard aSolarGuard; + 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 + { + // Obtain access to the configuration. + Reference<lang::XMultiServiceFactory> xProvider ( + ::comphelper::getProcessServiceFactory()->createInstance( + sConfigurationProviderServiceName), + UNO_QUERY); + if ( ! xProvider.is()) + return; + + // 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()) + return; + Reference<container::XHierarchicalNameAccess> xHierarchy (xRoot, UNO_QUERY); + if ( ! xHierarchy.is()) + return; + + // Get the node for the slide sorter preview cache. + mxCacheNode = Reference<container::XNameAccess>( + xHierarchy->getByHierarchicalName(sPathToNode), + UNO_QUERY); + } + 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx new file mode 100644 index 000000000000..00a7ad71bdca --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsCacheConfiguration.hxx @@ -0,0 +1,77 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx new file mode 100644 index 000000000000..0677035e31e4 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.cxx @@ -0,0 +1,381 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 "controller/SlideSorterController.hxx" + + +namespace sd { namespace slidesorter { namespace cache { + +GenericPageCache::GenericPageCache ( + const Size& rPreviewSize, + const bool bDoSuperSampling, + const SharedCacheContext& rpCacheContext) + : mpBitmapCache(), + maRequestQueue(rpCacheContext), + mpQueueProcessor(), + mpCacheContext(rpCacheContext), + maPreviewSize(rPreviewSize), + mbDoSuperSampling(bDoSuperSampling) +{ + // A large size may indicate an error of the caller. After all we + // are creating previews. + DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000, + "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. " + "This may indicate an error."); +} + + + + +GenericPageCache::~GenericPageCache (void) +{ + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Stop(); + maRequestQueue.Clear(); + if (mpQueueProcessor.get() != NULL) + mpQueueProcessor->Terminate(); + mpQueueProcessor.reset(); + + 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, + mbDoSuperSampling, + mpCacheContext)); +} + + + + +void GenericPageCache::ChangePreviewSize ( + const Size& rPreviewSize, + const bool bDoSuperSampling) +{ + if (rPreviewSize!=maPreviewSize || bDoSuperSampling!=mbDoSuperSampling) + { + // A large size may indicate an error of the caller. After all we + // are creating previews. + DBG_ASSERT (maPreviewSize.Width()<1000 && maPreviewSize.Height()<1000, + "GenericPageCache<>::GetPreviewBitmap(): bitmap requested with large width. " + "This may indicate an error."); + + if (mpBitmapCache.get() != NULL) + { + mpBitmapCache = PageCacheManager::Instance()->ChangeSize( + mpBitmapCache, maPreviewSize, rPreviewSize); + if (mpQueueProcessor.get() != NULL) + { + mpQueueProcessor->SetPreviewSize(rPreviewSize, bDoSuperSampling); + mpQueueProcessor->SetBitmapCache(mpBitmapCache); + } + } + maPreviewSize = rPreviewSize; + mbDoSuperSampling = bDoSuperSampling; + } +} + + + + +Bitmap GenericPageCache::GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize) +{ + OSL_ASSERT(aKey != NULL); + + Bitmap aPreview; + bool bMayBeUpToDate = true; + ProvideCacheAndProcessor(); + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + if (mpBitmapCache->HasBitmap(pPage)) + { + aPreview = mpBitmapCache->GetBitmap(pPage); + const Size aBitmapSize (aPreview.GetSizePixel()); + if (aBitmapSize != maPreviewSize) + { + // Scale the bitmap to the desired size when that is possible, + // i.e. the bitmap is not empty. + if (bResize && aBitmapSize.Width()>0 && aBitmapSize.Height()>0) + { + aPreview.Scale(maPreviewSize, BMP_SCALE_FAST); + } + bMayBeUpToDate = false; + } + else + 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, bMayBeUpToDate); + + return aPreview; +} + + + + +Bitmap GenericPageCache::GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize) +{ + OSL_ASSERT(aKey != NULL); + + ProvideCacheAndProcessor(); + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + Bitmap aMarkedPreview (mpBitmapCache->GetMarkedBitmap(pPage)); + const Size aBitmapSize (aMarkedPreview.GetSizePixel()); + if (bResize && aBitmapSize != maPreviewSize) + { + // 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) + { + aMarkedPreview.Scale(maPreviewSize, BMP_SCALE_FAST); + } + } + + return aMarkedPreview; +} + + + + +void GenericPageCache::SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rMarkedBitmap) +{ + OSL_ASSERT(aKey != NULL); + + ProvideCacheAndProcessor(); + const SdrPage* pPage = mpCacheContext->GetPage(aKey); + mpBitmapCache->SetMarkedBitmap(pPage, rMarkedBitmap); +} + + + + +void GenericPageCache::RequestPreviewBitmap ( + const CacheKey aKey, + const 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) + { + const Bitmap aPreview (mpBitmapCache->GetBitmap(pPage)); + if (aPreview.IsEmpty() || aPreview.GetSizePixel()!=maPreviewSize) + 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); + } +} + + + + +bool GenericPageCache::InvalidatePreviewBitmap (const CacheKey aKey) +{ + // Invalidate the page in all caches that reference it, not just this one. + ::boost::shared_ptr<cache::PageCacheManager> pCacheManager ( + cache::PageCacheManager::Instance()); + if (pCacheManager) + return pCacheManager->InvalidatePreviewBitmap( + mpCacheContext->GetModel(), + aKey); + else if (mpBitmapCache.get() != NULL) + return mpBitmapCache->InvalidateBitmap(mpCacheContext->GetPage(aKey)); + else + return false; +} + + + + +void GenericPageCache::ReleasePreviewBitmap (const 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 (const bool bUpdateCache) +{ + if (mpBitmapCache) + { + // 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 ( + const CacheKey aKey, + const 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); +} + + + + +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 + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx new file mode 100644 index 000000000000..f4dd4900b6ad --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsGenericPageCache.hxx @@ -0,0 +1,171 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <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 a reference to the SlideSorter and + thus has access to both view and model. This allows the cache to + fill itself with requests for all pages or just the visible ones. + @param rPreviewSize + The size of the previews is expected in pixel values. + @param bDoSuperSampling + When <TRUE/> the previews are rendered larger and then scaled + down to the requested size to improve image quality. + */ + GenericPageCache ( + const Size& rPreviewSize, + const bool bDoSuperSampling, + 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, + const bool bDoSuperSampling); + + /** 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 bResize + When <TRUE/> then when the available bitmap has not the + requested size, it is scaled before it is returned. When + <FALSE/> then the bitmap is returned in the wrong size and it is + the task of the caller to scale it. + @return + Returns a bitmap that is either empty, contains a scaled (up or + down) version or is the requested bitmap. + */ + Bitmap GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + Bitmap GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + void SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rMarkedBitmap); + + /** 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 bMayBeUpToDate + This flag helps the method to determine whether an existing + preview that matches the request is up to date. If the caller + knows 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 use <TRUE/>. + */ + void RequestPreviewBitmap ( + const CacheKey aKey, + const 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. + @return + When the key is kown then return <TRUE/>. + */ + bool InvalidatePreviewBitmap (const 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 (const 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 (const 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 (const CacheKey aKey, const bool bIsPrecious); + + 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; + + bool mbDoSuperSampling; + + /** Both bitmap cache and queue processor are created on demand by this + method. + */ + void ProvideCacheAndProcessor (void); +}; + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsPageCache.cxx b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx new file mode 100644 index 000000000000..7fb9d956834d --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsPageCache.cxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsGenericPageCache.hxx" +#include "SlsRequestFactory.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 bool bDoSuperSampling, + const SharedCacheContext& rpCacheContext) + : mpImplementation( + new GenericPageCache( + rPreviewSize, + bDoSuperSampling, + rpCacheContext)) +{ +} + + + + +PageCache::~PageCache (void) +{ +} + + + + +void PageCache::ChangeSize ( + const Size& rPreviewSize, + const bool bDoSuperSampling) +{ + mpImplementation->ChangePreviewSize(rPreviewSize, bDoSuperSampling); +} + + + + +Bitmap PageCache::GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize) +{ + return mpImplementation->GetPreviewBitmap(aKey, bResize); +} + + + + +Bitmap PageCache::GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize) +{ + return mpImplementation->GetMarkedPreviewBitmap(aKey, bResize); +} + + + + +void PageCache::SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rMarkedBitmap) +{ + mpImplementation->SetMarkedPreviewBitmap(aKey, rMarkedBitmap); +} + + + + +void PageCache::RequestPreviewBitmap (const CacheKey aKey) +{ + return mpImplementation->RequestPreviewBitmap(aKey); +} + + + + +void PageCache::InvalidatePreviewBitmap ( + const CacheKey aKey, + const bool bRequestPreview) +{ + if (mpImplementation->InvalidatePreviewBitmap(aKey) && bRequestPreview) + RequestPreviewBitmap(aKey); +} + + + + +void PageCache::ReleasePreviewBitmap (const CacheKey aKey) +{ + mpImplementation->ReleasePreviewBitmap(aKey); +} + + + + +void PageCache::InvalidateCache (const bool bUpdateCache) +{ + mpImplementation->InvalidateCache(bUpdateCache); +} + + + + +void PageCache::SetPreciousFlag ( + const CacheKey aKey, + const bool bIsPrecious) +{ + mpImplementation->SetPreciousFlag(aKey, bIsPrecious); +} + + + + +void PageCache::Pause (void) +{ + mpImplementation->Pause(); +} + + + + +void PageCache::Resume (void) +{ + mpImplementation->Resume(); +} + + +} } } // end of namespace ::sd::slidesorter::cache + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx new file mode 100644 index 000000000000..229db639ceb4 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsPageCacheManager.cxx @@ -0,0 +1,492 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 ::boost::unordered_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) const + { 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))); + 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; + } + else + { + OSL_ASSERT(iCacheToChange != mpPageCaches->end()); + } + } + + return pResult; +} + + + + +bool PageCacheManager::InvalidatePreviewBitmap ( + DocumentKey pDocument, + const SdrPage* pKey) +{ + bool bHasChanged (false); + + 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) + bHasChanged |= 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) + bHasChanged |= iCache2->mpCache->InvalidateBitmap(pKey); + } + } + + return bHasChanged; +} + + + + +void PageCacheManager::InvalidateAllPreviewBitmaps (DocumentKey pDocument) +{ + if (pDocument == NULL) + return; + + // 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->InvalidateCache(); + + // 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->InvalidateCache(); + } +} + + + + +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(); +} + + + + +void PageCacheManager::ReleasePreviewBitmap (const SdrPage* pPage) +{ + PageCacheContainer::iterator iCache; + for (iCache=mpPageCaches->begin(); iCache!=mpPageCaches->end(); ++iCache) + iCache->second->ReleaseBitmap(pPage); +} + + + + +::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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx new file mode 100644 index 000000000000..345c3c5d5513 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.cxx @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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" + +namespace sd { namespace slidesorter { namespace cache { + + +//===== QueueProcessor ====================================================== + +QueueProcessor::QueueProcessor ( + RequestQueue& rQueue, + const ::boost::shared_ptr<BitmapCache>& rpCache, + const Size& rPreviewSize, + const bool bDoSuperSampling, + const SharedCacheContext& rpCacheContext) + : maMutex(), + maTimer(), + mnTimeBetweenHighPriorityRequests (10/*ms*/), + mnTimeBetweenLowPriorityRequests (100/*ms*/), + mnTimeBetweenRequestsWhenNotIdle (1000/*ms*/), + maPreviewSize(rPreviewSize), + mbDoSuperSampling(bDoSuperSampling), + 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, + const bool bDoSuperSampling) +{ + maPreviewSize = rPreviewSize; + mbDoSuperSampling = bDoSuperSampling; +} + + + + +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 Bitmap aPreview ( + maBitmapFactory.CreateBitmap(*pSdPage, maPreviewSize, mbDoSuperSampling)); + mpCache->SetBitmap (pSdPage, aPreview, ePriorityClass!=NOT_VISIBLE); + + // Initiate a repaint of the new preview. + mpCacheContext->NotifyPreviewCreation(aKey, aPreview); + } + } + } + catch (::com::sun::star::uno::RuntimeException &aException) + { + (void) aException; + OSL_FAIL("RuntimeException caught in QueueProcessor"); + } + catch (::com::sun::star::uno::Exception &aException) + { + (void) aException; + OSL_FAIL("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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx new file mode 100644 index 000000000000..55139a300fe3 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessor.hxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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/SlideSorterView.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 bool bDoSuperSampling, + 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, + const bool bDoSuperSampling); + + /** 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; + bool mbDoSuperSampling; + 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx new file mode 100644 index 000000000000..e0f519860cad --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsQueueProcessorThread.hxx @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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) +{ + create(); +} + + + + +template <class Queue, class Request, class Cache, class Factory> + QueueProcessorThread<Queue, Request, Cache, Factory> + ::~QueueProcessorThread (void) +{ +} + + + + +template <class Queue, class Request, class Cache, class Factory> +void SAL_CALL QueueProcessorThread<Queue, Request, Cache, Factory>::run (void) +{ + while ( ! mbIsTerminated) + { + if (mrQueue.IsEmpty()) + { + // Sleep while the queue is empty. + suspend(); + } + + 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; + wait (aTimeToWait); + } + + else + { + ProcessQueueEntry(); + yield (); + } + } +} + + + + +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::MutexGuard aGuard (maMutex); + if (mbIsTerminated) + break; + if (mrQueue.IsEmpty()) + break; + } + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard (maMutex); + if (mbIsTerminated) + break; + + if (mrQueue.IsEmpty()) + break; + + // Get the requeuest with the highest priority from the queue. + nPriorityClass = mrQueue.GetFrontPriorityClass(); + pRequest = &mrQueue.GetFront(); + mrQueue.PopFront(); + bRequestIsValid = true; + + 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) +{ + resume (); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::Stop (void) +{ + suspend(); +} + + + + +template <class Queue, + class RequestData, + class BitmapCache, + class BitmapFactory> +void QueueProcessorThread< + Queue, RequestData, BitmapCache, BitmapFactory + >::RemoveRequest (RequestData& rRequest) +{ + // 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) +{ + // SolarMutexGuard aSolarGuard; + ::osl::Thread::terminate (); + { + ::osl::MutexGuard aGuard (maMutex); + 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; +} + + + + +} } } // end of namespace ::sd::slidesorter::cache + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx new file mode 100644 index 000000000000..017f7572ea9c --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx new file mode 100644 index 000000000000..94ca566a66da --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestFactory.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx new file mode 100644 index 000000000000..f710ab1a8c62 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestPriorityClass.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx new file mode 100644 index 000000000000..969e85c3c7f4 --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.cxx @@ -0,0 +1,291 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx new file mode 100644 index 000000000000..e59f7e3ab3bd --- /dev/null +++ b/sd/source/ui/slidesorter/cache/SlsRequestQueue.hxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/cache/makefile.mk b/sd/source/ui/slidesorter/cache/makefile.mk new file mode 100755 index 000000000000..58862a28645a --- /dev/null +++ b/sd/source/ui/slidesorter/cache/makefile.mk @@ -0,0 +1,64 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +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)$/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..0d2e49d31e97 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlideSorterController.cxx @@ -0,0 +1,1134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsTransferable.hxx" +#include "controller/SlsVisibleAreaManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsFontProvider.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsPageObjectPainter.hxx" +#include "view/SlsTheme.hxx" +#include "view/SlsToolTip.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 <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; +using namespace ::basegfx; + +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(), + mpInsertionIndicatorHandler(new InsertionIndicatorHandler(rSlideSorter)), + mpAnimator(new Animator(rSlideSorter)), + mpVisibleAreaManager(new VisibleAreaManager(rSlideSorter)), + mpListener(), + mnModelChangeLockCount(0), + mbIsForcedRearrangePending(false), + mbPreModelChangeDone(false), + mbPostModelChangePending(false), + maSelectionBeforeSwitch(), + mnCurrentPageBeforeSwitch(0), + mpEditModeChangeMasterPage(NULL), + maTotalWindowArea(), + mnPaintEntranceCount(0), + mbIsContextMenuOpen(false) +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + OSL_ASSERT(pWindow); + if (pWindow) + { + // 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()); + pWindow->SetCenterAllowed(false); + pWindow->SetMapMode(MapMode(MAP_PIXEL)); + pWindow->SetViewSize(mrView.GetModelArea().GetSize()); + } +} + + + + +void SlideSorterController::Init (void) +{ + 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->GetCoreSelection(); + 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; + OSL_FAIL( "sd::SlideSorterController::~SlideSorterController(), exception caught!" ); + } + + // dispose should have been called by now so that nothing is to be done + // to shut down cleanly. +} + + + + +void SlideSorterController::Dispose (void) +{ + mpInsertionIndicatorHandler->End(Animator::AM_Immediate); + mpSelectionManager.reset(); + mpAnimator->Dispose(); +} + + + + +model::SharedPageDescriptor SlideSorterController::GetPageAt ( + const Point& aWindowPosition) +{ + sal_Int32 nHitPageIndex (mrView.GetPageIndexAtPoint(aWindowPosition)); + model::SharedPageDescriptor pDescriptorAtPoint; + if (nHitPageIndex >= 0) + { + pDescriptorAtPoint = mrModel.GetPageDescriptor(nHitPageIndex); + + // Depending on a property we may have to check that the mouse is no + // just over the page object but over the preview area. + if (pDescriptorAtPoint + && mrSlideSorter.GetProperties()->IsOnlyPreviewTriggersMouseOver() + && ! pDescriptorAtPoint->HasState(PageDescriptor::ST_Selected)) + { + // Make sure that the mouse is over the preview area. + if ( ! mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + pDescriptorAtPoint, + view::PageObjectLayouter::Preview, + view::PageObjectLayouter::WindowCoordinateSystem).IsInside(aWindowPosition)) + { + pDescriptorAtPoint.reset(); + } + } + } + + 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; +} + + + + +::boost::shared_ptr<InsertionIndicatorHandler> + SlideSorterController::GetInsertionIndicatorHandler (void) const +{ + OSL_ASSERT(mpInsertionIndicatorHandler.get()!=NULL); + return mpInsertionIndicatorHandler; +} + + + + +void SlideSorterController::Paint ( + const Rectangle& rBBox, + ::Window* pWindow) +{ + if (mnPaintEntranceCount == 0) + { + ++mnPaintEntranceCount; + + try + { + 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; + + if (pWindow == NULL) + return false; + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell == NULL) + return false; + + switch (rEvent.GetCommand()) + { + case COMMAND_CONTEXTMENU: + { + SdPage* pPage = NULL; + sal_uInt16 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; + } + ::boost::scoped_ptr<InsertionIndicatorHandler::ForceShowContext> pContext; + 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. + mpInsertionIndicatorHandler->Start(false); + mpInsertionIndicatorHandler->UpdateIndicatorIcon( + dynamic_cast<Transferable*>(SD_MOD()->pTransferClip)); + mpInsertionIndicatorHandler->UpdatePosition( + pWindow->PixelToLogic(rEvent.GetMousePosPixel()), + InsertionIndicatorHandler::MoveMode); + pContext.reset(new InsertionIndicatorHandler::ForceShowContext( + mpInsertionIndicatorHandler)); + } + + pWindow->ReleaseMouse(); + + Point aMenuLocation (0,0); + if (rEvent.IsMouseEvent()) + { + // We have to explicitly specify the location of the menu + // when the slide sorter is placed in an undocked child + // menu. But when it is docked it does not hurt, so we + // specify the location always. + aMenuLocation = rEvent.GetMousePosPixel(); + } + else + { + // The event is not a mouse event. Use the center of the + // focused page as top left position of the context menu. + model::SharedPageDescriptor pDescriptor ( + GetFocusManager().GetFocusedPageDescriptor()); + if (pDescriptor.get() != NULL) + { + Rectangle aBBox ( + mrView.GetLayouter().GetPageObjectLayouter()->GetBoundingBox ( + pDescriptor, + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem)); + aMenuLocation = aBBox.Center(); + } + } + + mbIsContextMenuOpen = true; + if (pViewShell != NULL) + { + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher != NULL) + { + pDispatcher->ExecutePopup( + SdResId(nPopupId), + pWindow, + &aMenuLocation); + mrSlideSorter.GetView().UpdatePageUnderMouse(false); + ::rtl::Reference<SelectionFunction> pFunction(GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->ResetMouseAnchor(); + } + } + 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( + GetInsertionIndicatorHandler()->GetInsertionPageIndex()); + } + pContext.reset(); + bEventHasBeenHandled = true; + } + break; + + case COMMAND_WHEEL: + { + const CommandWheelData* pData = rEvent.GetWheelData(); + if (pData == NULL) + return false; + if (pData->IsMod1()) + { + // We do not support zooming with control+mouse wheel. + return false; + } + // Determine whether to scroll horizontally or vertically. This + // depends on the orientation of the scroll bar and the + // IsHoriz() flag of the event. + if ((mrSlideSorter.GetView().GetOrientation()==view::Layouter::HORIZONTAL) + == pData->IsHorz()) + { + GetScrollBarManager().Scroll( + ScrollBarManager::Orientation_Vertical, + ScrollBarManager::Unit_Slide, + -pData->GetNotchDelta()); + } + else + { + GetScrollBarManager().Scroll( + ScrollBarManager::Orientation_Horizontal, + ScrollBarManager::Unit_Slide, + -pData->GetNotchDelta()); + } + mrSlideSorter.GetView().UpdatePageUnderMouse(rEvent.GetMousePosPixel(), false); + + 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)); + + GetCurrentSlideManager()->PrepareModelChange(); + + if (mrSlideSorter.GetContentWindow()) + mrView.PreModelChange(); + + mbPostModelChangePending = true; +} + + + + +void SlideSorterController::PostModelChange (void) +{ + mbPostModelChangePending = false; + mrModel.Resync(); + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + 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(mbIsForcedRearrangePending); + } + + 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(); + SharedSdWindow pActiveWindow (mrSlideSorter.GetContentWindow()); + switch (pEvent->GetId()) + { + case VCLEVENT_WINDOW_ACTIVATE: + case VCLEVENT_WINDOW_SHOW: + if (pActiveWindow && pWindow == pActiveWindow->GetParent()) + mrView.RequestRepaint(); + break; + + case VCLEVENT_WINDOW_HIDE: + if (pActiveWindow && pWindow == pActiveWindow->GetParent()) + mrView.SetPageUnderMouse(SharedPageDescriptor()); + break; + + case VCLEVENT_WINDOW_GETFOCUS: + if (pActiveWindow) + if (pWindow == pActiveWindow.get()) + GetFocusManager().ShowFocus(false); + break; + + case VCLEVENT_WINDOW_LOSEFOCUS: + if (pActiveWindow && pWindow == pActiveWindow.get()) + { + GetFocusManager().HideFocus(); + mrView.GetToolTip().Hide(); + + // Select the current slide so that it is properly + // visualized when the focus is moved to the edit view. + GetPageSelector().SelectPage(GetCurrentSlideManager()->GetCurrentSlide()); + } + break; + + case VCLEVENT_APPLICATION_DATACHANGED: + { + // Invalidate the preview cache. + cache::PageCacheManager::Instance()->InvalidateAllCaches(); + + // Update the draw mode. + sal_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(); + + // Update theme colors. + mrSlideSorter.GetProperties()->HandleDataChangeEvent(); + mrSlideSorter.GetTheme()->Update(mrSlideSorter.GetProperties()); + mrView.HandleDataChangeEvent(); + } + break; + + default: + break; + } + } + + return sal_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->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) + { + if (mrSlideSorter.GetContentWindow()) + { + sal_uLong nMode = mrSlideSorter.GetContentWindow()->GetDrawMode(); + sal_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, + (sal_Bool)(nQuality==0))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_GRAYSCALE, + (sal_Bool)(nQuality==1))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_BLACKWHITE, + (sal_Bool)(nQuality==2))); + rSet.Put (SfxBoolItem (SID_OUTPUT_QUALITY_CONTRAST, + (sal_Bool)(nQuality==3))); + } + } + + if (rSet.GetItemState(SID_MAIL_SCROLLBODY_PAGEDOWN) == SFX_ITEM_AVAILABLE) + { + rSet.Put (SfxBoolItem( SID_MAIL_SCROLLBODY_PAGEDOWN, sal_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. + mrSlideSorter.GetContentWindow()->Invalidate(); +} + + + + +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); + + if (aNewContentArea.IsEmpty()) + return aNewContentArea; + + if (mnModelChangeLockCount>0) + { + mbIsForcedRearrangePending |= bForce; + return aNewContentArea; + } + else + mbIsForcedRearrangePending = false; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + if (bForce) + mrView.UpdateOrientation(); + + // Place the scroll bars. + aNewContentArea = GetScrollBarManager().PlaceScrollBars( + maTotalWindowArea, + mrView.GetOrientation() != view::Layouter::VERTICAL, + mrView.GetOrientation() != view::Layouter::HORIZONTAL); + + 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); + + // Keep the current slide in the visible area. + GetVisibleAreaManager().RequestCurrentSlideVisible(); + + mrView.RequestRepaint(); + } + + return aNewContentArea; +} + + + + +FunctionReference SlideSorterController::CreateSelectionFunction (SfxRequest& rRequest) +{ + FunctionReference xFunc( SelectionFunction::Create(mrSlideSorter, rRequest) ); + return xFunc; +} + + + + +::rtl::Reference<SelectionFunction> SlideSorterController::GetCurrentSelectionFunction (void) +{ + FunctionReference pFunction (mrSlideSorter.GetViewShell()->GetCurrentFunction()); + return ::rtl::Reference<SelectionFunction>(dynamic_cast<SelectionFunction*>(pFunction.get())); +} + + + + +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. + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return; + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + xAccessible (pWindow->GetAccessible(sal_False)); + if ( ! xAccessible.is()) + return; + + // 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) + return; + + ::accessibility::AccessibleSlideSorterObject* pChild + = pAccessibleView->GetAccessibleChildImplementation(nPageIndex); + if (pChild == NULL || pChild->GetPage() == NULL) + return; + + ::rtl::OUString sOldName (rsOldName); + ::rtl::OUString sNewName (pChild->GetPage()->GetName()); + pChild->FireAccessibleEvent( + ::com::sun::star::accessibility::AccessibleEventId::NAME_CHANGED, + makeAny(sOldName), + makeAny(sNewName)); +} + + + + +bool SlideSorterController::IsContextMenuOpen (void) const +{ + return mbIsContextMenuOpen; +} + + + + +void SlideSorterController::SetDocumentSlides (const Reference<container::XIndexAccess>& rxSlides) +{ + if (mrModel.GetDocumentSlides() != rxSlides) + { + ModelChangeLock aLock (*this); + PreModelChange(); + + mrModel.SetDocumentSlides(rxSlides); + mrView.Layout(); + + // Select just the current slide. + PageSelector::BroadcastLock aBroadcastLock (*mpPageSelector); + mpPageSelector->DeselectAllPages(); + mpPageSelector->SelectPage(mpCurrentSlideManager->GetCurrentSlide()); + } +} + + + + +::boost::shared_ptr<Animator> SlideSorterController::GetAnimator (void) const +{ + return mpAnimator; +} + + + + +VisibleAreaManager& SlideSorterController::GetVisibleAreaManager (void) const +{ + OSL_ASSERT(mpVisibleAreaManager); + return *mpVisibleAreaManager; +} + + + + +void SlideSorterController::CheckForMasterPageAssignment (void) +{ + if (mrModel.GetPageCount()%2==0) + return; + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + if (pDescriptor->UpdateMasterPage()) + { + mrView.GetPreviewCache()->InvalidatePreviewBitmap ( + pDescriptor->GetPage(), + true); + } + } +} + + + + +//===== 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx new file mode 100644 index 000000000000..71b6c024ae7a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsAnimationFunction.cxx @@ -0,0 +1,294 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" + + +#include <osl/diagnose.hxx> +#include <rtl/math.hxx> + +namespace sd { namespace slidesorter { namespace controller { + + +double AnimationFunction::Linear (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + return nTime; +} + + + + +double AnimationFunction::FastInSlowOut_Sine (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sin(nTime * M_PI/2)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::FastInSlowOut_Root (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sqrt(nTime)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::SlowInSlowOut_0to0_Sine (const double nTime) +{ + OSL_ASSERT(nTime>=0.0 && nTime<=1.0); + + const double nResult (sin(nTime * M_PI)); + + OSL_ASSERT(nResult>=0.0 && nResult<=1.0); + return nResult; +} + + + + +double AnimationFunction::Vibrate_Sine (const double nTime) +{ + return sin(nTime*M_PI*8); +} + + + + +Point AnimationFunction::ScalePoint (const Point& rPoint, const double nTime) +{ + return Point( + sal_Int32(::rtl::math::round(rPoint.X() * nTime)), + sal_Int32(::rtl::math::round(rPoint.Y() * nTime))); +} + + + + +double AnimationFunction::Blend ( + const double nStartValue, + const double nEndValue, + const double nTime) +{ + return nStartValue*(1-nTime) + nEndValue*nTime; +} + + + + +void AnimationFunction::ApplyVisualStateChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nTime) +{ + if (rpDescriptor) + { + rpDescriptor->GetVisualState().SetVisualStateBlend(nTime); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +void AnimationFunction::ApplyLocationOffsetChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const Point aLocationOffset) +{ + if (rpDescriptor) + { + const Rectangle aOldBoundingBox(rpDescriptor->GetBoundingBox()); + rpDescriptor->GetVisualState().SetLocationOffset(aLocationOffset); + rView.RequestRepaint(aOldBoundingBox); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +void AnimationFunction::ApplyButtonAlphaChange( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nButtonAlpha, + const double nButtonBarAlpha) +{ + if (rpDescriptor) + { + rpDescriptor->GetVisualState().SetButtonAlpha(nButtonAlpha); + rpDescriptor->GetVisualState().SetButtonBarAlpha(nButtonBarAlpha); + rView.RequestRepaint(rpDescriptor); + } +} + + + + +//===== AnimationBezierFunction =============================================== + +AnimationBezierFunction::AnimationBezierFunction ( + const double nX1, + const double nY1, + const double nX2, + const double nY2) + : mnX1(nX1), + mnY1(nY1), + mnX2(nX2), + mnY2(nY2) +{ +} + + + + +AnimationBezierFunction::AnimationBezierFunction ( + const double nX1, + const double nY1) + : mnX1(nX1), + mnY1(nY1), + mnX2(1-nY1), + mnY2(1-nX1) +{ +} + + + + +::basegfx::B2DPoint AnimationBezierFunction::operator() (const double nT) +{ + return ::basegfx::B2DPoint( + EvaluateComponent(nT, mnX1, mnX2), + EvaluateComponent(nT, mnY1, mnY2)); +} + + + + +double AnimationBezierFunction::EvaluateComponent ( + const double nT, + const double nV1, + const double nV2) +{ + const double nS (1-nT); + + // While the control point values 1 and 2 are explicitly given the start + // and end values are implicitly given. + const double nV0 (0); + const double nV3 (1); + + const double nV01 (nS*nV0 + nT*nV1); + const double nV12 (nS*nV1 + nT*nV2); + const double nV23 (nS*nV2 + nT*nV3); + + const double nV012 (nS*nV01 + nT*nV12); + const double nV123 (nS*nV12 + nT*nV23); + + const double nV0123 (nS*nV012 + nT*nV123); + + return nV0123; +} + + + + +//===== AnimationParametricFunction =========================================== + +AnimationParametricFunction::AnimationParametricFunction (const ParametricFunction& rFunction) + : maY() +{ + const sal_Int32 nSampleCount (64); + + // Sample the given parametric function. + ::std::vector<basegfx::B2DPoint> aPoints; + aPoints.reserve(nSampleCount); + for (sal_Int32 nIndex=0; nIndex<nSampleCount; ++nIndex) + { + const double nT (nIndex/double(nSampleCount-1)); + aPoints.push_back(basegfx::B2DPoint(rFunction(nT))); + } + + // Interpolate at evenly spaced points. + maY.clear(); + maY.reserve(nSampleCount); + double nX0 (aPoints[0].getX()); + double nY0 (aPoints[0].getY()); + double nX1 (aPoints[1].getX()); + double nY1 (aPoints[1].getY()); + sal_Int32 nIndex (1); + for (sal_Int32 nIndex2=0; nIndex2<nSampleCount; ++nIndex2) + { + const double nX (nIndex2 / double(nSampleCount-1)); + while (nX > nX1 && nIndex<nSampleCount) + { + nX0 = nX1; + nY0 = nY1; + nX1 = aPoints[nIndex].getX(); + nY1 = aPoints[nIndex].getY(); + ++nIndex; + } + const double nU ((nX-nX1) / (nX0 - nX1)); + const double nY (nY0*nU + nY1*(1-nU)); + maY.push_back(nY); + } +} + + + + +double AnimationParametricFunction::operator() (const double nX) +{ + const sal_Int32 nIndex0 (nX * maY.size()); + const double nX0 (nIndex0 / double(maY.size()-1)); + const sal_uInt32 nIndex1 (nIndex0 + 1); + const double nX1 (nIndex1 / double(maY.size()-1)); + + if (nIndex0<=0) + return maY[0]; + else if (sal_uInt32(nIndex0)>=maY.size() || nIndex1>=maY.size()) + return maY[maY.size()-1]; + + const double nU ((nX-nX1) / (nX0 - nX1)); + return maY[nIndex0]*nU + maY[nIndex1]*(1-nU); +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsAnimator.cxx b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx new file mode 100644 index 000000000000..6a634b15c9db --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsAnimator.cxx @@ -0,0 +1,398 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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" +#include <boost/bind.hpp> + +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::AnimationFunctor& rAnimation, + const double nStartOffset, + const double nDuration, + const double nGlobalTime, + const Animator::AnimationId nAnimationId, + const Animator::FinishFunctor& rFinishFunctor); + ~Animation (void); + /** Run next animation step. If animation has reached its end it is + expired. + */ + bool Run (const double nGlobalTime); + + /** Typically called when an animation has finished, but also from + Animator::Disposed(). The finish functor is called and the + animation is marked as expired to prevent another run. + */ + void Expire (void); + bool IsExpired (void); + + Animator::AnimationFunctor maAnimation; + Animator::FinishFunctor maFinishFunctor; + const Animator::AnimationId mnAnimationId; + const double mnDuration; + const double mnEnd; + const double mnGlobalTimeAtStart; + bool mbIsExpired; +}; + + + + +Animator::Animator (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maTimer(), + mbIsDisposed(false), + maAnimations(), + maElapsedTime(), + mpDrawLock(), + mnNextAnimationId(0) +{ + maTimer.SetTimeout(gnResolution); + maTimer.SetTimeoutHdl(LINK(this,Animator,TimeoutHandler)); +} + + + + +Animator::~Animator (void) +{ + if ( ! mbIsDisposed) + { + OSL_ASSERT(mbIsDisposed); + Dispose(); + } +} + + + + +void Animator::Dispose (void) +{ + mbIsDisposed = true; + + AnimationList aCopy (maAnimations); + AnimationList::const_iterator iAnimation; + for (iAnimation=aCopy.begin(); iAnimation!=aCopy.end(); ++iAnimation) + (*iAnimation)->Expire(); + + maTimer.Stop(); + if (mpDrawLock) + { + mpDrawLock->Dispose(); + mpDrawLock.reset(); + } +} + + + + +Animator::AnimationId Animator::AddAnimation ( + const AnimationFunctor& rAnimation, + const sal_Int32 nStartOffset, + const sal_Int32 nDuration, + const FinishFunctor& rFinishFunctor) +{ + // When the animator is already disposed then ignore this call + // silently (well, we show an assertion, but do not throw an exception.) + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return -1; + + boost::shared_ptr<Animation> pAnimation ( + new Animation( + rAnimation, + nStartOffset / 1000.0, + nDuration / 1000.0, + maElapsedTime.getElapsedTime(), + ++mnNextAnimationId, + rFinishFunctor)); + maAnimations.push_back(pAnimation); + + RequestNextFrame(); + + return pAnimation->mnAnimationId; +} + + + + +Animator::AnimationId Animator::AddInfiniteAnimation ( + const AnimationFunctor& rAnimation, + const double nDelta) +{ + (void)nDelta; + + // When the animator is already disposed then ignore this call + // silently (well, we show an assertion, but do not throw an exception.) + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return -1; + + boost::shared_ptr<Animation> pAnimation ( + new Animation( + rAnimation, + 0, + -1, + maElapsedTime.getElapsedTime(), + mnNextAnimationId++, + FinishFunctor())); + maAnimations.push_back(pAnimation); + + RequestNextFrame(); + + return pAnimation->mnAnimationId; +} + + + + +void Animator::RemoveAnimation (const Animator::AnimationId nId) +{ + OSL_ASSERT( ! mbIsDisposed); + + const AnimationList::iterator iAnimation (::std::find_if( + maAnimations.begin(), + maAnimations.end(), + ::boost::bind( + ::std::equal_to<Animator::AnimationId>(), + nId, + ::boost::bind(&Animation::mnAnimationId, _1)))); + if (iAnimation != maAnimations.end()) + { + OSL_ASSERT((*iAnimation)->mnAnimationId == nId); + (*iAnimation)->Expire(); + maAnimations.erase(iAnimation); + } + + if (maAnimations.empty()) + { + // Reset the animation id when we can. + mnNextAnimationId = 0; + + // No more animations => we do not have to suppress painting + // anymore. + mpDrawLock.reset(); + } +} + + + + +void Animator::RemoveAllAnimations (void) +{ + ::std::for_each( + maAnimations.begin(), + maAnimations.end(), + ::boost::bind( + &Animation::Expire, + _1)); + maAnimations.clear(); + mnNextAnimationId = 0; + + // No more animations => we do not have to suppress painting + // anymore. + mpDrawLock.reset(); +} + + + + +bool Animator::ProcessAnimations (const double nTime) +{ + bool bExpired (false); + + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return bExpired; + + + AnimationList aCopy (maAnimations); + AnimationList::const_iterator iAnimation; + for (iAnimation=aCopy.begin(); iAnimation!=aCopy.end(); ++iAnimation) + { + bExpired |= (*iAnimation)->Run(nTime); + } + + return bExpired; +} + + + + +void Animator::CleanUpAnimationList (void) +{ + OSL_ASSERT( ! mbIsDisposed); + if (mbIsDisposed) + return; + + AnimationList aActiveAnimations; + + AnimationList::const_iterator iAnimation; + for (iAnimation=maAnimations.begin(); iAnimation!=maAnimations.end(); ++iAnimation) + { + if ( ! (*iAnimation)->IsExpired()) + aActiveAnimations.push_back(*iAnimation); + } + + maAnimations.swap(aActiveAnimations); +} + + + + +void Animator::RequestNextFrame (const double nFrameStart) +{ + (void)nFrameStart; + if ( ! maTimer.IsActive()) + { + // 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 view::SlideSorterView::DrawLock(mrSlideSorter)); + maTimer.Start(); + } +} + + + + +IMPL_LINK(Animator, TimeoutHandler, Timer*, EMPTYARG) +{ + if (mbIsDisposed) + return 0; + + if (ProcessAnimations(maElapsedTime.getElapsedTime())) + CleanUpAnimationList(); + + // Unlock the draw lock. This should lead to a repaint. + mpDrawLock.reset(); + + if (maAnimations.size() > 0) + RequestNextFrame(); + + return 0; +} + + + + +//===== Animator::Animation =================================================== + +Animator::Animation::Animation ( + const Animator::AnimationFunctor& rAnimation, + const double nStartOffset, + const double nDuration, + const double nGlobalTime, + const Animator::AnimationId nId, + const Animator::FinishFunctor& rFinishFunctor) + : maAnimation(rAnimation), + maFinishFunctor(rFinishFunctor), + mnAnimationId(nId), + mnDuration(nDuration), + mnEnd(nGlobalTime + nDuration + nStartOffset), + mnGlobalTimeAtStart(nGlobalTime + nStartOffset), + mbIsExpired(false) +{ + Run(nGlobalTime); +} + + + + +Animator::Animation::~Animation (void) +{ +} + + + + +bool Animator::Animation::Run (const double nGlobalTime) +{ + if ( ! mbIsExpired) + { + if (mnDuration > 0) + { + if (nGlobalTime >= mnEnd) + { + maAnimation(1.0); + Expire(); + } + else if (nGlobalTime >= mnGlobalTimeAtStart) + { + maAnimation((nGlobalTime - mnGlobalTimeAtStart) / mnDuration); + } + } + else if (mnDuration < 0) + { + // Animations without end have to be expired by their owner. + maAnimation(nGlobalTime); + } + } + + return mbIsExpired; +} + + + + +void Animator::Animation::Expire (void) +{ + if ( ! mbIsExpired) + { + mbIsExpired = true; + if (maFinishFunctor) + maFinishFunctor(); + } +} + + + + +bool Animator::Animation::IsExpired (void) +{ + return mbIsExpired; +} + + + + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsClipboard.cxx b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx new file mode 100644 index 000000000000..a7433af91c3c --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsClipboard.cxx @@ -0,0 +1,893 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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/SlsTheme.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsInsertionIndicatorHandler.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 "controller/SlsTransferable.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "cache/SlsPageCache.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 <svx/svdstr.hrc> +#include <vcl/msgbox.hxx> +#include <tools/urlobj.hxx> +#include <rtl/ustring.hxx> +#include <osl/mutex.hxx> +#include <vcl/svapp.hxx> + +namespace sd { namespace slidesorter { namespace controller { + +class Clipboard::UndoContext +{ +public: + UndoContext ( + SdDrawDocument* pDocument, + const ::boost::shared_ptr<ViewShell>& rpMainViewShell, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : mpDocument(pDocument), + mpMainViewShell(rpMainViewShell) + { + if (mpDocument!=NULL && mpDocument->IsUndoEnabled()) + { + if (mpMainViewShell && mpMainViewShell->GetShellType() == ViewShell::ST_DRAW) + mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropPages)); + else + mpDocument->BegUndo(rpTheme->GetString(view::Theme::String_DragAndDropSlides)); + } + } + + ~UndoContext (void) + { + if (mpDocument!=NULL && mpDocument->IsUndoEnabled()) + mpDocument->EndUndo(); + if (mpMainViewShell && mpMainViewShell->GetViewFrame()!=NULL) + { + SfxBindings& rBindings = mpMainViewShell->GetViewFrame()->GetBindings(); + rBindings.Invalidate(SID_UNDO); + rBindings.Invalidate(SID_REDO); + } + } +private: + SdDrawDocument* mpDocument; + ::boost::shared_ptr<ViewShell> mpMainViewShell; +}; + + + + +Clipboard::Clipboard (SlideSorter& rSlideSorter) + : ViewClipboard(rSlideSorter.GetView()), + mrSlideSorter(rSlideSorter), + mrController(mrSlideSorter.GetController()), + maPagesToRemove(), + maPagesToSelect(), + mbUpdateSelectionPending(false), + mpUndoContext(), + mpSelectionObserverContext(), + mnDragFinishedUserEventId(0) +{ +} + + + + +Clipboard::~Clipboard (void) +{ + if (mnDragFinishedUserEventId != 0) + Application::RemoveUserEvent(mnDragFinishedUserEventId); +} + + + + +/** 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) + { + view::SlideSorterView::DrawLock aLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); + if(xFunc.is()) + xFunc->DoPaste(); + else + DoPaste(); + } + 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, sal_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.GetContentWindow()->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. + + ::boost::shared_ptr<controller::InsertionIndicatorHandler> pInsertionIndicatorHandler ( + mrController.GetInsertionIndicatorHandler()); + if (pInsertionIndicatorHandler->IsActive()) + { + // Use the insertion index of an active insertion indicator. + nInsertPosition = pInsertionIndicatorHandler->GetInsertionPageIndex(); + } + else if (mrController.GetSelectionManager()->GetInsertionPosition() >= 0) + { + // Use the insertion index of an insertion indicator that has been + // deactivated a short while ago. + nInsertPosition = mrController.GetSelectionManager()->GetInsertionPosition(); + } + else if (mrController.GetFocusManager().IsFocusShowing()) + { + // Use the focus to determine the insertion position. + SdInsertPasteDlg aDialog (pWindow); + if (aDialog.Execute() == RET_OK) + { + nInsertPosition = mrController.GetFocusManager().GetFocusedPageIndex(); + if ( ! aDialog.IsInsertBefore()) + nInsertPosition ++; + } + } + + return nInsertPosition; +} + + + + +sal_Int32 Clipboard::PasteTransferable (sal_Int32 nInsertPosition) +{ + SdTransferable* pClipTransferable = SD_MOD()->pTransferClip; + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + bool bMergeMasterPages = !pClipTransferable->HasSourceDoc (rModel.GetDocument()); + sal_uInt16 nInsertIndex (rModel.GetCoreIndex(nInsertPosition)); + sal_Int32 nInsertPageCount (0); + if (pClipTransferable->HasPageBookmarks()) + { + const List& rBookmarkList = pClipTransferable->GetPageBookmarks(); + const SolarMutexGuard aGuard; + + nInsertPageCount = (sal_uInt16) rBookmarkList.Count(); + rModel.GetDocument()->InsertBookmarkAsPage( + const_cast<List*>(&rBookmarkList), + NULL, + sal_False, + sal_False, + nInsertIndex, + sal_False, + pClipTransferable->GetPageDocShell(), + sal_True, + bMergeMasterPages, + sal_False); + } + else + { + SfxObjectShell* pShell = pClipTransferable->GetDocShell(); + DrawDocShell* pDataDocSh = (DrawDocShell*)pShell; + SdDrawDocument* pDataDoc = pDataDocSh->GetDoc(); + + if (pDataDoc!=NULL + && pDataDoc->GetSdPageCount(PK_STANDARD)) + { + const SolarMutexGuard aGuard; + + bMergeMasterPages = (pDataDoc != rModel.GetDocument()); + nInsertPageCount = pDataDoc->GetSdPageCount( PK_STANDARD ); + rModel.GetDocument()->InsertBookmarkAsPage( + NULL, + NULL, + sal_False, + sal_False, + nInsertIndex, + sal_False, + pDataDocSh, + sal_True, + bMergeMasterPages, + sal_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 (sal_uInt16 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); + } + } + } +} + + + + +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()); + } + + // Create a small set of representatives of the selection for which + // previews are included into the transferable so that an insertion + // indicator can be rendered. + aSelectedPages.Rewind(); + ::std::vector<Transferable::Representative> aRepresentatives; + aRepresentatives.reserve(3); + ::boost::shared_ptr<cache::PageCache> pPreviewCache ( + mrSlideSorter.GetView().GetPreviewCache()); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if ( ! pDescriptor || pDescriptor->GetPage()==NULL) + continue; + Bitmap aPreview (pPreviewCache->GetPreviewBitmap(pDescriptor->GetPage(), false)); + aRepresentatives.push_back(Transferable::Representative( + aPreview, + pDescriptor->HasState(model::PageDescriptor::ST_Excluded))); + if (aRepresentatives.size() >= 3) + break; + } + + if (aBookmarkList.Count() > 0) + { + mrSlideSorter.GetView().BrkAction(); + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + SdTransferable* pTransferable = new Transferable ( + pDocument, + NULL, + sal_False, + dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()), + aRepresentatives); + + 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& rPosition, + ::Window* pWindow) +{ + maPagesToRemove.clear(); + maPagesToSelect.clear(); + mbUpdateSelectionPending = false; + CreateSlideTransferable(pWindow, sal_True); + + mrController.GetInsertionIndicatorHandler()->UpdatePosition( + rPosition, + InsertionIndicatorHandler::UnknownMode); +} + + + + +void Clipboard::DragFinished (sal_Int8 nDropAction) +{ + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + if (pDragTransferable != NULL) + pDragTransferable->SetView (NULL); + + if (mnDragFinishedUserEventId == 0) + { + if ( ! Application::PostUserEvent( + mnDragFinishedUserEventId, + LINK(this, Clipboard, ProcessDragFinished), + reinterpret_cast<void*>(nDropAction))) + { + mnDragFinishedUserEventId = 0; + } + } +} + + + + +IMPL_LINK(Clipboard, ProcessDragFinished, void*, pUserData) +{ + const sal_Int8 nDropAction (static_cast<sal_Int8>(reinterpret_cast<sal_IntPtr>(pUserData))); + + mnDragFinishedUserEventId = 0; + + // Hide the substitution display and insertion indicator. + ::rtl::Reference<SelectionFunction> pFunction (mrController.GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->NotifyDragFinished(); + + 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(); + } + mpUndoContext.reset(); + mpSelectionObserverContext.reset(); + + return 1; +} + + + + +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, + sal_uInt16 nPage, + sal_uInt16 nLayer) +{ + sal_Int8 nAction (DND_ACTION_NONE); + + const Clipboard::DropType eDropType (IsDropAccepted()); + + switch (eDropType) + { + case DT_PAGE: + { + // Accept a drop. + nAction = 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())) + { + nAction = DND_ACTION_COPY; + } + else if (mrController.GetInsertionIndicatorHandler()->IsInsertionTrivial(nAction)) + { + nAction = DND_ACTION_NONE; + } + + // Show the insertion marker and the substitution for a drop. + SelectionFunction* pSelectionFunction = dynamic_cast<SelectionFunction*>( + mrSlideSorter.GetViewShell()->GetCurrentFunction().get()); + if (pSelectionFunction != NULL) + pSelectionFunction->MouseDragged(rEvent, nAction); + + // Scroll the window when the mouse reaches the window border. + // mrController.GetScrollBarManager().AutoScroll (rEvent.maPosPixel); + } + break; + + case DT_SHAPE: + nAction = ExecuteOrAcceptShapeDrop( + DC_ACCEPT, + rEvent.maPosPixel, + &rEvent, + rTargetHelper, + pTargetWindow, + nPage, + nLayer); + break; + + default: + nAction = DND_ACTION_NONE; + break; + } + + return nAction; +} + + + + +sal_Int8 Clipboard::ExecuteDrop ( + const ExecuteDropEvent& rEvent, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow, + sal_uInt16 nPage, + sal_uInt16 nLayer) +{ + sal_Int8 nResult = DND_ACTION_NONE; + mpUndoContext.reset(); + + switch (IsDropAccepted()) + { + case DT_PAGE: + { + const SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + const Point aEventModelPosition ( + pTargetWindow->PixelToLogic (rEvent.maPosPixel)); + const sal_Int32 nXOffset (labs (pDragTransferable->GetStartPos().X() + - aEventModelPosition.X())); + const sal_Int32 nYOffset (labs (pDragTransferable->GetStartPos().Y() + - aEventModelPosition.Y())); + bool bContinue = + ( pDragTransferable->GetView() != &mrSlideSorter.GetView() ) + || ( nXOffset >= 2 && nYOffset >= 2 ); + + ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler( + mrController.GetInsertionIndicatorHandler()); + // Get insertion position and then turn off the insertion indicator. + pInsertionIndicatorHandler->UpdatePosition(aEventModelPosition, rEvent.mnAction); + // sal_uInt16 nIndex = DetermineInsertPosition(*pDragTransferable); + + // Do not process the insertion when it is trivial, + // i.e. would insert pages at their original place. + if (pInsertionIndicatorHandler->IsInsertionTrivial(rEvent.mnAction)) + bContinue = false; + + // Tell the insertion indicator handler to hide before the model + // is modified. Doing it later may result in page objects whose + // animation state is not properly reset because they are then + // in another run then before the model change. + pInsertionIndicatorHandler->End(Animator::AM_Immediate); + + if (bContinue) + { + SlideSorterController::ModelChangeLock aModelChangeLock (mrController); + + // Handle a general drop operation. + mpUndoContext.reset(new UndoContext ( + mrSlideSorter.GetModel().GetDocument(), + mrSlideSorter.GetViewShell()->GetViewShellBase().GetMainViewShell(), + mrSlideSorter.GetTheme())); + mpSelectionObserverContext.reset(new SelectionObserver::Context(mrSlideSorter)); + + HandlePageDrop(*pDragTransferable); + nResult = rEvent.mnAction; + + // We leave the undo context alive for when moving or + // copying inside one view then the actions in + // NotifyDragFinished should be covered as well as + // well as the ones above. + } + + // Notify the receiving selection function that drag-and-drop is + // finished and the substitution handler can be released. + ::rtl::Reference<SelectionFunction> pFunction ( + mrController.GetCurrentSelectionFunction()); + if (pFunction.is()) + pFunction->NotifyDragFinished(); + } + break; + + case DT_SHAPE: + nResult = ExecuteOrAcceptShapeDrop( + DC_EXECUTE, + rEvent.maPosPixel, + &rEvent, + rTargetHelper, + pTargetWindow, + nPage, + nLayer); + break; + default: + break; + } + + return nResult; +} + + + + +void Clipboard::Abort (void) +{ + if (mpSelectionObserverContext) + { + mpSelectionObserverContext->Abort(); + mpSelectionObserverContext.reset(); + } +} + + + + +sal_uInt16 Clipboard::DetermineInsertPosition (const SdTransferable& ) +{ + // 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. + const sal_Int32 nInsertionIndex ( + mrController.GetInsertionIndicatorHandler()->GetInsertionPageIndex()); + + // Convert to insertion index to that of an SdModel. + if (nInsertionIndex >= 0) + return mrSlideSorter.GetModel().GetCoreIndex(nInsertionIndex); + else + return 0; +} + + + + +sal_uInt16 Clipboard::InsertSlides ( + const SdTransferable& rTransferable, + sal_uInt16 nInsertPosition) +{ + sal_uInt16 nInsertedPageCount = ViewClipboard::InsertSlides ( + rTransferable, + nInsertPosition); + + // Remember the inserted pages so that they can be selected when the + // operation is finished. + maPagesToSelect.clear(); + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if (pDocument != NULL) + for (sal_Int32 i=0; i<=nInsertedPageCount; i+=2) + maPagesToSelect.push_back( + dynamic_cast<SdPage*>(pDocument->GetPage(nInsertPosition+i))); + + 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, + sal_uInt16 nPage, + sal_uInt16 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) + nPage = pDescriptor->GetPageIndex(); + } + + // 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsCommand.hxx b/sd/source/ui/slidesorter/controller/SlsCommand.hxx new file mode 100644 index 000000000000..7198e0a2b211 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsCommand.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx new file mode 100644 index 000000000000..97de9f7b2c20 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "controller/SlsFocusManager.hxx" +#include "view/SlideSorterView.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(), + maSwitchPageDelayTimer() +{ + maSwitchPageDelayTimer.SetTimeout(100); + maSwitchPageDelayTimer.SetTimeoutHdl(LINK(this,CurrentSlideManager,SwitchPageCallback)); +} + + + + +CurrentSlideManager::~CurrentSlideManager (void) +{ +} + + + + +void CurrentSlideManager::NotifyCurrentSlideChange (const SdPage* pPage) +{ + if (pPage != NULL) + NotifyCurrentSlideChange( + mrSlideSorter.GetModel().GetIndex( + Reference<drawing::XDrawPage>( + const_cast<SdPage*>(pPage)->getUnoPage(), + UNO_QUERY))); + else + NotifyCurrentSlideChange(-1); +} + + + + +void CurrentSlideManager::NotifyCurrentSlideChange (const sal_Int32 nSlideIndex) +{ + if (mnCurrentSlideIndex != nSlideIndex) + { + ReleaseCurrentSlide(); + AcquireCurrentSlide(nSlideIndex); + + // Update the selection. + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + if (mpCurrentSlide) + { + mrSlideSorter.GetController().GetPageSelector().SelectPage(mpCurrentSlide); + mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(mpCurrentSlide); + } + } +} + + + + +void CurrentSlideManager::ReleaseCurrentSlide (void) +{ + if (mpCurrentSlide.get() != NULL) + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, false); + + 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) + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true); + } +} + + + + +void CurrentSlideManager::SwitchCurrentSlide ( + const sal_Int32 nSlideIndex, + const bool bUpdateSelection) +{ + SwitchCurrentSlide(mrSlideSorter.GetModel().GetPageDescriptor(nSlideIndex), bUpdateSelection); +} + + + + +void CurrentSlideManager::SwitchCurrentSlide ( + const SharedPageDescriptor& rpDescriptor, + const bool bUpdateSelection) +{ + if (rpDescriptor.get() != NULL && mpCurrentSlide!=rpDescriptor) + { + ReleaseCurrentSlide(); + AcquireCurrentSlide((rpDescriptor->GetPage()->GetPageNum()-1)/2); + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL && pViewShell->IsMainViewShell()) + { + // The slide sorter is the main view. + FrameView* pFrameView = pViewShell->GetFrameView(); + if (pFrameView != NULL) + pFrameView->SetSelectedPage(sal::static_int_cast<sal_uInt16>(mnCurrentSlideIndex)); + mrSlideSorter.GetController().GetPageSelector().SetCoreSelection(); + } + + // We do not tell the XController/ViewShellBase about the new + // slide right away. This is done asynchronously after a short + // delay to allow for more slide switches in the slide sorter. + // This goes under the assumption that slide switching inside + // the slide sorter is fast (no expensive redraw of the new page + // (unless the preview of the new slide is not yet preset)) and + // that slide switching in the edit view is slow (all shapes of + // the new slide have to be repainted.) + maSwitchPageDelayTimer.Start(); + + // We have to store the (index of the) new current slide at + // the tab control because there are other asynchronous + // notifications of the slide switching that otherwise + // overwrite the correct value. + SetCurrentSlideAtTabControl(mpCurrentSlide); + + if (bUpdateSelection) + { + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); + } + mrSlideSorter.GetController().GetFocusManager().SetFocusedPage(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) + { + sal_uInt16 nPageNumber = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + pDrawViewShell->SwitchPage(nPageNumber); + pDrawViewShell->GetPageTabControl()->SetCurPageId(nPageNumber+1); + } + } +} + + + + +void CurrentSlideManager::SetCurrentSlideAtTabControl (const SharedPageDescriptor& rpDescriptor) +{ + OSL_ASSERT(rpDescriptor.get() != NULL); + + ViewShellBase* pBase = mrSlideSorter.GetViewShellBase(); + if (pBase != NULL) + { + ::boost::shared_ptr<DrawViewShell> pDrawViewShell ( + ::boost::dynamic_pointer_cast<DrawViewShell>(pBase->GetMainViewShell())); + if (pDrawViewShell) + { + sal_uInt16 nPageNumber = (rpDescriptor->GetPage()->GetPageNum()-1)/2; + pDrawViewShell->GetPageTabControl()->SetCurPageId(nPageNumber+1); + } + } +} + + + + +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 (Exception 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) + mrSlideSorter.GetView().SetState(mpCurrentSlide, PageDescriptor::ST_Current, true); + } +} + + + + +IMPL_LINK(CurrentSlideManager, SwitchPageCallback, void*, EMPTYARG) +{ + if (mpCurrentSlide) + { + // 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. + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell==NULL || ! pViewShell->IsMainViewShell()) + SetCurrentSlideAtViewShellBase(mpCurrentSlide); + SetCurrentSlideAtXController(mpCurrentSlide); + } + + return 1; +} + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx new file mode 100644 index 000000000000..76a5f583f4a5 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.cxx @@ -0,0 +1,199 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsDragAndDropContext.hxx" + +#include "SlideSorter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsTransferable.hxx" +#include "DrawDocShell.hxx" +#include "drawdoc.hxx" +#include "app.hrc" +#include <sfx2/bindings.hxx> +#include <boost/bind.hpp> + +namespace sd { namespace slidesorter { namespace controller { + +DragAndDropContext::DragAndDropContext (SlideSorter& rSlideSorter) + : mpTargetSlideSorter(&rSlideSorter), + mnInsertionIndex(-1) +{ + ::std::vector<const SdPage*> aPages; + + // No Drag-and-Drop for master pages. + if (rSlideSorter.GetModel().GetEditMode() != EM_PAGE) + return; + + rSlideSorter.GetController().GetInsertionIndicatorHandler()->UpdateIndicatorIcon( + dynamic_cast<Transferable*>(SD_MOD()->pTransferDrag)); +} + + + + +DragAndDropContext::~DragAndDropContext (void) +{ + SetTargetSlideSorter (NULL, Point(0,0), InsertionIndicatorHandler::UnknownMode, false); +} + + + + +void DragAndDropContext::GetPagesFromBookmarks ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + DrawDocShell* pDocShell, + const List& rBookmarks) const +{ + if (pDocShell == NULL) + return; + + const SdDrawDocument* pDocument = pDocShell->GetDoc(); + if (pDocument == NULL) + return; + + for (sal_uLong nIndex=0,nCount=rBookmarks.Count(); nIndex<nCount; ++nIndex) + { + const String sPageName (*static_cast<String*>(rBookmarks.GetObject(nIndex))); + sal_Bool bIsMasterPage (sal_False); + const sal_uInt16 nPageIndex (pDocument->GetPageByName(sPageName, bIsMasterPage)); + if (nPageIndex == SDRPAGE_NOTFOUND) + continue; + + const SdPage* pPage = dynamic_cast<const SdPage*>(pDocument->GetPage(nPageIndex)); + if (pPage != NULL) + rPages.push_back(pPage); + } + rnSelectionCount = rBookmarks.Count(); +} + + + + +void DragAndDropContext::GetPagesFromSelection ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + model::PageEnumeration& rSelection) const +{ + // Show a new substitution for the selected page objects. + rnSelectionCount = 0; + + while (rSelection.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (rSelection.GetNextElement()); + if (rPages.size() < 3) + rPages.push_back(pDescriptor->GetPage()); + ++rnSelectionCount; + } +} + + + + +void DragAndDropContext::Dispose (void) +{ + mnInsertionIndex = -1; +} + + + + +void DragAndDropContext::UpdatePosition ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bAllowAutoScroll) +{ + if (mpTargetSlideSorter == NULL) + return; + + if (mpTargetSlideSorter->GetProperties()->IsUIReadOnly()) + return; + + // Convert window coordinates into model coordinates (we need the + // window coordinates for auto-scrolling because that remains + // constant while scrolling.) + SharedSdWindow pWindow (mpTargetSlideSorter->GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + ::boost::shared_ptr<InsertionIndicatorHandler> pInsertionIndicatorHandler ( + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()); + + if ( ! (bAllowAutoScroll + && mpTargetSlideSorter->GetController().GetScrollBarManager().AutoScroll( + rMousePosition, + ::boost::bind( + &DragAndDropContext::UpdatePosition, this, rMousePosition, eMode, false)))) + { + pInsertionIndicatorHandler->UpdatePosition(aMouseModelPosition, eMode); + + // Remember the new insertion index. + mnInsertionIndex = pInsertionIndicatorHandler->GetInsertionPageIndex(); + if (pInsertionIndicatorHandler->IsInsertionTrivial(mnInsertionIndex, eMode)) + mnInsertionIndex = -1; + } +} + + + + +void DragAndDropContext::SetTargetSlideSorter ( + SlideSorter* pSlideSorter, + const Point aMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bIsOverSourceView) +{ + if (mpTargetSlideSorter != NULL) + { + mpTargetSlideSorter->GetController().GetScrollBarManager().StopAutoScroll(); + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->End( + Animator::AM_Animated); + } + + mpTargetSlideSorter = pSlideSorter; + + if (mpTargetSlideSorter != NULL) + { + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->Start( + bIsOverSourceView); + mpTargetSlideSorter->GetController().GetInsertionIndicatorHandler()->UpdatePosition( + aMousePosition, + eMode); + + } +} + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx new file mode 100644 index 000000000000..7536f88d9474 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsDragAndDropContext.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_SUBSTITUTION_HANDLER_HXX +#define SD_SLIDESORTER_SUBSTITUTION_HANDLER_HXX + +#include <tools/gen.hxx> + +#include "model/SlsSharedPageDescriptor.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include <vector> + + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + + +namespace sd { namespace slidesorter { namespace controller { + +/** A DragAndDropContext object handles an active drag and drop operation. + When the mouse is moved from one slide sorter window to another the + target SlideSorter object is exchanged accordingly. +*/ +class DragAndDropContext +{ +public: + /** Create a substitution display of the currently selected pages or, + when provided, the pages in the transferable. + */ + DragAndDropContext (SlideSorter& rSlideSorter); + ~DragAndDropContext (void); + + /** Call this method (for example as reaction to ESC key press) to avoid + processing (ie moving or inserting) the substition when the called + DragAndDropContext object is destroyed. + */ + void Dispose (void); + + /** 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& rMousePosition, + const InsertionIndicatorHandler::Mode eMode, + const bool bAllowAutoScroll = true); + + void SetTargetSlideSorter ( + SlideSorter* pSlideSorter = NULL, + const Point aMousePosition = Point(0,0), + const InsertionIndicatorHandler::Mode eMode = InsertionIndicatorHandler::UnknownMode, + const bool bIsOverSourceView = false); + +private: + SlideSorter* mpTargetSlideSorter; + model::SharedPageDescriptor mpHitDescriptor; + sal_Int32 mnInsertionIndex; + + void GetPagesFromBookmarks ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + DrawDocShell* pDocShell, + const List& rBookmarks) const; + void GetPagesFromSelection ( + ::std::vector<const SdPage*>& rPages, + sal_Int32& rnSelectionCount, + model::PageEnumeration& rSelection) const; +}; + + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx new file mode 100644 index 000000000000..03ca44d4b848 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsFocusManager.cxx @@ -0,0 +1,402 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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/SlsCurrentSlideManager.hxx" +#include "controller/SlsVisibleAreaManager.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" + +#define UNIFY_FOCUS_AND_CURRENT_PAGE + +namespace sd { namespace slidesorter { namespace controller { + +FocusManager::FocusManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mnPageIndex(0), + mbPageIsFocused(false), + mbIsVerticalWrapActive(false) +{ + if (mrSlideSorter.GetModel().GetPageCount() > 0) + mnPageIndex = 0; +} + + + + +FocusManager::~FocusManager (void) +{ +} + + + + +void FocusManager::MoveFocus (FocusMoveDirection eDirection) +{ + if (mnPageIndex >= 0 && mbPageIsFocused) + { + HideFocusIndicator (GetFocusedPageDescriptor()); + + const sal_Int32 nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount()); + const sal_Int32 nPageCount (mrSlideSorter.GetModel().GetPageCount()); + switch (eDirection) + { + case FMD_NONE: + // Nothing to be done. + break; + + case FMD_LEFT: + if (mnPageIndex > 0) + mnPageIndex -= 1; + else if (mbIsVerticalWrapActive) + mnPageIndex = nPageCount-1; + break; + + case FMD_RIGHT: + if (mnPageIndex < nPageCount-1) + mnPageIndex += 1; + else if (mbIsVerticalWrapActive) + mnPageIndex = 0; + break; + + case FMD_UP: + { + const sal_Int32 nCandidate (mnPageIndex - nColumnCount); + if (nCandidate < 0) + { + if (mbIsVerticalWrapActive) + { + // Wrap arround to the bottom row or the one above + // and go to the correct column. + const sal_Int32 nLastIndex (nPageCount-1); + const sal_Int32 nLastColumn (nLastIndex % nColumnCount); + const sal_Int32 nCurrentColumn (mnPageIndex%nColumnCount); + if (nLastColumn >= nCurrentColumn) + { + // The last row contains the current column. + mnPageIndex = nLastIndex - (nLastColumn-nCurrentColumn); + } + else + { + // Only the second to last row contains the current column. + mnPageIndex = nLastIndex - nLastColumn + - nColumnCount + + nCurrentColumn; + } + } + } + else + { + // Move the focus the previous row. + mnPageIndex = nCandidate; + } + } + break; + + case FMD_DOWN: + { + const sal_Int32 nCandidate (mnPageIndex + nColumnCount); + if (nCandidate >= nPageCount) + { + if (mbIsVerticalWrapActive) + { + // Wrap arround to the correct column. + mnPageIndex = mnPageIndex % nColumnCount; + } + else + { + // Do not move the focus. + } + } + else + { + // Move the focus to the next row. + mnPageIndex = nCandidate; + } + } + break; + } + + if (mnPageIndex < 0) + { + OSL_ASSERT(mnPageIndex>=0); + mnPageIndex = 0; + } + else if (mnPageIndex >= nPageCount) + { + OSL_ASSERT(mnPageIndex<nPageCount); + mnPageIndex = nPageCount - 1; + } + + if (mbPageIsFocused) + { + ShowFocusIndicator(GetFocusedPageDescriptor(), true); + } + } +} + + + + +void FocusManager::ShowFocus (const bool bScrollToFocus) +{ + mbPageIsFocused = true; + ShowFocusIndicator(GetFocusedPageDescriptor(), bScrollToFocus); +} + + + + +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.GetContentWindow()->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; +} + + + + +void FocusManager::SetFocusedPageToCurrentPage (void) +{ + SetFocusedPage(mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); +} + + + + +bool FocusManager::IsFocusShowing (void) const +{ + return HasFocus() && mbPageIsFocused; +} + + + + +void FocusManager::HideFocusIndicator (const model::SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get() != NULL) + { + mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, false); + } +} + + + + +void FocusManager::ShowFocusIndicator ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bScrollToFocus) +{ + if (rpDescriptor.get() != NULL) + { + mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, true); + + if (bScrollToFocus) + { + // Scroll the focused page object into the visible area and repaint + // it, so that the focus indicator becomes visible. + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true); + } + 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->GetToolBox().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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx new file mode 100644 index 000000000000..e7fff7b9f52a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.cxx @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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()); + static_cast<view::SlideSorterView*>(mpView)->SetState( + pDescriptor, + model::PageDescriptor::ST_Excluded, + eState==EXCLUDED); + } + } + + 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); + sal_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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.hxx b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.hxx new file mode 100644 index 000000000000..6bdf37e4c249 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsHideSlideFunction.hxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx new file mode 100644 index 000000000000..882adab932a8 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsInsertionIndicatorHandler.cxx @@ -0,0 +1,327 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsProperties.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsInsertionIndicatorOverlay.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> + +#include "SlideSorter.hxx" + +using namespace ::com::sun::star::datatransfer::dnd::DNDConstants; + +namespace sd { namespace slidesorter { namespace controller { + + +InsertionIndicatorHandler::InsertionIndicatorHandler (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mpInsertAnimator(), + mpInsertionIndicatorOverlay(new view::InsertionIndicatorOverlay(rSlideSorter)), + maInsertPosition(), + meMode(MoveMode), + mbIsActive(false), + mbIsReadOnly(mrSlideSorter.GetModel().IsReadOnly()), + mbIsOverSourceView(true), + maIconSize(0,0), + mbIsForcedShow(false) +{ +} + + + + +InsertionIndicatorHandler::~InsertionIndicatorHandler (void) +{ +} + + + + +void InsertionIndicatorHandler::Start (const bool bIsOverSourceView) +{ + if (mbIsActive) + { + OSL_ASSERT(!mbIsActive); + } + + mbIsReadOnly = mrSlideSorter.GetModel().IsReadOnly(); + if (mbIsReadOnly) + return; + + mbIsActive = true; + mbIsOverSourceView = bIsOverSourceView; +} + + + + +void InsertionIndicatorHandler::End (const controller::Animator::AnimationMode eMode) +{ + if (mbIsForcedShow || ! mbIsActive || mbIsReadOnly) + return; + + GetInsertAnimator()->Reset(eMode); + + mbIsActive = false; + // maInsertPosition = view::InsertPosition(); + meMode = UnknownMode; + + mpInsertionIndicatorOverlay->Hide(); + mpInsertionIndicatorOverlay.reset(new view::InsertionIndicatorOverlay(mrSlideSorter)); +} + + + + +void InsertionIndicatorHandler::ForceShow (void) +{ + mbIsForcedShow = true; +} + + + + +void InsertionIndicatorHandler::ForceEnd (void) +{ + mbIsForcedShow = false; + End(Animator::AM_Immediate); +} + + + + +void InsertionIndicatorHandler::UpdateIndicatorIcon (const Transferable* pTransferable) +{ + mpInsertionIndicatorOverlay->Create(pTransferable); + maIconSize = mpInsertionIndicatorOverlay->GetSize(); +} + + + + +InsertionIndicatorHandler::Mode InsertionIndicatorHandler::GetModeFromDndAction ( + const sal_Int8 nDndAction) +{ + if ((nDndAction & ACTION_MOVE) != 0) + return MoveMode; + else if ((nDndAction & ACTION_COPY) != 0) + return CopyMode; + else + return UnknownMode; +} + + + + +void InsertionIndicatorHandler::UpdatePosition ( + const Point& rMouseModelPosition, + const Mode eMode) +{ + if ( ! mbIsActive) + return; + + if (mbIsReadOnly) + return; + + SetPosition(rMouseModelPosition, eMode); +} + + + + +void InsertionIndicatorHandler::UpdatePosition ( + const Point& rMouseModelPosition, + const sal_Int8 nDndAction) +{ + UpdatePosition(rMouseModelPosition, GetModeFromDndAction(nDndAction)); +} + + + + +bool InsertionIndicatorHandler::IsActive (void) const +{ + return mbIsActive; +} + + + + +sal_Int32 InsertionIndicatorHandler::GetInsertionPageIndex (void) const +{ + if (mbIsReadOnly) + return -1; + else + return maInsertPosition.GetIndex(); +} + + + + +void InsertionIndicatorHandler::SetPosition ( + const Point& rPoint, + const Mode eMode) +{ + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + + const view::InsertPosition aInsertPosition (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + + static sal_Int32 TargetIndex (1); + if (aInsertPosition.GetIndex() == TargetIndex) + { + const view::InsertPosition aPosition (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + const view::InsertPosition aPosition2 (rLayouter.GetInsertPosition( + rPoint, + maIconSize, + mrSlideSorter.GetModel())); + } + + if (maInsertPosition != aInsertPosition + || meMode != eMode + // || ! mpInsertionIndicatorOverlay->IsVisible() + ) + { + maInsertPosition = aInsertPosition; + meMode = eMode; + mbIsInsertionTrivial = IsInsertionTrivial(maInsertPosition.GetIndex(), eMode); + if (maInsertPosition.GetIndex()>=0 && ! mbIsInsertionTrivial) + { + mpInsertionIndicatorOverlay->SetLocation(maInsertPosition.GetLocation()); + + GetInsertAnimator()->SetInsertPosition(maInsertPosition); + mpInsertionIndicatorOverlay->Show(); + } + else + { + GetInsertAnimator()->Reset(Animator::AM_Animated); + mpInsertionIndicatorOverlay->Hide(); + } + } +} + + + + +::boost::shared_ptr<view::InsertAnimator> InsertionIndicatorHandler::GetInsertAnimator (void) +{ + if ( ! mpInsertAnimator) + mpInsertAnimator.reset(new view::InsertAnimator(mrSlideSorter)); + return mpInsertAnimator; +} + + + + +bool InsertionIndicatorHandler::IsInsertionTrivial ( + const sal_Int32 nInsertionIndex, + const Mode eMode) const +{ + if (eMode == CopyMode) + return false; + else if (eMode == UnknownMode) + return true; + + if ( ! mbIsOverSourceView) + return false; + + // 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()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + + // Get the page number and compare it to the last one. + const sal_Int32 nPageNumber (pDescriptor->GetPageIndex()); + if (nCurrentIndex>=0 && nPageNumber>(nCurrentIndex+1)) + return false; + else + nCurrentIndex = nPageNumber; + + // Remember indices of the first and last page of the selection. + if (nFirstIndex == -1) + nFirstIndex = nPageNumber; + nLastIndex = nPageNumber; + } + + // When we come here then the selection has no holes. 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. + if (nInsertionIndex<nFirstIndex || nInsertionIndex>(nLastIndex+1)) + return false; + + return true; +} + + + + +bool InsertionIndicatorHandler::IsInsertionTrivial (const sal_Int8 nDndAction) +{ + return IsInsertionTrivial(GetInsertionPageIndex(), GetModeFromDndAction(nDndAction)); +} + + + + +//===== InsertionIndicatorHandler::ForceShowContext =========================== + +InsertionIndicatorHandler::ForceShowContext::ForceShowContext ( + const ::boost::shared_ptr<InsertionIndicatorHandler>& rpHandler) + : mpHandler(rpHandler) +{ + mpHandler->ForceShow(); +} + + + + +InsertionIndicatorHandler::ForceShowContext::~ForceShowContext (void) +{ + mpHandler->ForceEnd(); +} + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsListener.cxx b/sd/source/ui/slidesorter/controller/SlsListener.cxx new file mode 100644 index 000000000000..3604f55a8c29 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsListener.cxx @@ -0,0 +1,701 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#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 "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "cache/SlsPageCache.hxx" +#include "cache/SlsPageCacheManager.hxx" +#include "drawdoc.hxx" +#include "DrawDocShell.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> +#include <tools/diagnose_ex.h> + + +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()); + StartListening(*mrSlideSorter.GetModel().GetDocument()->GetDocSh()); + 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()->GetDocSh()); + 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&) + { + DBG_UNHANDLED_EXCEPTION(); + } + try + { + xSet->addPropertyChangeListener(String::CreateFromAscii("IsMasterPageMode"), this); + } + catch (beans::UnknownPropertyException&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + // 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&) + { + DBG_UNHANDLED_EXCEPTION(); + } + + mbListeningToController = false; + mxControllerWeak = Reference<frame::XController>(); + } +} + + + + +void Listener::Notify ( + SfxBroadcaster& rBroadcaster, + const SfxHint& rHint) +{ + if (rHint.ISA(SdrHint)) + { + SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint)); + switch (rSdrHint.GetKind()) + { + case HINT_PAGEORDERCHG: + if (&rBroadcaster == mrSlideSorter.GetModel().GetDocument()) + HandleModelChange(rSdrHint.GetPage()); + break; + + default: + break; + } + } + 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; + } + } + else if (rHint.ISA(SfxSimpleHint)) + { + SfxSimpleHint& rSfxSimpleHint (*PTR_CAST(SfxSimpleHint,&rHint)); + switch (rSfxSimpleHint.GetId()) + { + case SFX_HINT_DOCCHANGED: + mrController.CheckForMasterPageAssignment(); + 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().GetCoreSelection(); + UpdateEditMode(); + } + break; + + + case tools::EventMultiplexerEvent::EID_CONTROLLER_DETACHED: + DisconnectFromController(); + break; + + case tools::EventMultiplexerEvent::EID_SHAPE_CHANGED: + case tools::EventMultiplexerEvent::EID_SHAPE_INSERTED: + case tools::EventMultiplexerEvent::EID_SHAPE_REMOVED: + HandleShapeModification(static_cast<const SdrPage*>(pEvent->mpUserData)); + 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().GetCoreSelection(); + // 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()->NotifyCurrentSlideChange(nCurrentPage-1); + } + catch (beans::UnknownPropertyException&) + { + DBG_UNHANDLED_EXCEPTION(); + } + 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().GetCoreSelection(); + 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&) + { + // 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::HandleModelChange (const SdrPage* pPage) +{ + // Notify model and selection observer about the page. The return value + // of the model call acts as filter as to which events to pass to the + // selection observer. + if (mrSlideSorter.GetModel().NotifyPageEvent(pPage)) + { + // The page of the hint belongs (or belonged) to the model. + + // Tell the cache manager that the preview bitmaps for a deleted + // page can be removed from all caches. + if (pPage!=NULL && ! pPage->IsInserted()) + cache::PageCacheManager::Instance()->ReleasePreviewBitmap(pPage); + + mrController.GetSelectionManager()->GetSelectionObserver()->NotifyPageEvent(pPage); + } + + // Tell the controller about the model change only when the document is + // in a sane state, not just in the middle of a larger change. + SdDrawDocument* pDocument (mrSlideSorter.GetModel().GetDocument()); + if (pDocument != NULL + && pDocument->GetMasterSdPageCount(PK_STANDARD) == pDocument->GetMasterSdPageCount(PK_NOTES)) + { + // A model change can make updates of some text fields necessary + // (like page numbers and page count.) Invalidate all previews in + // the cache to cope with this. Doing this on demand would be a + // nice optimization. + cache::PageCacheManager::Instance()->InvalidateAllPreviewBitmaps(pDocument->getUnoModel()); + + mrController.HandleModelChange(); + } +} + + + +void Listener::HandleShapeModification (const SdrPage* pPage) +{ + if (pPage == NULL) + return; + + // Invalidate the preview of the page (in all slide sorters that display + // it.) + ::boost::shared_ptr<cache::PageCacheManager> pCacheManager (cache::PageCacheManager::Instance()); + if ( ! pCacheManager) + return; + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if (pDocument == NULL) + { + OSL_ASSERT(pDocument!=NULL); + return; + } + pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pPage); + mrSlideSorter.GetView().GetPreviewCache()->RequestPreviewBitmap(pPage); + + // When the page is a master page then invalidate the previews of all + // pages that are linked to this master page. + if (pPage->IsMasterPage()) + { + for (sal_uInt16 nIndex=0,nCount=pDocument->GetSdPageCount(PK_STANDARD); + nIndex<nCount; + ++nIndex) + { + const SdPage* pCandidate = pDocument->GetSdPage(nIndex, PK_STANDARD); + if (pCandidate!=NULL && pCandidate->TRG_HasMasterPage()) + { + if (&pCandidate->TRG_GetMasterPage() == pPage) + pCacheManager->InvalidatePreviewBitmap(pDocument->getUnoModel(), pCandidate); + } + else + { + OSL_ASSERT(pCandidate!=NULL && pCandidate->TRG_HasMasterPage()); + } + } + } +} + + + + +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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsListener.hxx b/sd/source/ui/slidesorter/controller/SlsListener.hxx new file mode 100644 index 000000000000..36d24af055fa --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsListener.hxx @@ -0,0 +1,197 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#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 <svl/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); + + /** Handle a change in the order of slides or when the set of slides has + changed, i.e. a slide has been created. + */ + void HandleModelChange (const SdrPage* pPage); + + /** Handle a modification to a shape on the given page. When this is a + regular page then update its preview. When it is a master page then + additionally update the previews of all pages linked to it. + */ + void HandleShapeModification (const SdrPage* pPage); + + /** 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsPageObjectFactory.cxx b/sd/source/ui/slidesorter/controller/SlsPageObjectFactory.cxx new file mode 100644 index 000000000000..726371d6ea7d --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsPageObjectFactory.cxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx new file mode 100644 index 000000000000..cfd34db8177f --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsPageSelector.cxx @@ -0,0 +1,491 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "controller/SlsAnimator.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsVisibleAreaManager.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> +#include <boost/bind.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(), + mpCurrentPage(), + mnUpdateLockCount(0), + mbIsUpdateCurrentPagePending(false) +{ + CountSelectedPages (); +} + + + + +void PageSelector::SelectAllPages (void) +{ + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + PageSelector::UpdateLock aLock (*this); + + int nPageCount = mrModel.GetPageCount(); + for (int nPageIndex=0; nPageIndex<nPageCount; nPageIndex++) + SelectPage(nPageIndex); +} + + + + +void PageSelector::DeselectAllPages (void) +{ + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + PageSelector::UpdateLock aLock (*this); + + 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; + mpSelectionAnchor.reset(); +} + + + + +void PageSelector::GetCoreSelection (void) +{ + PageSelector::UpdateLock aLock (*this); + + bool bSelectionHasChanged (true); + mnSelectedPageCount = 0; + model::PageEnumeration aAllPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + if (pDescriptor->GetCoreSelection()) + { + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(pDescriptor); + mrSlideSorter.GetView().RequestRepaint(pDescriptor); + bSelectionHasChanged = true; + } + + if (pDescriptor->HasState(PageDescriptor::ST_Selected)) + mnSelectedPageCount++; + } + + if (bSelectionHasChanged) + { + if (mnBroadcastDisableLevel > 0) + mbSelectionChangeBroadcastPending = true; + else + mrController.GetSelectionManager()->SelectionHasChanged(); + } +} + + + + +void PageSelector::SetCoreSelection (void) +{ + model::PageEnumeration aAllPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aAllPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->SetCoreSelection(); + } +} + + + + +void PageSelector::SelectPage (int nPageIndex) +{ + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get() != NULL) + SelectPage(pDescriptor); +} + + + + +void PageSelector::SelectPage (const SdPage* pPage) +{ + const sal_Int32 nPageIndex (mrModel.GetIndex(pPage)); + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage) + SelectPage(pDescriptor); +} + + + + +void PageSelector::SelectPage (const SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor.get()!=NULL + && mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, true)) + { + ++mnSelectedPageCount; + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true); + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); + + mpMostRecentlySelectedPage = rpDescriptor; + if (mpSelectionAnchor == NULL) + mpSelectionAnchor = rpDescriptor; + + if (mnBroadcastDisableLevel > 0) + mbSelectionChangeBroadcastPending = true; + else + mrController.GetSelectionManager()->SelectionHasChanged(); + UpdateCurrentPage(); + + CheckConsistency(); + } +} + + + + +void PageSelector::DeselectPage ( + int nPageIndex, + const bool bUpdateCurrentPage) +{ + model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get() != NULL) + DeselectPage(pDescriptor, bUpdateCurrentPage); +} + + + + +void PageSelector::DeselectPage ( + const SdPage* pPage, + const bool bUpdateCurrentPage) +{ + const sal_Int32 nPageIndex (mrModel.GetIndex(pPage)); + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get()!=NULL && pDescriptor->GetPage()==pPage) + DeselectPage(pDescriptor, bUpdateCurrentPage); +} + + + + +void PageSelector::DeselectPage ( + const SharedPageDescriptor& rpDescriptor, + const bool bUpdateCurrentPage) +{ + if (rpDescriptor.get()!=NULL + && mrSlideSorter.GetView().SetState(rpDescriptor, PageDescriptor::ST_Selected, false)) + { + --mnSelectedPageCount; + mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor); + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); + if (mpMostRecentlySelectedPage == rpDescriptor) + mpMostRecentlySelectedPage.reset(); + if (mnBroadcastDisableLevel > 0) + mbSelectionChangeBroadcastPending = true; + else + mrController.GetSelectionManager()->SelectionHasChanged(); + if (bUpdateCurrentPage) + UpdateCurrentPage(); + + CheckConsistency(); + } +} + + + + +void PageSelector::CheckConsistency (void) const +{ + int nSelectionCount (0); + for (int nPageIndex=0,nPageCount=mrModel.GetPageCount(); nPageIndex<nPageCount; nPageIndex++) + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + assert(pDescriptor); + if (pDescriptor->HasState(PageDescriptor::ST_Selected)) + ++nSelectionCount; + } + if (nSelectionCount!=mnSelectedPageCount) + { + assert(nSelectionCount==mnSelectedPageCount); + } +} + + + + +bool PageSelector::IsPageSelected (int nPageIndex) +{ + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nPageIndex)); + if (pDescriptor.get() != NULL) + return pDescriptor->HasState(PageDescriptor::ST_Selected); + else + return false; +} + + + + +int PageSelector::GetPageCount (void) const +{ + return mrModel.GetPageCount(); +} + + + + +int PageSelector::GetSelectedPageCount (void) const +{ + return mnSelectedPageCount; +} + + + + +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 (void) +{ + if (mnBroadcastDisableLevel > 0) + mnBroadcastDisableLevel --; + if (mnBroadcastDisableLevel==0 && mbSelectionChangeBroadcastPending) + { + mrController.GetSelectionManager()->SelectionHasChanged(); + 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->HasState(PageDescriptor::ST_Selected)) + pSelection->push_back(pDescriptor->GetPage()); + } + + return pSelection; +} + + + + +void PageSelector::SetPageSelection ( + const ::boost::shared_ptr<PageSelection>& rpSelection, + const bool bUpdateCurrentPage) +{ + PageSelection::const_iterator iPage; + for (iPage=rpSelection->begin(); iPage!=rpSelection->end(); ++iPage) + SelectPage(*iPage); + if (bUpdateCurrentPage) + UpdateCurrentPage(); +} + + + + +void PageSelector::UpdateCurrentPage (const bool bUpdateOnlyWhenPending) +{ + if (mnUpdateLockCount > 0) + { + mbIsUpdateCurrentPagePending = true; + return; + } + + if ( ! mbIsUpdateCurrentPagePending && bUpdateOnlyWhenPending) + return; + + mbIsUpdateCurrentPagePending = false; + + // Make the first selected page the current page. + const sal_Int32 nPageCount (GetPageCount()); + for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (pDescriptor && pDescriptor->HasState(PageDescriptor::ST_Selected)) + { + // Switching the current slide normally sets also the selection + // to just the new current slide. To prevent that, we store + // (and at the end of this scope restore) the current selection. + ::boost::shared_ptr<PageSelection> pSelection (GetPageSelection()); + + mrController.GetCurrentSlideManager()->SwitchCurrentSlide(pDescriptor); + + // Restore the selection and prevent a recursive call to + // UpdateCurrentPage(). + SetPageSelection(pSelection, false); + return; + } + } + + // No page is selected. Do not change the current slide. +} + + + + +//===== PageSelector::UpdateLock ============================================== + +PageSelector::UpdateLock::UpdateLock (SlideSorter& rSlideSorter) + : mpSelector(&rSlideSorter.GetController().GetPageSelector()) +{ + ++mpSelector->mnUpdateLockCount; +} + + + + +PageSelector::UpdateLock::UpdateLock (PageSelector& rSelector) + : mpSelector(&rSelector) +{ + ++mpSelector->mnUpdateLockCount; +} + + + + +PageSelector::UpdateLock::~UpdateLock (void) +{ + Release(); +} + +void PageSelector::UpdateLock::Release (void) +{ + if (mpSelector != NULL) + { + --mpSelector->mnUpdateLockCount; + OSL_ASSERT(mpSelector->mnUpdateLockCount >= 0); + if (mpSelector->mnUpdateLockCount == 0) + mpSelector->UpdateCurrentPage(true); + + mpSelector = NULL; + } +} + + + + +//===== PageSelector::BroadcastLock ============================================== + +PageSelector::BroadcastLock::BroadcastLock (SlideSorter& rSlideSorter) + : mrSelector(rSlideSorter.GetController().GetPageSelector()) +{ + mrSelector.DisableBroadcasting(); +} + + + + +PageSelector::BroadcastLock::BroadcastLock (PageSelector& rSelector) + : mrSelector(rSelector) +{ + mrSelector.DisableBroadcasting(); +} + + + + +PageSelector::BroadcastLock::~BroadcastLock (void) +{ + mrSelector.EnableBroadcasting(); +} + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsProperties.cxx b/sd/source/ui/slidesorter/controller/SlsProperties.cxx new file mode 100644 index 000000000000..88a17a8444ac --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsProperties.cxx @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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(true), + mbIsSuspendPreviewUpdatesDuringFullScreenPresentation(true), + maBackgroundColor(Application::GetSettings().GetStyleSettings().GetWindowColor()), + maTextColor(Application::GetSettings().GetStyleSettings().GetActiveTextColor()), + maSelectionColor(Application::GetSettings().GetStyleSettings().GetHighlightColor()), + maHighlightColor(Application::GetSettings().GetStyleSettings().GetMenuHighlightColor()), + mbIsUIReadOnly(false), + mbIsOnlyPreviewTriggersMouseOver(true), + mbIsHighContrastModeActive( + Application::GetSettings().GetStyleSettings().GetHighContrastMode()) +{ +} + + + + +Properties::~Properties (void) +{ +} + + + + +void Properties::HandleDataChangeEvent (void) +{ + maBackgroundColor = Application::GetSettings().GetStyleSettings().GetWindowColor(); + maTextColor = Application::GetSettings().GetStyleSettings().GetActiveTextColor(); + maSelectionColor = Application::GetSettings().GetStyleSettings().GetHighlightColor(); + maHighlightColor = Application::GetSettings().GetStyleSettings().GetMenuHighlightColor(); + mbIsHighContrastModeActive + = Application::GetSettings().GetStyleSettings().GetHighContrastMode(); +} + + + + +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; +} + + + + +bool Properties::IsOnlyPreviewTriggersMouseOver (void) const +{ + return mbIsOnlyPreviewTriggersMouseOver; +} + + + + +void Properties::SetOnlyPreviewTriggersMouseOver (const bool bFlag) +{ + mbIsOnlyPreviewTriggersMouseOver = bFlag; +} + + + + +bool Properties::IsHighContrastModeActive (void) const +{ + return mbIsHighContrastModeActive; +} + + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx new file mode 100644 index 000000000000..71ac9450ca21 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsScrollBarManager.cxx @@ -0,0 +1,740 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "controller/SlsVisibleAreaManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsTheme.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 (20,20), + mnHorizontalScrollFactor (0.15), + mnVerticalScrollFactor (0.25), + mpScrollBarFiller(mrSlideSorter.GetScrollBarFiller()), + maAutoScrollTimer(), + maAutoScrollOffset(0,0), + mbIsAutoScrollActive(false), + mpContentWindow(mrSlideSorter.GetContentWindow()), + maAutoScrollFunctor() +{ + // 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(25); + 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, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed) +{ + Rectangle aRemainingSpace (DetermineScrollBarVisibilities( + rAvailableArea, + bIsHorizontalScrollBarAllowed, + bIsVerticalScrollBarAllowed)); + + if (mpHorizontalScrollBar!=NULL && mpHorizontalScrollBar->IsVisible()) + PlaceHorizontalScrollBar (rAvailableArea); + + if (mpVerticalScrollBar!=NULL && mpVerticalScrollBar->IsVisible()) + PlaceVerticalScrollBar (rAvailableArea); + + if (mpScrollBarFiller!=NULL && mpScrollBarFiller->IsVisible()) + PlaceFiller (rAvailableArea); + + return aRemainingSpace; +} + + + + +void ScrollBarManager::PlaceHorizontalScrollBar (const Rectangle& aAvailableArea) +{ + // 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) +{ + const double nThumbPosition (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(nThumbPosition); + mnVerticalPosition = nThumbPosition / double(mpVerticalScrollBar->GetRange().Len()); +} + + + + +void ScrollBarManager::PlaceFiller (const Rectangle& aArea) +{ + mpScrollBarFiller->SetPosSizePixel( + Point( + aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1, + aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1), + Size ( + mpVerticalScrollBar->GetSizePixel().Width(), + mpHorizontalScrollBar->GetSizePixel().Height())); +} + + + + +void ScrollBarManager::UpdateScrollBars (bool bResetThumbPosition, bool bUseScrolling) +{ + Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + 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.GetContentWindow()!=NULL) + { + double nRelativePosition = double(pScrollBar->GetThumbPos()) + / double(pScrollBar->GetRange().Len()); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + mrSlideSorter.GetContentWindow()->SetVisibleXY(-1, nRelativePosition); + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); + } + return sal_True; +} + + + + +IMPL_LINK(ScrollBarManager, HorizontalScrollBarHandler, ScrollBar*, pScrollBar) +{ + if (pScrollBar!=NULL + && pScrollBar==mpHorizontalScrollBar.get() + && pScrollBar->IsVisible() + && mrSlideSorter.GetContentWindow()!=NULL) + { + double nRelativePosition = double(pScrollBar->GetThumbPos()) + / double(pScrollBar->GetRange().Len()); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + mrSlideSorter.GetContentWindow()->SetVisibleXY(nRelativePosition, -1); + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); + } + return sal_True; +} + + + + +void ScrollBarManager::SetWindowOrigin ( + double nHorizontalPosition, + double nVerticalPosition) +{ + mnHorizontalPosition = nHorizontalPosition; + mnVerticalPosition = nVerticalPosition; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + 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, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed) +{ + // Test which combination of scroll bars is the best. + bool bShowHorizontal = false; + bool bShowVertical = false; + if (mrSlideSorter.GetModel().GetPageCount() == 0) + { + // No pages => no scroll bars. + } + else if (TestScrollBarVisibilities(false, false, rAvailableArea)) + { + // Nothing to be done. + } + else if (bIsHorizontalScrollBarAllowed + && TestScrollBarVisibilities(true, false, rAvailableArea)) + { + bShowHorizontal = true; + } + else if (bIsVerticalScrollBarAllowed + && TestScrollBarVisibilities(false, true, rAvailableArea)) + { + bShowVertical = true; + } + else + { + bShowHorizontal = true; + bShowVertical = true; + } + + // Make the visibility of the scroll bars permanent. + mpVerticalScrollBar->Show(bShowVertical); + mpHorizontalScrollBar->Show(bShowHorizontal); + mpScrollBarFiller->Show(bShowVertical && 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) +{ + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + + // 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 (mrSlideSorter.GetView().GetLayouter().Rearrange ( + mrSlideSorter.GetView().GetOrientation(), + aBrowserSize, + rModel.GetPageDescriptor(0)->GetPage()->GetSize(), + rModel.GetPageCount())); + + if (bRearrangeSuccess) + { + Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetTotalBoundingBox().GetSize(); + Size aWindowModelSize = mpContentWindow->PixelToLogic(aBrowserSize); + + // The content may be clipped, i.e. not fully visible, in one + // direction only when the scroll bar is visible in that direction. + if (aPageSize.Width() > aWindowModelSize.Width()) + if ( ! bHorizontalScrollBarVisible) + return false; + if (aPageSize.Height() > aWindowModelSize.Height()) + if ( ! bVerticalScrollBarVisible) + return false; + + return true; + } + else + return false; +} + + + + +void ScrollBarManager::SetTopLeft (const Point aNewTopLeft) +{ + if (( ! mpVerticalScrollBar + || mpVerticalScrollBar->GetThumbPos() == aNewTopLeft.Y()) + && ( ! mpHorizontalScrollBar + || mpHorizontalScrollBar->GetThumbPos() == aNewTopLeft.X())) + return; + + // Flush pending repaints before scrolling to avoid temporary artifacts. + mrSlideSorter.GetContentWindow()->Update(); + + if (mpVerticalScrollBar) + { + mpVerticalScrollBar->SetThumbPos(aNewTopLeft.Y()); + mnVerticalPosition = aNewTopLeft.Y() / double(mpVerticalScrollBar->GetRange().Len()); + } + if (mpHorizontalScrollBar) + { + mpHorizontalScrollBar->SetThumbPos(aNewTopLeft.X()); + mnHorizontalPosition = aNewTopLeft.X() / double(mpHorizontalScrollBar->GetRange().Len()); + } + + mrSlideSorter.GetContentWindow()->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); +} + + + + +sal_Int32 ScrollBarManager::GetTop (void) const +{ + if (mpVerticalScrollBar != NULL) + return mpVerticalScrollBar->GetThumbPos(); + else + return 0; +} + + + + +sal_Int32 ScrollBarManager::GetLeft (void) const +{ + if (mpHorizontalScrollBar != NULL) + return mpHorizontalScrollBar->GetThumbPos(); + else + return 0; +} + + + + +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) +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + + 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, + const ::boost::function<void(void)>& rAutoScrollFunctor) +{ + maAutoScrollFunctor = rAutoScrollFunctor; + CalcAutoScrollOffset(rMouseWindowPosition); + bool bResult (true); + if ( ! mbIsAutoScrollActive) + bResult = RepeatAutoScroll(); + + return bResult; +} + + + + +void ScrollBarManager::StopAutoScroll (void) +{ + maAutoScrollTimer.Stop(); + mbIsAutoScrollActive = false; +} + + + + +bool ScrollBarManager::RepeatAutoScroll (void) +{ + if (maAutoScrollOffset != Size(0,0)) + { + if (mrSlideSorter.GetViewShell() != NULL) + { + mrSlideSorter.GetViewShell()->Scroll( + maAutoScrollOffset.Width(), + maAutoScrollOffset.Height()); + mrSlideSorter.GetView().InvalidatePageObjectVisibilities(); + + if (maAutoScrollFunctor) + maAutoScrollFunctor(); + + mbIsAutoScrollActive = true; + maAutoScrollTimer.Start(); + + return true; + } + } + + maAutoScrollFunctor = ::boost::function<void(void)>(); + mbIsAutoScrollActive = false; + return false; +} + + + + +IMPL_LINK(ScrollBarManager, AutoScrollTimeoutHandler, Timer *, EMPTYARG) +{ + RepeatAutoScroll(); + + return 0; +} + + + + +void ScrollBarManager::Scroll( + const Orientation eOrientation, + const Unit eUnit, + const sal_Int32 nDistance) +{ + bool bIsVertical (false); + switch (eOrientation) + { + case Orientation_Horizontal: bIsVertical = false; break; + case Orientation_Vertical: bIsVertical = true; break; + default: + OSL_ASSERT(eOrientation==Orientation_Horizontal || eOrientation==Orientation_Vertical); + return; + } + + Point aNewTopLeft ( + mpHorizontalScrollBar ? mpHorizontalScrollBar->GetThumbPos() : 0, + mpVerticalScrollBar ? mpVerticalScrollBar->GetThumbPos() : 0); + switch (eUnit) + { + case Unit_Pixel: + if (bIsVertical) + aNewTopLeft.Y() += nDistance; + else + aNewTopLeft.X() += nDistance; + break; + + case Unit_Slide: + { + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + + // Calculate estimate of new location. + if (bIsVertical) + aNewTopLeft.Y() += nDistance * rLayouter.GetPageObjectSize().Height(); + else + aNewTopLeft.X() += nDistance * rLayouter.GetPageObjectSize().Width(); + + // Adapt location to show whole slides. + if (bIsVertical) + if (nDistance > 0) + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()+mpVerticalScrollBar->GetVisibleSize()), + true)); + aNewTopLeft.Y() = rLayouter.GetPageObjectBox(nIndex,true).Bottom() + - mpVerticalScrollBar->GetVisibleSize(); + } + else + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()), + true)); + aNewTopLeft.Y() = rLayouter.GetPageObjectBox(nIndex,true).Top(); + } + else + if (nDistance > 0) + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X()+mpVerticalScrollBar->GetVisibleSize(), aNewTopLeft.Y()), + true)); + aNewTopLeft.X() = rLayouter.GetPageObjectBox(nIndex,true).Right() + - mpVerticalScrollBar->GetVisibleSize(); + } + else + { + const sal_Int32 nIndex (rLayouter.GetIndexAtPoint( + Point(aNewTopLeft.X(), aNewTopLeft.Y()), + true)); + aNewTopLeft.X() = rLayouter.GetPageObjectBox(nIndex,true).Left(); + } + } + } + mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking(); + SetTopLeft(aNewTopLeft); +} + + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionCommand.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.cxx new file mode 100644 index 000000000000..174c3b944ab3 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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::AddSlide (sal_uInt16 nPageIndex) +{ + maPagesToSelect.push_back(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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionCommand.hxx b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.hxx new file mode 100644 index 000000000000..1bc80260ad72 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionCommand.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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); + + /** Remember the specified page to be selected when this command is + executed. + */ + void AddSlide (sal_uInt16 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx new file mode 100644 index 000000000000..c52581f990a8 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionFunction.cxx @@ -0,0 +1,2027 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "SlsDragAndDropContext.hxx" +#include "controller/SlsTransferable.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/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsVisibleAreaManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsButtonBar.hxx" +#include "framework/FrameworkHelper.hxx" +#include "ViewShellBase.hxx" +#include "DrawController.hxx" +#include "Window.hxx" +#include "sdpage.hxx" +#include "drawdoc.hxx" +#include "DrawDocShell.hxx" +#include "sdxfer.hxx" +#include "ViewShell.hxx" +#include "ViewShellBase.hxx" +#include "FrameView.hxx" +#include "app.hrc" +#include "sdresid.hxx" +#include "strings.hrc" +#include <vcl/sound.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/dispatch.hxx> +#include <svx/svdpagv.hxx> +#include <vcl/msgbox.hxx> +#include <svx/svxids.hrc> +#include <boost/bind.hpp> +#include <boost/optional.hpp> + +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); +static const sal_uInt32 MOUSE_DRAG (0x00000800); +// 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 OVER_BUTTON_AREA (0x00080000); +static const sal_uInt32 OVER_BUTTON (0x00100000); +static const sal_uInt32 SHIFT_MODIFIER (0x00200000); +static const sal_uInt32 CONTROL_MODIFIER (0x00400000); + +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 NOT_OVER_PAGE (0x00000000); + +// Masks +static const sal_uInt32 MODIFIER_MASK (SHIFT_MODIFIER | CONTROL_MODIFIER); +static const sal_uInt32 BUTTON_MASK (LEFT_BUTTON | RIGHT_BUTTON | MIDDLE_BUTTON); + +} // end of anonymous namespace + + + +// 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 + +namespace sd { namespace slidesorter { namespace controller { + +//===== SelectionFunction::EventDescriptor ==================================== + +class SelectionFunction::EventDescriptor +{ +public: + Point maMousePosition; + Point maMouseModelPosition; + model::SharedPageDescriptor mpHitDescriptor; + SdrPage* mpHitPage; + sal_uInt32 mnEventCode; + bool mbIsOverButton; + InsertionIndicatorHandler::Mode meDragMode; + bool mbMakeSelectionVisible; + bool mbIsLeaving; + + EventDescriptor ( + sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter); + EventDescriptor ( + sal_uInt32 nEventType, + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction, + SlideSorter& rSlideSorter); + EventDescriptor ( + const KeyEvent& rEvent, + SlideSorter& rSlideSorter); + + void SetDragMode (const InsertionIndicatorHandler::Mode eMode); + +private: + /** 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 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 KeyEvent& rEvent) const; + + /** Compute a numerical code that describes the current state like + whether the selection rectangle is visible or whether the page under + the mouse or the one that has the focus is selected. + */ + sal_uInt32 EncodeState (void) const; +}; + + + + +//===== SelectionFunction::ModeHandler ======================================== + +class SelectionFunction::ModeHandler +{ +public: + ModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const bool bIsMouseOverIndicatorAllowed); + virtual ~ModeHandler (void); + + virtual Mode GetMode (void) const = 0; + virtual void Abort (void) = 0; + virtual void ProcessEvent (EventDescriptor& rDescriptor); + + /** Set the selection to exactly the specified page and also set it as + the current page. + */ + void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor); + + /// Deselect all pages. + void DeselectAllPages (void); + void SelectOnePage (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); + + void StartDrag ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode); + + bool IsMouseOverIndicatorAllowed (void) const; + +protected: + SlideSorter& mrSlideSorter; + SelectionFunction& mrSelectionFunction; + + virtual bool ProcessButtonDownEvent (EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (EventDescriptor& rDescriptor); + virtual bool HandleUnprocessedEvent (EventDescriptor& rDescriptor); + + void ReprocessEvent (EventDescriptor& rDescriptor); + +private: + const bool mbIsMouseOverIndicatorAllowed; +}; + + +/** This is the default handler for processing events. It activates the + multi selection or drag-and-drop when the right conditions are met. +*/ +class NormalModeHandler : public SelectionFunction::ModeHandler +{ +public: + NormalModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction); + virtual ~NormalModeHandler (void); + + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + + void ResetButtonDownLocation (void); + +protected: + virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + ::boost::optional<Point> maButtonDownLocation; + + /** Select all pages between and including the selection anchor and the + specified page. + */ + void RangeSelect (const model::SharedPageDescriptor& rpDescriptor); +}; + + +/** Handle events during a multi selection, which typically is started by + pressing the left mouse button when not over a page. +*/ +class MultiSelectionModeHandler : public SelectionFunction::ModeHandler +{ +public: + /** Start a rectangle selection at the given position. + */ + MultiSelectionModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMouseModelPosition, + const sal_uInt32 nEventCode); + virtual ~MultiSelectionModeHandler (void); + + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + virtual void ProcessEvent (SelectionFunction::EventDescriptor& rDescriptor); + + enum SelectionMode { SM_Normal, SM_Add, SM_Toggle }; + + void SetSelectionMode (const SelectionMode eSelectionMode); + void SetSelectionModeFromModifier (const sal_uInt32 nEventCode); + +protected: + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool HandleUnprocessedEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + SelectionMode meSelectionMode; + Point maSecondCorner; + Pointer maSavedPointer; + sal_Int32 mnAnchorIndex; + sal_Int32 mnSecondIndex; + view::ButtonBar::Lock maButtonBarLock; + + virtual void UpdateModelPosition (const Point& rMouseModelPosition); + virtual void UpdateSelection (void); + + /** Update the rectangle selection so that the given position becomes + the new second point of the selection rectangle. + */ + void UpdatePosition ( + const Point& rMousePosition, + const bool bAllowAutoScroll); + + void UpdateSelectionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bIsInSelection) const; +}; + + +/** Handle events during drag-and-drop. +*/ +class DragAndDropModeHandler : public SelectionFunction::ModeHandler +{ +public: + DragAndDropModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMousePosition, + ::Window* pWindow); + virtual ~DragAndDropModeHandler (void); + + virtual SelectionFunction::Mode GetMode (void) const; + virtual void Abort (void); + +protected: + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor); + +private: + ::boost::scoped_ptr<DragAndDropContext> mpDragAndDropContext; +}; + + +/** Handle events while the left mouse button is pressed over the button + bar. +*/ +class ButtonModeHandler : public SelectionFunction::ModeHandler +{ +public: + ButtonModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction); + virtual ~ButtonModeHandler (void); + virtual void Abort (void); + + virtual SelectionFunction::Mode GetMode (void) const; + +protected: + virtual bool ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor); + virtual bool ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor); +}; + + + + +//===== SelectionFunction ===================================================== + +TYPEINIT1(SelectionFunction, FuPoor); + + +SelectionFunction::SelectionFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest) + : FuPoor ( + rSlideSorter.GetViewShell(), + rSlideSorter.GetContentWindow().get(), + &rSlideSorter.GetView(), + rSlideSorter.GetModel().GetDocument(), + rRequest), + mrSlideSorter(rSlideSorter), + mrController(mrSlideSorter.GetController()), + mbDragSelection(false), + maInsertionMarkerBox(), + mbProcessingMouseButtonDown(false), + mnShiftKeySelectionAnchor(-1), + mpModeHandler(new NormalModeHandler(rSlideSorter, *this)) +{ +} + + + + +SelectionFunction::~SelectionFunction (void) +{ + mpModeHandler.reset(); +} + + + + +FunctionReference SelectionFunction::Create( + SlideSorter& rSlideSorter, + SfxRequest& rRequest) +{ + FunctionReference xFunc( new SelectionFunction( rSlideSorter, rRequest ) ); + return xFunc; +} + + + + +sal_Bool SelectionFunction::MouseButtonDown (const MouseEvent& rEvent) +{ + // remember button state for creation of own MouseEvents + SetMouseButtonCode (rEvent.GetButtons()); + aMDPos = rEvent.GetPosPixel(); + mbProcessingMouseButtonDown = true; + + // mpWindow->CaptureMouse(); + + ProcessMouseEvent(BUTTON_DOWN, rEvent); + + return sal_True; +} + + + + +sal_Bool SelectionFunction::MouseMove (const MouseEvent& rEvent) +{ + ProcessMouseEvent(MOUSE_MOTION, rEvent); + return sal_True; +} + + + + +sal_Bool SelectionFunction::MouseButtonUp (const MouseEvent& rEvent) +{ + mrController.GetScrollBarManager().StopAutoScroll (); + + ProcessMouseEvent(BUTTON_UP, rEvent); + + mbProcessingMouseButtonDown = false; +// mpWindow->ReleaseMouse(); + + return sal_True; +} + + + + +void SelectionFunction::NotifyDragFinished (void) +{ + SwitchToNormalMode(); +} + + + + +sal_Bool SelectionFunction::KeyInput (const KeyEvent& rEvent) +{ + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aLock (mrSlideSorter); + FocusManager& rFocusManager (mrController.GetFocusManager()); + sal_Bool bResult = sal_False; + + const KeyCode& rCode (rEvent.GetKeyCode()); + switch (rCode.GetCode()) + { + case KEY_RETURN: + { + model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (rFocusManager.HasFocus() && pDescriptor && pViewShell!=NULL) + { + // The Return key triggers different functions depending on + // whether the slide sorter is the main view or displayed in + // the right pane. + if (pViewShell->IsMainViewShell()) + { + mpModeHandler->SetCurrentPage(pDescriptor); + mpModeHandler->SwitchView(pDescriptor); + } + else + { + pViewShell->GetDispatcher()->Execute( + SID_INSERTPAGE, + SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD); + } + bResult = sal_True; + } + break; + } + + case KEY_TAB: + if ( ! rFocusManager.IsFocusShowing()) + { + rFocusManager.ShowFocus(); + bResult = sal_True; + } + break; + + case KEY_ESCAPE: + // When there is an active multiselection or drag-and-drop + // operation then stop that. + mpModeHandler->Abort(); + SwitchToNormalMode(); + bResult = sal_True; + break; + + case KEY_SPACE: + { + // Toggle the selection state. + model::SharedPageDescriptor pDescriptor (rFocusManager.GetFocusedPageDescriptor()); + if (pDescriptor && rCode.IsMod1()) + { + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + mrController.GetPageSelector().DeselectPage(pDescriptor, false); + else + mrController.GetPageSelector().SelectPage(pDescriptor); + } + bResult = sal_True; + } + break; + + + // Move the focus indicator left. + case KEY_LEFT: + MoveFocus(FocusManager::FMD_LEFT, rCode.IsShift(), rCode.IsMod1()); + bResult = sal_True; + break; + + // Move the focus indicator right. + case KEY_RIGHT: + MoveFocus(FocusManager::FMD_RIGHT, rCode.IsShift(), rCode.IsMod1()); + bResult = sal_True; + break; + + // Move the focus indicator up. + case KEY_UP: + MoveFocus(FocusManager::FMD_UP, rCode.IsShift(), rCode.IsMod1()); + bResult = sal_True; + break; + + // Move the focus indicator down. + case KEY_DOWN: + MoveFocus(FocusManager::FMD_DOWN, rCode.IsShift(), rCode.IsMod1()); + bResult = sal_True; + break; + + // Go to previous page. No wrap around. + case KEY_PAGEUP: + GotoNextPage(-1); + bResult = sal_True; + break; + + // Go to next page. No wrap around.. + case KEY_PAGEDOWN: + GotoNextPage(+1); + bResult = sal_True; + break; + + case KEY_HOME: + GotoPage(0); + bResult = sal_True; + break; + + case KEY_END: + GotoPage(mrSlideSorter.GetModel().GetPageCount()-1); + bResult = sal_True; + break; + + case KEY_DELETE: + case KEY_BACKSPACE: + { + if (mrSlideSorter.GetProperties()->IsUIReadOnly()) + break; + + mrController.GetSelectionManager()->DeleteSelectedPages(rCode.GetCode()==KEY_DELETE); + + mnShiftKeySelectionAnchor = -1; + bResult = sal_True; + } + break; + + case KEY_F10: + if (rCode.IsShift()) + { + mpModeHandler->SelectOnePage( + mrSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); + } + break; + + default: + break; + } + + if ( ! bResult) + bResult = FuPoor::KeyInput(rEvent); + + return bResult; +} + + + + +void SelectionFunction::MoveFocus ( + const FocusManager::FocusMoveDirection eDirection, + const bool bIsShiftDown, + const bool bIsControlDown) +{ + // Remember the anchor of shift key multi selection. + if (bIsShiftDown) + { + if (mnShiftKeySelectionAnchor<0) + { + model::SharedPageDescriptor pFocusedDescriptor ( + mrController.GetFocusManager().GetFocusedPageDescriptor()); + mnShiftKeySelectionAnchor = pFocusedDescriptor->GetPageIndex(); + } + } + else if ( ! bIsControlDown) + ResetShiftKeySelectionAnchor(); + + mrController.GetFocusManager().MoveFocus(eDirection); + + PageSelector& rSelector (mrController.GetPageSelector()); + model::SharedPageDescriptor pFocusedDescriptor ( + mrController.GetFocusManager().GetFocusedPageDescriptor()); + if (bIsShiftDown) + { + // When shift is pressed then select all pages in the range between + // the currently and the previously focused pages, including them. + if (pFocusedDescriptor) + { + sal_Int32 nPageRangeEnd (pFocusedDescriptor->GetPageIndex()); + model::PageEnumeration aPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration( + mrSlideSorter.GetModel())); + while (aPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + if (pDescriptor) + { + const sal_Int32 nPageIndex(pDescriptor->GetPageIndex()); + if ((nPageIndex>=mnShiftKeySelectionAnchor && nPageIndex<=nPageRangeEnd) + || (nPageIndex<=mnShiftKeySelectionAnchor && nPageIndex>=nPageRangeEnd)) + { + rSelector.SelectPage(pDescriptor); + } + else + { + rSelector.DeselectPage(pDescriptor); + } + } + } + } + } + else if (bIsControlDown) + { + // When control is pressed then do not alter the selection or the + // current page, just move the focus. + } + else + { + // Without shift just select the focused page. + mpModeHandler->SelectOnePage(pFocusedDescriptor); + } +} + + + + +void SelectionFunction::Activate() +{ + FuPoor::Activate(); +} + + + + +void SelectionFunction::Deactivate() +{ + FuPoor::Deactivate(); +} + + + +void SelectionFunction::ScrollStart (void) +{ +} + + + + +void SelectionFunction::ScrollEnd (void) +{ +} + + + + +void SelectionFunction::DoCut (void) +{ + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) + { + mrController.GetClipboard().DoCut(); + } +} + + + + +void SelectionFunction::DoCopy (void) +{ + mrController.GetClipboard().DoCopy(); +} + + + + +void SelectionFunction::DoPaste (void) +{ + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) + { + mrController.GetClipboard().DoPaste(); + } +} + + + + +bool SelectionFunction::cancel (void) +{ + mrController.GetFocusManager().ToggleFocus(); + return true; +} + + + + +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; + GotoPage(nIndex + nOffset); + } + ResetShiftKeySelectionAnchor(); +} + + + + +void SelectionFunction::GotoPage (int nIndex) +{ + sal_uInt16 nPageCount = (sal_uInt16)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) + mpModeHandler->SetCurrentPage(pNextPageDescriptor); + else + { + OSL_ASSERT(pNextPageDescriptor.get() != NULL); + } + ResetShiftKeySelectionAnchor(); +} + + + + +void SelectionFunction::ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent) +{ + // #95491# remember button state for creation of own MouseEvents + SetMouseButtonCode (rEvent.GetButtons()); + + EventDescriptor aEventDescriptor (nEventType, rEvent, mrSlideSorter); + ProcessEvent(aEventDescriptor); +} + + + + +void SelectionFunction::MouseDragged ( + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction) +{ + EventDescriptor aEventDescriptor (MOUSE_DRAG, rEvent, nDragAction, mrSlideSorter); + ProcessEvent(aEventDescriptor); +} + + + + +void SelectionFunction::ProcessKeyEvent (const KeyEvent& rEvent) +{ + EventDescriptor aEventDescriptor (rEvent, mrSlideSorter); + ProcessEvent(aEventDescriptor); +} + + + + +void SelectionFunction::ProcessEvent (EventDescriptor& rDescriptor) +{ + // The call to ProcessEvent may switch to another mode handler. + // Prevent the untimely destruction of the called handler by aquiring a + // temporary reference here. + ::boost::shared_ptr<ModeHandler> pModeHandler (mpModeHandler); + pModeHandler->ProcessEvent(rDescriptor); +} + + + + +bool Match ( + const sal_uInt32 nEventCode, + const sal_uInt32 nPositivePattern) +{ + return (nEventCode & nPositivePattern)==nPositivePattern; +} + + + + +void SelectionFunction::SwitchToNormalMode (void) +{ + if (mpModeHandler->GetMode() != NormalMode) + SwitchMode(::boost::shared_ptr<ModeHandler>( + new NormalModeHandler(mrSlideSorter, *this))); +} + + + + +void SelectionFunction::SwitchToDragAndDropMode (const Point aMousePosition) +{ + if (mpModeHandler->GetMode() != DragAndDropMode) + { + SwitchMode(::boost::shared_ptr<ModeHandler>( + new DragAndDropModeHandler(mrSlideSorter, *this, aMousePosition, mpWindow))); + } +} + + + + +void SelectionFunction::SwitchToMultiSelectionMode ( + const Point aMousePosition, + const sal_uInt32 nEventCode) +{ + if (mpModeHandler->GetMode() != MultiSelectionMode) + SwitchMode(::boost::shared_ptr<ModeHandler>( + new MultiSelectionModeHandler(mrSlideSorter, *this, aMousePosition, nEventCode))); +} + + + + +bool SelectionFunction::SwitchToButtonMode (void) +{ + // Do not show the buttons for draw pages. + ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell()); + if (pMainViewShell + && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW + && mpModeHandler->GetMode() != ButtonMode) + { + SwitchMode(::boost::shared_ptr<ModeHandler>(new ButtonModeHandler(mrSlideSorter, *this))); + return true; + } + else + return false; +} + + + + +void SelectionFunction::SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler) +{ + // Not all modes allow mouse over indicator. + if (mpModeHandler->IsMouseOverIndicatorAllowed() != rpHandler->IsMouseOverIndicatorAllowed()) + { + if ( ! rpHandler->IsMouseOverIndicatorAllowed()) + { + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); + mrSlideSorter.GetView().GetButtonBar().ResetPage(); + } + else + mrSlideSorter.GetView().UpdatePageUnderMouse(false); + } + + mpModeHandler = rpHandler; +} + + + + +void SelectionFunction::ResetShiftKeySelectionAnchor (void) +{ + mnShiftKeySelectionAnchor = -1; +} + + + + +void SelectionFunction::ResetMouseAnchor (void) +{ + if (mpModeHandler && mpModeHandler->GetMode() == NormalMode) + { + ::boost::shared_ptr<NormalModeHandler> pHandler ( + ::boost::dynamic_pointer_cast<NormalModeHandler>(mpModeHandler)); + if (pHandler) + pHandler->ResetButtonDownLocation(); + } +} + + + + +//===== EventDescriptor ======================================================= + +SelectionFunction::EventDescriptor::EventDescriptor ( + const sal_uInt32 nEventType, + const MouseEvent& rEvent, + SlideSorter& rSlideSorter) + : maMousePosition(rEvent.GetPosPixel()), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(nEventType), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::MoveMode), + mbMakeSelectionVisible(true), + mbIsLeaving(false) +{ + maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); + mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); + if (mpHitDescriptor) + { + mpHitPage = mpHitDescriptor->GetPage(); + } + + mnEventCode |= EncodeMouseEvent(rEvent); + mnEventCode |= EncodeState(); + + // Detect the mouse leaving the window. When not button is pressed then + // we can call IsLeaveWindow at the event. Otherwise we have to make an + // explicit test. + mbIsLeaving = rEvent.IsLeaveWindow() + || ! Rectangle(Point(0,0), + rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); +} + + + + +SelectionFunction::EventDescriptor::EventDescriptor ( + const sal_uInt32 nEventType, + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction, + SlideSorter& rSlideSorter) + : maMousePosition(rEvent.maPosPixel), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(nEventType), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::GetModeFromDndAction(nDragAction)), + mbMakeSelectionVisible(true), + mbIsLeaving(false) +{ + maMouseModelPosition = rSlideSorter.GetContentWindow()->PixelToLogic(maMousePosition); + mpHitDescriptor = rSlideSorter.GetController().GetPageAt(maMousePosition); + if (mpHitDescriptor) + { + mpHitPage = mpHitDescriptor->GetPage(); + } + + mnEventCode |= EncodeState(); + + // Detect the mouse leaving the window. When not button is pressed then + // we can call IsLeaveWindow at the event. Otherwise we have to make an + // explicit test. + mbIsLeaving = rEvent.mbLeaving + || ! Rectangle(Point(0,0), + rSlideSorter.GetContentWindow()->GetOutputSizePixel()).IsInside(maMousePosition); +} + + + + +SelectionFunction::EventDescriptor::EventDescriptor ( + const KeyEvent& rEvent, + SlideSorter& rSlideSorter) + : maMousePosition(), + maMouseModelPosition(), + mpHitDescriptor(), + mpHitPage(), + mnEventCode(KEY_EVENT), + mbIsOverButton(rSlideSorter.GetView().GetButtonBar().IsMouseOverButton()), + meDragMode(InsertionIndicatorHandler::MoveMode), + mbMakeSelectionVisible(true), + mbIsLeaving(false) +{ + model::SharedPageDescriptor pHitDescriptor ( + rSlideSorter.GetController().GetFocusManager().GetFocusedPageDescriptor()); + if (pHitDescriptor.get() != NULL) + { + mpHitPage = pHitDescriptor->GetPage(); + mpHitDescriptor = pHitDescriptor; + } + + mnEventCode |= EncodeKeyEvent(rEvent) | EncodeState(); +} + + + + +void SelectionFunction::EventDescriptor::SetDragMode (const InsertionIndicatorHandler::Mode eMode) +{ + meDragMode = eMode; +} + + + + +sal_uInt32 SelectionFunction::EventDescriptor::EncodeMouseEvent ( + const MouseEvent& rEvent) const +{ + // Initialize with the type of mouse event. + sal_uInt32 nEventCode (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 pressed modifier keys. + if (rEvent.IsShift()) + nEventCode |= SHIFT_MODIFIER; + if (rEvent.IsMod1()) + nEventCode |= CONTROL_MODIFIER; + + // Detect whether the mouse is over one of the active elements inside a + // page object. + if (mbIsOverButton) + nEventCode |= OVER_BUTTON; + + return nEventCode; +} + + + + +sal_uInt32 SelectionFunction::EventDescriptor::EncodeKeyEvent (const KeyEvent& rEvent) const +{ + // The key code in the lower 16 bit. + sal_uInt32 nEventCode (rEvent.GetKeyCode().GetCode()); + + // Detect pressed modifier keys. + if (rEvent.GetKeyCode().IsShift()) + nEventCode |= SHIFT_MODIFIER; + if (rEvent.GetKeyCode().IsMod1()) + nEventCode |= CONTROL_MODIFIER; + + return nEventCode; +} + + + + +sal_uInt32 SelectionFunction::EventDescriptor::EncodeState (void) const +{ + sal_uInt32 nEventCode (0); + + // Detect whether the event has happened over a page object. + if (mpHitPage!=NULL && mpHitDescriptor) + { + if (mpHitDescriptor->HasState(model::PageDescriptor::ST_Selected)) + nEventCode |= OVER_SELECTED_PAGE; + else + nEventCode |= OVER_UNSELECTED_PAGE; + + // Detect whether the mouse is over one of the active elements + // inside a page object. + if (mbIsOverButton) + nEventCode |= OVER_BUTTON; + } + + return nEventCode; +} + + + + +//===== SelectionFunction::ModeHandler ======================================== + +SelectionFunction::ModeHandler::ModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const bool bIsMouseOverIndicatorAllowed) + : mrSlideSorter(rSlideSorter), + mrSelectionFunction(rSelectionFunction), + mbIsMouseOverIndicatorAllowed(bIsMouseOverIndicatorAllowed) +{ +} + + + + +SelectionFunction::ModeHandler::~ModeHandler (void) +{ +} + + + + +void SelectionFunction::ModeHandler::ReprocessEvent (EventDescriptor& rDescriptor) +{ + mrSelectionFunction.ProcessEvent(rDescriptor); +} + + + + +void SelectionFunction::ModeHandler::ProcessEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + + bool bIsProcessed (false); + switch (rDescriptor.mnEventCode & (BUTTON_DOWN | BUTTON_UP | MOUSE_MOTION | MOUSE_DRAG)) + { + case BUTTON_DOWN: + bIsProcessed = ProcessButtonDownEvent(rDescriptor); + break; + + case BUTTON_UP: + bIsProcessed = ProcessButtonUpEvent(rDescriptor); + break; + + case MOUSE_MOTION: + bIsProcessed = ProcessMotionEvent(rDescriptor); + break; + + case MOUSE_DRAG: + bIsProcessed = ProcessDragEvent(rDescriptor); + break; + } + + if ( ! bIsProcessed) + HandleUnprocessedEvent(rDescriptor); +} + + + + +bool SelectionFunction::ModeHandler::ProcessButtonDownEvent (EventDescriptor&) +{ + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessButtonUpEvent (EventDescriptor&) +{ + mrSelectionFunction.SwitchToNormalMode(); + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessMotionEvent (EventDescriptor& rDescriptor) +{ + if (mbIsMouseOverIndicatorAllowed) + mrSlideSorter.GetView().UpdatePageUnderMouse( + rDescriptor.maMousePosition, + (rDescriptor.mnEventCode & LEFT_BUTTON) != 0, + true); + + if (rDescriptor.mbIsLeaving) + { + mrSelectionFunction.SwitchToNormalMode(); + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor()); + + return true; + } + else + return false; +} + + + + +bool SelectionFunction::ModeHandler::ProcessDragEvent (EventDescriptor&) +{ + return false; +} + + + + +bool SelectionFunction::ModeHandler::HandleUnprocessedEvent (EventDescriptor&) +{ + return false; +} + + + + +void SelectionFunction::ModeHandler::SetCurrentPage ( + const model::SharedPageDescriptor& rpDescriptor) +{ + SelectOnePage(rpDescriptor); + mrSlideSorter.GetController().GetCurrentSlideManager()->SwitchCurrentSlide(rpDescriptor); +} + + + + +void SelectionFunction::ModeHandler::DeselectAllPages (void) +{ + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSelectionFunction.ResetShiftKeySelectionAnchor(); +} + + + + +void SelectionFunction::ModeHandler::SelectOnePage ( + const model::SharedPageDescriptor& rpDescriptor) +{ + DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); +} + + + + +void SelectionFunction::ModeHandler::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(), sal_True); + pViewShell->GetFrameView()->SetSelectedPage( + (rpDescriptor->GetPage()->GetPageNum()-1)/2); + } + if (mrSlideSorter.GetViewShellBase() != NULL) + framework::FrameworkHelper::Instance(*mrSlideSorter.GetViewShellBase())->RequestView( + framework::FrameworkHelper::msImpressViewURL, + framework::FrameworkHelper::msCenterPaneURL); + } +} + + + + +void SelectionFunction::ModeHandler::StartDrag ( + const Point& rMousePosition, + const InsertionIndicatorHandler::Mode eMode) +{ + (void)eMode; + // Do not start a drag-and-drop operation when one is already active. + // (when dragging pages from one document into another, pressing a + // modifier key can trigger a MouseMotion event in the originating + // window (focus still in there). Together with the mouse button pressed + // (drag-and-drop is active) this triggers the start of drag-and-drop.) + if (SD_MOD()->pTransferDrag != NULL) + return; + + if ( ! mrSlideSorter.GetProperties()->IsUIReadOnly()) + { + mrSelectionFunction.SwitchToDragAndDropMode(rMousePosition); + } +} + + + + +bool SelectionFunction::ModeHandler::IsMouseOverIndicatorAllowed (void) const +{ + return mbIsMouseOverIndicatorAllowed; +} + + + + +//===== NormalModeHandler ===================================================== + +NormalModeHandler::NormalModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction) + : ModeHandler(rSlideSorter, rSelectionFunction, true), + maButtonDownLocation() +{ +} + + + + +NormalModeHandler::~NormalModeHandler (void) +{ +} + + + + +SelectionFunction::Mode NormalModeHandler::GetMode (void) const +{ + return SelectionFunction::NormalMode; +} + + + + +void NormalModeHandler::Abort (void) +{ +} + + + + +bool NormalModeHandler::ProcessButtonDownEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // Remember the location where the left button is pressed. With + // that we can filter away motion events that are caused by key + // presses. We also can tune the minimal motion distance that + // triggers a drag-and-drop operation. + if ((rDescriptor.mnEventCode & BUTTON_DOWN) != 0) + maButtonDownLocation = rDescriptor.maMousePosition; + + switch (rDescriptor.mnEventCode) + { + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE: + SetCurrentPage(rDescriptor.mpHitDescriptor); + break; + + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + 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(rDescriptor.mpHitDescriptor); + SwitchView(rDescriptor.mpHitDescriptor); + break; + + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | SHIFT_MODIFIER: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | SHIFT_MODIFIER: + // Range selection with the shift modifier. + RangeSelect(rDescriptor.mpHitDescriptor); + break; + + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: + OSL_ASSERT(mrSlideSorter.GetView().GetButtonBar().IsMouseOverButton()); + + // Switch to button mode only when the buttons are visible + // (or being faded in.) + if (mrSlideSorter.GetView().GetButtonBar().IsVisible(rDescriptor.mpHitDescriptor)) + { + if (mrSelectionFunction.SwitchToButtonMode()) + ReprocessEvent(rDescriptor); + } + else + { + // When the buttons are not (yet) visible then behave like + // the left button had been clicked over any other part of + // the slide. + SetCurrentPage(rDescriptor.mpHitDescriptor); + } + break; + + // Right button for context menu. + case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | 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. + SetCurrentPage(rDescriptor.mpHitDescriptor); + rDescriptor.mbMakeSelectionVisible = false; + break; + + case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + // Do not change the selection. Just adjust the insertion indicator. + rDescriptor.mbMakeSelectionVisible = false; + break; + + case BUTTON_DOWN | RIGHT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: + // Remember the current selection so that when a multi selection + // is started, we can restore the previous selection. + mrSlideSorter.GetModel().SaveCurrentSelection(); + DeselectAllPages(); + break; + + case ANY_MODIFIER(BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + // Remember the current selection so that when a multi selection + // is started, we can restore the previous selection. + mrSlideSorter.GetModel().SaveCurrentSelection(); + DeselectAllPages(); + break; + + default: + return false; + } + return true; +} + + + + +bool NormalModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + bool bIsProcessed (true); + switch (rDescriptor.mnEventCode) + { + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE: + SetCurrentPage(rDescriptor.mpHitDescriptor); + break; + + // Multi selection with the control modifier. + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | CONTROL_MODIFIER: + mrSlideSorter.GetController().GetPageSelector().DeselectPage( + rDescriptor.mpHitDescriptor); + break; + + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | CONTROL_MODIFIER: + mrSlideSorter.GetController().GetPageSelector().SelectPage( + rDescriptor.mpHitDescriptor); + mrSlideSorter.GetView().UpdatePageUnderMouse( + rDescriptor.mpHitDescriptor, + rDescriptor.maMousePosition, + false); + break; + case BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE: + break; + + default: + bIsProcessed = false; + break; + } + mrSelectionFunction.SwitchToNormalMode(); + return bIsProcessed; +} + + + + + +bool NormalModeHandler::ProcessMotionEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if (ModeHandler::ProcessMotionEvent(rDescriptor)) + return true; + + bool bIsProcessed (true); + switch (rDescriptor.mnEventCode) + { + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE): + // SetCurrentPage(rDescriptor.mpHitDescriptor); + // Fallthrough + + // A mouse motion without visible substitution starts that. + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE): + { + if (maButtonDownLocation) + { + const sal_Int32 nDistance (maButtonDownLocation + ? ::std::max ( + abs(maButtonDownLocation->X() - rDescriptor.maMousePosition.X()), + abs(maButtonDownLocation->Y() - rDescriptor.maMousePosition.Y())) + : 0); + if (nDistance > 3) + StartDrag( + rDescriptor.maMousePosition, + (rDescriptor.mnEventCode & CONTROL_MODIFIER) != 0 + ? InsertionIndicatorHandler::CopyMode + : InsertionIndicatorHandler::MoveMode); + } + } + break; + + // A mouse motion not over a page starts a rectangle selection. + case ANY_MODIFIER(MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK | NOT_OVER_PAGE): + mrSelectionFunction.SwitchToMultiSelectionMode( + rDescriptor.maMouseModelPosition, + rDescriptor.mnEventCode); + break; + + default: + bIsProcessed = false; + break; + } + return bIsProcessed; +} + + + + +bool NormalModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + mrSelectionFunction.SwitchToDragAndDropMode(rDescriptor.maMousePosition); + ReprocessEvent(rDescriptor); + return true; +} + + + + +void NormalModeHandler::RangeSelect (const model::SharedPageDescriptor& rpDescriptor) +{ + PageSelector::UpdateLock aLock (mrSlideSorter); + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + + model::SharedPageDescriptor pAnchor (rSelector.GetSelectionAnchor()); + DeselectAllPages(); + + if (pAnchor.get() != NULL) + { + // Select all pages between the anchor and the given one, including + // the two. + const sal_uInt16 nAnchorIndex ((pAnchor->GetPage()->GetPageNum()-1) / 2); + const sal_uInt16 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.) + const sal_uInt16 nStep ((nAnchorIndex < nOtherIndex) ? +1 : -1); + sal_uInt16 nIndex (nAnchorIndex); + while (true) + { + rSelector.SelectPage(nIndex); + if (nIndex == nOtherIndex) + break; + nIndex = nIndex + nStep; + } + } +} + + + + +void NormalModeHandler::ResetButtonDownLocation (void) +{ + maButtonDownLocation = ::boost::optional<Point>(); +} + + + + +//===== MultiSelectionModeHandler ============================================= + +MultiSelectionModeHandler::MultiSelectionModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMouseModelPosition, + const sal_uInt32 nEventCode) + : ModeHandler(rSlideSorter, rSelectionFunction, false), + meSelectionMode(SM_Normal), + maSecondCorner(rMouseModelPosition), + maSavedPointer(mrSlideSorter.GetContentWindow()->GetPointer()), + mnAnchorIndex(-1), + mnSecondIndex(-1), + maButtonBarLock(rSlideSorter) +{ + const Pointer aSelectionPointer (POINTER_TEXT); + mrSlideSorter.GetContentWindow()->SetPointer(aSelectionPointer); + SetSelectionModeFromModifier(nEventCode); +} + + + + + +MultiSelectionModeHandler::~MultiSelectionModeHandler (void) +{ + mrSlideSorter.GetContentWindow()->SetPointer(maSavedPointer); +} + + + + +SelectionFunction::Mode MultiSelectionModeHandler::GetMode (void) const +{ + return SelectionFunction::MultiSelectionMode; +} + + + + +void MultiSelectionModeHandler::Abort (void) +{ + mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); +} + + + + +void MultiSelectionModeHandler::ProcessEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // During a multi selection we do not want sudden jumps of the + // visible area caused by moving newly selected pages into view. + // Therefore disable that temporarily. The disabler object is + // released at the end of the event processing, after the focus and + // current slide have been updated. + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + + ModeHandler::ProcessEvent(rDescriptor); +} + + + + +bool MultiSelectionModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON | SINGLE_CLICK)) + { + mrSelectionFunction.SwitchToNormalMode(); + return true; + } + else + return false; +} + + + + +bool MultiSelectionModeHandler::ProcessMotionEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + // The selection rectangle is visible. Handle events accordingly. + if (Match(rDescriptor.mnEventCode, MOUSE_MOTION | LEFT_BUTTON | SINGLE_CLICK)) + { + SetSelectionModeFromModifier(rDescriptor.mnEventCode); + UpdatePosition(rDescriptor.maMousePosition, true); + rDescriptor.mbMakeSelectionVisible = false; + return true; + } + else + return false; +} + + + +bool MultiSelectionModeHandler::HandleUnprocessedEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if ( ! ModeHandler::HandleUnprocessedEvent(rDescriptor)) + { + // If the event has not been processed then stop multi selection. + mrSelectionFunction.SwitchToNormalMode(); + ReprocessEvent(rDescriptor); + } + return true; +} + + + + +void MultiSelectionModeHandler::UpdatePosition ( + const Point& rMousePosition, + const bool bAllowAutoScroll) +{ + VisibleAreaManager::TemporaryDisabler aDisabler (mrSlideSorter); + + // Convert window coordinates into model coordinates (we need the + // window coordinates for auto-scrolling because that remains + // constant while scrolling.) + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + + if ( ! (bAllowAutoScroll && mrSlideSorter.GetController().GetScrollBarManager().AutoScroll( + rMousePosition, + ::boost::bind( + &MultiSelectionModeHandler::UpdatePosition, + this, + rMousePosition, + false)))) + { + UpdateModelPosition(aMouseModelPosition); + } +} + + + + +void MultiSelectionModeHandler::SetSelectionModeFromModifier ( + const sal_uInt32 nEventCode) +{ + switch (nEventCode & MODIFIER_MASK) + { + case NO_MODIFIER: + SetSelectionMode(SM_Normal); + break; + + case SHIFT_MODIFIER: + SetSelectionMode(SM_Add); + break; + + case CONTROL_MODIFIER: + SetSelectionMode(SM_Toggle); + break; + } +} + + + + +void MultiSelectionModeHandler::SetSelectionMode (const SelectionMode eSelectionMode) +{ + if (meSelectionMode != eSelectionMode) + { + meSelectionMode = eSelectionMode; + UpdateSelection(); + } +} + + + + +void MultiSelectionModeHandler::UpdateSelectionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bIsInSelection) const +{ + // Determine whether the page was selected before the rectangle + // selection was started. + const bool bWasSelected (rpDescriptor->HasState(model::PageDescriptor::ST_WasSelected)); + + // Combine the two selection states depending on the selection mode. + bool bSelect (false); + switch(meSelectionMode) + { + case SM_Normal: + bSelect = bIsInSelection; + break; + + case SM_Add: + bSelect = bIsInSelection || bWasSelected; + break; + + case SM_Toggle: + if (bIsInSelection) + bSelect = !bWasSelected; + else + bSelect = bWasSelected; + break; + } + + // Set the new selection state. + if (bSelect) + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); + else + mrSlideSorter.GetController().GetPageSelector().DeselectPage(rpDescriptor); +} + + + + +void MultiSelectionModeHandler::UpdateModelPosition (const Point& rMouseModelPosition) +{ + maSecondCorner = rMouseModelPosition; + UpdateSelection(); +} + + + + +void MultiSelectionModeHandler::UpdateSelection (void) +{ + view::SlideSorterView::DrawLock aLock (mrSlideSorter); + + model::SlideSorterModel& rModel (mrSlideSorter.GetModel()); + const sal_Int32 nPageCount (rModel.GetPageCount()); + + const sal_Int32 nIndexUnderMouse ( + mrSlideSorter.GetView().GetLayouter().GetIndexAtPoint ( + maSecondCorner, + false, + false)); + if (nIndexUnderMouse>=0 && nIndexUnderMouse<nPageCount) + { + if (mnAnchorIndex < 0) + mnAnchorIndex = nIndexUnderMouse; + mnSecondIndex = nIndexUnderMouse; + + Range aRange (mnAnchorIndex, mnSecondIndex); + aRange.Justify(); + + for (sal_Int32 nIndex=0; nIndex<nPageCount; ++nIndex) + { + UpdateSelectionState(rModel.GetPageDescriptor(nIndex), aRange.IsInside(nIndex)); + } + } +} + + + + +//===== DragAndDropModeHandler ================================================ + +DragAndDropModeHandler::DragAndDropModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction, + const Point& rMousePosition, + ::Window* pWindow) + : ModeHandler(rSlideSorter, rSelectionFunction, false) +{ + SdTransferable* pDragTransferable = SD_MOD()->pTransferDrag; + if (pDragTransferable==NULL && mrSlideSorter.GetViewShell() != NULL) + { + SlideSorterViewShell* pSlideSorterViewShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + if (pSlideSorterViewShell != NULL) + pSlideSorterViewShell->StartDrag(rMousePosition, pWindow); + pDragTransferable = SD_MOD()->pTransferDrag; + } + + mpDragAndDropContext.reset(new DragAndDropContext(mrSlideSorter)); + mrSlideSorter.GetController().GetInsertionIndicatorHandler()->Start( + pDragTransferable != NULL + && pDragTransferable->GetView()==&mrSlideSorter.GetView()); +} + + + + +DragAndDropModeHandler::~DragAndDropModeHandler (void) +{ + if (mpDragAndDropContext) + { + // Disconnect the substitution handler from this selection function. + mpDragAndDropContext->SetTargetSlideSorter(); + mpDragAndDropContext.reset(); + } + mrSlideSorter.GetController().GetInsertionIndicatorHandler()->End(Animator::AM_Animated); +} + + + + +SelectionFunction::Mode DragAndDropModeHandler::GetMode (void) const +{ + return SelectionFunction::DragAndDropMode; +} + + + + +void DragAndDropModeHandler::Abort (void) +{ + mrSlideSorter.GetController().GetClipboard().Abort(); + if (mpDragAndDropContext) + mpDragAndDropContext->Dispose(); + // mrSlideSorter.GetView().RequestRepaint(mrSlideSorter.GetModel().RestoreSelection()); +} + + + + +bool DragAndDropModeHandler::ProcessButtonUpEvent ( + SelectionFunction::EventDescriptor& rDescriptor) +{ + if (Match(rDescriptor.mnEventCode, BUTTON_UP | LEFT_BUTTON)) + { + // The following Process() call may lead to the desctruction + // of rDescriptor.mpHitDescriptor so release our reference to it. + rDescriptor.mpHitDescriptor.reset(); + mrSelectionFunction.SwitchToNormalMode(); + return true; + } + else + return false; +} + + + + +bool DragAndDropModeHandler::ProcessDragEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + OSL_ASSERT(mpDragAndDropContext); + + if (rDescriptor.mbIsLeaving) + { + mrSelectionFunction.SwitchToNormalMode(); + } + else if (mpDragAndDropContext) + { + mpDragAndDropContext->UpdatePosition( + rDescriptor.maMousePosition, + rDescriptor.meDragMode); + } + + return true; +} + + + + +//===== ButtonModeHandler ===================================================== + +ButtonModeHandler::ButtonModeHandler ( + SlideSorter& rSlideSorter, + SelectionFunction& rSelectionFunction) + : ModeHandler(rSlideSorter, rSelectionFunction, true) +{ +} + + + + +ButtonModeHandler::~ButtonModeHandler (void) +{ +} + + + + +SelectionFunction::Mode ButtonModeHandler::GetMode (void) const +{ + return SelectionFunction::ButtonMode; +} + + + + +void ButtonModeHandler::Abort (void) +{ +} + + + + +bool ButtonModeHandler::ProcessButtonDownEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode) + { + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_UNSELECTED_PAGE | OVER_BUTTON: + case BUTTON_DOWN | LEFT_BUTTON | SINGLE_CLICK | OVER_SELECTED_PAGE | OVER_BUTTON: + // Remember page and button index. When mouse button is + // released over same page and button then invoke action of that + // button. + mrSlideSorter.GetView().GetButtonBar().ProcessButtonDownEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition); + return true; + + default: + return false; + } +} + + + + +bool ButtonModeHandler::ProcessButtonUpEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode & BUTTON_MASK) + { + case LEFT_BUTTON: + mrSlideSorter.GetView().GetButtonBar().ProcessButtonUpEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition); + mrSelectionFunction.SwitchToNormalMode(); + return true; + } + + return false; +} + + + + +bool ButtonModeHandler::ProcessMotionEvent (SelectionFunction::EventDescriptor& rDescriptor) +{ + switch (rDescriptor.mnEventCode & (MOUSE_MOTION | BUTTON_MASK)) + { + case MOUSE_MOTION | LEFT_BUTTON: + mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition, + true); + return true; + + case MOUSE_MOTION: + mrSlideSorter.GetView().GetButtonBar().ProcessMouseMotionEvent( + rDescriptor.mpHitDescriptor, + rDescriptor.maMouseModelPosition, + false); + return true; + } + + return false; +} + + + + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx new file mode 100644 index 000000000000..2eff162d5f53 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionManager.cxx @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "SlsCommand.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsAnimator.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.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 { + + +class SelectionManager::PageInsertionListener + : public SfxListener +{ +public: + +}; + + +SelectionManager::SelectionManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mrController(rSlideSorter.GetController()), + maSelectionBeforeSwitch(), + mbIsMakeSelectionVisiblePending(true), + mnInsertionPosition(-1), + mnAnimationId(Animator::NotAnAnimationId), + maRequestedTopLeft(), + mpPageInsertionListener(), + mpSelectionObserver(new SelectionObserver(rSlideSorter)) +{ +} + + + + +SelectionManager::~SelectionManager (void) +{ + if (mnAnimationId != Animator::NotAnAnimationId) + mrController.GetAnimator()->RemoveAnimation(mnAnimationId); +} + + + + +void SelectionManager::DeleteSelectedPages (const bool bSelectFollowingPage) +{ + // Create some locks to prevent updates of the model, view, selection + // state while modifying any of them. + SlideSorterController::ModelChangeLock aLock (mrController); + SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aSelectionLock (mrSlideSorter); + + // 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; + sal_Int32 nNewCurrentSlide (-1); + while (aPageEnumeration.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + aSelectedPages.push_back(pDescriptor->GetPage()); + if (bSelectFollowingPage || nNewCurrentSlide<0) + nNewCurrentSlide = pDescriptor->GetPageIndex(); + } + if (aSelectedPages.empty()) + return; + + // Determine the slide to select (and thereby make the current slide) + // after the deletion. + if (bSelectFollowingPage) + nNewCurrentSlide -= aSelectedPages.size() - 1; + else + --nNewCurrentSlide; + + // 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(); + + // Set the new current slide. + if (nNewCurrentSlide < 0) + nNewCurrentSlide = 0; + else if (nNewCurrentSlide >= mrSlideSorter.GetModel().GetPageCount()) + nNewCurrentSlide = mrSlideSorter.GetModel().GetPageCount()-1; + mrController.GetPageSelector().CountSelectedPages(); + mrController.GetPageSelector().SelectPage(nNewCurrentSlide); + mrController.GetFocusManager().SetFocusedPage(nNewCurrentSlide); +} + + + + +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; + + const sal_uInt16 nPage (model::FromCoreIndex((*aI)->GetPageNum())); + + Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); + xPages->remove(xPage); + } + } + catch( Exception& ) + { + OSL_FAIL("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; + + const sal_uInt16 nPage (model::FromCoreIndex((*aI)->GetPageNum())); + + Reference< XDrawPage > xPage( xPages->getByIndex( nPage ), UNO_QUERY_THROW ); + xPages->remove(xPage); + } + } + catch( Exception& ) + { + OSL_FAIL("SelectionManager::DeleteSelectedMasterPages(), exception caught!"); + } +} + + + + +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); + pViewShell->Invalidate(SID_ASSIGN_LAYOUT); + + // 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; + } +} + + + + +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)); +} + + + + +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 = model::FromCoreIndex(nPosition) + 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; +} + + + + +::boost::shared_ptr<SelectionObserver> SelectionManager::GetSelectionObserver (void) const +{ + return mpSelectionObserver; +} + +} } } // end of namespace ::sd::slidesorter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx new file mode 100644 index 000000000000..b40bd667131c --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSelectionObserver.cxx @@ -0,0 +1,173 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlideSorter.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionObserver.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsFocusManager.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include <svx/svdmodel.hxx> +#include "drawdoc.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +SelectionObserver::Context::Context (SlideSorter& rSlideSorter) + : mpSelectionObserver( + rSlideSorter.GetController().GetSelectionManager()->GetSelectionObserver()) +{ + if (mpSelectionObserver) + mpSelectionObserver->StartObservation(); +} + + + + +SelectionObserver::Context::~Context(void) +{ + if (mpSelectionObserver) + mpSelectionObserver->EndObservation(); +} + + + + +void SelectionObserver::Context::Abort(void) +{ + if (mpSelectionObserver) + { + mpSelectionObserver->AbortObservation(); + mpSelectionObserver.reset(); + } +} + + + + +//===== SelectionObserver ===================================================== + +SelectionObserver::SelectionObserver (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mpDocument(mrSlideSorter.GetModel().GetDocument()), + mbIsOvservationActive(false), + maInsertedPages(), + maDeletedPages() +{ +} + + + + +SelectionObserver::~SelectionObserver (void) +{ +} + + + + +void SelectionObserver::NotifyPageEvent (const SdrPage* pSdrPage) +{ + if ( ! mbIsOvservationActive) + return; + + const SdPage* pPage = dynamic_cast<const SdPage*>(pSdrPage); + if (pPage == NULL) + return; + + if (pPage->IsInserted()) + maInsertedPages.push_back(pPage); + else + { + ::std::vector<const SdPage*>::iterator iPage( + ::std::find(maInsertedPages.begin(), maInsertedPages.end(), pPage)); + if (iPage != maInsertedPages.end()) + maInsertedPages.erase(iPage); + + maDeletedPages.push_back(pPage->GetPageNum()); + } +} + + + +void SelectionObserver::StartObservation (void) +{ + OSL_ASSERT(!mbIsOvservationActive); + maInsertedPages.clear(); + maDeletedPages.clear(); + mbIsOvservationActive = true; +} + + + + +void SelectionObserver::AbortObservation (void) +{ + OSL_ASSERT(mbIsOvservationActive); + mbIsOvservationActive = false; + maInsertedPages.clear(); + maDeletedPages.clear(); +} + + + + +void SelectionObserver::EndObservation (void) +{ + OSL_ASSERT(mbIsOvservationActive); + mbIsOvservationActive = false; + + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + rSelector.DeselectAllPages(); + if ( ! maInsertedPages.empty()) + { + // Select the inserted pages. + for (::std::vector<const SdPage*>::const_iterator + iPage(maInsertedPages.begin()), + iEnd(maInsertedPages.end()); + iPage!=iEnd; + ++iPage) + { + rSelector.SelectPage(*iPage); + } + maInsertedPages.clear(); + } + maDeletedPages.clear(); + + aUpdateLock.Release(); + mrSlideSorter.GetController().GetFocusManager().SetFocusedPageToCurrentPage(); + +} + + + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx new file mode 100644 index 000000000000..d34fcbd4992a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSlideFunction.cxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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.GetContentWindow().get(), + &rSlideSorter.GetView(), + rSlideSorter.GetModel().GetDocument(), + rRequest) +{ +} + +void SlideFunction::ScrollStart (void) +{ +} + +void SlideFunction::ScrollEnd (void) +{ +} + +sal_Bool SlideFunction::MouseMove(const MouseEvent& ) +{ + return sal_False; +} + +sal_Bool SlideFunction::MouseButtonUp(const MouseEvent& ) +{ + return sal_False; + +} + +sal_Bool SlideFunction::MouseButtonDown(const MouseEvent& ) +{ + return sal_False; +} + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx new file mode 100644 index 000000000000..ad756c9727ae --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsSlotManager.cxx @@ -0,0 +1,1345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <editeng/outlobj.hxx> + +#include "controller/SlsSlotManager.hxx" +#include "SlideSorter.hxx" +#include "SlideSorterViewShell.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsClipboard.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsSelectionFunction.hxx" +#include "controller/SlsSelectionManager.hxx" +#include "controller/SlsSelectionObserver.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 "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 "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/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 <svl/intitem.hxx> +#include <svl/whiter.hxx> +#include <svl/itempool.hxx> +#include <svl/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> + +#include <boost/bind.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::presentation; + +namespace sd { namespace slidesorter { namespace controller { + +namespace { + +/** The state of a set of slides with respect to being excluded from the + slide show. +*/ +enum SlideExclusionState {UNDEFINED, EXCLUDED, INCLUDED, MIXED}; + +/** Return for the given set of slides whether they included are + excluded from the slide show. +*/ +SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet); + +} // end of anonymous namespace + + + +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: + ChangeSlideExclusionState(model::SharedPageDescriptor(), true); + break; + + case SID_SHOW_SLIDE: + ChangeSlideExclusionState(model::SharedPageDescriptor(), false); + break; + + case SID_PAGES_PER_ROW: + if (rRequest.GetArgs() != NULL) + { + SFX_REQUEST_ARG(rRequest, pPagesPerRow, SfxUInt16Item, + SID_PAGES_PER_ROW, sal_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.GetContentWindow().get(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_CUSTOMSHOW_DLG: + FuCustomShowDlg::Create ( + pShell, + mrSlideSorter.GetContentWindow().get(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_EXPAND_PAGE: + FuExpandPage::Create ( + pShell, + mrSlideSorter.GetContentWindow().get(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_SUMMARY_PAGE: + FuSummaryPage::Create ( + pShell, + mrSlideSorter.GetContentWindow().get(), + &mrSlideSorter.GetView(), + pDocument, + rRequest); + break; + + case SID_INSERTPAGE: + case SID_INSERT_MASTER_PAGE: + InsertSlide(rRequest); + rRequest.Done(); + break; + + case SID_DUPLICATE_PAGE: + DuplicateSelectedSlides(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: + { + pShell->mpImpl->AssignLayout( rRequest, mrSlideSorter.GetModel().GetPageType() ); + 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) + { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + SlideSorterController::ModelChangeLock aModelLock (mrSlideSorter.GetController()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); + pViewShell->ImpSidUndo (sal_False, rRequest); + } + break; + } + + case SID_REDO: + { + SlideSorterViewShell* pViewShell + = dynamic_cast<SlideSorterViewShell*>(mrSlideSorter.GetViewShell()); + if (pViewShell != NULL) + { + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + SlideSorterController::ModelChangeLock aModelLock (mrSlideSorter.GetController()); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + SelectionObserver::Context aContext (mrSlideSorter); + pViewShell->ImpSidRedo (sal_False, rRequest); + } + break; + } + + default: + break; + } +} + + + + +void SlotManager::ExecCtrl (SfxRequest& rRequest) +{ + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + sal_uInt16 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); + sal_uInt16 nWhich = aIter.FirstWhich(); + while (nWhich) + { + sal_uInt16 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, + (sal_uInt16)mrSlideSorter.GetView().GetLayouter().GetColumnCount() + ) + ); + break; + } + nWhich = aIter.NextWhich(); + } +} + +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()) + { + sal_uInt16 nSId = pShell->GetCurrentFunction()->GetSlotID(); + + rSet.Put( SfxBoolItem( nSId, sal_True ) ); + } + rSet.Put( SfxBoolItem( SID_DRAWINGMODE, sal_False ) ); + rSet.Put( SfxBoolItem( SID_DIAMODE, sal_True ) ); + rSet.Put( SfxBoolItem( SID_OUTLINEMODE, sal_False ) ); + rSet.Put( SfxBoolItem( SID_NOTESMODE, sal_False ) ); + rSet.Put( SfxBoolItem( SID_HANDOUTMODE, sal_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 ) + { + if( !pObj->IsEmptyPresObj() ) + { + bDisable = false; + } + else + { + // check if the object is in edit, than its temporarely not empty + SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pObj ); + if( pTextObj ) + { + OutlinerParaObject* pParaObj = pTextObj->GetEditOutlinerParaObject(); + if( pParaObj ) + { + delete pParaObj; + 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 ) ) + { + sal_Bool bDisable = sal_True; + model::PageEnumeration aAllPages ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrSlideSorter.GetModel())); + while (aAllPages.HasMoreElements()) + { + SdPage* pPage = aAllPages.GetNextElement()->GetPage(); + + if( !pPage->IsExcluded() ) + bDisable = sal_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())); + const SlideExclusionState eState (GetSlideExclusionState(aSelectedPages)); + switch (eState) + { + case MIXED: + // Show both entries. + break; + + case EXCLUDED: + rSet.DisableItem(SID_HIDE_SLIDE); + break; + + case INCLUDED: + rSet.DisableItem(SID_SHOW_SLIDE); + break; + + case UNDEFINED: + rSet.DisableItem(SID_HIDE_SLIDE); + rSet.DisableItem(SID_SHOW_SLIDE); + break; + } + } + + + PageKind ePageKind = mrSlideSorter.GetModel().GetPageType(); + if ((eEditMode == EM_MASTERPAGE) && (ePageKind != PK_HANDOUT)) + { + rSet.DisableItem(SID_ASSIGN_LAYOUT); + } + + if ((eEditMode == EM_MASTERPAGE) || (ePageKind==PK_NOTES)) + { + rSet.DisableItem(SID_INSERTPAGE); + } + + // Disable some slots when in master page mode. + if (eEditMode == EM_MASTERPAGE) + { + if (rSet.GetItemState(SID_INSERTPAGE) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_INSERTPAGE); + if (rSet.GetItemState(SID_DUPLICATE_PAGE) == SFX_ITEM_AVAILABLE) + rSet.DisableItem(SID_DUPLICATE_PAGE); + } +} + + + + +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; + sal_uInt16 nFirstPage; + sal_uInt16 nSelectedPages = (sal_uInt16)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())); + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if (pDescriptor) + { + pPage = pDescriptor->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.GetContentWindow().get(), + aPageName, aDescr); + 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( sal_uInt16 nPageId, const String & rName ) +{ + sal_Bool bOutDummy; + SdDrawDocument* pDocument = mrSlideSorter.GetModel().GetDocument(); + if( pDocument->GetPageByName( rName, bOutDummy ) != SDRPAGE_NOTFOUND ) + return false; + + SdPage* pPageToRename = NULL; + PageKind ePageKind = mrSlideSorter.GetModel().GetPageType(); + + ::svl::IUndoManager* 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(); + sal_uInt8 nBackground = rLayerAdmin.GetLayerID( String( SdResId( STR_LAYER_BCKGRND )), sal_False ); + sal_uInt8 nBgObj = rLayerAdmin.GetLayerID( String( SdResId( STR_LAYER_BCKGRNDOBJ )), sal_False ); + SetOfByte aVisibleLayers = pPageToRename->TRG_GetMasterPageVisibleLayers(); + + // (#67720#) + ModifyPageUndoAction* pAction = new ModifyPageUndoAction( + 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 && ( sal_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( sal_True ); + + // inform navigator about change + SfxBoolItem aItem( SID_NAVIGATOR_INIT, sal_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) +{ + const sal_Int32 nInsertionIndex (GetInsertionPosition()); + + PageSelector::BroadcastLock aBroadcastLock (mrSlideSorter); + + SdPage* pNewPage = NULL; + if (mrSlideSorter.GetModel().GetEditMode() == EM_PAGE) + { + SlideSorterViewShell* pShell = dynamic_cast<SlideSorterViewShell*>( + mrSlideSorter.GetViewShell()); + if (pShell != NULL) + { + pNewPage = pShell->CreateOrDuplicatePage ( + rRequest, + mrSlideSorter.GetModel().GetPageType(), + nInsertionIndex>=0 + ? mrSlideSorter.GetModel().GetPageDescriptor(nInsertionIndex)->GetPage() + : NULL); + } + } + 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. + pNewPage = pDocument->GetMasterSdPage( + (sal_uInt16)(nInsertionIndex+1), PK_STANDARD); + pNewPage->CreateTitleAndLayout (sal_True,sal_True); + } + } + } + if (pNewPage == NULL) + return; + + // When a new page has been inserted then select it, make it the + // current page, and focus it. + view::SlideSorterView::DrawLock aDrawLock (mrSlideSorter); + PageSelector::UpdateLock aUpdateLock (mrSlideSorter); + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(pNewPage); +} + + + + +void SlotManager::DuplicateSelectedSlides (SfxRequest& rRequest) +{ + // Create a list of the pages that are to be duplicated. The process of + // duplication alters the selection. + sal_Int32 nInsertPosition (0); + ::std::vector<SdPage*> aPagesToDuplicate; + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration(mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + if (pDescriptor && pDescriptor->GetPage()) + { + aPagesToDuplicate.push_back(pDescriptor->GetPage()); + nInsertPosition = pDescriptor->GetPage()->GetPageNum()+2; + } + } + + // Duplicate the pages in aPagesToDuplicate and collect the newly + // created pages in aPagesToSelect. + const bool bUndo (aPagesToDuplicate.size()>1 && mrSlideSorter.GetView().IsUndoEnabled()); + if (bUndo) + mrSlideSorter.GetView().BegUndo(String(SdResId(STR_INSERTPAGE))); + + ::std::vector<SdPage*> aPagesToSelect; + for(::std::vector<SdPage*>::const_iterator + iPage(aPagesToDuplicate.begin()), + iEnd(aPagesToDuplicate.end()); + iPage!=iEnd; + ++iPage, nInsertPosition+=2) + { + aPagesToSelect.push_back( + mrSlideSorter.GetViewShell()->CreateOrDuplicatePage( + rRequest, PK_STANDARD, *iPage, nInsertPosition)); + } + aPagesToDuplicate.clear(); + + if (bUndo) + mrSlideSorter.GetView().EndUndo(); + + // Set the selection to the pages in aPagesToSelect. + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + rSelector.DeselectAllPages(); + ::std::for_each ( + aPagesToSelect.begin(), + aPagesToSelect.end(), + ::boost::bind( + static_cast<void (PageSelector::*)(const SdPage*)>(&PageSelector::SelectPage), + rSelector, + _1)); +} + +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; +} + + + + +void SlotManager::ChangeSlideExclusionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bExcludeSlide) +{ + if (rpDescriptor) + { + mrSlideSorter.GetView().SetState( + rpDescriptor, + model::PageDescriptor::ST_Excluded, + bExcludeSlide); + } + else + { + model::PageEnumeration aSelectedPages ( + model::PageEnumerationProvider::CreateSelectedPagesEnumeration( + mrSlideSorter.GetModel())); + while (aSelectedPages.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aSelectedPages.GetNextElement()); + mrSlideSorter.GetView().SetState( + pDescriptor, + model::PageDescriptor::ST_Excluded, + bExcludeSlide); + } + } + + SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings()); + rBindings.Invalidate(SID_PRESENTATION); + rBindings.Invalidate(SID_REHEARSE_TIMINGS); + rBindings.Invalidate(SID_HIDE_SLIDE); + rBindings.Invalidate(SID_SHOW_SLIDE); + mrSlideSorter.GetModel().GetDocument()->SetChanged(); +} + + + + +sal_Int32 SlotManager::GetInsertionPosition (void) +{ + PageSelector& rSelector (mrSlideSorter.GetController().GetPageSelector()); + + // The insertion indicator is preferred. After all the user explicitly + // used it to define the insertion position. + if (mrSlideSorter.GetController().GetInsertionIndicatorHandler()->IsActive()) + { + // Select the page before the insertion indicator. + return mrSlideSorter.GetController().GetInsertionIndicatorHandler()->GetInsertionPageIndex() + - 1; + } + + // Is there a stored insertion position? + else if (mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() >= 0) + { + return mrSlideSorter.GetController().GetSelectionManager()->GetInsertionPosition() - 1; + } + + // Use the index of the last selected slide. + else if (rSelector.GetSelectedPageCount() > 0) + { + for (int nIndex=rSelector.GetPageCount()-1; nIndex>=0; --nIndex) + if (rSelector.IsPageSelected(nIndex)) + return nIndex; + + // We should never get here. + OSL_ASSERT(false); + return rSelector.GetPageCount() - 1; + } + + // Select the last page when there is at least one page. + else if (rSelector.GetPageCount() > 0) + { + return rSelector.GetPageCount() - 1; + } + + // Hope for the best that CreateOrDuplicatePage() can cope with an empty + // selection. + else + { + // We should never get here because there has to be at least one page. + OSL_ASSERT(false); + return -1; + } +} + + + + +void SlotManager::NotifyEditModeChange (void) +{ + SfxBindings& rBindings (mrSlideSorter.GetViewShell()->GetViewFrame()->GetBindings()); + rBindings.Invalidate(SID_PRESENTATION); + rBindings.Invalidate(SID_INSERTPAGE); + rBindings.Invalidate(SID_DUPLICATE_PAGE); +} + + + + +//----------------------------------------------------------------------------- + +namespace { + + + +SlideExclusionState GetSlideExclusionState (model::PageEnumeration& rPageSet) +{ + SlideExclusionState eState (UNDEFINED); + sal_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 anonymous namespace + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsTransferable.cxx b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx new file mode 100644 index 000000000000..aa94aad2c56a --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsTransferable.cxx @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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/SlsTransferable.hxx" + +#include "SlideSorterViewShell.hxx" +#include "View.hxx" + +namespace sd { namespace slidesorter { namespace controller { + +Transferable::Transferable ( + SdDrawDocument* pSrcDoc, + ::sd::View* pWorkView, + sal_Bool bInitOnGetData, + SlideSorterViewShell* pViewShell, + const ::std::vector<Representative>& rRepresentatives) + : SdTransferable (pSrcDoc, pWorkView, bInitOnGetData), + mpViewShell(pViewShell), + maRepresentatives(rRepresentatives) +{ + 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); +} + + + + +const ::std::vector<Transferable::Representative>& Transferable::GetRepresentatives (void) const +{ + return maRepresentatives; +} + + +} } } // end of namespace ::sd::slidesorter::controller + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx new file mode 100644 index 000000000000..76e9e411e81e --- /dev/null +++ b/sd/source/ui/slidesorter/controller/SlsVisibleAreaManager.cxx @@ -0,0 +1,305 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "controller/SlsVisibleAreaManager.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsProperties.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "controller/SlsScrollBarManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" + + +namespace sd { namespace slidesorter { namespace controller { + +namespace { + class VisibleAreaScroller + { + public: + VisibleAreaScroller ( + SlideSorter& rSlideSorter, + const Point aStart, + const Point aEnd); + void operator() (const double nValue); + private: + SlideSorter& mrSlideSorter; + Point maStart; + const Point maEnd; + const ::boost::function<double(double)> maAccelerationFunction; + }; + +} // end of anonymous namespace + + + +VisibleAreaManager::VisibleAreaManager (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maVisibleRequests(), + mnScrollAnimationId(Animator::NotAnAnimationId), + maRequestedVisibleTopLeft(), + meRequestedAnimationMode(Animator::AM_Immediate), + mbIsCurrentSlideTrackingActive(true), + mnDisableCount(0) +{ +} + + + + +VisibleAreaManager::~VisibleAreaManager (void) +{ +} + + + + +void VisibleAreaManager::ActivateCurrentSlideTracking (void) +{ + mbIsCurrentSlideTrackingActive = true; +} + + + + +void VisibleAreaManager::DeactivateCurrentSlideTracking (void) +{ + mbIsCurrentSlideTrackingActive = false; +} + + + + +void VisibleAreaManager::RequestVisible ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bForce) +{ + if (rpDescriptor) + { + if (mnDisableCount == 0) + { + maVisibleRequests.push_back( + mrSlideSorter.GetView().GetLayouter().GetPageObjectBox( + rpDescriptor->GetPageIndex(), + true)); + } + if (bForce && ! mbIsCurrentSlideTrackingActive) + ActivateCurrentSlideTracking(); + MakeVisible(); + } +} + + + + +void VisibleAreaManager::RequestCurrentSlideVisible (void) +{ + if (mbIsCurrentSlideTrackingActive && mnDisableCount==0) + RequestVisible( + mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide()); +} + + + + +void VisibleAreaManager::MakeVisible (void) +{ + if (maVisibleRequests.empty()) + return; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return; + const Point aCurrentTopLeft (pWindow->PixelToLogic(Point(0,0))); + + const ::boost::optional<Point> aNewVisibleTopLeft (GetRequestedTopLeft()); + maVisibleRequests.clear(); + if ( ! aNewVisibleTopLeft) + return; + + // We now know what the visible area shall be. Scroll accordingly + // unless that is not already the visible area or a running scroll + // animation has it as its target area. + if (mnScrollAnimationId!=Animator::NotAnAnimationId + && maRequestedVisibleTopLeft==aNewVisibleTopLeft) + return; + + // Stop a running animation. + if (mnScrollAnimationId != Animator::NotAnAnimationId) + mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(mnScrollAnimationId); + + maRequestedVisibleTopLeft = aNewVisibleTopLeft.get(); + VisibleAreaScroller aAnimation( + mrSlideSorter, + aCurrentTopLeft, + maRequestedVisibleTopLeft); + if (meRequestedAnimationMode==Animator::AM_Animated + && mrSlideSorter.GetProperties()->IsSmoothSelectionScrolling()) + { + mnScrollAnimationId = mrSlideSorter.GetController().GetAnimator()->AddAnimation( + aAnimation, + 0, + 300); + } + else + { + // Execute the animation at its final value. + aAnimation(1.0); + } + meRequestedAnimationMode = Animator::AM_Immediate; +} + + + + +::boost::optional<Point> VisibleAreaManager::GetRequestedTopLeft (void) const +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return ::boost::optional<Point>(); + + // Get the currently visible area and the model area. + const Rectangle aVisibleArea (pWindow->PixelToLogic( + Rectangle( + Point(0,0), + pWindow->GetOutputSizePixel()))); + const Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea()); + + sal_Int32 nVisibleTop (aVisibleArea.Top()); + const sal_Int32 nVisibleWidth (aVisibleArea.GetWidth()); + sal_Int32 nVisibleLeft (aVisibleArea.Left()); + const sal_Int32 nVisibleHeight (aVisibleArea.GetHeight()); + + // Find the longest run of boxes whose union fits into the visible area. + Rectangle aBoundingBox; + for (::std::vector<Rectangle>::const_iterator + iBox(maVisibleRequests.begin()), + iEnd(maVisibleRequests.end()); + iBox!=iEnd; + ++iBox) + { + if (nVisibleTop+nVisibleHeight <= iBox->Bottom()) + nVisibleTop = iBox->Bottom()-nVisibleHeight; + if (nVisibleTop > iBox->Top()) + nVisibleTop = iBox->Top(); + + if (nVisibleLeft+nVisibleWidth <= iBox->Right()) + nVisibleLeft = iBox->Right()-nVisibleWidth; + if (nVisibleLeft > iBox->Left()) + nVisibleLeft = iBox->Left(); + + // Make sure the visible area does not move outside the model area. + if (nVisibleTop + nVisibleHeight > aModelArea.Bottom()) + nVisibleTop = aModelArea.Bottom() - nVisibleHeight; + if (nVisibleTop < aModelArea.Top()) + nVisibleTop = aModelArea.Top(); + + if (nVisibleLeft + nVisibleWidth > aModelArea.Right()) + nVisibleLeft = aModelArea.Right() - nVisibleWidth; + if (nVisibleLeft < aModelArea.Left()) + nVisibleLeft = aModelArea.Left(); + } + + const Point aRequestedTopLeft (nVisibleLeft, nVisibleTop); + if (aRequestedTopLeft == aVisibleArea.TopLeft()) + return ::boost::optional<Point>(); + else + return ::boost::optional<Point>(aRequestedTopLeft); +} + + + + +//===== VisibleAreaManager::TemporaryDisabler ================================= + +VisibleAreaManager::TemporaryDisabler::TemporaryDisabler (SlideSorter& rSlideSorter) + : mrVisibleAreaManager(rSlideSorter.GetController().GetVisibleAreaManager()) +{ + ++mrVisibleAreaManager.mnDisableCount; +} + + + + +VisibleAreaManager::TemporaryDisabler::~TemporaryDisabler (void) +{ + --mrVisibleAreaManager.mnDisableCount; +} + + + +//===== VerticalVisibleAreaScroller =========================================== + +namespace { + +const static sal_Int32 gnMaxScrollDistance = 300; + +VisibleAreaScroller::VisibleAreaScroller ( + SlideSorter& rSlideSorter, + const Point aStart, + const Point aEnd) + : mrSlideSorter(rSlideSorter), + maStart(aStart), + maEnd(aEnd), + maAccelerationFunction( + controller::AnimationParametricFunction( + controller::AnimationBezierFunction (0.1,0.6))) +{ + // When the distance to scroll is larger than a threshold then first + // jump to within this distance of the final value and start the + // animation from there. + if (abs(aStart.X()-aEnd.X()) > gnMaxScrollDistance) + { + if (aStart.X() < aEnd.X()) + maStart.X() = aEnd.X()-gnMaxScrollDistance; + else + maStart.X() = aEnd.X()+gnMaxScrollDistance; + } + if (abs(aStart.Y()-aEnd.Y()) > gnMaxScrollDistance) + { + if (aStart.Y() < aEnd.Y()) + maStart.Y() = aEnd.Y()-gnMaxScrollDistance; + else + maStart.Y() = aEnd.Y()+gnMaxScrollDistance; + } +} + + + + +void VisibleAreaScroller::operator() (const double nTime) +{ + const double nLocalTime (maAccelerationFunction(nTime)); + mrSlideSorter.GetController().GetScrollBarManager().SetTopLeft( + Point( + sal_Int32(0.5 + maStart.X() * (1.0 - nLocalTime) + maEnd.X() * nLocalTime), + sal_Int32 (0.5 + maStart.Y() * (1.0 - nLocalTime) + maEnd.Y() * nLocalTime))); +} + +} // end of anonymous namespace + +} } } // end of namespace ::sd::slidesorter::controller diff --git a/sd/source/ui/slidesorter/controller/makefile.mk b/sd/source/ui/slidesorter/controller/makefile.mk new file mode 100755 index 000000000000..460ef16ed3f1 --- /dev/null +++ b/sd/source/ui/slidesorter/controller/makefile.mk @@ -0,0 +1,69 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +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)$/SlsAnimationFunction.obj \ + $(SLO)$/SlsClipboard.obj \ + $(SLO)$/SlsCurrentSlideManager.obj \ + $(SLO)$/SlsDragAndDropContext.obj \ + $(SLO)$/SlsFocusManager.obj \ + $(SLO)$/SlsInsertionIndicatorHandler.obj\ + $(SLO)$/SlsListener.obj \ + $(SLO)$/SlsPageSelector.obj \ + $(SLO)$/SlsProperties.obj \ + $(SLO)$/SlsScrollBarManager.obj \ + $(SLO)$/SlsSelectionCommand.obj \ + $(SLO)$/SlsSelectionFunction.obj \ + $(SLO)$/SlsSelectionManager.obj \ + $(SLO)$/SlsSelectionObserver.obj \ + $(SLO)$/SlsSlotManager.obj \ + $(SLO)$/SlsTransferable.obj \ + $(SLO)$/SlsVisibleAreaManager.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..aaf99ad19886 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/cache/SlsCacheContext.hxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 SdrPage; +class Bitmap; + +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 Bitmap& 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..026235861e66 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCache.hxx @@ -0,0 +1,182 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <tools/gen.hxx> +#include <boost/scoped_ptr.hpp> +#include <vcl/bitmap.hxx> + + +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 is another somewhat similar methods for requesting new previews: + 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. + </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 bool bDoSuperSampling, + const SharedCacheContext& rpCacheContext); + + ~PageCache (void); + + void ChangeSize( + const Size& rPreviewSize, + const bool bDoSuperSampling); + + /** 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 in the right + size 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 bResize + When <TRUE/> then when the available bitmap has not the + requested size, it is scaled before it is returned. When + <FALSE/> then the bitmap is returned in the wrong size and it is + the task of the caller to scale it. + @return + Returns a bitmap that is either empty, contains a scaled (up or + down) version or is the requested bitmap. + */ + Bitmap GetPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + + Bitmap GetMarkedPreviewBitmap ( + const CacheKey aKey, + const bool bResize); + void SetMarkedPreviewBitmap ( + const CacheKey aKey, + const Bitmap& rBitmap); + + /** 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 (const CacheKey aKey); + + /** Tell the cache that the bitmap associated with the given request + data is not up-to-date anymore. This will invalidate all previews + in other caches that represent the same page as well. + @param bRequestPreview + When <TRUE/> then a new preview is requested and will lead + eventually to a repaint of the associated page object. + */ + void InvalidatePreviewBitmap ( + const CacheKey aKey, + const bool bRequestPreview); + + /** 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 (const 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 (const 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 (const CacheKey aKey, const bool bIsPrecious); + + void Pause (void); + void Resume (void); + +private: + ::boost::scoped_ptr<GenericPageCache> mpImplementation; +}; + +} } } // end of namespace ::sd::slidesorter::cache + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..0e9407b6db75 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/cache/SlsPageCacheManager.hxx @@ -0,0 +1,191 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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. + */ + bool InvalidatePreviewBitmap ( + DocumentKey pDocument, + const SdrPage* pPage); + + /** Invalidate the preview bitmaps for all slides that belong to the + specified document. This is necessary after model changes that + affect e.g. page number fiels. + */ + void InvalidateAllPreviewBitmaps (DocumentKey pDocument); + + /** 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); + + /** Call this method when a page has been deleted and its preview + is not needed anymore. + */ + void ReleasePreviewBitmap (const SdrPage* pPage); + +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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..4e7628450ca3 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlideSorterController.hxx @@ -0,0 +1,346 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <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 InsertionIndicatorHandler; +class Listener; +class PageSelector; +class ScrollBarManager; +class SelectionFunction; +class SelectionManager; +class SelectionObserver; +class SlotManager; +class VisibleAreaManager; + +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); + + void Dispose (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); + + /** Return the descriptor of the page that is rendered under the + given position. This takes the IsOnlyPreviewTriggersMouseOver + property into account. + @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); + + 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; + ::boost::shared_ptr<InsertionIndicatorHandler> GetInsertionIndicatorHandler (void) const; + + /** 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); + + /** This factory method creates a selection function. + */ + virtual FunctionReference CreateSelectionFunction (SfxRequest& rRequest); + + /** When the current function of the view shell is the slide sorter + selection function then return a reference to it. Otherwise return + an empty reference. + */ + ::rtl::Reference<SelectionFunction> GetCurrentSelectionFunction (void); + + /** 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; + + /** 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; + + VisibleAreaManager& GetVisibleAreaManager (void) const; + + void CheckForMasterPageAssignment (void); + +private: + SlideSorter& mrSlideSorter; + model::SlideSorterModel& mrModel; + view::SlideSorterView& mrView; + ::boost::scoped_ptr<PageSelector> mpPageSelector; + ::boost::scoped_ptr<FocusManager> mpFocusManager; + ::boost::shared_ptr<SlotManager> mpSlotManager; + ::boost::scoped_ptr<controller::Clipboard> mpClipboard; + ::boost::scoped_ptr<ScrollBarManager> mpScrollBarManager; + mutable ::boost::shared_ptr<CurrentSlideManager> mpCurrentSlideManager; + ::boost::shared_ptr<SelectionManager> mpSelectionManager; + ::boost::shared_ptr<InsertionIndicatorHandler> mpInsertionIndicatorHandler; + ::boost::shared_ptr<Animator> mpAnimator; + ::boost::scoped_ptr<VisibleAreaManager> mpVisibleAreaManager; + + // 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 mbIsForcedRearrangePending; + + 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; + + /** 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx b/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx new file mode 100644 index 000000000000..38d0b2b22749 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsAnimationFunction.hxx @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_CONTROLLER_ANIMATION_FUNCTION_HXX +#define SD_SLIDESORTER_CONTROLLER_ANIMATION_FUNCTION_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include <basegfx/point/b2dpoint.hxx> +#include <boost/noncopyable.hpp> +#include <boost/function.hpp> +#include <tools/gen.hxx> +#include <vector> + +namespace sd { namespace slidesorter { namespace view { +class SlideSorterView; +} } } + + + +namespace sd { namespace slidesorter { namespace controller { + +/** A collection of functions that are usefull when creating animations. + They are collected here until a better place is found. +*/ +class AnimationFunction + : private ::boost::noncopyable +{ +public: + /** Acceleration function that maps [0,1] to [0,1] linearly, ie it + returns the given time value unaltered. + */ + static double Linear (const double nTime); + + /** Acceleration function that maps [0,1] to [0,1]. Speed starts fast + and ends slow following the sine function. + */ + static double FastInSlowOut_Sine (const double nTime); + + /** Acceleration function that maps [0,1] to [0,1]. Speed starts fast + and ends slow following the square root function. + */ + static double FastInSlowOut_Root (const double nTime); + + /** Acceleration function that maps [0,1] to [0,0]. Speed starts slow, + rises, drops and ends slow following the sine function. + */ + static double SlowInSlowOut_0to0_Sine (const double nTime); + + /** Acceleration function that maps [0,1] to [0,0]. Speed starts slow, + rises and drops several times and ends slow following multiple + cycles of the the sine function. + */ + static double Vibrate_Sine (const double nTime); + + /** Scale point linearly. + */ + static Point ScalePoint (const Point& rPoint, const double nTime); + + /** Blend two points together according to the given weight. + */ + static double Blend (const double nStartValue, const double nEndValue, const double nWeight); + + /** Apply a gradual visual state change. The kind of change, i.e. the + previous and the new states are expected to be already set. This + method only adjusts the blending of the visual representation from + one state to the other. + */ + static void ApplyVisualStateChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nTime); + + /** Apply a gradual change of a previously set offset to the location of + a page object. + */ + static void ApplyLocationOffsetChange ( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const Point aLocationOffset); + + /** Apply a gradual change the alpha value from the old value to a + new value (set prior to this call.) + */ + static void ApplyButtonAlphaChange( + const model::SharedPageDescriptor& rpDescriptor, + view::SlideSorterView& rView, + const double nButtonAlpha, + const double nButtonBarAlpha); +}; + + + + +class AnimationBezierFunction +{ +public: + /** Create a cubic bezier curve whose start and end points are given + implicitly as P0=(0,0) and P3=(1,1). + */ + AnimationBezierFunction ( + const double nX1, + const double nY1, + const double nX2, + const double nY2); + + /** Create a cubic bezier curve whose start and end points are given + implicitly as P0=(0,0) and P3=(1,1). The second control point is + implicitly given as P2=(1-nY1,1-nX1). + */ + AnimationBezierFunction ( + const double nX1, + const double nY1); + + ::basegfx::B2DPoint operator() (const double nT); + +private: + const double mnX1; + const double mnY1; + const double mnX2; + const double mnY2; + + double EvaluateComponent ( + const double nT, + const double nV1, + const double nV2); +}; + + + + +/** Turn a parametric function into one whose y-Values depend on its + x-Values. Note a lot of interpolation takes place. The resulting + accuracy should be good enough for the purpose of acceleration + function for animations. +*/ +class AnimationParametricFunction +{ +public: + typedef ::boost::function<basegfx::B2DPoint(double)> ParametricFunction; + AnimationParametricFunction (const ParametricFunction& rFunction); + + double operator() (const double nX); + +private: + /** y-Values of the parametric function given to the constructor + evaluated (and interpolated) for evenly spaced x-Values. + */ + ::std::vector<double> maY; +}; + + + + +} } } // 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..e06bc6ca6708 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsAnimator.hxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "view/SlideSorterView.hxx" +#include <canvas/elapsedtime.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: + /** In some circumstances we have to avoid animation and jump to the + final animation state immediately. Use this enum instead of a bool + to be more expressive. + */ + enum AnimationMode { AM_Animated, AM_Immediate }; + + Animator (SlideSorter& rSlideSorter); + ~Animator (void); + + /** When disposed the animator will stop its work immediately and not + process any timer events anymore. + */ + void Dispose (void); + + /** An animation object is called with values between 0 and 1 as single + argument to its operator() method. + */ + typedef ::boost::function1<void, double> AnimationFunctor; + typedef ::boost::function0<void> FinishFunctor; + + typedef sal_Int32 AnimationId; + static const AnimationId NotAnAnimationId = -1; + + /** 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 nStartOffset + Time in milli seconds before the animation is started. + @param nDuration + The duration in milli seconds. + */ + AnimationId AddAnimation ( + const AnimationFunctor& rAnimation, + const sal_Int32 nStartOffset, + const sal_Int32 nDuration, + const FinishFunctor& rFinishFunctor = FinishFunctor()); + + AnimationId AddInfiniteAnimation ( + const AnimationFunctor& rAnimation, + const double nDelta); + + /** Abort and remove an animation. In order to reduce the bookkeeping + on the caller side, it is OK to call this method with an animation + function that is not currently being animated. Such a call is + silently ignored. + */ + void RemoveAnimation (const AnimationId nAnimationId); + + /** A typical use case for this method is the temporary shutdown of the + slidesorter when the slide sorter bar is put into a cache due to a + change of the edit mode. + */ + void RemoveAllAnimations (void); + +private: + SlideSorter& mrSlideSorter; + Timer maTimer; + bool mbIsDisposed; + class Animation; + typedef ::std::vector<boost::shared_ptr<Animation> > AnimationList; + AnimationList maAnimations; + ::canvas::tools::ElapsedTime maElapsedTime; + + ::boost::scoped_ptr<view::SlideSorterView::DrawLock> mpDrawLock; + + AnimationId mnNextAnimationId; + + DECL_LINK(TimeoutHandler, Timer*); + + /** Execute one step of every active animation. + @param nTime + Time measured in milli seconds with some arbitrary reference point. + @return + When one or more animation has finished then <TRUE/> is + returned. Call CleanUpAnimationList() in this case. + */ + bool ProcessAnimations (const double nTime); + + /** Remove animations that have expired. + */ + void CleanUpAnimationList (void); + + void RequestNextFrame (const double nFrameStart = 0); +}; + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..fc97dd32829a --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsClipboard.hxx @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "controller/SlsSelectionObserver.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, + sal_uInt16 nPage = SDRPAGE_NOTFOUND, + sal_uInt16 nLayer = SDRPAGE_NOTFOUND ); + + sal_Int8 ExecuteDrop ( + const ExecuteDropEvent& rEvt, + DropTargetHelper& rTargetHelper, + ::sd::Window* pTargetWindow = NULL, + sal_uInt16 nPage = SDRPAGE_NOTFOUND, + sal_uInt16 nLayer = SDRPAGE_NOTFOUND); + + void Abort (void); + +protected: + virtual sal_uInt16 DetermineInsertPosition ( + const SdTransferable& rTransferable); + + virtual sal_uInt16 InsertSlides ( + const SdTransferable& rTransferable, + sal_uInt16 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 (sal_False). + */ + bool mbUpdateSelectionPending; + + /** Used when a drop is executed to combine all undo actions into one. + Typically created in ExecuteDrop() and released in DragFinish(). + */ + class UndoContext; + ::boost::scoped_ptr<UndoContext> mpUndoContext; + + ::boost::scoped_ptr<SelectionObserver::Context> mpSelectionObserverContext; + sal_uLong mnDragFinishedUserEventId; + + 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, + sal_uInt16 nPage, + sal_uInt16 nLayer); + + /** Asynchronous part of DragFinished. The argument is the sal_Int8 + nDropAction, disguised as void*. + */ + DECL_LINK(ProcessDragFinished, void*); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..8bc96827c02e --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsCurrentSlideManager.hxx @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <vcl/timer.hxx> +#include <tools/link.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. + + Switching pages is triggered only after a little delay. This allows + fast travelling through a larger set of slides without having to wait + for the edit view to update its content after every slide change. +*/ +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 NotifyCurrentSlideChange (const sal_Int32 nSlideIndex); + void NotifyCurrentSlideChange (const SdPage* pPage); + + /** 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. + @param nSlideIndex + Zero based index in the range [0,number-of-slides). + @param bUpdateSelection + When <TRUE/> then the page selection is cleared and only the new + current slide is selected. + */ + void SwitchCurrentSlide ( + const sal_Int32 nSlideIndex, + const bool bUpdateSelection = false); + void SwitchCurrentSlide ( + const model::SharedPageDescriptor& rpSlide, + const bool bUpdateSelection = false); + + /** 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; + /** Timer to control the delay after which to ask + XController/ViewShellBase to switch to another slide. + */ + Timer maSwitchPageDelayTimer; + + bool IsCurrentSlideIsValid (void); + void SetCurrentSlideAtViewShellBase (const model::SharedPageDescriptor& rpSlide); + void SetCurrentSlideAtTabControl (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); + + DECL_LINK(SwitchPageCallback,void*); +}; + + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..d077e64d5fbb --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsFocusManager.hxx @@ -0,0 +1,236 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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. + @param bScrollToFocus + When <TRUE/> (the default) then the view is scrolled so that the + focus rectangle lies inside its visible area. + */ + void ShowFocus (const bool bScrollToFocus = true); + + /** 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; + + /** 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); + + void SetFocusedPageToCurrentPage (void); + + /** 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; + + /** When vertical wrap is active then pressing UP in the top row moves + the focus to the bottom row, DOWN in the bottom row moves the focus + to the top row. + */ + bool mbIsVerticalWrapActive; + + /** 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. + @param bScrollToFocus + When <TRUE/> (the default) then the view is scrolled so that the + focus rectangle lies inside its visible area. + */ + void ShowFocusIndicator ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bScrollToFocus); + + /** 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx b/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx new file mode 100644 index 000000000000..e257c5729b10 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsInsertionIndicatorHandler.hxx @@ -0,0 +1,153 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_INSERTION_INDICATOR_HANDLER_HXX +#define SD_SLIDESORTER_INSERTION_INDICATOR_HANDLER_HXX + +#include "view/SlsInsertAnimator.hxx" + +#include "view/SlsLayouter.hxx" + +namespace sd { namespace slidesorter { class SlideSorter; } } +namespace sd { namespace slidesorter { namespace model { +class PageEnumeration; +} } } +namespace sd { namespace slidesorter { namespace view { +class InsertAnimator; +class InsertionIndicatorOverlay; +} } } + + +namespace sd { namespace slidesorter { namespace controller { + +class Transferable; + + +/** Manage the visibility and location of the insertion indicator. Its + actual display is controlled by the InsertionIndicatorOverlay. +*/ +class InsertionIndicatorHandler +{ +public: + InsertionIndicatorHandler (SlideSorter& rSlideSorter); + ~InsertionIndicatorHandler (void); + + enum Mode { CopyMode, MoveMode, UnknownMode }; + static Mode GetModeFromDndAction (const sal_Int8 nDndAction); + + /** Activate the insertion marker at the given coordinates. + */ + void Start (const bool bIsOverSourceView); + + /** Deactivate the insertion marker. + */ + void End (const controller::Animator::AnimationMode eMode); + + /** This context make sure that the insertion indicator is shown + (provided that the clipboard is not empty) while the context is + alive. Typically used while a context menu is displayed. + */ + class ForceShowContext + { + public: + ForceShowContext (const ::boost::shared_ptr<InsertionIndicatorHandler>& rpHandler); + ~ForceShowContext (void); + private: + const ::boost::shared_ptr<InsertionIndicatorHandler> mpHandler; + }; + + /** Update the indicator icon from the current transferable (from the + clipboard or an active drag and drop operation.) + */ + void UpdateIndicatorIcon (const Transferable* pTransferable); + + /** Set the position of the insertion marker to the given coordinates. + */ + void UpdatePosition ( + const Point& rMouseModelPosition, + const Mode eMode); + void UpdatePosition ( + const Point& rMouseModelPosition, + const sal_Int8 nDndAction); + + /** Return whether the insertion marker is active. + */ + bool IsActive (void) const; + + /** Return the insertion index that corresponds with the current + graphical location of the insertion indicator. + */ + sal_Int32 GetInsertionPageIndex (void) const; + + /** Determine whether moving the current selection to the current + position of the insertion marker would alter the document. This + would be the case when the selection is not consecutive or would be + moved to a position outside and not adjacent to the selection. + */ + bool IsInsertionTrivial ( + const sal_Int32 nInsertionIndex, + const Mode eMode) const; + /** This method is like the other variant. It operates implicitly + on the current insertion index as would be returned by + GetInsertionPageIndex(). + */ + bool IsInsertionTrivial (const sal_Int8 nDndAction); + +private: + SlideSorter& mrSlideSorter; + ::boost::shared_ptr<view::InsertAnimator> mpInsertAnimator; + ::boost::shared_ptr<view::InsertionIndicatorOverlay> mpInsertionIndicatorOverlay; + view::InsertPosition maInsertPosition; + Mode meMode; + bool mbIsInsertionTrivial; + bool mbIsActive; + bool mbIsReadOnly; + bool mbIsOverSourceView; + Size maIconSize; + bool mbIsForcedShow; + + void SetPosition ( + const Point& rPoint, + const Mode eMode); + ::boost::shared_ptr<view::InsertAnimator> GetInsertAnimator (void); + + /** Make the insertion indicator visible (that is the show part) and + keep it visible, even when the mouse leaves the window (that is the + force part). We need this when a context menu is displayed (mouse + over the popup menu triggers a mouse leave event) while the + insertion indicator remains visible in the background. + + In effect all calls to End() are ignored until ForceEnd() is called. + */ + void ForceShow (void); + void ForceEnd (void); +}; + + +} } } // 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..db39444aea1f --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsPageObjectFactory.hxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..2aa7ee13f873 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsPageSelector.hxx @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 corresponding pages of the SdPage objects and issue + redraw requests where necessary. + */ + void GetCoreSelection (void); + + /** Update the selection state of the SdPage objects to be the same as + that of the correspinding page descriptors. + */ + void SetCoreSelection (void); + + /** Select the specified descriptor. The selection state of the other + descriptors is not affected. + */ + void SelectPage (int nPageIndex); + /** Select the descriptor that is associated with the given page. The + selection state of the other descriptors is not affected. + */ + void SelectPage (const SdPage* pPage); + /** Select the specified descriptor. The selection state of the other + descriptors is not affected. + */ + 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. + @param bUpdateCurrentPage + When <TRUE/> then the current page is updated to the first slide + of the remaining selection. + */ + void DeselectPage ( + int nPageIndex, + const bool bUpdateCurrentPage = true); + void DeselectPage ( + const SdPage* pPage, + const bool bUpdateCurrentPage = true); + void DeselectPage ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bUpdateCurrentPage = true); + + /** 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; + + /** 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. + @param bUpdateCurrentPage + When <TRUE/> (the default value) then after setting the + selection update the current page to the first page of the + selection. + When called from withing UpdateCurrentPage() then this flag is + used to prevent a recursion loop. + */ + void SetPageSelection ( + const ::boost::shared_ptr<PageSelection>& rSelection, + const bool bUpdateCurrentPage = true); + + /** Call this method after the the model has changed to set the number + of selected pages. + */ + void CountSelectedPages (void); + + /** Use the UpdateLock whenever you do a complex selection, i.e. call + more than one method in a row. An active lock prevents intermediate + changes of the current slide. + */ + class UpdateLock + { + public: + UpdateLock (SlideSorter& rSlideSorter); + UpdateLock (PageSelector& rPageSelector); + ~UpdateLock (void); + void Release (void); + private: + PageSelector* mpSelector; + }; + + class BroadcastLock + { + public: + BroadcastLock (SlideSorter& rSlideSorter); + BroadcastLock (PageSelector& rPageSelector); + ~BroadcastLock (void); + private: + PageSelector& mrSelector; + }; + +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; + sal_Int32 mnUpdateLockCount; + bool mbIsUpdateCurrentPagePending; + + /** 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 (void); + + /** Disable the broadcasting of selection change events. Subsequent + changes of the selection will set a flag that triggers the sending + of events when EnableBroadcasting() is called. + */ + void DisableBroadcasting (void); + + void UpdateCurrentPage (const bool bUpdateOnlyWhenPending = false); + + void CheckConsistency (void) const; +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..2e9a183c36d4 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsProperties.hxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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); + + /** Call this method after receiving a VCLEVENT_APPLICATION_DATACHANGED + event. + */ + void HandleDataChangeEvent (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); + + /** The mouse over effect (and whether a mouse motion starts a multi + selection or a drag-and-drop) can be triggered by just the preview + area or the whole page object area. + */ + bool IsOnlyPreviewTriggersMouseOver (void) const; + void SetOnlyPreviewTriggersMouseOver (const bool bFlag); + + bool IsHighContrastModeActive (void) const; + +private: + bool mbIsHighlightCurrentSlide; + bool mbIsShowSelection; + bool mbIsShowFocus; + bool mbIsCenterSelection; + bool mbIsSmoothSelectionScrolling; + bool mbIsSuspendPreviewUpdatesDuringFullScreenPresentation; + Color maBackgroundColor; + Color maTextColor; + Color maSelectionColor; + Color maHighlightColor; + bool mbIsUIReadOnly; + bool mbIsOnlyPreviewTriggersMouseOver; + bool mbIsHighContrastModeActive; +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..2894650da197 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsScrollBarManager.hxx @@ -0,0 +1,286 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "SlideSorter.hxx" + +#include <tools/link.hxx> +#include <tools/gen.hxx> +#include <vcl/timer.hxx> +#include <boost/shared_ptr.hpp> +#include <boost/function.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 horizontal + and/or vertical scroll bar is enabled. + @param rAvailableArea + The scroll bars will be placed inside this rectangle. It is + expected to be given in pixel relative to its parent. + @param bIsHorizontalScrollBarAllowed + Only when this flag is <TRUE/> the horizontal scroll may be + displayed. + @param bIsVerticalScrollBarAllowed + Only when this flag is <TRUE/> the horizontal scroll may be + displayed. + @return + Returns the space that remains after the scroll bars are + placed. + */ + Rectangle PlaceScrollBars ( + const Rectangle& rAvailableArea, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed); + + /** Update the vertical and horizontal scroll bars so that the visible + area has the given top and left values. + */ + void SetTopLeft (const Point aNewTopLeft); + + sal_Int32 GetTop (void) const; + + sal_Int32 GetLeft (void) const; + + /** 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. + @param rMouseWindowPosition + The mouse position for which the scroll amount is calculated. + @param rAutoScrollFunctor + Every time when the window is scrolled then this functor is executed. + @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, + const ::boost::function<void(void)>& rAutoScrollFunctor); + + void StopAutoScroll (void); + + enum Orientation { Orientation_Horizontal, Orientation_Vertical }; + enum Unit { Unit_Pixel, Unit_Slide }; + /** Scroll the slide sorter by setting the thumbs of the scroll bars and + by moving the content of the content window. + @param eOrientation + Defines whether to scroll horizontally or vertically. + @param eUnit + Defines whether the distance is a pixel value or the number of + slides to scroll. + */ + void Scroll( + const Orientation eOrientation, + const Unit eUnit, + const sal_Int32 nDistance); + +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; + bool mbIsAutoScrollActive; + + /** The content window is the one whose view port is controlled by the + scroll bars. + */ + SharedSdWindow mpContentWindow; + + ::boost::function<void(void)> maAutoScrollFunctor; + + 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, + const bool bIsHorizontalScrollBarAllowed, + const bool bIsVerticalScrollBarAllowed); + + /** 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); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..9e399d7262f8 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionFunction.hxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "model/SlsSharedPageDescriptor.hxx" +#include "controller/SlsFocusManager.hxx" +#include "controller/SlsInsertionIndicatorHandler.hxx" +#include "fupoor.hxx" +#include <svtools/transfer.hxx> +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> + +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 DragAndDropContext; + + +class SelectionFunction + : public FuPoor, + private ::boost::noncopyable +{ +public: + TYPEINFO(); + + static FunctionReference Create( SlideSorter& rSlideSorter, SfxRequest& rRequest ); + + // Mouse- & Key-Events + virtual sal_Bool KeyInput(const KeyEvent& rKEvt); + virtual sal_Bool MouseMove(const MouseEvent& rMEvt); + virtual sal_Bool MouseButtonUp(const MouseEvent& rMEvt); + virtual sal_Bool MouseButtonDown(const MouseEvent& rMEvt); + + virtual void Activate(); + virtual void Deactivate(); + + 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(); + + void MouseDragged ( + const AcceptDropEvent& rEvent, + const sal_Int8 nDragAction); + + /** Turn of substitution display and insertion indicator. + */ + void NotifyDragFinished (void); + + /** Call when drag-and-drop or multi selection is started or stopped in + order to update permission of mouse over indication. + */ + void UpdateMouseOverIndicationPermission (void); + + class EventDescriptor; + class ModeHandler; + friend class ModeHandler; + enum Mode + { + NormalMode, + MultiSelectionMode, + DragAndDropMode, + ButtonMode + }; + void SwitchToNormalMode (void); + void SwitchToDragAndDropMode(const Point aMousePosition); + void SwitchToMultiSelectionMode (const Point aMousePosition, const sal_uInt32 nEventCode); + bool SwitchToButtonMode (void); + + void ResetShiftKeySelectionAnchor (void); + /** Special case handling for when the context menu is hidden. This + method will reinitialize the current mouse position to prevent the + mouse motion during the time the context menu is displayed from + being interpreted as drag-and-drop start. + */ + void ResetMouseAnchor (void); + +protected: + SlideSorter& mrSlideSorter; + SlideSorterController& mrController; + + SelectionFunction ( + SlideSorter& rSlideSorter, + SfxRequest& rRequest); + + virtual ~SelectionFunction(); + +private: + + /// 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; + + bool mbIsDeselectionPending; + + /** Remember the slide where the shift key was pressed and started a + multiselection via keyboard. + */ + sal_Int32 mnShiftKeySelectionAnchor; + + /** The selection function can be in one of several mutually + exclusive modes. + */ + ::boost::shared_ptr<ModeHandler> mpModeHandler; + + /** 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); + + /** Make the slide with the given index the new current slide. + @param nIndex + Index of the new current slide. When the new index is outside + the range of valid page numbers it is clipped to that range. + */ + void GotoPage (int nIndex); + + 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(). + + void ProcessEvent (EventDescriptor& rEvent); + + void MoveFocus ( + const FocusManager::FocusMoveDirection eDirection, + const bool bIsShiftDown, + const bool bIsControlDown); + + void StopDragAndDrop (void); + + void SwitchMode (const ::boost::shared_ptr<ModeHandler>& rpHandler); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file 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..05bb8ef9a895 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionManager.hxx @@ -0,0 +1,170 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "controller/SlsAnimator.hxx" +#include <sal/types.h> +#include <tools/gen.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <vector> + +class Link; +class SdPage; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace controller { + +class SlideSorterController; +class SelectionObserver; + +/** 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. + @param bSelectFollowingPage + When <TRUE/> then after deleting the selected pages make the + slide after the last selected page the new current page. + When <FALSE/> then make the first slide before the selected + pages the new current slide. + */ + void DeleteSelectedPages (const bool bSelectFollowingPage = true); + + /** 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); + + /** 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); + + ::boost::shared_ptr<SelectionObserver> GetSelectionObserver (void) const; + +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; + + /** Animation id for a scroll animation the will eventually set the top + and left of the visible area to maRequestedTopLeft. + */ + Animator::AnimationId mnAnimationId; + Point maRequestedTopLeft; + + class PageInsertionListener; + ::boost::scoped_ptr<PageInsertionListener> mpPageInsertionListener; + + ::boost::shared_ptr<SelectionObserver> mpSelectionObserver; + + /** 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); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx b/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx new file mode 100644 index 000000000000..0fb45b403af1 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSelectionObserver.hxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_CONTROLLER_SELECTION_OBSERVER_HXX +#define SD_SLIDESORTER_CONTROLLER_SELECTION_OBSERVER_HXX + +#include <tools/gen.hxx> +#include <vector> +#include <boost/shared_ptr.hpp> + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +class SdDrawDocument; +class SdrPage; + +namespace sd { namespace slidesorter { namespace controller { + +/** Observe insertions and deletions of pages between calls to + StartObservation() and EndObservation(). When the later is called + the selection is set to just the newly inserted pages. +*/ +class SelectionObserver +{ +public: + SelectionObserver (SlideSorter& rSlideSorter); + virtual ~SelectionObserver (void); + + void NotifyPageEvent (const SdrPage* pPage); + void StartObservation (void); + void AbortObservation (void); + void EndObservation (void); + + /** Use this little class instead of calling StartObservation and + EndObservation directly so that EndObservation is not forgotten or + omitted due to an exception or some break or return in the middle of + code. + */ + class Context + { + public: + Context (SlideSorter& rSlideSorter); + ~Context(void); + void Abort (void); + private: + ::boost::shared_ptr<SelectionObserver> mpSelectionObserver; + }; + +private: + SlideSorter& mrSlideSorter; + SdDrawDocument* mpDocument; + bool mbIsOvservationActive; + + ::std::vector<const SdPage*> maInsertedPages; + ::std::vector<sal_Int32> maDeletedPages; +}; + +} } } // 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..774e4c09cc7c --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSlideFunction.hxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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(); + + virtual sal_Bool MouseMove (const MouseEvent& rMEvt); + virtual sal_Bool MouseButtonUp (const MouseEvent& rMEvt); + virtual sal_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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..c21df03ad6d4 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsSlotManager.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "model/SlsSharedPageDescriptor.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 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); + + /** Exclude or include one slide or all selected slides. + @param rpDescriptor + When the pointer is empty then apply the new state to all + selected pages. Otherwise apply the new state to just the + specified state. + */ + void ChangeSlideExclusionState ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bExcludeSlide); + + /** Call this after a change from normal mode to master mode or back. + The affected slots are invalidated. + */ + void NotifyEditModeChange (void); + +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( sal_uInt16 nPageId, const String& rName); + + /** Handle SID_INSERTPAGE slot calls. + */ + void InsertSlide (SfxRequest& rRequest); + + void DuplicateSelectedSlides (SfxRequest& rRequest); + + /** Use one of several ways to determine where to insert a new page. + This can be the current selection or the insertion indicator. + */ + sal_Int32 GetInsertionPosition (void); + + DECL_LINK(UserEventCallback, void*); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/controller/SlsTransferable.hxx b/sd/source/ui/slidesorter/inc/controller/SlsTransferable.hxx new file mode 100644 index 000000000000..321823f6c14e --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsTransferable.hxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_TRANSFERABLE_HXX +#define SD_SLIDESORTER_TRANSFERABLE_HXX + +#include "sdxfer.hxx" + +class SdDrawDocument; +namespace sd { 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: + class Representative + { + public: + Representative (const Bitmap& rBitmap, const bool bIsExcluded) + : maBitmap(rBitmap), mbIsExcluded(bIsExcluded) {} + Representative (const Representative& rOther) + : maBitmap(rOther.maBitmap), mbIsExcluded(rOther.mbIsExcluded) {} + Representative operator= (Representative const& rOther) + { if (&rOther != this) {maBitmap = rOther.maBitmap; mbIsExcluded = rOther.mbIsExcluded; } + return *this; + } + + Bitmap maBitmap; + bool mbIsExcluded; + }; + + + Transferable ( + SdDrawDocument* pSrcDoc, + ::sd::View* pWorkView, + sal_Bool bInitOnGetData, + SlideSorterViewShell* pViewShell, + const ::std::vector<Representative>& rRepresentatives); + + virtual ~Transferable (void); + + virtual void DragFinished (sal_Int8 nDropAction); + + const ::std::vector<Representative>& GetRepresentatives (void) const; + +private: + SlideSorterViewShell* mpViewShell; + const ::std::vector<Representative> maRepresentatives; + + virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); +}; + +} } } // end of namespace ::sd::slidesorter::controller + +#endif diff --git a/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx b/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx new file mode 100644 index 000000000000..cdaf9b1588ea --- /dev/null +++ b/sd/source/ui/slidesorter/inc/controller/SlsVisibleAreaManager.hxx @@ -0,0 +1,100 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VISIBLE_AREA_MANAGER_HXX +#define SD_SLIDESORTER_VISIBLE_AREA_MANAGER_HXX + +#include "controller/SlsAnimator.hxx" +#include "model/SlsSharedPageDescriptor.hxx" +#include <boost/noncopyable.hpp> +#include <boost/optional.hpp> + +namespace sd { namespace slidesorter { namespace controller { + + +/** Manage requests for scrolling page objects into view. +*/ +class VisibleAreaManager + : public ::boost::noncopyable +{ +public: + VisibleAreaManager (SlideSorter& rSlideSorter); + ~VisibleAreaManager (void); + + void ActivateCurrentSlideTracking (void); + void DeactivateCurrentSlideTracking (void); + + /** Request the current slide to be moved into the visible area. + This request is only obeyed when the current slide tracking is + active. + @see ActivateCurrentSlideTracking() and DeactivateCurrentSlideTracking() + */ + void RequestCurrentSlideVisible (void); + + /** Request to make the specified page object visible. + */ + void RequestVisible ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bForce = false); + + /** Temporarily disable the update of the visible area. + */ + class TemporaryDisabler + { + public: + TemporaryDisabler (SlideSorter& rSlideSorter); + ~TemporaryDisabler (void); + private: + VisibleAreaManager& mrVisibleAreaManager; + }; + +private: + SlideSorter& mrSlideSorter; + + /** List of rectangle that someone wants to be moved into the visible + area. + Cleared on every call to ForgetVisibleRequests() and MakeVisible(). + */ + ::std::vector<Rectangle> maVisibleRequests; + + /** Animation id for a scroll animation that sets the top + and left of the visible area to maRequestedVisibleTopLeft. + */ + Animator::AnimationId mnScrollAnimationId; + Point maRequestedVisibleTopLeft; + Animator::AnimationMode meRequestedAnimationMode; + bool mbIsCurrentSlideTrackingActive; + int mnDisableCount; + + void MakeVisible (void); + ::boost::optional<Point> GetRequestedTopLeft (void) const; +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#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..d059b48624d2 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlideSorterModel.hxx @@ -0,0 +1,254 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 <vcl/region.hxx> + +#include <memory> +#include <vector> +#include <functional> + +namespace css = ::com::sun::star; + +class SdrPage; +class SdPage; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace controller { +class PageObjectFactory; +} } } + +namespace sd { namespace slidesorter { namespace model { + +class DocumentPageContainer; + +inline sal_Int32 FromCoreIndex (const sal_uInt16 nCoreIndex) { return (nCoreIndex-1)/2; } +inline sal_uInt16 ToCoreIndex (const sal_Int32 nIndex) { return nIndex*2+1; } + +/** 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); + void Init (void); + + virtual ~SlideSorterModel (void); + void Dispose (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; + + /** Return a page descriptor for the given SdrPage. 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 SdrPage 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 SdrPage* pPage) const; + + /** Return an index for accessing an SdrModel that corresponds to the + given SlideSorterModel index. In many cases we just have to apply + the n*2+1 magic. Only when a special model is set, like a custom + slide show, then the returned value is different. + */ + sal_uInt16 GetCoreIndex (const sal_Int32 nIndex) 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); + + /** 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); + + bool IsReadOnly (void) const; + + /** The current selection is saved by copying the ST_Selected state into + ST_WasSelected for slides. + */ + void SaveCurrentSelection (void); + + /** The current selection is restored from the ST_WasSelected state from + the slides. + @returns + The returned region has to be repainted to reflect the updated + selection states. + */ + Region RestoreSelection (void); + + /** Typically called from controller::Listener this method handles the + insertion and deletion of single pages. + @return + Returns <TRUE/> when the given page is relevant for the current + page kind and edit mode. + */ + bool NotifyPageEvent (const SdrPage* pPage); + +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; + + /** Resize the descriptor container according to current values of + page kind and edit mode. + */ + void AdaptSize (void); + + SdPage* GetPage (const sal_Int32 nCoreIndex) const; + void InsertSlide (SdPage* pPage); + void DeleteSlide (const SdPage* pPage); + void UpdateIndices (const sal_Int32 nFirstIndex); +}; + +} } } // end of namespace ::sd::slidesorter::model + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..fe4b1cc12506 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsEnumeration.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..ab699d729356 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsPageDescriptor.hxx @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "model/SlsVisualState.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> +#include <boost/scoped_ptr.hpp> + + +class SdPage; +class SdrPage; + +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); + + ~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; + void SetPageIndex (const sal_Int32 nIndex); + + bool UpdateMasterPage (void); + + enum State { ST_Visible, ST_Selected, ST_WasSelected, + ST_Focused, ST_MouseOver, ST_Current, ST_Excluded }; + + bool HasState (const State eState) const; + + bool SetState (const State eState, const bool bStateValue); + + /** 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 GetCoreSelection (void); + + /** Set the selection flags of the SdPage objects to the corresponding + selection states of the page descriptors. + */ + void SetCoreSelection (void); + + VisualState& GetVisualState (void); + + Rectangle GetBoundingBox (void) const; + Point GetLocation (const bool bIgnoreLocation = false) const; + void SetBoundingBox (const Rectangle& rBoundingBox); + +private: + SdPage* mpPage; + css::uno::Reference<css::drawing::XDrawPage> mxPage; + SdrPage const* mpMasterPage; + + /** This index is displayed as page number in the view. It may or may + not be the actual page index. + */ + sal_Int32 mnIndex; + + Rectangle maBoundingBox; + VisualState maVisualState; + + bool mbIsSelected : 1; + bool mbWasSelected : 1; + bool mbIsVisible : 1; + bool mbIsFocused : 1; + bool mbIsCurrent : 1; + bool mbIsMouseOver : 1; + + + // 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..36a49f720589 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsPageEnumeration.hxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..6f9923308374 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsPageEnumerationProvider.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..93bcf89215e6 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsSharedPageDescriptor.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx b/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx new file mode 100644 index 000000000000..03b242fdd29a --- /dev/null +++ b/sd/source/ui/slidesorter/inc/model/SlsVisualState.hxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VISUAL_STATE_HXX +#define SD_SLIDESORTER_VISUAL_STATE_HXX + +#include <sal/types.h> +#include <tools/gen.hxx> +#include <boost/function.hpp> + +namespace sd { namespace slidesorter { namespace model { + +class PageDescriptor; + +/** This class gives access to values related to the visualization of page + objects. This includes animation state when blending from one state to + another. +*/ +class VisualState +{ +public: + enum State { + VS_Selected, + VS_Focused, + VS_Current, + VS_Excluded, + VS_None }; + + VisualState (const sal_Int32 nPageId); + ~VisualState (void); + + State GetCurrentVisualState (void) const; + State GetOldVisualState (void) const; + void SetVisualState (const State eState); + double GetVisualStateBlend (void) const; + void SetVisualStateBlend (const double nBlend); + + void UpdateVisualState (const PageDescriptor& rDescriptor); + + void SetMouseOverState (const bool bIsMouseOver); + + sal_Int32 GetStateAnimationId (void) const; + void SetStateAnimationId (const sal_Int32 nAnimationId); + + Point GetLocationOffset (void) const; + bool SetLocationOffset (const Point& rPoint); + sal_Int32 GetLocationAnimationId (void) const; + void SetLocationAnimationId (const sal_Int32 nAnimationId); + + double GetButtonAlpha (void) const; + void SetButtonAlpha (const double nAlpha); + double GetButtonBarAlpha (void) const; + void SetButtonBarAlpha (const double nAlpha); + sal_Int32 GetButtonAlphaAnimationId (void) const; + void SetButtonAlphaAnimationId (const sal_Int32 nAnimationId); + + sal_Int32 mnPageId; // For debugging + +private: + State meCurrentVisualState; + State meOldVisualState; + double mnVisualStateBlend; + sal_Int32 mnStateAnimationId; + bool mbOldMouseOverState; + bool mbCurrentMouseOverState; + + Point maLocationOffset; + sal_Int32 mnLocationAnimationId; + + double mnButtonAlpha; + double mnButtonBarAlpha; + sal_Int32 mnButtonAlphaAnimationId; +}; + +} } } // 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..099f6544f861 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlideSorterView.hxx @@ -0,0 +1,304 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsSharedPageDescriptor.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsILayerPainter.hxx" + +#include "View.hxx" +#include <sfx2/viewfrm.hxx> +#include "pres.hxx" +#include <tools/gen.hxx> +#include <svx/svdmodel.hxx> +#include <vcl/region.hxx> +#include <vcl/outdev.hxx> +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> +#include <memory> +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> + +class Point; + +namespace sd { namespace slidesorter { namespace controller { +class SlideSorterController; +class Properties; +} } } + +namespace sd { namespace slidesorter { namespace cache { +class PageCache; +} } } + +namespace sd { namespace slidesorter { namespace model { +class SlideSorterModel; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class ButtonBar; +class LayeredDevice; +class Layouter; +class PageObjectPainter; +class SelectionPainter; +class ToolTip; + + +class SlideSorterView + : public sd::View, + public ::boost::noncopyable +{ +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); + void Init (void); + + virtual ~SlideSorterView (void); + void Dispose (void); + + /** Set the general way of layouting the page objects. Note that this + method does not trigger any repaints or layouts. + */ + bool SetOrientation (const Layouter::Orientation eOrientation); + Layouter::Orientation GetOrientation (void) const; + + void RequestRepaint (void); + void RequestRepaint (const model::SharedPageDescriptor& rDescriptor); + void RequestRepaint (const Rectangle& rRepaintBox); + void RequestRepaint (const Region& rRepaintRegion); + + Rectangle GetModelArea (void); + + /** 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; + + 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 = NULL); + void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea); + + virtual void ConfigurationChanged ( + utl::ConfigurationBroadcaster* pBroadcaster, + sal_uInt32 nHint); + + void HandleDataChangeEvent (void); + + 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. + */ + // ::boost::shared_ptr<sd::Window> GetWindow (void) const; + + ::boost::shared_ptr<cache::PageCache> GetPreviewCache (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); + + /** 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. + */ + Pair GetVisiblePageRange (void); + + /** Add a shape to the page. Typically used from inside + PostModelChange(). + */ + // void AddSdrObject (SdrObject& rObject); + + /** Add a listener that is called when the set of visible slides. + @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 AddVisibilityChangeListener (const Link& rListener); + + /** Remove a listener that is called when the set of visible slides changes. + @param rListener + It is save to pass a listener that was not added or has been + removed previously. Such calls are ignored. + */ + void RemoveVisibilityChangeListener (const Link& rListener); + + /** The page under the mouse is not highlighted in some contexts. Call + this method on context changes. + */ + void UpdatePageUnderMouse (bool bAnimate); + void UpdatePageUnderMouse ( + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate = true); + void UpdatePageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate = true); + void SetPageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate = true); + + bool SetState ( + const model::SharedPageDescriptor& rpDescriptor, + const model::PageDescriptor::State eState, + const bool bStateValue, + const bool bAnimate = true); + + void UpdateOrientation (void); + + ::boost::shared_ptr<PageObjectPainter> GetPageObjectPainter (void); + ::boost::shared_ptr<LayeredDevice> GetLayeredDevice (void) const; + + class DrawLock + { + public: + DrawLock (view::SlideSorterView& rView, const SharedSdWindow& rpWindow); + DrawLock (SlideSorter& rSlideSorter); + ~DrawLock (void); + /** When the DrawLock is disposed then it will not request a repaint + on destruction. + */ + void Dispose (void); + private: + view::SlideSorterView& mrView; + SharedSdWindow mpWindow; + }; + + ButtonBar& GetButtonBar (void) const; + ToolTip& GetToolTip (void) const; + +protected: + virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint); + +private: + SlideSorter& mrSlideSorter; + model::SlideSorterModel& mrModel; + bool mbIsDisposed; + ::std::auto_ptr<Layouter> mpLayouter; + bool mbPageObjectVisibilitiesValid; + ::boost::shared_ptr<cache::PageCache> mpPreviewCache; + ::boost::shared_ptr<LayeredDevice> mpLayeredDevice; + Range maVisiblePageRange; + bool mbModelChangedWhileModifyEnabled; + Size maPreviewSize; + bool mbPreciousFlagUpdatePending; + Layouter::Orientation meOrientation; + ::boost::shared_ptr<controller::Properties> mpProperties; + model::SharedPageDescriptor mpPageUnderMouse; + sal_Int32 mnButtonUnderMouse; + ::boost::shared_ptr<PageObjectPainter> mpPageObjectPainter; + ::boost::shared_ptr<SelectionPainter> mpSelectionPainter; + Region maRedrawRegion; + SharedILayerPainter mpBackgroundPainter; + ::boost::scoped_ptr<ButtonBar> mpButtonBar; + ::boost::scoped_ptr<ToolTip> mpToolTip; + bool mbIsRearrangePending; + ::std::vector<Link> maVisibilityChangeListeners; + + /** Determine the visibility of all page objects. + */ + void DeterminePageObjectVisibilities (void); + + void UpdatePreciousFlags (void); + void RequestRearrange (void); + void Rearrange (void); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/view/SlsButtonBar.hxx b/sd/source/ui/slidesorter/inc/view/SlsButtonBar.hxx new file mode 100644 index 000000000000..460c915f8a56 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsButtonBar.hxx @@ -0,0 +1,362 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_BUTTON_BAR_HXX +#define SD_SLIDESORTER_VIEW_BUTTON_BAR_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include <tools/gen.hxx> +#include <rtl/ustring.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/bmpacc.hxx> +#include <boost/scoped_ptr.hpp> + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + + +namespace sd { namespace slidesorter { namespace view { + +class Theme; + +class Button; +typedef ::boost::shared_ptr<Button> SharedButton; + +/** This is a container of buttons and a coordinating controller. + The last means that it receives mouse events and forwards them to + the right button. +*/ +class ButtonBar +{ +public: + ButtonBar (SlideSorter& rSlideSorter); + ~ButtonBar (void); + + void ProcessButtonDownEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation); + void ProcessButtonUpEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation); + void ProcessMouseMotionEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation, + const bool bIsMouseButtonDown); + + void ResetPage (void); + + /** Return the number of buttons that are to be displayed in page + objects which the mouse hovers over. + @param bIsExcluded + When this flag is <TRUE/> then return the number of + buttons that is to be displayed for pages that are + excluded from the slide show. + */ + sal_Int32 GetButtonCount (const bool bIsExcluded) const; + + /** Return the specified button. + @param nIndex + Valid values lie in the range [0,GetButtonCount()). + @param bIsExcluded + When this flag is <TRUE/> then return a button that is to + be displayed for pages that are excluded from the slide + show. + @return + Returns an empty pointer when the given index is not valid. + */ + ::boost::shared_ptr<Button> GetButton ( + const bool bIsExcluded, + const sal_Int32 nIndex) const; + + bool IsMouseOverBar (void) const; + + /** Paint the specified page object. When this is not the same as the + one under the mouse (mpDescriptor) then the buttons are all + painted in their normal state. + */ + void Paint ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpPageDescriptor); + + bool IsMouseOverButton (void) const; + + void RequestLayout (void); + + /** Return the help text for the button under the mouse. + @return + When the mouse is not over a button then an empty string + is returned. + */ + ::rtl::OUString GetButtonHelpText (void) const; + + /** Request the button bar to be shown. + @param bAnimate + This flag controls whether to just show the button bar (<FALSE/>) + or to fade it in smoothly (<TRUE/>.) + */ + void RequestFadeIn ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate); + + /** Request the button bar to be hidden. + @param bAnimate + This flag controls whether to just hide the button bar (<FALSE/>) + or to fade it out smoothly (<TRUE/>.) + */ + void RequestFadeOut ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate); + + /** Return whether the button bar is visible for the givn descriptor (or + being faded in.) + */ + bool IsVisible (const model::SharedPageDescriptor& rpDescriptor); + + void HandleDataChangeEvent (void); + + class BackgroundTheme; + + /** While at least one Lock object exists the button bar will not be + displayed. Used, e.g. during a mouse multiselection to avoid + confusing and unhelpfull visual signals. + */ + class Lock + { + public: + Lock (SlideSorter& rSlideSorter); + ~Lock (void); + private: + ButtonBar& mrButtonBar; + }; + +private: + SlideSorter& mrSlideSorter; + Size maPageObjectSize; + Rectangle maButtonBoundingBox; + Point maBackgroundLocation; + model::SharedPageDescriptor mpDescriptor; + bool mbIsExcluded; + boost::shared_ptr<Button> mpButtonUnderMouse; + // The button on which the mouse button was pressed. + boost::shared_ptr<Button> mpDownButton; + ::std::vector<SharedButton> maRegularButtons; + ::std::vector<SharedButton> maExcludedButtons; + BitmapEx maNormalBackground; + BitmapEx maButtonDownBackground; + bool mbIsMouseOverBar; + ::boost::scoped_ptr<BackgroundTheme> mpBackgroundTheme; + int mnLockCount; + + /** Remember the specified page. If it differs from mpDescriptor then + the buttons are placed anew. + @return + The returned flag indicates wether the mpDescriptor member + is set to a new value. + */ + bool SetPage (const model::SharedPageDescriptor& rpDescriptor); + SharedButton GetButtonAt (const Point aModelLocation); + bool SetButtonUnderMouse (const SharedButton& rButton = SharedButton()); + void PaintButtonBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpPageDescriptor, + const Point aOffset); + void LayoutButtons (const Size aPageModelSize); + bool LayoutButtons (void); + BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const; + bool IsMouseOverBar (const Point aModelLocation) const; + void StartFadeAnimation ( + const model::SharedPageDescriptor& rpDescriptor, + const double nTargetAlpha, + const bool bFadeIn); + + void AcquireLock (void); + void ReleaseLock (void); +}; + + + + +class Button +{ +public: + Button ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsHelpText); + virtual ~Button (void); + + enum State { State_Normal, State_Hover, State_Down }; + enum IconSize { IconSize_Large, IconSize_Medium, IconSize_Small }; + + /** Set a new state. + @return + When the new state is different from the old state + then <TRUE/> is returned. + */ + bool SetState (const State eState); + State GetState (void) const; + + virtual void Place (const Rectangle aButtonBarBox) = 0; + virtual void Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const = 0; + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor) = 0; + + /** Return the bounding box of the layouted button. + */ + Rectangle GetBoundingBox (void) const; + /** Return the minimum size required to completely paint the + button. + */ + virtual Size GetSize (void) const = 0; + virtual Size GetSize (const IconSize eIconSize) const = 0; + ::rtl::OUString GetHelpText (void) const; + bool IsDown (void) const; + void SetActiveState (const bool bIsActive); + bool IsActive (void) const; + void SetIconSize (const IconSize eIconSize); + IconSize GetIconSize (void) const; + /** By default a button is always enabled. Override to change this. + */ + virtual bool IsEnabled (void) const; + +protected: + SlideSorter& mrSlideSorter; + State meState; + Rectangle maBoundingBox; + const ::rtl::OUString msHelpText; + // Buttons that lie (partly) outside the button bar are deactivated. + bool mbIsActive; + IconSize meIconSize; +}; + + + +class TextButton : public Button +{ +public: + TextButton ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsText, + const ::rtl::OUString& rsHelpText); + + virtual void Place (const Rectangle aButtonBarBox); + virtual void Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const; + virtual Size GetSize (void) const; + virtual Size GetSize (const IconSize eIconSize) const; + +private: + const ::rtl::OUString msText; +}; + + + +class ImageButton : public Button +{ +public: + ImageButton ( + SlideSorter& rSlideSorter, + const BitmapEx& rLargeIcon, + const BitmapEx& rLargeHoverIcon, + const BitmapEx& rMediumIcon, + const BitmapEx& rMediumHoverIcon, + const BitmapEx& rSmallIcon, + const BitmapEx& rSmallHoverIcon, + const ::rtl::OUString& rsHelpText); + + virtual void Place (const Rectangle aButtonBarBox); + virtual void Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const; + virtual Size GetSize (void) const; + virtual Size GetSize (const IconSize eIconSize) const; + +private: + const BitmapEx maLargeIcon; + const BitmapEx maLargeHoverIcon; + const BitmapEx maMediumIcon; + const BitmapEx maMediumHoverIcon; + const BitmapEx maSmallIcon; + const BitmapEx maSmallHoverIcon; +}; + + +class UnhideButton : public ImageButton +{ +public: + UnhideButton (SlideSorter& rSlideSorter); + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +class StartShowButton : public ImageButton +{ +public: + StartShowButton (SlideSorter& rSlideSorter); + virtual bool IsEnabled (void) const; + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +class HideButton : public ImageButton +{ +public: + HideButton (SlideSorter& rSlideSorter); + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +class DuplicateButton : public ImageButton +{ +public: + DuplicateButton (SlideSorter& rSlideSorter); + virtual bool IsEnabled (void) const; + +protected: + virtual void ProcessClick (const model::SharedPageDescriptor& rpDescriptor); +}; + + +} } } // 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..82487471edb0 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsFontProvider.hxx @@ -0,0 +1,97 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx b/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx new file mode 100644 index 000000000000..853890ee5894 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsILayerPainter.hxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_LAYER_PAINTER_HXX +#define SD_SLIDESORTER_VIEW_LAYER_PAINTER_HXX + +#include <boost/shared_ptr.hpp> +#include <sal/types.h> + +class OutputDevice; +class Rectangle; + +namespace sd { namespace slidesorter { namespace view { + +class ILayerInvalidator +{ +public: + virtual void Invalidate (const Rectangle& rInvalidationBox) = 0; +}; +typedef ::boost::shared_ptr<ILayerInvalidator> SharedILayerInvalidator; + +class ILayerPainter +{ +public: + virtual void SetLayerInvalidator ( + const SharedILayerInvalidator& rpInvalidator) = 0; + virtual void Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea) = 0; +}; +typedef ::boost::shared_ptr<ILayerPainter> SharedILayerPainter; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx b/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx new file mode 100644 index 000000000000..cfd789818408 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsInsertAnimator.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_INSERT_ANIMATOR_HXX +#define SD_SLIDESORTER_VIEW_INSERT_ANIMATOR_HXX + +#include "controller/SlsAnimator.hxx" +#include <boost/scoped_ptr.hpp> +#include <boost/noncopyable.hpp> + +namespace sd { namespace slidesorter { namespace view { + +class InsertPosition; + + +/** Animate the positions of page objects to make room at the insert + position while a move or copy operation takes place. +*/ +class InsertAnimator + : private ::boost::noncopyable +{ +public: + InsertAnimator (SlideSorter& rSlideSorter); + + /** Set the position at which we have to make room for the display of an + icon. + */ + void SetInsertPosition (const InsertPosition& rInsertPosition); + + enum ResetMode { RM_Normal, RM_AbortAnimations }; + /** Restore the normal position of all page objects. + @param eMode + This flag controls wether to start an animation that ends in the + normal positions of all slides (AM_Animated) or to restore the + normal positions immediately (AM_Immediate). + */ + void Reset (const controller::Animator::AnimationMode eMode); + +private: + class Implementation; + ::boost::shared_ptr<Implementation> mpImplementation; +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx b/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx new file mode 100644 index 000000000000..a9a640d978cf --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsInsertionIndicatorOverlay.hxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_INSERTION_INDICATOR_OVERLAY_HXX +#define SD_SLIDESORTER_INSERTION_INDICATOR_OVERLAY_HXX + +#include "model/SlsSharedPageDescriptor.hxx" +#include "view/SlsILayerPainter.hxx" +#include "controller/SlsTransferable.hxx" + +#include <tools/gen.hxx> +#include <vcl/bitmapex.hxx> +#include <boost/scoped_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <vector> + +class OutputDevice; +class SdPage; + +namespace sd { namespace slidesorter { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace model { +class PageEnumeration; +} } } + +namespace sd { namespace slidesorter { namespace controller { +class Transferable; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class FramePainter; +class LayeredDevice; + +/** The insertion indicator is painted as a vertical or horizonal bar + in the space between slides. +*/ +class InsertionIndicatorOverlay + : public ILayerPainter, + public ::boost::enable_shared_from_this<InsertionIndicatorOverlay> +{ +public: + InsertionIndicatorOverlay (SlideSorter& rSlideSorter); + virtual ~InsertionIndicatorOverlay (void); + + virtual void SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator); + + void Create (const controller::Transferable* pTransferable); + + /** Given a position in model coordinates this method calculates the + insertion marker both as an index in the document and as a location + used for drawing the insertion indicator. + */ + void SetLocation (const Point& rPosition); + + Size GetSize (void) const; + + virtual void Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea); + + bool IsVisible (void) const; + void Hide (void); + void Show (void); + + Rectangle GetBoundingBox (void) const; + +private: + SlideSorter& mrSlideSorter; + bool mbIsVisible; + const sal_Int32 mnLayerIndex; + SharedILayerInvalidator mpLayerInvalidator; + // Center of the insertion indicator. + Point maLocation; + BitmapEx maIcon; + Point maIconOffset; + ::boost::scoped_ptr<FramePainter> mpShadowPainter; + + void SetPositionAndSize (const Rectangle& rBoundingBox); + void SelectRepresentatives ( + model::PageEnumeration& rSelection, + ::std::vector<model::SharedPageDescriptor>& rDescriptors) const; + Point PaintRepresentatives ( + OutputDevice& rContent, + const Size aPreviewSize, + const sal_Int32 nOffset, + const ::std::vector<controller::Transferable::Representative>& rPages) const; + void PaintPageCount ( + OutputDevice& rDevice, + const sal_Int32 nSelectionCount, + const Size aPreviewSize, + const Point aFirstPageOffset) const; + /** Setup the insertion indicator by creating the icon. It consists of + scaled down previews of some of the selected pages. + */ + void Create ( + const ::std::vector<controller::Transferable::Representative>& rPages, + const sal_Int32 nSelectionCount); +}; + + + +} } } // 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..997b8159db0b --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsLayouter.hxx @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "SlideSorter.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsTheme.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 { + +class InsertPosition; + + + +/** 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: + enum Orientation { HORIZONTAL, VERTICAL, GRID }; + + Layouter ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<Theme>& rpTheme); + ~Layouter (void); + + ::boost::shared_ptr<PageObjectLayouter> GetPageObjectLayouter (void) const; + /** 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 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 eOrientation + This defines the generaly layout and specifies whether there may + be more than one row or more than one column. + @param rWindowSize + The size of the window in pixels that the slide sorter is + displayed in. This can differ from the size of mpWindow during + detection of whether or not the scroll bars should be visible. + @param rPreviewModelSize + Size of each page in model coordinates. + @param rpWindow + The map mode of this window 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 Rearrange ( + const Orientation eOrientation, + const Size& rWindowSize, + const Size& rPreviewModelSize, + const sal_uInt32 nPageCount); + + /** Change the zoom factor. This does not change the general layout + (number of columns). + */ + void _SetZoom (double nZoomFactor); + void _SetZoom (Fraction nZoomFactor); + + /** Return the number of columns. + */ + sal_Int32 GetColumnCount (void) const; + + sal_Int32 GetRowCount (void) const; + + sal_Int32 GetRow (const sal_Int32 nIndex) const; + + sal_Int32 GetColumn (const sal_Int32 nIndex) const; + + sal_Int32 GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) 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 window coordinates of the nIndex-th page + object. + */ + Rectangle GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap = false) const; + + /** Return the bounding box in model coordinates of the page that + contains the given amount of page objects. + */ + Rectangle GetTotalBoundingBox (void) const; + + /** Return the index of the first fully or partially visible page + object. This takes into account only the vertical dimension. + @return + The second index may be larger than the number of existing + page objects. + */ + Range GetRangeOfVisiblePageObjects (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. + @param bClampToValidRange + When <TRUE/> then values outside the valid range [0,mnPageCount) + are mapped to 0 (when smaller than 0) or mnPageCount-1 when + equal to or larger than mnPageCount. + When <FALSE/> then -1 is returned for values outside the valid range. + @return + The returned index may be larger than the number of existing + page objects. + */ + sal_Int32 GetIndexAtPoint ( + const Point& rModelPosition, + const bool bIncludePageBorders = false, + const bool bClampToValidRange = true) const; + + /** Return an object that describes the logical and visual properties of + where to do an insert operation when the user would release the the + mouse button at the given position after a drag operation and of + where and how to display an insertion indicator. + @param rModelPosition + 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 rIndicatorSize + The size of the insertion indicator. This size is used to adapt + the location when at the left or right of a row or at the top or + bottom of a column. + @param rModel + The model is used to get access to the selection states of the + pages. This in turn is used to determine the visual bounding + boxes. + */ + InsertPosition GetInsertPosition ( + const Point& rModelPosition, + const Size& rIndicatorSize, + model::SlideSorterModel& rModel) const; + + Range GetValidHorizontalSizeRange (void) const; + Range GetValidVerticalSizeRange (void) const; + + class Implementation; + +private: + ::boost::scoped_ptr<Implementation> mpImplementation; + SharedSdWindow mpWindow; +}; + + + + + +/** Collect all values concerning the logical and visual properties of the + insertion position that is used for drag-and-drop and copy-and-past. +*/ +class InsertPosition +{ +public: + InsertPosition (void); + InsertPosition& operator= (const InsertPosition& rInsertPosition); + bool operator== (const InsertPosition& rInsertPosition) const; + bool operator!= (const InsertPosition& rInsertPosition) const; + + void SetLogicalPosition ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const sal_Int32 nIndex, + const bool bIsAtRunStart, + const bool bIsAtRunEnd, + const bool bIsExtraSpaceNeeded); + void SetGeometricalPosition( + const Point aLocation, + const Point aLeadingOffset, + const Point aTrailingOffset); + + sal_Int32 GetRow (void) const { return mnRow; } + sal_Int32 GetColumn (void) const { return mnColumn; } + sal_Int32 GetIndex (void) const { return mnIndex; } + Point GetLocation (void) const { return maLocation; } + Point GetLeadingOffset (void) const { return maLeadingOffset; } + Point GetTrailingOffset (void) const { return maTrailingOffset; } + bool IsAtRunStart (void) const { return mbIsAtRunStart; } + bool IsAtRunEnd (void) const { return mbIsAtRunEnd; } + bool IsExtraSpaceNeeded (void) const { return mbIsExtraSpaceNeeded; } + +private: + sal_Int32 mnRow; + sal_Int32 mnColumn; + sal_Int32 mnIndex; + bool mbIsAtRunStart : 1; + bool mbIsAtRunEnd : 1; + bool mbIsExtraSpaceNeeded : 1; + Point maLocation; + Point maLeadingOffset; + Point maTrailingOffset; +}; + + + +} } } // end of namespace ::sd::slidesorter::view + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..27207ed9570b --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObject.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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; + +protected: + virtual sdr::contact::ViewContact* CreateObjectSpecificViewContact(); +}; + + + +} } } // end of namespace ::sd::slidesorter::view + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx new file mode 100644 index 000000000000..8e61a8b1b47c --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectLayouter.hxx @@ -0,0 +1,145 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_PAGE_OBJECT_LAYOUTER_HXX +#define SD_SLIDESORTER_PAGE_OBJECT_LAYOUTER_HXX + +#include "SlideSorter.hxx" +#include "model/SlsSharedPageDescriptor.hxx" +#include "tools/gen.hxx" +#include <vcl/image.hxx> + +namespace sd { namespace slidesorter { namespace view { + + +/** In contrast to the Layouter that places page objects in the view, the + PageObjectLayouter places the parts of individual page objects like page + number area, borders, preview. +*/ +class PageObjectLayouter +{ +public: + /** Create a new PageObjectLayouter object. + @param rPageObjectSize + In general either the width or the height will be 0 in order to + signal that this size component has to be calculated from the other. + This calculation will make the preview as large as possible. + @param nPageCount + The page count is used to determine how wide the page number + area has to be, how many digits to except for the largest page number. + */ + PageObjectLayouter( + const ::boost::shared_ptr<Theme>& rpTheme, + const Size& rPageObjectWindowSize, + const Size& rPreviewModelSize, + const SharedSdWindow& rpWindow, + const sal_Int32 nPageCount); + ~PageObjectLayouter(void); + + enum Part { + // The focus indicator is painted outside the actual page object. + FocusIndicator, + // This is the outer bounding box that includes the preview, page + // number, title. + PageObject, + // Bounding box of the actual preview. + Preview, + // Bounding box of the mouse indicator indicator frame. + MouseOverIndicator, + // Bounding box of the page number. + PageNumber, + // Bounding box of the pane name. + Name, + // Indicator whether or not there is a slide transition associated + // with this slide. + TransitionEffectIndicator + }; + /** Two coordinate systems are supported. They differ only in + translation not in scale. Both relate to pixel values in the window. + A position in the model coordinate system does not change when the window content is + scrolled up or down. In the window coordinate system (relative + to the top left point of the window)scrolling leads to different values. + */ + enum CoordinateSystem { + WindowCoordinateSystem, + ModelCoordinateSystem + }; + + /** Return the bounding box of the page object or one of its graphical + parts. + @param rWindow + This device is used to translate between model and window + coordinates. + @param rpPageDescriptor + The page for which to calculate the bounding box. This may be + NULL. When it is NULL then a generic bounding box is calculated + for the location (0,0). + @param ePart + 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 ( + const model::SharedPageDescriptor& rpPageDescriptor, + const Part ePart, + const CoordinateSystem eCoordinateSystem); + Rectangle GetBoundingBox ( + const Point& rPageObjectLocation, + const Part ePart, + const CoordinateSystem eCoordinateSystem); + Size GetSize ( + const Part ePart, + const CoordinateSystem eCoordinateSystem); + + Image GetTransitionEffectIcon (void) const; + +private: + SharedSdWindow mpWindow; + Size maPageObjectSize; + double mnModelToWindowScale; + Rectangle maFocusIndicatorBoundingBox; + Rectangle maPageObjectBoundingBox; + Rectangle maPageNumberAreaBoundingBox; + Rectangle maPreviewBoundingBox; + Rectangle maTransitionEffectBoundingBox; + const Image maTransitionEffectIcon; + const ::boost::shared_ptr<Font> mpPageNumberFont; + + Size GetPageNumberAreaSize (const int nPageCount); + Rectangle CalculatePreviewBoundingBox ( + Size& rPageObjectSize, + const Size& rPreviewModelSize, + const sal_Int32 nPageNumberAreaWidth, + const sal_Int32 nFocusIndicatorWidth); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx b/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx new file mode 100644 index 000000000000..e4e28a2e38b2 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectPainter.hxx @@ -0,0 +1,138 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_PAGE_OBJECT_PAINTER_HEADER +#define SD_SLIDESORTER_PAGE_OBJECT_PAINTER_HEADER + +#include "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsTheme.hxx" +#include <boost/scoped_ptr.hpp> + +namespace sd { namespace slidesorter { namespace cache { +class PageCache; +} } } + +namespace sd { namespace slidesorter { namespace view { + +class ButtonBar; +class Layouter; +class PageObjectLayouter; +class FramePainter; + +class PageObjectPainter +{ +public: + PageObjectPainter (const SlideSorter& rSlideSorter); + ~PageObjectPainter (void); + + void PaintPageObject ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor); + + void NotifyResize (const bool bForce = false); + + /** Called when the theme changes, either because it is replaced with + another or because the system colors have changed. So, even when + the given theme is the same object as the one already in use by this + painter everything that depends on the theme is updated. + */ + void SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme); + + /** Return a preview bitmap for the given page descriptor. When the + page is excluded from the show then the preview is marked + accordingly. + @rpDescriptor + Defines the page for which to return the preview. + @pReferenceDevice + When not <NULL/> then this reference device is used to created a + compatible bitmap. + @return + The returned bitmap may have a different size then the preview area. + */ + Bitmap GetPreviewBitmap ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice* pReferenceDevice) const; + +private: + const Layouter& mrLayouter; + ::boost::shared_ptr<PageObjectLayouter> mpPageObjectLayouter; + ::boost::shared_ptr<cache::PageCache> mpCache; + ::boost::shared_ptr<controller::Properties> mpProperties; + ::boost::shared_ptr<view::Theme> mpTheme; + ::boost::shared_ptr<Font> mpPageNumberFont; + ::boost::scoped_ptr<FramePainter> mpShadowPainter; + ::boost::scoped_ptr<FramePainter> mpFocusBorderPainter; + Bitmap maNormalBackground; + Bitmap maSelectionBackground; + Bitmap maFocusedSelectionBackground; + Bitmap maFocusedBackground; + Bitmap maMouseOverBackground; + Bitmap maMouseOverFocusedBackground; + Bitmap maMouseOverSelectedAndFocusedBackground; + ::rtl::OUString msUnhideString; + ButtonBar& mrButtonBar; + + void PaintBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor); + void PaintPreview ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const; + void PaintPageNumber ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const; + void PaintTransitionEffect ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const; + void PaintBorder ( + OutputDevice& rDevice, + const Theme::GradientColorType eColorType, + const Rectangle& rBox) const; + Bitmap& GetBackgroundForState ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice& rTemplateDevice); + Bitmap& GetBackground( + Bitmap& rBackground, + Theme::GradientColorType eType, + const OutputDevice& rTemplateDevice, + const bool bHasFocusBorder); + Bitmap CreateBackgroundBitmap( + const OutputDevice& rReferenceDevice, + const Theme::GradientColorType eType, + const bool bHasFocusBorder) const; + Bitmap CreateMarkedPreview( + const Size& rSize, + const Bitmap& rPreview, + const BitmapEx& rOverlay, + const OutputDevice* pReferenceDevice) const; +}; + +} } } // 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..815a9382b682 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewContact.hxx @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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; + + 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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..4040d31aa694 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsPageObjectViewObjectContact.hxx @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/inc/view/SlsResource.hrc b/sd/source/ui/slidesorter/inc/view/SlsResource.hrc new file mode 100644 index 000000000000..2b85a37d35dc --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsResource.hrc @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_ICONS_HRC +#define SD_SLIDESORTER_ICONS_HRC + +#include "glob.hrc" + +#define IMAGE_COMMAND1_LARGE 1 +#define IMAGE_COMMAND1_LARGE_HOVER 2 +#define IMAGE_COMMAND1_MEDIUM 3 +#define IMAGE_COMMAND1_MEDIUM_HOVER 4 +#define IMAGE_COMMAND1_SMALL 5 +#define IMAGE_COMMAND1_SMALL_HOVER 6 + +#define IMAGE_COMMAND1_LARGE_HC 7 +#define IMAGE_COMMAND1_LARGE_HOVER_HC 8 +#define IMAGE_COMMAND1_MEDIUM_HC 9 +#define IMAGE_COMMAND1_MEDIUM_HOVER_HC 10 +#define IMAGE_COMMAND1_SMALL_HC 11 +#define IMAGE_COMMAND1_SMALL_HOVER_HC 12 + + +#define IMAGE_COMMAND2_LARGE 20 +#define IMAGE_COMMAND2_LARGE_HOVER 21 +#define IMAGE_COMMAND2_MEDIUM 22 +#define IMAGE_COMMAND2_MEDIUM_HOVER 23 +#define IMAGE_COMMAND2_SMALL 24 +#define IMAGE_COMMAND2_SMALL_HOVER 25 + +#define IMAGE_COMMAND2_LARGE_HC 26 +#define IMAGE_COMMAND2_LARGE_HOVER_HC 27 +#define IMAGE_COMMAND2_MEDIUM_HC 28 +#define IMAGE_COMMAND2_MEDIUM_HOVER_HC 29 +#define IMAGE_COMMAND2_SMALL_HC 30 +#define IMAGE_COMMAND2_SMALL_HOVER_HC 31 + +#define IMAGE_COMMAND2B_LARGE 40 +#define IMAGE_COMMAND2B_LARGE_HOVER 41 +#define IMAGE_COMMAND2B_MEDIUM 42 +#define IMAGE_COMMAND2B_MEDIUM_HOVER 43 +#define IMAGE_COMMAND2B_SMALL 44 +#define IMAGE_COMMAND2B_SMALL_HOVER 45 + +#define IMAGE_COMMAND2B_LARGE_HC 46 +#define IMAGE_COMMAND2B_LARGE_HOVER_HC 47 +#define IMAGE_COMMAND2B_MEDIUM_HC 48 +#define IMAGE_COMMAND2B_MEDIUM_HOVER_HC 49 +#define IMAGE_COMMAND2B_SMALL_HC 50 +#define IMAGE_COMMAND2B_SMALL_HOVER_HC 51 + + +#define IMAGE_COMMAND3_LARGE 60 +#define IMAGE_COMMAND3_LARGE_HOVER 61 +#define IMAGE_COMMAND3_MEDIUM 62 +#define IMAGE_COMMAND3_MEDIUM_HOVER 63 +#define IMAGE_COMMAND3_SMALL 64 +#define IMAGE_COMMAND3_SMALL_HOVER 65 + +#define IMAGE_COMMAND3_LARGE_HC 66 +#define IMAGE_COMMAND3_LARGE_HOVER_HC 67 +#define IMAGE_COMMAND3_MEDIUM_HC 68 +#define IMAGE_COMMAND3_MEDIUM_HOVER_HC 69 +#define IMAGE_COMMAND3_SMALL_HC 70 +#define IMAGE_COMMAND3_SMALL_HOVER_HC 71 + +#define IMAGE_BUTTONBAR_LARGE 80 +#define IMAGE_BUTTONBAR_LARGE_HC 81 +#define IMAGE_BUTTONBAR_MEDIUM 82 +#define IMAGE_BUTTONBAR_MEDIUM_HC 83 +#define IMAGE_BUTTONBAR_SMALL 84 +#define IMAGE_BUTTONBAR_SMALL_HC 85 + +#define IMAGE_SHADOW 90 +#define IMAGE_INSERT_SHADOW 91 +#define IMAGE_HIDE_SLIDE_OVERLAY 92 +#define IMAGE_FOCUS_BORDER 93 + +#define STRING_DRAG_AND_DROP_PAGES 101 +#define STRING_DRAG_AND_DROP_SLIDES 102 + +#define STRING_COMMAND1 110 +#define STRING_COMMAND2_A 111 +#define STRING_COMMAND2_B 112 +#define STRING_COMMAND3 113 + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx b/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx new file mode 100644 index 000000000000..0781d8ea3519 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsTheme.hxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_THEME_HXX +#define SD_SLIDESORTER_VIEW_THEME_HXX + +#include "model/SlsVisualState.hxx" + +#include <vcl/bitmapex.hxx> +#include <vcl/font.hxx> +#include <vcl/gradient.hxx> +#include <tools/color.hxx> + +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> + + +namespace sd { namespace slidesorter { namespace controller { +class Properties; +} } } + +namespace sd { namespace slidesorter { namespace view { + + +/** Collection of colors and styles that are used to paint the slide sorter + view. +*/ +class Theme +{ +public: + Theme (const ::boost::shared_ptr<controller::Properties>& rpProperties); + + /** Call this method to update some colors as response to a change of + a system color change. + */ + void Update ( + const ::boost::shared_ptr<controller::Properties>& rpProperties); + + // BitmapEx GetInsertIndicatorIcon (void) const; + + enum FontType { + Font_PageNumber, + Font_PageCount, + Font_Button + }; + static ::boost::shared_ptr<Font> GetFont ( + const FontType eType, + const OutputDevice& rDevice); + + enum ColorType { + Color_Background, + Color_ButtonBackground, + Color_ButtonText, + Color_ButtonTextHover, + Color_PageNumberDefault, + Color_PageNumberHover, + Color_PageNumberHighContrast, + Color_PageNumberBrightBackground, + Color_PageNumberDarkBackground, + Color_Selection, + Color_PreviewBorder, + Color_PageCountFontColor, + _ColorType_Size_ + }; + ColorData GetColor (const ColorType eType); + void SetColor (const ColorType eType, const ColorData aColorData); + + enum GradientColorType { + Gradient_NormalPage, + Gradient_SelectedPage, + Gradient_SelectedAndFocusedPage, + Gradient_MouseOverPage, + Gradient_MouseOverSelectedAndFocusedPage, + Gradient_FocusedPage, + Gradient_ButtonBackground, + _GradientColorType_Size_ + }; + enum GradientColorClass { + Border1, + Border2, + Fill1, + Fill2, + Base + }; + ColorData GetGradientColor ( + const GradientColorType eType, + const GradientColorClass eClass); + sal_Int32 GetGradientOffset ( + const GradientColorType eType, + const GradientColorClass eClass); + void SetGradient ( + const GradientColorType eType, + const ColorData aBaseColor, + const sal_Int32 nSaturationOverride, + const sal_Int32 nBrightnessOverride, + const sal_Int32 nFillStartOffset, + const sal_Int32 nFillEndOffset, + const sal_Int32 nBorderStartOffset, + const sal_Int32 nBorderEndOffset); + sal_Int32 GetGradientSaturationOverride (const GradientColorType eType); + sal_Int32 GetGradientBrightnessOverride (const GradientColorType eType); + void SetGradientSaturationOverride (const GradientColorType eType, const sal_Int32 nValue); + void SetGradientBrightnessOverride (const GradientColorType eType, const sal_Int32 nValue); + + enum IconType + { + Icon_RawShadow, + Icon_RawInsertShadow, + Icon_HideSlideOverlay, + Icon_FocusBorder, + Icon_ButtonBarLarge, + Icon_ButtonBarMedium, + Icon_ButtonBarSmall, + Icon_Command1Large, + Icon_Command1LargeHover, + Icon_Command1Medium, + Icon_Command1MediumHover, + Icon_Command1Small, + Icon_Command1SmallHover, + Icon_Command2Large, + Icon_Command2LargeHover, + Icon_Command2Medium, + Icon_Command2MediumHover, + Icon_Command2Small, + Icon_Command2SmallHover, + Icon_Command2BLarge, + Icon_Command2BLargeHover, + Icon_Command2BMedium, + Icon_Command2BMediumHover, + Icon_Command2BSmall, + Icon_Command2BSmallHover, + Icon_Command3Large, + Icon_Command3LargeHover, + Icon_Command3Medium, + Icon_Command3MediumHover, + Icon_Command3Small, + Icon_Command3SmallHover, + _IconType_Size_ + }; + const BitmapEx& GetIcon (const IconType eType); + + enum IntegerValueType + { + Integer_ButtonCornerRadius, + Integer_ButtonMaxAlpha, + Integer_ButtonBarMaxAlpha, + Integer_ButtonPaintType, + Integer_ButtonBorder, + Integer_ButtonGap, + Integer_ButtonFadeInDelay, + Integer_ButtonFadeInDuration, + Integer_ButtonFadeOutDelay, + Integer_ButtonFadeOutDuration, + Integer_ToolTipDelay, + Integer_FocusIndicatorWidth, + _IntegerValueType_Size_ + }; + sal_Int32 GetIntegerValue (const IntegerValueType eType) const; + void SetIntegerValue (const IntegerValueType eType, const sal_Int32 nValue); + + enum StringType + { + String_Unhide, + String_DragAndDropPages, + String_DragAndDropSlides, + String_Command1, + String_Command2, + String_Command2B, + String_Command3, + _StringType_Size_ + }; + ::rtl::OUString GetString (const StringType eType) const; + +private: + bool mbIsHighContrastMode; + class GradientDescriptor + { + public: + ColorData maBaseColor; + + sal_Int32 mnSaturationOverride; + sal_Int32 mnBrightnessOverride; + + ColorData maFillColor1; + ColorData maFillColor2; + ColorData maBorderColor1; + ColorData maBorderColor2; + + sal_Int32 mnFillOffset1; + sal_Int32 mnFillOffset2; + sal_Int32 mnBorderOffset1; + sal_Int32 mnBorderOffset2; + }; + ColorData maBackgroundColor; + ColorData maPageBackgroundColor; + ::std::vector<GradientDescriptor> maGradients; + ::std::vector<BitmapEx> maIcons; + ::std::vector<ColorData> maColor; + ::std::vector<sal_Int32> maIntegerValues; + ::std::vector<rtl::OUString> maStrings; + + GradientDescriptor& GetGradient (const GradientColorType eType); + /** Guarded initialization of the specified icon in the maIcons + container. Call only while a LocalResource object is active. + */ + void InitializeIcon (const IconType eType, sal_uInt16 nResourceId); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx b/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx new file mode 100644 index 000000000000..48a4c7c3d272 --- /dev/null +++ b/sd/source/ui/slidesorter/inc/view/SlsToolTip.hxx @@ -0,0 +1,97 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_TOOL_TIP_HXX +#define SD_SLIDESORTER_VIEW_TOOL_TIP_HXX + +#include "SlideSorter.hxx" +#include "model/SlsSharedPageDescriptor.hxx" + +namespace sd { namespace slidesorter { namespace view { + +/** Manage the display of tool tips. The tool tip text changes when the + mouse is moved from slide to slide or from button to button. + After the mouse enters a slide the first display of the tool tip is + delayed for a short time in order to not draw attention from the slide + or its button bar. +*/ +class ToolTip +{ +public: + ToolTip (SlideSorter& rSlideSorter); + ~ToolTip (void); + + /** Set a new page. This modifies the default help text. After a page + change a timer is started to delay the display of the tool tip for + the new page. + @param rpPage + When this is empty then the tool tip is hidden. + */ + void SetPage (const model::SharedPageDescriptor& rpPage); + + /** Set and show the default help text. + */ + void ShowDefaultHelpText (const ::rtl::OUString& rsHelpText); + + /** Show a previously set default help text. + */ + void ShowDefaultHelpText (void); + + /** Show a temporary help text. + */ + void ShowHelpText (const ::rtl::OUString& rsHelpText); + + /** Hide the tool tip. + @return + Returns whether the tool tip was visible at the time this method + was called. + */ + bool Hide (void); + +private: + SlideSorter& mrSlideSorter; + model::SharedPageDescriptor mpDescriptor; + ::rtl::OUString msDefaultHelpText; + ::rtl::OUString msCurrentHelpText; + sal_uLong mnHelpWindowHandle; + Timer maTimer; + + /** Request to show the tool tip. + @param bForce + When <TRUE/> then the tool tip is show right away. Otherwise it + is shown after a short delay. + */ + void Show (const bool bForce); + void DoShow (void); + + DECL_LINK(DelayTrigger, void*); +}; + + +} } } // 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..c294bf05ffa0 --- /dev/null +++ b/sd/source/ui/slidesorter/makefile.mk @@ -0,0 +1,58 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +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..57c887d6f02c --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlideSorterModel.cxx @@ -0,0 +1,740 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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/SlsProperties.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsSlotManager.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 "DrawDocShell.hxx" +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "FrameView.hxx" + +#include <tools/diagnose_ex.h> + +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; + }; + + bool PrintModel (const SlideSorterModel& rModel) + { + for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if (pDescriptor) + { + OSL_TRACE("%d %d %d %d %x", + nIndex, + pDescriptor->GetPageIndex(), + pDescriptor->GetVisualState().mnPageId, + FromCoreIndex(pDescriptor->GetPage()->GetPageNum()), + pDescriptor->GetPage()); + } + else + { + OSL_TRACE("%d", nIndex); + } + } + + return true; + } + bool CheckModel (const SlideSorterModel& rModel) + { + for (sal_Int32 nIndex=0,nCount=rModel.GetPageCount(); nIndex<nCount; ++nIndex) + { + SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + { + PrintModel(rModel); + OSL_ASSERT(pDescriptor); + return false; + } + if (nIndex != pDescriptor->GetPageIndex()) + { + PrintModel(rModel); + OSL_ASSERT(nIndex == pDescriptor->GetPageIndex()); + return false; + } + if (nIndex != pDescriptor->GetVisualState().mnPageId) + { + PrintModel(rModel); + OSL_ASSERT(nIndex == pDescriptor->GetVisualState().mnPageId); + return false; + } + } + + return true; + } +} + + + + +SlideSorterModel::SlideSorterModel (SlideSorter& rSlideSorter) + : maMutex(), + mrSlideSorter(rSlideSorter), + mxSlides(), + mePageKind(PK_STANDARD), + meEditMode(EM_PAGE), + maPageDescriptors(0) +{ +} + + + + +SlideSorterModel::~SlideSorterModel (void) +{ + ClearDescriptorList (); +} + + + + +void SlideSorterModel::Init (void) +{ +} + + + + +void SlideSorterModel::Dispose (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; +} + + + + +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()) + { + SdPage* pPage = GetPage(nPageIndex); + pDescriptor.reset(new PageDescriptor ( + Reference<drawing::XDrawPage>(mxSlides->getByIndex(nPageIndex),UNO_QUERY), + pPage, + nPageIndex)); + 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(RTL_CONSTASCII_USTRINGPARAM("Number")))); + sal_Int16 nNumber (-1); + aNumber >>= nNumber; + nNumber -= 1; + SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false)); + if (pDescriptor.get() != NULL + && pDescriptor->GetXDrawPage() == rxSlide) + { + return nNumber; + } + } + catch (uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + + // 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; +} + + + + +sal_Int32 SlideSorterModel::GetIndex (const SdrPage* pPage) const +{ + if (pPage == NULL) + return -1; + + ::osl::MutexGuard aGuard (maMutex); + + // First try to guess the right index. + sal_Int16 nNumber ((pPage->GetPageNum()-1)/2); + SharedPageDescriptor pDescriptor (GetPageDescriptor(nNumber, false)); + if (pDescriptor.get() != NULL + && pDescriptor->GetPage() == pPage) + { + return nNumber; + } + + // 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) + { + 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->GetPage() == pPage) + return nIndex; + } + + return -1; +} + + + + +sal_uInt16 SlideSorterModel::GetCoreIndex (const sal_Int32 nIndex) const +{ + SharedPageDescriptor pDescriptor (GetPageDescriptor(nIndex)); + if (pDescriptor) + return pDescriptor->GetPage()->GetPageNum(); + else + return mxSlides->getCount()*2+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); + + // Check if document and this model really differ. + bool bIsUpToDate (true); + SdDrawDocument* pDocument = GetDocument(); + if (pDocument!=NULL && maPageDescriptors.size()==pDocument->GetSdPageCount(mePageKind)) + { + for (sal_Int32 nIndex=0,nCount=maPageDescriptors.size(); nIndex<nCount; ++nIndex) + { + if (maPageDescriptors[nIndex] + && maPageDescriptors[nIndex]->GetPage() + != GetPage(nIndex)) + { + OSL_TRACE("page %d differs\n", nIndex); + bIsUpToDate = false; + break; + } + } + } + else + { + bIsUpToDate = false; + OSL_TRACE("models differ"); + } + + if ( ! bIsUpToDate) + { + SynchronizeDocumentSelection(); // Try to make the current selection persistent. + ClearDescriptorList (); + AdaptSize(); + SynchronizeModelSelection(); + mrSlideSorter.GetController().GetPageSelector().CountSelectedPages(); + } + CheckModel(*this); +} + + + + +void SlideSorterModel::ClearDescriptorList (void) +{ + DescriptorContainer aDescriptors; + + { + ::osl::MutexGuard aGuard (maMutex); + aDescriptors.swap(maPageDescriptors); + } + + for (DescriptorContainer::iterator iDescriptor=aDescriptors.begin(), iEnd=aDescriptors.end(); + iDescriptor!=iEnd; + ++iDescriptor) + { + if (iDescriptor->get() != NULL) + { + if ( ! iDescriptor->unique()) + { + OSL_TRACE("SlideSorterModel::ClearDescriptorList: trying to delete page descriptor that is still used with count %d", iDescriptor->use_count()); + // No assertion here because that can hang the office when + // opening a dialog from here. + } + iDescriptor->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->HasState(PageDescriptor::ST_Selected)); + } +} + + + + +void SlideSorterModel::SynchronizeModelSelection (void) +{ + ::osl::MutexGuard aGuard (maMutex); + + PageEnumeration aAllPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aAllPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aAllPages.GetNextElement()); + pDescriptor->SetState(PageDescriptor::ST_Selected, pDescriptor->GetPage()->IsSelected()); + } +} + + + + +::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()->NotifyCurrentSlideChange(-1); + + mxSlides = rxSlides; + Resync(); + + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell != NULL) + { + SdPage* pPage = pViewShell->getCurrentPage(); + if (pPage != NULL) + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + pPage); + 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()->NotifyCurrentSlideChange( + pFrameView->GetSelectedPage()); + else + { + // No frame view. As a last resort use the first slide as + // current slide. + mrSlideSorter.GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + sal_Int32(0)); + } + } + } + + mrSlideSorter.GetController().GetSlotManager()->NotifyEditModeChange(); +} + + + + +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); +} + + + + +bool SlideSorterModel::IsReadOnly (void) const +{ + if (mrSlideSorter.GetViewShellBase() != NULL + && mrSlideSorter.GetViewShellBase()->GetDocShell()) + return mrSlideSorter.GetViewShellBase()->GetDocShell()->IsReadOnly(); + else + return true; +} + + + + +void SlideSorterModel::SaveCurrentSelection (void) +{ + PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + pDescriptor->SetState( + PageDescriptor::ST_WasSelected, + pDescriptor->HasState(PageDescriptor::ST_Selected)); + } +} + + + + +Region SlideSorterModel::RestoreSelection (void) +{ + Region aRepaintRegion; + PageEnumeration aPages (PageEnumerationProvider::CreateAllPagesEnumeration(*this)); + while (aPages.HasMoreElements()) + { + SharedPageDescriptor pDescriptor (aPages.GetNextElement()); + if (pDescriptor->SetState( + PageDescriptor::ST_Selected, + pDescriptor->HasState(PageDescriptor::ST_WasSelected))) + { + aRepaintRegion.Union(pDescriptor->GetBoundingBox()); + } + } + return aRepaintRegion; +} + + + + +bool SlideSorterModel::NotifyPageEvent (const SdrPage* pSdrPage) +{ + ::osl::MutexGuard aGuard (maMutex); + + SdPage* pPage = const_cast<SdPage*>(dynamic_cast<const SdPage*>(pSdrPage)); + if (pPage == NULL) + return false; + + // We are only interested in pages that are currently served by this + // model. + if (pPage->GetPageKind() != mePageKind) + return false; + if (pPage->IsMasterPage() != (meEditMode==EM_MASTERPAGE)) + return false; + + if (pPage->IsInserted()) + InsertSlide(pPage); + else + DeleteSlide(pPage); + CheckModel(*this); + + return true; +} + + + + +void SlideSorterModel::InsertSlide (SdPage* pPage) +{ + // Find the index at which to insert the given page. + sal_uInt16 nCoreIndex (pPage->GetPageNum()); + sal_Int32 nIndex (FromCoreIndex(nCoreIndex)); + if (pPage != GetPage(nIndex)) + return; + + // Check that the pages in the document before and after the given page + // are present in this model. + if (nIndex>0) + if (GetPage(nIndex-1) != GetPageDescriptor(nIndex-1)->GetPage()) + return; + if (size_t(nIndex)<maPageDescriptors.size()-1) + if (GetPage(nIndex+1) != GetPageDescriptor(nIndex)->GetPage()) + return; + + // Insert the given page at index nIndex + maPageDescriptors.insert( + maPageDescriptors.begin()+nIndex, + SharedPageDescriptor( + new PageDescriptor ( + Reference<drawing::XDrawPage>(mxSlides->getByIndex(nIndex),UNO_QUERY), + pPage, + nIndex))); + + // Update page indices. + UpdateIndices(nIndex+1); + OSL_TRACE("page inserted"); +} + + + + +void SlideSorterModel::DeleteSlide (const SdPage* pPage) +{ + const sal_Int32 nIndex (GetIndex(pPage)); + if (maPageDescriptors[nIndex]) + if (maPageDescriptors[nIndex]->GetPage() != pPage) + return; + + maPageDescriptors.erase(maPageDescriptors.begin()+nIndex); + UpdateIndices(nIndex); + OSL_TRACE("page removed"); +} + + + + +void SlideSorterModel::UpdateIndices (const sal_Int32 nFirstIndex) +{ + for (sal_Int32 nDescriptorIndex=0,nCount=maPageDescriptors.size(); + nDescriptorIndex<nCount; + ++nDescriptorIndex) + { + SharedPageDescriptor& rpDescriptor (maPageDescriptors[nDescriptorIndex]); + if (rpDescriptor) + { + if (nDescriptorIndex < nFirstIndex) + { + if (rpDescriptor->GetPageIndex()!=nDescriptorIndex) + { + OSL_ASSERT(rpDescriptor->GetPageIndex()==nDescriptorIndex); + } + } + else + { + rpDescriptor->SetPageIndex(nDescriptorIndex); + } + } + } +} + + + + +SdPage* SlideSorterModel::GetPage (const sal_Int32 nSdIndex) const +{ + SdDrawDocument* pModel = const_cast<SlideSorterModel*>(this)->GetDocument(); + if (pModel != NULL) + { + if (meEditMode == EM_PAGE) + return pModel->GetSdPage ((sal_uInt16)nSdIndex, mePageKind); + else + return pModel->GetMasterSdPage ((sal_uInt16)nSdIndex, mePageKind); + } + else + return NULL; +} + + +} } } // end of namespace ::sd::slidesorter::model + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx new file mode 100644 index 000000000000..bb1beb58f2ff --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsPageDescriptor.cxx @@ -0,0 +1,292 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "sdpage.hxx" +#include "drawdoc.hxx" + +#include <svx/svdopage.hxx> +#include <svx/svdpagv.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <svx/sdr/contact/viewobjectcontact.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) + : mpPage(pPage), + mxPage(rxPage), + mpMasterPage(NULL), + mnIndex(nIndex), + maBoundingBox(), + maVisualState(nIndex), + mbIsSelected(false), + mbWasSelected(false), + mbIsVisible(false), + mbIsFocused(false), + mbIsCurrent(false), + mbIsMouseOver(false) +{ + OSL_ASSERT(mpPage); + OSL_ASSERT(mpPage == SdPage::getImplementation(rxPage)); + if (mpPage!=NULL && mpPage->TRG_HasMasterPage()) + mpMasterPage = &mpPage->TRG_GetMasterPage(); +} + + + + +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; +} + + + + +void PageDescriptor::SetPageIndex (const sal_Int32 nNewIndex) +{ + mnIndex = nNewIndex; + maVisualState.mnPageId = nNewIndex; +} + + + + +bool PageDescriptor::UpdateMasterPage (void) +{ + const SdrPage* pMaster = NULL; + if (mpPage!=NULL && mpPage->TRG_HasMasterPage()) + pMaster = &mpPage->TRG_GetMasterPage(); + if (mpMasterPage != pMaster) + { + mpMasterPage = pMaster; + return true; + } + else + return false; +} + + + + +bool PageDescriptor::HasState (const State eState) const +{ + switch (eState) + { + case ST_Visible: + return mbIsVisible; + + case ST_Selected: + return mbIsSelected; + + case ST_WasSelected: + return mbWasSelected; + + case ST_Focused: + return mbIsFocused; + + case ST_MouseOver: + return mbIsMouseOver; + + case ST_Current: + return mbIsCurrent; + + case ST_Excluded: + return mpPage!=NULL && mpPage->IsExcluded(); + + default: + OSL_ASSERT(false); + return false; + } +} + + + + +bool PageDescriptor::SetState (const State eState, const bool bNewStateValue) +{ + bool bModified (false); + switch (eState) + { + case ST_Visible: + bModified = (bNewStateValue!=mbIsVisible); + if (bModified) + mbIsVisible = bNewStateValue; + break; + + case ST_Selected: + bModified = (bNewStateValue!=mbIsSelected); + if (bModified) + mbIsSelected = bNewStateValue; + break; + + case ST_WasSelected: + bModified = (bNewStateValue!=mbWasSelected); + if (bModified) + mbWasSelected = bNewStateValue; + break; + + case ST_Focused: + bModified = (bNewStateValue!=mbIsFocused); + if (bModified) + mbIsFocused = bNewStateValue; + break; + + case ST_MouseOver: + bModified = (bNewStateValue!=mbIsMouseOver); + if (bModified) + mbIsMouseOver = bNewStateValue; + break; + + case ST_Current: + bModified = (bNewStateValue!=mbIsCurrent); + if (bModified) + mbIsCurrent = bNewStateValue; + break; + + case ST_Excluded: + // This is a state of the page and has to be handled differently + // from the view-only states. + if (mpPage != NULL) + if (bNewStateValue != (mpPage->IsExcluded()==sal_True)) + { + mpPage->SetExcluded(bNewStateValue); + bModified = true; + } + break; + } + + if (bModified) + maVisualState.UpdateVisualState(*this); + return bModified; +} + + + + +VisualState& PageDescriptor::GetVisualState (void) +{ + return maVisualState; +} + + + + +bool PageDescriptor::GetCoreSelection (void) +{ + if (mpPage!=NULL && (mpPage->IsSelected()==sal_True) != mbIsSelected) + return SetState(ST_Selected, !mbIsSelected); + else + return false; +} + + + + +void PageDescriptor::SetCoreSelection (void) +{ + if (mpPage != NULL) + if (HasState(ST_Selected)) + mpPage->SetSelected(sal_True); + else + mpPage->SetSelected(sal_False); + else + { + OSL_ASSERT(mpPage!=NULL); + } +} + + + + +Rectangle PageDescriptor::GetBoundingBox (void) const +{ + Rectangle aBox (maBoundingBox); + const Point aOffset (maVisualState.GetLocationOffset()); + aBox.Move(aOffset.X(), aOffset.Y()); + return aBox; +} + + + + +Point PageDescriptor::GetLocation (const bool bIgnoreOffset) const +{ + if (bIgnoreOffset) + return maBoundingBox.TopLeft(); + else + return maBoundingBox.TopLeft() + maVisualState.GetLocationOffset(); +} + + + + +void PageDescriptor::SetBoundingBox (const Rectangle& rBoundingBox) +{ + maBoundingBox = rBoundingBox; +} + + + +} } } // end of namespace ::sd::slidesorter::model + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx b/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx new file mode 100644 index 000000000000..3eac80cbd5b0 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsPageEnumeration.cxx @@ -0,0 +1,286 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx new file mode 100644 index 000000000000..98240924a75c --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsPageEnumerationProvider.cxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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) const + { + (void)rpDescriptor; + return true; + } +}; + + + + + +class SelectedPagesPredicate +{ +public: + bool operator() (const SharedPageDescriptor& rpDescriptor) + { + return rpDescriptor->HasState(PageDescriptor::ST_Selected); + } +}; + + + + +class VisiblePagesPredicate +{ +public: + bool operator() (const SharedPageDescriptor& rpDescriptor) + { + return rpDescriptor->HasState(PageDescriptor::ST_Visible); + } +}; + +} + + + + +PageEnumeration PageEnumerationProvider::CreateAllPagesEnumeration ( + const SlideSorterModel& rModel) +{ + 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/model/SlsVisualState.cxx b/sd/source/ui/slidesorter/model/SlsVisualState.cxx new file mode 100644 index 000000000000..3dee5e914ab9 --- /dev/null +++ b/sd/source/ui/slidesorter/model/SlsVisualState.cxx @@ -0,0 +1,236 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "model/SlsVisualState.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "controller/SlsAnimator.hxx" + +namespace sd { namespace slidesorter { namespace model { + +VisualState::VisualState (const sal_Int32 nPageId) + : mnPageId(nPageId), + meCurrentVisualState(VS_None), + meOldVisualState(VS_None), + mnVisualStateBlend(1.0), + mnStateAnimationId(controller::Animator::NotAnAnimationId), + maLocationOffset(0,0), + mnLocationAnimationId(controller::Animator::NotAnAnimationId), + mnButtonAlpha(1.0), + mnButtonBarAlpha(1.0), + mnButtonAlphaAnimationId(controller::Animator::NotAnAnimationId) +{ +} + + + + +VisualState::~VisualState (void) +{ + if (mnStateAnimationId != controller::Animator::NotAnAnimationId + || mnLocationAnimationId != controller::Animator::NotAnAnimationId) + { + OSL_ASSERT(mnStateAnimationId == controller::Animator::NotAnAnimationId); + OSL_ASSERT(mnLocationAnimationId == controller::Animator::NotAnAnimationId); + } +} + + + + +VisualState::State VisualState::GetCurrentVisualState (void) const +{ + return meCurrentVisualState; +} + + + + +VisualState::State VisualState::GetOldVisualState (void) const +{ + return meOldVisualState; +} + + + + +void VisualState::SetVisualState (const State eState) +{ + meOldVisualState = meCurrentVisualState; + meCurrentVisualState = eState; + mnVisualStateBlend = 1.0; +} + + + + +double VisualState::GetVisualStateBlend (void) const +{ + return mnVisualStateBlend; +} + + + + +void VisualState::SetVisualStateBlend (const double nBlend) +{ + mnVisualStateBlend = nBlend; +} + + + + +void VisualState::UpdateVisualState (const PageDescriptor& rDescriptor) +{ + if (rDescriptor.HasState(PageDescriptor::ST_Excluded)) + SetVisualState(VS_Excluded); + else if (rDescriptor.HasState(PageDescriptor::ST_Current)) + SetVisualState(VS_Current); + else if (rDescriptor.HasState(PageDescriptor::ST_Focused)) + SetVisualState(VS_Focused); + else if (rDescriptor.HasState(PageDescriptor::ST_Selected)) + SetVisualState(VS_Selected); + else + SetVisualState(VS_None); + + SetMouseOverState(rDescriptor.HasState(PageDescriptor::ST_MouseOver)); +} + + + + +void VisualState::SetMouseOverState (const bool bIsMouseOver) +{ + mbOldMouseOverState = mbCurrentMouseOverState; + mbCurrentMouseOverState = bIsMouseOver; +} + + + + +sal_Int32 VisualState::GetStateAnimationId (void) const +{ + return mnStateAnimationId; +} + + + + +void VisualState::SetStateAnimationId (const sal_Int32 nAnimationId) +{ + mnStateAnimationId = nAnimationId; +} + + + + +Point VisualState::GetLocationOffset (void) const +{ + return maLocationOffset; +} + + + + +bool VisualState::SetLocationOffset (const Point& rOffset) +{ + if (maLocationOffset != rOffset) + { + maLocationOffset = rOffset; + return true; + } + else + return false; +} + + + + +sal_Int32 VisualState::GetLocationAnimationId (void) const +{ + return mnLocationAnimationId; +} + + + + +void VisualState::SetLocationAnimationId (const sal_Int32 nAnimationId) +{ + mnLocationAnimationId = nAnimationId; +} + + + + +double VisualState::GetButtonAlpha (void) const +{ + return mnButtonAlpha; +} + + + + +void VisualState::SetButtonAlpha (const double nAlpha) +{ + mnButtonAlpha = nAlpha; +} + + + + +double VisualState::GetButtonBarAlpha (void) const +{ + return mnButtonBarAlpha; +} + + + + +void VisualState::SetButtonBarAlpha (const double nAlpha) +{ + mnButtonBarAlpha = nAlpha; +} + + + + +sal_Int32 VisualState::GetButtonAlphaAnimationId (void) const +{ + return mnButtonAlphaAnimationId; +} + + + + +void VisualState::SetButtonAlphaAnimationId (const sal_Int32 nAnimationId) +{ + mnButtonAlphaAnimationId = nAnimationId; +} + + +} } } // 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 100755 index 000000000000..0347d05a8100 --- /dev/null +++ b/sd/source/ui/slidesorter/model/makefile.mk @@ -0,0 +1,57 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +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)$/SlsVisualState.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..0c75e7a047dc --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorter.cxx @@ -0,0 +1,703 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "controller/SlsProperties.hxx" +#include "controller/SlsAnimator.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsTheme.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), + mbOwnesContentWindow(false), + mpHorizontalScrollBar(rpHorizontalScrollBar), + mpVerticalScrollBar(rpVerticalScrollBar), + mpScrollBarBox(rpScrollBarBox), + mbLayoutPending(true), + mpProperties(new controller::Properties()), + mpTheme(new view::Theme(mpProperties)) +{ +} + + + + +SlideSorter::SlideSorter ( + ViewShellBase& rBase, + ViewShell* pViewShell, + ::Window& rParentWindow) + : mbIsValid(false), + mpSlideSorterController(), + mpSlideSorterModel(), + mpSlideSorterView(), + mxControllerWeak(), + mpViewShell(pViewShell), + mpViewShellBase(&rBase), + mpContentWindow(new ContentWindow(rParentWindow,*this )), + mbOwnesContentWindow(true), + mpHorizontalScrollBar(new ScrollBar(&rParentWindow,WinBits(WB_HSCROLL | WB_DRAG))), + mpVerticalScrollBar(new ScrollBar(&rParentWindow,WinBits(WB_VSCROLL | WB_DRAG))), + mpScrollBarBox(new ScrollBarBox(&rParentWindow)), + mbLayoutPending(true), + mpProperties(new controller::Properties()), + mpTheme(new view::Theme(mpProperties)) +{ +} + + + + +void SlideSorter::Init (void) +{ + if (mpViewShellBase != NULL) + mxControllerWeak = mpViewShellBase->GetController(); + + // Reinitialize colors in Properties with window specific values. + if (mpContentWindow) + { + mpProperties->SetBackgroundColor( + mpContentWindow->GetSettings().GetStyleSettings().GetWindowColor()); + mpProperties->SetTextColor( + mpContentWindow->GetSettings().GetStyleSettings().GetWindowTextColor()); + mpProperties->SetSelectionColor( + mpContentWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + mpProperties->SetHighlightColor( + mpContentWindow->GetSettings().GetStyleSettings().GetMenuHighlightColor()); + } + + CreateModelViewController (); + + SetupListeners (); + + // Initialize the window. + SharedSdWindow pContentWindow (GetContentWindow()); + if (pContentWindow) + { + ::Window* pParentWindow = pContentWindow->GetParent(); + if (pParentWindow != NULL) + pParentWindow->SetBackground(Wallpaper()); + pContentWindow->SetBackground(Wallpaper()); + pContentWindow->SetViewOrigin (Point(0,0)); + // We do our own scrolling while dragging a page selection. + pContentWindow->SetUseDropScroll (false); + // Change the winbits so that the active window accepts the focus. + pContentWindow->SetStyle ((pContentWindow->GetStyle() & ~WB_DIALOGCONTROL) | WB_TABSTOP); + pContentWindow->Hide(); + + // Set view pointer of base class. + SetupControls(pParentWindow); + + mbIsValid = true; + } +} + + + + +SlideSorter::~SlideSorter (void) +{ + mbIsValid = false; + + ReleaseListeners(); + + // Dispose model, view and controller to avoid calls between them when + // they are being destructed and one or two of them are already gone. + mpSlideSorterController->Dispose(); + mpSlideSorterView->Dispose(); + mpSlideSorterModel->Dispose(); + + // Reset the auto pointers explicitly to control the order of destruction. + mpSlideSorterController.reset(); + mpSlideSorterView.reset(); + mpSlideSorterModel.reset(); + + mpHorizontalScrollBar.reset(); + mpVerticalScrollBar.reset(); + mpScrollBarBox.reset(); + + if (mbOwnesContentWindow) + { + OSL_ASSERT(mpContentWindow.unique()); + } + else + { + // Assume that outside this class only the owner holds a reference + // to the content window. + OSL_ASSERT(mpContentWindow.use_count()==2); + } + 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()); +} + + + + +::SharedSdWindow SlideSorter::GetContentWindow (void) const +{ + return mpContentWindow; +} + + + + +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) +{ + SharedSdWindow pWindow (GetContentWindow()); + if (pWindow) + { + ::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(); + + SharedSdWindow pWindow (GetContentWindow()); + if (pWindow) + { + 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"); + + // Now that model, view, and controller are constructed, do the + // initialization that relies on all three being in place. + mpSlideSorterModel->Init(); + mpSlideSorterController->Init(); + mpSlideSorterView->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 + && GetContentWindow() + && GetContentWindow()->IsVisible()) + { + // Prevent untimely redraws while the view is not yet correctly + // resized. + view::SlideSorterView::DrawLock aLock (*this); + GetContentWindow()->EnablePaint (sal_False); + + mpSlideSorterController->Resize (Rectangle(aOrigin, rSize)); + + GetContentWindow()->EnablePaint (sal_True); + + mbLayoutPending = false; + } +} + + + + +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) +{ + // Stop all animations for they have been started for the old window. + mpSlideSorterController->GetAnimator()->RemoveAllAnimations(); + + 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. But because at that time the correct + // accessibility object can not be constructed we do that now.) + 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 + { + ContentWindow* pWindow = dynamic_cast<ContentWindow*>(GetContentWindow().get()); + if (pWindow != NULL) + pWindow->SetCurrentFunction(rpFunction); + } +} + + + + +::boost::shared_ptr<controller::Properties> SlideSorter::GetProperties (void) const +{ + OSL_ASSERT(mpProperties); + return mpProperties; +} + + + + +::boost::shared_ptr<view::Theme> SlideSorter::GetTheme (void) const +{ + OSL_ASSERT(mpTheme); + return mpTheme; +} + + + + +//===== 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.cxx b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.cxx new file mode 100644 index 000000000000..e78fa4218c74 --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.cxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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, + sal_uInt16 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 (sal_True); +} + + + + +SlideSorterChildWindow::~SlideSorterChildWindow (void) +{} + + +SFX_IMPL_DOCKINGWINDOW(SlideSorterChildWindow, SID_SLIDE_BROWSER) + +} } // end of namespace ::sd::slidesorter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.src b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.src new file mode 100644 index 000000000000..829b18d63a97 --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterChildWindow.src @@ -0,0 +1,52 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "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..de3affaa1f5d --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterService.cxx @@ -0,0 +1,646 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "view/SlsLayouter.hxx" +#include "DrawController.hxx" +#include <toolkit/helper/vclunohelper.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <osl/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::Layouter; + +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(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Draw.SlideSorter")); +} + + + + +Sequence<rtl::OUString> SAL_CALL SlideSorterService_getSupportedServiceNames (void) + throw (RuntimeException) +{ + static const ::rtl::OUString sServiceName( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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(RTL_CONSTASCII_USTRINGPARAM("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()->NotifyCurrentSlideChange( + 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->GetProperties()->IsHighlightCurrentSlide(); +} + + + + +void SAL_CALL SlideSorterService::setIsHighlightCurrentSlide (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + { + mpSlideSorter->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->GetProperties()->IsShowSelection(); +} + + + + +void SAL_CALL SlideSorterService::setIsShowSelection (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetProperties()->SetShowSelection(bValue); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsShowFocus (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetProperties()->IsShowFocus(); +} + + + + +void SAL_CALL SlideSorterService::setIsShowFocus (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetProperties()->SetShowFocus(bValue); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsCenterSelection (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetProperties()->IsCenterSelection(); +} + + + + +void SAL_CALL SlideSorterService::setIsCenterSelection (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetProperties()->SetCenterSelection(bValue); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsSuspendPreviewUpdatesDuringFullScreenPresentation (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return true; + else + return mpSlideSorter->GetProperties() + ->IsSuspendPreviewUpdatesDuringFullScreenPresentation(); +} + + + + +void SAL_CALL SlideSorterService::setIsSuspendPreviewUpdatesDuringFullScreenPresentation ( + sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->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() != Layouter::HORIZONTAL; +} + + + + +void SAL_CALL SlideSorterService::setIsOrientationVertical (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->GetView().SetOrientation(bValue + ? Layouter::GRID + : Layouter::HORIZONTAL); +} + + + + +sal_Bool SAL_CALL SlideSorterService::getIsSmoothScrolling (void) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() == NULL || ! mpSlideSorter->IsValid()) + return false; + else + return mpSlideSorter->GetProperties()->IsSmoothSelectionScrolling(); +} + + + + +void SAL_CALL SlideSorterService::setIsSmoothScrolling (sal_Bool bValue) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->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->GetProperties()->GetBackgroundColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setBackgroundColor (util::Color aBackgroundColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->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->GetProperties()->GetTextColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setTextColor (util::Color aTextColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->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->GetProperties()->GetSelectionColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setSelectionColor (util::Color aSelectionColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->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->GetProperties()->GetHighlightColor().GetColor()); +} + + + + +void SAL_CALL SlideSorterService::setHighlightColor (util::Color aHighlightColor) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->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->GetProperties()->IsUIReadOnly(); +} + + + + +void SAL_CALL SlideSorterService::setIsUIReadOnly (sal_Bool bIsUIReadOnly) + throw (RuntimeException) +{ + ThrowIfDisposed(); + if (mpSlideSorter.get() != NULL && mpSlideSorter->IsValid()) + mpSlideSorter->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::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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/shell/SlideSorterService.hxx b/sd/source/ui/slidesorter/shell/SlideSorterService.hxx new file mode 100644 index 000000000000..12f6d629266c --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterService.hxx @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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); + + /** 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx new file mode 100644 index 000000000000..7719008b3fe2 --- /dev/null +++ b/sd/source/ui/slidesorter/shell/SlideSorterViewShell.cxx @@ -0,0 +1,823 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "controller/SlsSelectionFunction.hxx" +#include "controller/SlsProperties.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, + const bool bIsCenterPane) +{ + (void)bIsCenterPane; + + ::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(), + mbIsArrangeGUIElementsPending(true) +{ + 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; + OSL_FAIL("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.) + SharedSdWindow pWindow (mpSlideSorter->GetContentWindow()); + if (pWindow) + { + 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) +{ + // 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 || mpSlideSorter.get() == NULL) + return NULL; + + OSL_ASSERT(mpSlideSorter.get()!=NULL); + + ::accessibility::AccessibleSlideSorterView *pAccessibleView = + new ::accessibility::AccessibleSlideSorterView( + *mpSlideSorter.get(), + pWindow->GetAccessibleParentWindow()->GetAccessible(), + pWindow); + + ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> xRet(pAccessibleView); + + pAccessibleView->Init(); + + return xRet; +} + + + + +SlideSorter& SlideSorterViewShell::GetSlideSorter (void) const +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + return *mpSlideSorter; +} + + + + +bool SlideSorterViewShell::RelocateToParentWindow (::Window* pParentWindow) +{ + OSL_ASSERT(mpSlideSorter); + if ( ! mpSlideSorter) + return false; + + if (pParentWindow == NULL) + WriteFrameViewData(); + const bool bSuccess (mpSlideSorter->RelocateToWindow(pParentWindow)); + if (pParentWindow != NULL) + ReadFrameViewData(mpFrameView); + + return bSuccess; +} + + + + +::svl::IUndoManager* 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(); + } +} + + + + +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(); + } + + if (pCurrentPage == NULL) + { + + } + + 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::Paint ( + const Rectangle& rBBox, + ::sd::Window* pWindow) +{ + SetActiveWindow (pWindow); + OSL_ASSERT(mpSlideSorter); + if (mpSlideSorter) + mpSlideSorter->GetController().Paint(rBBox,pWindow); +} + + + + +void SlideSorterViewShell::ArrangeGUIElements (void) +{ + if (IsActive()) + { + OSL_ASSERT(mpSlideSorter.get()!=NULL); + mpSlideSorter->ArrangeGUIElements(maViewPos, maViewSize); + mbIsArrangeGUIElementsPending = false; + } + else + mbIsArrangeGUIElementsPending = true; +} + + + + +void SlideSorterViewShell::Activate (sal_Bool bIsMDIActivate) +{ + ViewShell::Activate(bIsMDIActivate); + if (mbIsArrangeGUIElementsPending) + ArrangeGUIElements(); +} + + + + +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()); + + sal_uInt16 nSlidesPerRow (pFrameView->GetSlidesPerRow()); + if (nSlidesPerRow > 0 + && rView.GetOrientation() == view::Layouter::GRID + && IsMainViewShell()) + { + rView.GetLayouter().SetColumnCount(nSlidesPerRow,nSlidesPerRow); + } + if (IsMainViewShell()) + mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + mpFrameView->GetSelectedPage()); + mpSlideSorter->GetController().Rearrange(true); + + // DrawMode for 'main' window + if (GetActiveWindow()->GetDrawMode() != pFrameView->GetDrawMode() ) + GetActiveWindow()->SetDrawMode( pFrameView->GetDrawMode() ); + } + + // When this slide sorter is not displayed in the main window then we do + // not share the same frame view and have to find other ways to acquire + // certain values. + if ( ! IsMainViewShell()) + { + ::boost::shared_ptr<ViewShell> pMainViewShell = GetViewShellBase().GetMainViewShell(); + if (pMainViewShell.get() != NULL) + mpSlideSorter->GetController().GetCurrentSlideManager()->NotifyCurrentSlideChange( + pMainViewShell->getCurrentPage()); + } +} + + + + +void SlideSorterViewShell::WriteFrameViewData (void) +{ + OSL_ASSERT(mpSlideSorter.get()!=NULL); + if (mpFrameView != NULL) + { + view::SlideSorterView& rView (mpSlideSorter->GetView()); + mpFrameView->SetSlidesPerRow((sal_uInt16)rView.GetLayouter().GetColumnCount()); + + // DrawMode for 'main' window + if( mpFrameView->GetDrawMode() != GetActiveWindow()->GetDrawMode() ) + mpFrameView->SetDrawMode( GetActiveWindow()->GetDrawMode() ); + + SdPage* pActualPage = GetActualPage(); + if (pActualPage != NULL) + { + if (IsMainViewShell()) + mpFrameView->SetSelectedPage((pActualPage->GetPageNum()- 1) / 2); + // else + // The slide sorter is not expected to switch the current page + // other then by double clicks. That is handled seperatly. + } + 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((sal_uInt16)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().GetLayouter().GetPageObjectSize()); + + 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); + + 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, + sal_uInt16 nPage, + sal_uInt16 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, + sal_uInt16 nPage, + sal_uInt16 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/shell/makefile.mk b/sd/source/ui/slidesorter/shell/makefile.mk new file mode 100755 index 000000000000..94209c34dc2b --- /dev/null +++ b/sd/source/ui/slidesorter/shell/makefile.mk @@ -0,0 +1,55 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +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..8bbe698205a6 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlideSorterView.cxx @@ -0,0 +1,1135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 "SlsLayeredDevice.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsPageObjectPainter.hxx" +#include "view/SlsILayerPainter.hxx" +#include "view/SlsButtonBar.hxx" +#include "view/SlsToolTip.hxx" +#include "controller/SlideSorterController.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 "taskpane/SlideSorterCacheDisplay.hxx" +#include "DrawDocShell.hxx" +#include "PaneDockingWindow.hxx" + +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "Window.hxx" +#include "sdresid.hxx" +#include "glob.hrc" + +#include <svl/itempool.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdopage.hxx> +#include <svx/xlndsit.hxx> +#include <svx/xlnclit.hxx> +#include <vcl/svapp.hxx> +#include <vcl/scrbar.hxx> +#include <tools/poly.hxx> +#include <vcl/lineinfo.hxx> +#include <algorithm> +#include <svx/sdrpagewindow.hxx> +#include <svl/itempool.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <canvas/elapsedtime.hxx> + +//#define DEBUG_TIMING +#include <svl/itempool.hxx> +#ifdef DEBUG_TIMING +#include <vector> +#endif +#include <boost/foreach.hpp> + + +using namespace std; +using namespace ::sd::slidesorter::model; +using namespace ::drawinglayer::primitive2d; + + +namespace sd { namespace slidesorter { namespace view { + +namespace { + /** Wrapper around the SlideSorterView that supports the IPainter + interface and that allows the LayeredDevice to hold the + SlideSorterView (held as scoped_ptr by the SlideSorter) as + shared_ptr. + */ + class Painter : public ILayerPainter + { + public: + Painter (SlideSorterView& rView) : mrView(rView) {} + virtual ~Painter (void) {} + + virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea) + { + mrView.Paint(rDevice,rRepaintArea); + } + + virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {} + + private: + SlideSorterView& mrView; + }; +} + + + +class BackgroundPainter + : public ILayerPainter, + public ::boost::noncopyable +{ +public: + BackgroundPainter (const Color aBackgroundColor) : maBackgroundColor(aBackgroundColor) {} + virtual ~BackgroundPainter (void) {} + + virtual void Paint (OutputDevice& rDevice, const Rectangle& rRepaintArea) + { + rDevice.SetFillColor(maBackgroundColor); + rDevice.SetLineColor(); + rDevice.DrawRect(rRepaintArea); + } + + virtual void SetLayerInvalidator (const SharedILayerInvalidator&) {} + + void SetColor (const Color aColor) { maBackgroundColor = aColor; } + +private: + Color maBackgroundColor; +}; + + + +TYPEINIT1(SlideSorterView, ::sd::View); + +SlideSorterView::SlideSorterView (SlideSorter& rSlideSorter) + : ::sd::View ( + rSlideSorter.GetModel().GetDocument(), + rSlideSorter.GetContentWindow().get(), + rSlideSorter.GetViewShell()), + mrSlideSorter(rSlideSorter), + mrModel(rSlideSorter.GetModel()), + mbIsDisposed(false), + mpLayouter (new Layouter(rSlideSorter.GetContentWindow(), rSlideSorter.GetTheme())), + mbPageObjectVisibilitiesValid (false), + mpPreviewCache(), + mpLayeredDevice(new LayeredDevice(rSlideSorter.GetContentWindow())), + maVisiblePageRange(-1,-1), + mbModelChangedWhileModifyEnabled(true), + maPreviewSize(0,0), + mbPreciousFlagUpdatePending(true), + meOrientation(Layouter::GRID), + mpProperties(rSlideSorter.GetProperties()), + mpPageUnderMouse(), + mnButtonUnderMouse(-1), + mpPageObjectPainter(), + mpSelectionPainter(), + mpBackgroundPainter( + new BackgroundPainter(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background))), + mpButtonBar(new ButtonBar(mrSlideSorter)), + mpToolTip(new ToolTip(mrSlideSorter)), + mbIsRearrangePending(true), + maVisibilityChangeListeners() +{ + // Hide the page that contains the page objects. + SetPageVisible (sal_False); + + + // Register the background painter on level 1 to avoid the creation of a + // background buffer. + mpLayeredDevice->RegisterPainter(mpBackgroundPainter, 1); + + // Wrap a shared_ptr-held-wrapper around this view and register it as + // painter at the layered device. There is no explicit destruction: in + // the SlideSorterView destructor the layered device is destroyed and + // with it the only reference to the wrapper which therefore is also + // destroyed. + SharedILayerPainter pPainter (new Painter(*this)); + + // The painter is placed on level 1 to avoid buffering. This should be + // a little faster during animations because the previews are painted + // directly into the window, not via the buffer. + mpLayeredDevice->RegisterPainter(pPainter, 1); +} + + + + +SlideSorterView::~SlideSorterView (void) +{ + if ( ! mbIsDisposed) + { + OSL_ASSERT(mbIsDisposed); + Dispose(); + } +} + + + + +void SlideSorterView::Init (void) +{ + HandleModelChange(); +} + + + + +void SlideSorterView::Dispose (void) +{ + mpSelectionPainter.reset(); + + mpLayeredDevice->Dispose(); + mpPreviewCache.reset(); + + SetPageUnderMouse(SharedPageDescriptor(),false); + + // 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) + + OSL_ASSERT(mpLayeredDevice.unique()); + mpLayeredDevice.reset(); + + mbIsDisposed = true; +} + + + + +sal_Int32 SlideSorterView::GetPageIndexAtPoint (const Point& rWindowPosition) const +{ + sal_Int32 nIndex (-1); + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + nIndex = mpLayouter->GetIndexAtPoint(pWindow->PixelToLogic(rWindowPosition), false, false); + + // Clip the page index against the page count. + if (nIndex >= mrModel.GetPageCount()) + nIndex = -1; + } + + return nIndex; +} + + + + +Layouter& SlideSorterView::GetLayouter (void) +{ + return *mpLayouter.get(); +} + + + + +void SlideSorterView::ModelHasChanged (void) +{ + // Ignore this call. Rely on hints sent by the model to get informed of + // model changes. +} + + + + +void SlideSorterView::LocalModelHasChanged(void) +{ + mbModelChangedWhileModifyEnabled = false; + + // First call our base class. + View::ModelHasChanged (); +} + + + + +void SlideSorterView::PreModelChange (void) +{ + // Reset the slide under the mouse. It will be re-set in PostModelChange(). + SetPageUnderMouse(SharedPageDescriptor()); +} + + + + +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)); + + // The new page objects have to be scaled and positioned. + RequestRearrange(); + RequestRepaint(); +} + + + + +/** 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) +{ + // 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); + + RequestRepaint(); +} + + + + +void SlideSorterView::HandleDataChangeEvent (void) +{ + GetPageObjectPainter()->SetTheme(mrSlideSorter.GetTheme()); + + // Update the color used by the background painter. + ::boost::shared_ptr<BackgroundPainter> pPainter ( + ::boost::dynamic_pointer_cast<BackgroundPainter>(mpBackgroundPainter)); + if (pPainter) + pPainter->SetColor(mrSlideSorter.GetTheme()->GetColor(Theme::Color_Background)); + + if (mpButtonBar) + mpButtonBar->HandleDataChangeEvent(); + + RequestRepaint(); +} + + + + +void SlideSorterView::Resize (void) +{ + UpdateOrientation(); + + mpLayeredDevice->Resize(); + RequestRearrange(); +} + + + + +void SlideSorterView::RequestRearrange (void) +{ + mbIsRearrangePending = true; + Rearrange(); +} + + + + +void SlideSorterView::Rearrange (void) +{ + if ( ! mbIsRearrangePending) + return; + if (mrModel.GetPageCount() <= 0) + return; + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if ( ! pWindow) + return; + const Size aWindowSize (pWindow->GetSizePixel()); + if (aWindowSize.Width()<=0 || aWindowSize.Height()<=0) + return; + + const bool bRearrangeSuccess ( + mpLayouter->Rearrange ( + meOrientation, + aWindowSize, + mrModel.GetPageDescriptor(0)->GetPage()->GetSize(), + mrModel.GetPageCount())); + if (bRearrangeSuccess) + { + mbIsRearrangePending = false; + Layout(); + UpdatePageUnderMouse(false); + // RequestRepaint(); + } +} + + + + +void SlideSorterView::UpdateOrientation (void) +{ + // The layout of slides depends on whether the slide sorter is + // displayed in the center or the side pane. + if (mrSlideSorter.GetViewShell()->IsMainViewShell()) + SetOrientation(Layouter::GRID); + else + { + // Get access to the docking window. + ::Window* pWindow = mrSlideSorter.GetContentWindow().get(); + PaneDockingWindow* pDockingWindow = NULL; + while (pWindow!=NULL && pDockingWindow==NULL) + { + pDockingWindow = dynamic_cast<PaneDockingWindow*>(pWindow); + pWindow = pWindow->GetParent(); + } + + if (pDockingWindow != NULL) + { + const long nScrollBarSize ( + Application::GetSettings().GetStyleSettings().GetScrollBarSize()); + switch (pDockingWindow->GetOrientation()) + { + case PaneDockingWindow::HorizontalOrientation: + if (SetOrientation(Layouter::HORIZONTAL)) + { + const Range aRange (mpLayouter->GetValidVerticalSizeRange()); + pDockingWindow->SetValidSizeRange(Range( + aRange.Min() + nScrollBarSize, + aRange.Max() + nScrollBarSize)); + } + break; + + case PaneDockingWindow::VerticalOrientation: + if (SetOrientation(Layouter::VERTICAL)) + { + const Range aRange (mpLayouter->GetValidHorizontalSizeRange()); + pDockingWindow->SetValidSizeRange(Range( + aRange.Min() + nScrollBarSize, + aRange.Max() + nScrollBarSize)); + } + break; + + case PaneDockingWindow::UnknownOrientation: + if (SetOrientation(Layouter::GRID)) + { + const sal_Int32 nAdditionalSize (10); + pDockingWindow->SetMinOutputSizePixel(Size( + mpLayouter->GetValidHorizontalSizeRange().Min() + + nScrollBarSize + + nAdditionalSize, + mpLayouter->GetValidVerticalSizeRange().Min() + + nScrollBarSize + + nAdditionalSize)); + } + return; + } + } + else + { + // We are not placed in a docking window. One possible reason + // is that the slide sorter is temporarily into a cache and was + // reparented to a non-docking window. + SetOrientation(Layouter::GRID); + } + } +} + + + + +void SlideSorterView::Layout () +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + // Set the model area, i.e. the smallest rectangle that includes all + // page objects. + const Rectangle aViewBox (mpLayouter->GetTotalBoundingBox()); + pWindow->SetViewOrigin (aViewBox.TopLeft()); + pWindow->SetViewSize (aViewBox.GetSize()); + + ::boost::shared_ptr<PageObjectLayouter> pPageObjectLayouter( + mpLayouter->GetPageObjectLayouter()); + if (pPageObjectLayouter) + { + const Size aNewPreviewSize (mpLayouter->GetPageObjectLayouter()->GetSize( + PageObjectLayouter::Preview, + PageObjectLayouter::WindowCoordinateSystem)); + if (maPreviewSize != aNewPreviewSize && GetPreviewCache()) + { + mpPreviewCache->ChangeSize(aNewPreviewSize, true); + maPreviewSize = aNewPreviewSize; + } + } + + // Iterate over all page objects and place them relative to the + // containing page. + model::PageEnumeration aPageEnumeration ( + model::PageEnumerationProvider::CreateAllPagesEnumeration(mrModel)); + while (aPageEnumeration.HasMoreElements()) + { + model::SharedPageDescriptor pDescriptor (aPageEnumeration.GetNextElement()); + pDescriptor->SetBoundingBox(mpLayouter->GetPageObjectBox(pDescriptor->GetPageIndex())); + } + + GetPageObjectPainter()->NotifyResize(); + } + + InvalidatePageObjectVisibilities (); +} + + + + +void SlideSorterView::InvalidatePageObjectVisibilities (void) +{ + mbPageObjectVisibilitiesValid = false; +} + + + + +void SlideSorterView::DeterminePageObjectVisibilities (void) +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + // Set this flag to true here so that an invalidate during the + // visibility calculation can correctly invalidate it again. + mbPageObjectVisibilitiesValid = true; + + Rectangle aViewArea (pWindow->PixelToLogic(Rectangle(Point(0,0),pWindow->GetSizePixel()))); + const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(aViewArea)); + const Range aUnion( + ::std::min(maVisiblePageRange.Min(), aRange.Min()), + ::std::max(maVisiblePageRange.Max(), aRange.Max())); + + // For page objects that just dropped off the visible area we + // decrease the priority of pending requests for preview bitmaps. + if (maVisiblePageRange != aRange) + mbPreciousFlagUpdatePending |= true; + + model::SharedPageDescriptor pDescriptor; + for (int nIndex=aUnion.Min(); nIndex<=aUnion.Max(); nIndex++) + { + pDescriptor = mrModel.GetPageDescriptor(nIndex); + if (pDescriptor.get() != NULL) + SetState( + pDescriptor, + PageDescriptor::ST_Visible, + aRange.IsInside(nIndex)); + } + + // Broadcast a change of the set of visible page objects. + if (maVisiblePageRange != aRange) + { + maVisiblePageRange = aRange; + + // Tell the listeners that the visibility of some objects has + // changed. + ::std::vector<Link>& aChangeListeners (maVisibilityChangeListeners); + for (::std::vector<Link>::const_iterator + iLink(aChangeListeners.begin()), + iEnd(aChangeListeners.end()); + iLink!=iEnd; + ++iLink) + { + iLink->Call(NULL); + } + } + + + // Restore the mouse over state. + UpdatePageUnderMouse(true); + } +} + + + + +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(), + maVisiblePageRange.IsInside(nIndex)); + SSCD_SET_VISIBILITY(mrModel.GetDocument(), nIndex, + maVisiblePageRange.IsInside(nIndex)); + } + 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; + } + } + } +} + + + + +bool SlideSorterView::SetOrientation (const Layouter::Orientation eOrientation) +{ + if (meOrientation != eOrientation) + { + meOrientation = eOrientation; + return true; + } + else + return false; +} + + + + +Layouter::Orientation SlideSorterView::GetOrientation (void) const +{ + return meOrientation; +} + + + + +void SlideSorterView::RequestRepaint (void) +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers( + Rectangle( + pWindow->PixelToLogic(Point(0,0)), + pWindow->PixelToLogic(pWindow->GetSizePixel()))); + pWindow->Invalidate(); + } +} + + + + +void SlideSorterView::RequestRepaint (const model::SharedPageDescriptor& rpDescriptor) +{ + if (rpDescriptor) + RequestRepaint(rpDescriptor->GetBoundingBox()); +} + + + + +void SlideSorterView::RequestRepaint (const Rectangle& rRepaintBox) +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers(rRepaintBox); + pWindow->Invalidate(rRepaintBox); + } +} + + + +void SlideSorterView::RequestRepaint (const Region& rRepaintRegion) +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + mpLayeredDevice->InvalidateAllLayers(rRepaintRegion); + pWindow->Invalidate(rRepaintRegion); + } +} + + + + +Rectangle SlideSorterView::GetModelArea (void) +{ + return mpLayouter->GetTotalBoundingBox(); +} + + +#ifdef DEBUG_TIMING +static ::canvas::tools::ElapsedTime gaTimer; +static const size_t gFrameTimeCount (10); +static size_t gFrameTimeIndex (0); +static ::std::vector<double> gFrameTimes (gFrameTimeCount, 0); +static double gFrameTimeSum (0); +static const Rectangle gFrameTimeBox (10,10,150,20); +static double gnLastFrameStart = 0; +#endif + +void SlideSorterView::CompleteRedraw ( + OutputDevice* pDevice, + const Region& rPaintArea, + sdr::contact::ViewObjectContactRedirector* pRedirector) +{ + (void)pRedirector; +#ifdef DEBUG_TIMING + const double nStartTime (gaTimer.getElapsedTime()); + OSL_TRACE("SlideSorterView::CompleteRedraw start at %f, %s", + nStartTime, + mnLockRedrawSmph ? "locked" : ""); +#endif + + if (pDevice == NULL || pDevice!=mrSlideSorter.GetContentWindow().get()) + return; + + // The parent implementation of CompleteRedraw is called only when + // painting is locked. We do all the painting ourself. When painting + // is locked the parent implementation keeps track of the repaint + // requests and later, when painting is unlocked, calls CompleteRedraw + // for all missed repaints. + + if (mnLockRedrawSmph == 0) + { + mrSlideSorter.GetContentWindow()->IncrementLockCount(); + if (mpLayeredDevice->HandleMapModeChange()) + DeterminePageObjectVisibilities(); + mpLayeredDevice->Repaint(rPaintArea); + mrSlideSorter.GetContentWindow()->DecrementLockCount(); + } + else + { + maRedrawRegion.Union(rPaintArea); + } + +#ifdef DEBUG_TIMING + const double nEndTime (gaTimer.getElapsedTime()); + OSL_TRACE("SlideSorterView::CompleteRedraw end at %f after %fms", nEndTime, (nEndTime-nStartTime)*1000); + gFrameTimeSum -= gFrameTimes[gFrameTimeIndex]; + gFrameTimes[gFrameTimeIndex] = nStartTime - gnLastFrameStart; + gnLastFrameStart = nStartTime; + gFrameTimeSum += gFrameTimes[gFrameTimeIndex]; + gFrameTimeIndex = (gFrameTimeIndex+1) % gFrameTimeCount; + + + mrSlideSorter.GetContentWindow()->SetFillColor(COL_BLUE); + mrSlideSorter.GetContentWindow()->DrawRect(gFrameTimeBox); + mrSlideSorter.GetContentWindow()->SetTextColor(COL_WHITE); + mrSlideSorter.GetContentWindow()->DrawText( + gFrameTimeBox, + ::rtl::OUString::valueOf(1 / (gFrameTimeSum / gFrameTimeCount)), + TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER); + // mrSlideSorter.GetContentWindow()->Invalidate(gFrameTimeBox); +#endif +} + + + + +void SlideSorterView::Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea) +{ + if ( ! mpPageObjectPainter) + if ( ! GetPageObjectPainter()) + return; + + // Update the page visibilities when they have been invalidated. + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + + if (mbPreciousFlagUpdatePending) + UpdatePreciousFlags(); + + if (mbIsRearrangePending) + Rearrange(); + + // Paint all page objects that are fully or partially inside the + // repaint region. + const Range aRange (mpLayouter->GetRangeOfVisiblePageObjects(rRepaintArea)); + for (sal_Int32 nIndex=aRange.Min(); nIndex<=aRange.Max(); ++nIndex) + { + model::SharedPageDescriptor pDescriptor (mrModel.GetPageDescriptor(nIndex)); + if (!pDescriptor || ! pDescriptor->HasState(PageDescriptor::ST_Visible)) + continue; + + mpPageObjectPainter->PaintPageObject(rDevice, pDescriptor); + } +} + + + + +void SlideSorterView::ConfigurationChanged ( + utl::ConfigurationBroadcaster* pBroadcaster, + sal_uInt32 nHint) +{ + // Some changes of the configuration (some of the colors for example) + // may affect the previews. Throw away the old ones and create new ones. + cache::PageCacheManager::Instance()->InvalidateAllCaches(); + + ::sd::View::ConfigurationChanged(pBroadcaster, nHint); + RequestRepaint(); + +} + + + + +::boost::shared_ptr<cache::PageCache> SlideSorterView::GetPreviewCache (void) +{ + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow && mpPreviewCache.get() == NULL) + { + mpPreviewCache.reset( + new cache::PageCache( + mpLayouter->GetPageObjectSize(), + false, + cache::SharedCacheContext(new ViewCacheContext(mrSlideSorter)))); + } + + return mpPreviewCache; +} + + + + +Pair SlideSorterView::GetVisiblePageRange (void) +{ + if ( ! mbPageObjectVisibilitiesValid) + DeterminePageObjectVisibilities(); + return maVisiblePageRange; +} + + + + +void SlideSorterView::AddVisibilityChangeListener (const Link& rListener) +{ + if (::std::find ( + maVisibilityChangeListeners.begin(), + maVisibilityChangeListeners.end(), + rListener) == maVisibilityChangeListeners.end()) + { + maVisibilityChangeListeners.push_back(rListener); + } +} + + + + +void SlideSorterView::RemoveVisibilityChangeListener(const Link&rListener) +{ + maVisibilityChangeListeners.erase ( + ::std::find ( + maVisibilityChangeListeners.begin(), + maVisibilityChangeListeners.end(), + rListener)); +} + + + + +ButtonBar& SlideSorterView::GetButtonBar (void) const +{ + OSL_ASSERT(mpButtonBar); + return *mpButtonBar; +} + + + + +ToolTip& SlideSorterView::GetToolTip (void) const +{ + OSL_ASSERT(mpToolTip); + return *mpToolTip; +} + + + + +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::UpdatePageUnderMouse (bool bAnimate) +{ + ::boost::shared_ptr<ScrollBar> pVScrollBar (mrSlideSorter.GetVerticalScrollBar()); + ::boost::shared_ptr<ScrollBar> pHScrollBar (mrSlideSorter.GetHorizontalScrollBar()); + if ((pVScrollBar && pVScrollBar->IsVisible() && pVScrollBar->IsTracking()) + || (pHScrollBar && pHScrollBar->IsVisible() && pHScrollBar->IsTracking())) + { + // One of the scroll bars is tracking mouse movement. Do not + // highlight the slide under the mouse in this case. + SetPageUnderMouse(SharedPageDescriptor(),false); + return; + } + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow && pWindow->IsVisible() && ! pWindow->IsMouseCaptured()) + { + const Window::PointerState aPointerState (pWindow->GetPointerState()); + const Rectangle aWindowBox (pWindow->GetPosPixel(), pWindow->GetSizePixel()); + if (aWindowBox.IsInside(aPointerState.maPos)) + { + UpdatePageUnderMouse ( + aPointerState.maPos, + (aPointerState.mnState & MOUSE_LEFT)!=0, + bAnimate); + return; + } + } + + SetPageUnderMouse(SharedPageDescriptor(),false); +} + + + + +void SlideSorterView::UpdatePageUnderMouse ( + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate) +{ + UpdatePageUnderMouse( + mrSlideSorter.GetController().GetPageAt(rMousePosition), + rMousePosition, + bIsMouseButtonDown, + bAnimate); +} + + + + +void SlideSorterView::UpdatePageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const Point& rMousePosition, + const bool bIsMouseButtonDown, + const bool bAnimate) +{ + // Update the page under the mouse. + SetPageUnderMouse(rpDescriptor, bAnimate); + + // Tell the button bar about the new mouse position. + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + const Point aMouseModelPosition (pWindow->PixelToLogic(rMousePosition)); + + ::boost::shared_ptr<ViewShell> pMainViewShell (mrSlideSorter.GetViewShellBase()->GetMainViewShell()); + if (pMainViewShell + && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW) + { + const bool bIsMouseOverButtonBar (GetButtonBar().IsMouseOverBar()); + GetButtonBar().ProcessMouseMotionEvent(rpDescriptor, aMouseModelPosition, bIsMouseButtonDown); + // Set the help text of the slide when the mouse was moved from the + // button bar back over the preview. + if (rpDescriptor + && GetButtonBar().IsMouseOverBar() != bIsMouseOverButtonBar + && bIsMouseOverButtonBar) + { + mpToolTip->ShowDefaultHelpText(); + } + } +} + + + + +void SlideSorterView::SetPageUnderMouse ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate) +{ + if (mpPageUnderMouse != rpDescriptor) + { + if (mpPageUnderMouse) + SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, false, bAnimate); + + mpPageUnderMouse = rpDescriptor; + + if (mpPageUnderMouse) + SetState(mpPageUnderMouse, PageDescriptor::ST_MouseOver, true, bAnimate); + + // Change the quick help text to display the name of the page under + // the mouse. + mpToolTip->SetPage(rpDescriptor); + } +} + + + + +bool SlideSorterView::SetState ( + const model::SharedPageDescriptor& rpDescriptor, + const PageDescriptor::State eState, + const bool bStateValue, + const bool bAnimate) +{ + model::SharedPageDescriptor pDescriptor (rpDescriptor); + if ( ! pDescriptor) + return false; + + const bool bModified (pDescriptor->SetState(eState, bStateValue)); + if ( ! bModified) + return false; + + // When the page object is not visible (i.e. not on the screen then + // nothing has to be painted. + if (pDescriptor->HasState(PageDescriptor::ST_Visible)) + { + // For most states a change of that state leads to visible + // difference and we have to request a repaint. + if (eState != PageDescriptor::ST_WasSelected) + RequestRepaint(pDescriptor); + } + + ::boost::shared_ptr<ViewShell> pMainViewShell(mrSlideSorter.GetViewShellBase()->GetMainViewShell()); + if (pMainViewShell + && pMainViewShell->GetShellType()!=ViewShell::ST_DRAW) + { + // Fade in or out the buttons. + if (eState == PageDescriptor::ST_MouseOver) + { + if (bStateValue) + GetButtonBar().RequestFadeIn(rpDescriptor, bAnimate); + else + GetButtonBar().RequestFadeOut(rpDescriptor, bAnimate); + } + } + + return bModified; +} + + + + +::boost::shared_ptr<PageObjectPainter> SlideSorterView::GetPageObjectPainter (void) +{ + if ( ! mpPageObjectPainter) + mpPageObjectPainter.reset(new PageObjectPainter(mrSlideSorter)); + return mpPageObjectPainter; +} + + + + +::boost::shared_ptr<LayeredDevice> SlideSorterView::GetLayeredDevice (void) const +{ + return mpLayeredDevice; +} + + + + +//===== SlideSorterView::DrawLock ============================================= + +SlideSorterView::DrawLock::DrawLock ( + view::SlideSorterView& rView, + const SharedSdWindow& rpWindow) + : mrView(rView), + mpWindow(rpWindow) +{ + if (mrView.mnLockRedrawSmph == 0) + mrView.maRedrawRegion.SetEmpty(); + ++mrView.mnLockRedrawSmph; +} + + + + +SlideSorterView::DrawLock::DrawLock (SlideSorter& rSlideSorter) + : mrView(rSlideSorter.GetView()), + mpWindow(rSlideSorter.GetContentWindow()) +{ + if (mrView.mnLockRedrawSmph == 0) + mrView.maRedrawRegion.SetEmpty(); + ++mrView.mnLockRedrawSmph; +} + + + + +SlideSorterView::DrawLock::~DrawLock (void) +{ + OSL_ASSERT(mrView.mnLockRedrawSmph>0); + --mrView.mnLockRedrawSmph; + if (mrView.mnLockRedrawSmph == 0) + if (mpWindow) + { + mpWindow->Invalidate(mrView.maRedrawRegion); + mpWindow->Update(); + } +} + + + + +void SlideSorterView::DrawLock::Dispose (void) +{ + mpWindow.reset(); +} + + +} } } // end of namespace ::sd::slidesorter::view + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/view/SlsButtonBar.cxx b/sd/source/ui/slidesorter/view/SlsButtonBar.cxx new file mode 100644 index 000000000000..f338a998c56f --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsButtonBar.cxx @@ -0,0 +1,1558 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsButtonBar.hxx" + +#include "SlideSorter.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlideSorterModel.hxx" +#include "view/SlsTheme.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsToolTip.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsSlotManager.hxx" +#include "controller/SlsCurrentSlideManager.hxx" +#include "controller/SlsPageSelector.hxx" +#include "controller/SlsAnimator.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "app.hrc" +#include "drawdoc.hxx" +#include <svx/svxids.hrc> +#include <sfx2/dispatch.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/virdev.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <com/sun/star/presentation/XPresentation2.hpp> +#include <boost/bind.hpp> + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::presentation::XPresentation2; + +namespace sd { namespace slidesorter { namespace view { + +/** Base class for the painter of the background bar onto which the buttons + are painted. It also provides some size information. +*/ +class ButtonBar::BackgroundTheme +{ +public: + BackgroundTheme( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons); + /** Set the preview bounding box, the maximal area in which to display + buttons. A call to this method triggers a call to Layout(). + */ + void SetPreviewBoundingBox (const Rectangle& rPreviewBoundingBox); + Button::IconSize GetIconSize (void) const; + + virtual BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const = 0; + virtual Point GetBackgroundLocation (void) = 0; + virtual Rectangle GetButtonArea (void) = 0; + +protected: + ::boost::shared_ptr<Theme> mpTheme; + Rectangle maPreviewBoundingBox; + Size maMinimumLargeButtonAreaSize; + Size maMinimumMediumButtonAreaSize; + Size maMinimumSmallButtonAreaSize; + Button::IconSize meIconSize; + + virtual void Layout (void) = 0; + +private: + void UpdateMinimumIconSizes(const ::std::vector<SharedButton>& rButtons); +}; + + +namespace { + /** Rectangular button bar that covers the whole width of the preview. + */ + class RectangleBackgroundTheme : public ButtonBar::BackgroundTheme + { + public: + RectangleBackgroundTheme( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons); + virtual BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const; + virtual Point GetBackgroundLocation (void); + virtual Rectangle GetButtonArea (void); + protected: + virtual void Layout (void); + private: + sal_Int32 mnBarHeight; + }; + + /** Button bar is composed of three images, the left and right end of + the bar and the center image. Buttons are only placed over the + center image. The center image is painted as is, it is not scaled. + */ + class BitmapBackgroundTheme : public ButtonBar::BackgroundTheme + { + public: + BitmapBackgroundTheme( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons); + virtual BitmapEx CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const; + virtual Point GetBackgroundLocation (void); + virtual Rectangle GetButtonArea (void); + protected: + virtual void Layout (void); + private: + Rectangle maButtonArea; + Point maBackgroundLocation; + }; + + /** The source mask is essentially multiplied with the given alpha value. + The result is writen to the result mask. + */ + void AdaptTransparency (AlphaMask& rMask, const AlphaMask& rSourceMask, const double nAlpha) + { + BitmapWriteAccess* pBitmap = rMask.AcquireWriteAccess(); + const BitmapReadAccess* pSourceBitmap = const_cast<AlphaMask&>(rSourceMask).AcquireReadAccess(); + + if (pBitmap!=NULL && pSourceBitmap!=NULL) + { + const sal_Int32 nWidth (pBitmap->Width()); + const sal_Int32 nHeight (pBitmap->Height()); + + for (sal_Int32 nY = 0; nY<nHeight; ++nY) + for (sal_Int32 nX = 0; nX<nWidth; ++nX) + { + const sal_uInt8 nValue (255 - pSourceBitmap->GetPixel(nY, nX).GetBlueOrIndex()); + const sal_uInt8 nNewValue (nValue * (1-nAlpha)); + pBitmap->SetPixel(nY, nX, 255-nNewValue); + } + } + } + +} // end of anonymous namespace + + +//===== ButtonBar::Lock ======================================================= + +ButtonBar::Lock::Lock (SlideSorter& rSlideSorter) + : mrButtonBar(rSlideSorter.GetView().GetButtonBar()) +{ + mrButtonBar.AcquireLock(); +} + + + + +ButtonBar::Lock::~Lock (void) +{ + mrButtonBar.ReleaseLock(); +} + + + + +//===== ButtonBar ============================================================= + +ButtonBar::ButtonBar (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + maPageObjectSize(0,0), + maButtonBoundingBox(), + maBackgroundLocation(), + mpDescriptor(), + mbIsExcluded(false), + mpButtonUnderMouse(), + mpDownButton(), + maRegularButtons(), + maExcludedButtons(), + maNormalBackground(), + maButtonDownBackground(), + mbIsMouseOverBar(false), + mpBackgroundTheme(), + mnLockCount(0) +{ + HandleDataChangeEvent(); +} + + + + +ButtonBar::~ButtonBar (void) +{ +} + + + + +void ButtonBar::ProcessButtonDownEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation) +{ + SetButtonUnderMouse(GetButtonAt(aMouseModelLocation)); + if (mpButtonUnderMouse) + mpButtonUnderMouse->SetState(Button::State_Down); + mpDownButton = mpButtonUnderMouse; + + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); +} + + + + +void ButtonBar::ProcessButtonUpEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation) +{ + SetButtonUnderMouse(GetButtonAt(aMouseModelLocation)); + if (mpButtonUnderMouse) + { + mpButtonUnderMouse->SetState(Button::State_Hover); + if (mpButtonUnderMouse == mpDownButton) + { + // This is done only when the buttons are sufficiently visible. + if (mpDescriptor->GetVisualState().GetButtonAlpha()<0.7) + { + mpButtonUnderMouse->ProcessClick(mpDescriptor); + mbIsExcluded = mpDescriptor->HasState(model::PageDescriptor::ST_Excluded); + ProcessMouseMotionEvent (rpDescriptor, aMouseModelLocation, false); + } + } + } + mpDownButton.reset(); + mrSlideSorter.GetView().RequestRepaint(rpDescriptor); +} + + + + +void ButtonBar::ProcessMouseMotionEvent ( + const model::SharedPageDescriptor& rpDescriptor, + const Point aMouseModelLocation, + const bool bIsMouseButtonDown) +{ + model::SharedPageDescriptor pOldDescriptor (mpDescriptor); + bool bPageHasChanged (false); + bool bButtonHasChanged (false); + bool bButtonStateHasChanged (false); + + // Update the page object for which to manage the buttons. + bPageHasChanged = SetPage(rpDescriptor); + mbIsMouseOverBar = IsMouseOverBar(aMouseModelLocation); + + // Update button under mouse. + if (rpDescriptor) + { + bButtonHasChanged = SetButtonUnderMouse(GetButtonAt(aMouseModelLocation)); + + if (mpButtonUnderMouse) + { + // When the mouse button is down, mark the button under the + // mouse only as pressed when it is the same button the mouse + // button was pressed over, and where the button release would + // lead to a click action. + if (bIsMouseButtonDown) + { + if (mpButtonUnderMouse==mpDownButton) + bButtonStateHasChanged = mpButtonUnderMouse->SetState(Button::State_Down); + } + else + bButtonStateHasChanged = mpButtonUnderMouse->SetState(Button::State_Hover); + } + } + + // Show a quick help text when the mouse is over a button. + if (bButtonHasChanged) + { + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (pWindow) + { + if (mpButtonUnderMouse) + mrSlideSorter.GetView().GetToolTip().ShowHelpText(mpButtonUnderMouse->GetHelpText()); + else + mrSlideSorter.GetView().GetToolTip().ShowDefaultHelpText(); + } + } + + if (bPageHasChanged || bButtonHasChanged || bButtonStateHasChanged) + { + if (pOldDescriptor) + mrSlideSorter.GetView().RequestRepaint(pOldDescriptor); + if (mpDescriptor && pOldDescriptor!=mpDescriptor) + mrSlideSorter.GetView().RequestRepaint(mpDescriptor); + } +} + + + + +void ButtonBar::ResetPage (void) +{ + SetPage(model::SharedPageDescriptor()); +} + + + + +bool ButtonBar::SetPage (const model::SharedPageDescriptor& rpDescriptor) +{ + if (mpDescriptor != rpDescriptor) + { + mpDescriptor = rpDescriptor; + + if (mpDescriptor) + mbIsExcluded = mpDescriptor->HasState(model::PageDescriptor::ST_Excluded); + else + mbIsExcluded = false; + SetButtonUnderMouse(); + mpDownButton.reset(); + + return true; + } + else + return false; +} + + + + +sal_Int32 ButtonBar::GetButtonCount (const bool bIsExcluded) const +{ + if (bIsExcluded) + return maExcludedButtons.size(); + else + return maRegularButtons.size(); +} + + + + +::boost::shared_ptr<Button> ButtonBar::GetButton ( + const bool bIsExcluded, + const sal_Int32 nIndex) const +{ + const ::std::vector<boost::shared_ptr<Button> >& rButtons (bIsExcluded + ? maExcludedButtons + : maRegularButtons); + + if (nIndex<0 || sal_uInt32(nIndex)>=rButtons.size()) + { + OSL_ASSERT(nIndex<0 || sal_uInt32(nIndex)>=rButtons.size()); + return ::boost::shared_ptr<Button>(); + } + else + return rButtons[sal_uInt32(nIndex)]; +} + + + + +SharedButton ButtonBar::GetButtonAt (const Point aModelLocation) +{ + if (IsMouseOverBar(aModelLocation)) + { + const Point aLocalLocation (aModelLocation - mpDescriptor->GetBoundingBox().TopLeft()); + ::std::vector<SharedButton>& rButtons ( + mbIsExcluded ? maExcludedButtons : maRegularButtons); + for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex) + { + if (rButtons[sal_uInt32(nIndex)]->GetBoundingBox().IsInside(aLocalLocation)) + { + if (rButtons[sal_uInt32(nIndex)]->IsEnabled()) + return rButtons[sal_uInt32(nIndex)]; + else + return SharedButton(); + } + } + } + + return SharedButton(); +} + + + + +bool ButtonBar::IsMouseOverBar (void) const +{ + return mbIsMouseOverBar; +} + + + + +bool ButtonBar::SetButtonUnderMouse (const SharedButton& rButton) +{ + if (mpButtonUnderMouse != rButton) + { + if (mpButtonUnderMouse) + mpButtonUnderMouse->SetState(Button::State_Normal); + + mpButtonUnderMouse = rButton; + + return true; + } + else + return false; +} + + + + +void ButtonBar::Paint ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + + const double nButtonBarAlpha (rpDescriptor->GetVisualState().GetButtonBarAlpha()); + if (nButtonBarAlpha >= 1) + return; + + LayoutButtons(rpDescriptor->GetBoundingBox().GetSize()); + + const Point aOffset (rpDescriptor->GetBoundingBox().TopLeft()); + + // Paint the background. + PaintButtonBackground(rDevice, rpDescriptor, aOffset); + + // Paint the buttons. + const ::std::vector<SharedButton>& rButtons ( + rpDescriptor->HasState(model::PageDescriptor::ST_Excluded) + ? maExcludedButtons + : maRegularButtons); + + + const double nButtonAlpha (rpDescriptor->GetVisualState().GetButtonAlpha()); + for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex) + rButtons[nIndex]->Paint( + rDevice, + aOffset, + nButtonAlpha, + mrSlideSorter.GetTheme()); +} + + + + +bool ButtonBar::IsMouseOverButton (void) const +{ + return mpButtonUnderMouse; +} + + + + +void ButtonBar::PaintButtonBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor, + const Point aOffset) +{ + BitmapEx* pBitmap = NULL; + if (maButtonDownBackground.IsEmpty() || maNormalBackground.IsEmpty()) + { + if (mpBackgroundTheme) + { + maButtonDownBackground = mpBackgroundTheme->CreateBackground(rDevice, true); + maNormalBackground = mpBackgroundTheme->CreateBackground(rDevice, false); + } + } + if (mpButtonUnderMouse && mpButtonUnderMouse->IsDown()) + pBitmap = &maButtonDownBackground; + else + pBitmap = &maNormalBackground; + if (pBitmap != NULL) + { + AlphaMask aMask (pBitmap->GetSizePixel()); + AdaptTransparency( + aMask, + pBitmap->GetAlpha(), + rpDescriptor->GetVisualState().GetButtonBarAlpha()); + rDevice.DrawBitmapEx(maBackgroundLocation+aOffset, BitmapEx(pBitmap->GetBitmap(), aMask)); + } +} + + + + +bool ButtonBar::IsMouseOverBar (const Point aModelLocation) const +{ + if ( ! mpDescriptor || ! mpDescriptor->GetBoundingBox().IsInside(aModelLocation)) + return false; + + if ( ! maButtonBoundingBox.IsInside(aModelLocation - mpDescriptor->GetBoundingBox().TopLeft())) + return false; + + return true; +} + + + + +void ButtonBar::RequestLayout (void) +{ + maPageObjectSize = Size(0,0); +} + + + + +void ButtonBar::LayoutButtons (const Size aPageObjectSize) +{ + if (maPageObjectSize != aPageObjectSize) + { + maPageObjectSize = aPageObjectSize; + + if (mpBackgroundTheme) + { + mpBackgroundTheme->SetPreviewBoundingBox( + mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + Point(0,0), + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + LayoutButtons(); + } + + // Release the background bitmaps so that on the next paint + // they are created anew in the right size. + maNormalBackground.SetEmpty(); + maButtonDownBackground.SetEmpty(); + } +} + + + + +bool ButtonBar::LayoutButtons (void) +{ + const sal_Int32 nGap (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonGap)); + const sal_Int32 nBorder (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonBorder)); + + const Button::IconSize eIconSize (mpBackgroundTheme->GetIconSize()); + + // Tell buttons which size they are. + for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex) + maExcludedButtons[nIndex]->SetIconSize(eIconSize); + for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex) + maRegularButtons[nIndex]->SetIconSize(eIconSize); + + // Determine maximal height and total width of the buttons. + // Start with the buttons used for the excluded state. + sal_Int32 nMaximumHeight (0); + sal_Int32 nExcludedTotalWidth ((maExcludedButtons.size()-1) * nGap + 2*nBorder); + for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex) + { + const Size aSize (maExcludedButtons[nIndex]->GetSize()); + if (aSize.Height() > nMaximumHeight) + nMaximumHeight = aSize.Height(); + nExcludedTotalWidth += aSize.Width(); + } + + // Do the same for the regular buttons. + sal_Int32 nRegularTotalWidth ((maRegularButtons.size()-1) * nGap + 2*nBorder); + for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex) + { + const Size aSize (maRegularButtons[nIndex]->GetSize()); + if (aSize.Height() > nMaximumHeight) + nMaximumHeight = aSize.Height(); + nRegularTotalWidth += aSize.Width(); + } + nMaximumHeight += 2*nBorder; + + // Set up the bounding box of the button bar. + maButtonBoundingBox = mpBackgroundTheme->GetButtonArea(); + maBackgroundLocation = mpBackgroundTheme->GetBackgroundLocation(); + if (mrSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ButtonPaintType) == 1) + { + // Center the buttons. + maButtonBoundingBox.Left() += (maButtonBoundingBox.GetWidth() - nRegularTotalWidth)/2; + maButtonBoundingBox.Right() = maButtonBoundingBox.Left() + nRegularTotalWidth - 1; + } + + // Place the buttons. + Rectangle aBox (maButtonBoundingBox); + aBox.Right() -= nBorder; + for (sal_Int32 nIndex=maRegularButtons.size()-1; nIndex>=0; --nIndex) + { + maRegularButtons[nIndex]->Place(aBox); + aBox.Right() = maRegularButtons[nIndex]->GetBoundingBox().Left() - nGap; + } + + // For slides excluded from the show there is only one icon placed + // exactly like the second of the regular icons. + if (maRegularButtons.size()>=2 && maExcludedButtons.size()>=1) + { + aBox = maRegularButtons[1]->GetBoundingBox(); + maExcludedButtons[0]->Place(aBox); + } + + // We return true only when there is no inactive button. + for (sal_uInt32 nIndex=0; nIndex<maExcludedButtons.size(); ++nIndex) + if ( ! maExcludedButtons[nIndex]->IsActive()) + return false; + for (sal_uInt32 nIndex=0; nIndex<maRegularButtons.size(); ++nIndex) + if ( ! maRegularButtons[nIndex]->IsActive()) + return false; + + return true; +} + + + + +void ButtonBar::RequestFadeIn ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate) +{ + if ( ! rpDescriptor) + return; + if (mnLockCount > 0) + return; + + const double nMinAlpha (0); + if ( ! bAnimate) + { + rpDescriptor->GetVisualState().SetButtonAlpha(nMinAlpha); + rpDescriptor->GetVisualState().SetButtonBarAlpha(nMinAlpha); + } + else + StartFadeAnimation(rpDescriptor, nMinAlpha, true); +} + + + + +void ButtonBar::RequestFadeOut ( + const model::SharedPageDescriptor& rpDescriptor, + const bool bAnimate) +{ + if ( ! rpDescriptor) + return; + if (mnLockCount > 0) + return; + + const double nMaxAlpha (1); + if ( ! bAnimate) + { + rpDescriptor->GetVisualState().SetButtonAlpha(nMaxAlpha); + rpDescriptor->GetVisualState().SetButtonBarAlpha(nMaxAlpha); + } + else + StartFadeAnimation(rpDescriptor, nMaxAlpha, false); +} + + + + +bool ButtonBar::IsVisible (const model::SharedPageDescriptor& rpDescriptor) +{ + const double nMaxAlpha (1); + return rpDescriptor && rpDescriptor->GetVisualState().GetButtonBarAlpha() < nMaxAlpha; +} + + + + +void ButtonBar::HandleDataChangeEvent (void) +{ + maExcludedButtons.clear(); + maExcludedButtons.push_back(::boost::shared_ptr<Button>(new UnhideButton(mrSlideSorter))); + + maRegularButtons.clear(); + maRegularButtons.push_back(::boost::shared_ptr<Button>(new StartShowButton(mrSlideSorter))); + maRegularButtons.push_back(::boost::shared_ptr<Button>(new HideButton(mrSlideSorter))); + maRegularButtons.push_back(::boost::shared_ptr<Button>(new DuplicateButton(mrSlideSorter))); + + mpBackgroundTheme.reset( + new BitmapBackgroundTheme( + mrSlideSorter.GetTheme(), + maRegularButtons)); + + // Force layout on next Paint(). + maPageObjectSize = Size(0,0); +} + + + + +void ButtonBar::StartFadeAnimation ( + const model::SharedPageDescriptor& rpDescriptor, + const double nTargetAlpha, + const bool bFadeIn) +{ + model::SharedPageDescriptor pDescriptor (rpDescriptor); + + const double nCurrentButtonAlpha (pDescriptor->GetVisualState().GetButtonAlpha()); + const double nCurrentButtonBarAlpha (pDescriptor->GetVisualState().GetButtonBarAlpha()); + + // Stop a running animation. + const controller::Animator::AnimationId nId ( + pDescriptor->GetVisualState().GetButtonAlphaAnimationId()); + if (nId != controller::Animator::NotAnAnimationId) + mrSlideSorter.GetController().GetAnimator()->RemoveAnimation(nId); + + // Prepare the blending functors that translate [0,1] animation + // times into alpha values of buttons and button bar. + const ::boost::function<double(double)> aButtonBlendFunctor ( + ::boost::bind( + controller::AnimationFunction::Blend, + nCurrentButtonAlpha, + nTargetAlpha, + ::boost::bind(controller::AnimationFunction::Linear, _1))); + const ::boost::function<double(double)> aButtonBarBlendFunctor ( + ::boost::bind( + controller::AnimationFunction::Blend, + nCurrentButtonBarAlpha, + nTargetAlpha, + ::boost::bind(controller::AnimationFunction::Linear, _1))); + + // Delay the fade in a little bit when the buttons are not visible at + // all so that we do not leave a trail of half-visible buttons when the + // mouse is moved across the screen. No delay on fade out or when the + // buttons are already showing. Fade out is faster than fade in. + const double nDelay (nCurrentButtonBarAlpha>0 && nCurrentButtonBarAlpha<1 + ? 0 + : (mrSlideSorter.GetTheme()->GetIntegerValue(bFadeIn + ? Theme::Integer_ButtonFadeInDelay + : Theme::Integer_ButtonFadeOutDelay))); + const double nDuration (mrSlideSorter.GetTheme()->GetIntegerValue(bFadeIn + ? Theme::Integer_ButtonFadeInDuration + : Theme::Integer_ButtonFadeOutDuration)); + pDescriptor->GetVisualState().SetButtonAlphaAnimationId( + mrSlideSorter.GetController().GetAnimator()->AddAnimation( + ::boost::bind( + controller::AnimationFunction::ApplyButtonAlphaChange, + pDescriptor, + ::boost::ref(mrSlideSorter.GetView()), + ::boost::bind(aButtonBlendFunctor, _1), + ::boost::bind(aButtonBarBlendFunctor, _1)), + nDelay, + nDuration, + ::boost::bind( + &model::VisualState::SetButtonAlphaAnimationId, + ::boost::ref(pDescriptor->GetVisualState()), + controller::Animator::NotAnAnimationId) + )); +} + + + + +void ButtonBar::AcquireLock (void) +{ + if (mnLockCount == 0 && mpDescriptor) + RequestFadeOut(mpDescriptor, true); + + ++mnLockCount; +} + + + + +void ButtonBar::ReleaseLock (void) +{ + --mnLockCount; + + if (mnLockCount == 0 && mpDescriptor) + RequestFadeIn(mpDescriptor, true); +} + + + + +//===== BackgroundTheme ===================================================== + +ButtonBar::BackgroundTheme::BackgroundTheme ( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons) + : mpTheme(rpTheme) +{ + UpdateMinimumIconSizes(rButtons); +} + + + + +void ButtonBar::BackgroundTheme::SetPreviewBoundingBox (const Rectangle& rPreviewBoundingBox) +{ + maPreviewBoundingBox = rPreviewBoundingBox; + Layout(); +} + + + + +void ButtonBar::BackgroundTheme::UpdateMinimumIconSizes ( + const ::std::vector<SharedButton>& rButtons) +{ + OSL_ASSERT(mpTheme); + + sal_Int32 nMaximumHeightLarge (0); + sal_Int32 nMaximumHeightMedium (0); + sal_Int32 nMaximumHeightSmall (0); + const sal_Int32 nGap (mpTheme->GetIntegerValue(Theme::Integer_ButtonGap)); + const sal_Int32 nBorder (mpTheme->GetIntegerValue(Theme::Integer_ButtonBorder)); + sal_Int32 nTotalWidthLarge ((rButtons.size()-1) * nGap + 2*nBorder); + sal_Int32 nTotalWidthMedium ((rButtons.size()-1) * nGap + 2*nBorder); + sal_Int32 nTotalWidthSmall ((rButtons.size()-1) * nGap + 2*nBorder); + for (sal_uInt32 nIndex=0; nIndex<rButtons.size(); ++nIndex) + { + // Update large size. + Size aSize = rButtons[nIndex]->GetSize(Button::IconSize_Large); + if (aSize.Height() > nMaximumHeightLarge) + nMaximumHeightLarge = aSize.Height(); + nTotalWidthLarge += aSize.Width(); + + // Update medium size. + aSize = rButtons[nIndex]->GetSize(Button::IconSize_Medium); + if (aSize.Height() > nMaximumHeightMedium) + nMaximumHeightMedium = aSize.Height(); + nTotalWidthMedium += aSize.Width(); + + // Update small size. + aSize = rButtons[nIndex]->GetSize(Button::IconSize_Small); + if (aSize.Height() > nMaximumHeightSmall) + nMaximumHeightSmall = aSize.Height(); + nTotalWidthSmall += aSize.Width(); + } + maMinimumLargeButtonAreaSize = Size(nTotalWidthLarge, nMaximumHeightLarge+2*nBorder); + maMinimumMediumButtonAreaSize = Size(nTotalWidthMedium, nMaximumHeightMedium+2*nBorder); + maMinimumSmallButtonAreaSize = Size(nTotalWidthSmall, nMaximumHeightSmall+2*nBorder); +} + + + + +Button::IconSize ButtonBar::BackgroundTheme::GetIconSize (void) const +{ + return meIconSize; +} + + + + +//===== RectangleBackgroundTheme ============================================ + +RectangleBackgroundTheme::RectangleBackgroundTheme ( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons) + : BackgroundTheme(rpTheme, rButtons), + mnBarHeight(0) +{ +} + + + + +BitmapEx RectangleBackgroundTheme::CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const +{ + OSL_ASSERT(mpTheme); + + // Setup background color. + Color aTopFillColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Fill1)); + Color aTopBorderColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Border1)); + Color aBottomFillColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Fill2)); + Color aBottomBorderColor (mpTheme->GetGradientColor( + Theme::Gradient_ButtonBackground, + Theme::Border2)); + if (bIsButtonDown) + { + aTopFillColor.DecreaseLuminance(50); + aTopBorderColor.DecreaseLuminance(50); + aBottomFillColor.DecreaseLuminance(50); + aBottomBorderColor.DecreaseLuminance(50); + } + + const int nWidth (maPreviewBoundingBox.GetWidth()+2); + const int nHeight (mnBarHeight); + const int nCenter (nHeight / 2); + + VirtualDevice aDevice (rTemplateDevice, 0, 8); + aDevice.SetOutputSizePixel(Size(nWidth,nHeight)); + + // Fill upper and lower half. + aDevice.SetLineColor(); + aDevice.SetFillColor(aTopFillColor); + aDevice.DrawRect(Rectangle(0,0,nWidth-1,nCenter)); + aDevice.SetFillColor(aBottomFillColor); + aDevice.DrawRect(Rectangle(0,nCenter,nWidth-1,nHeight-1)); + + // Draw border. + aDevice.SetFillColor(); + aDevice.SetLineColor(aTopBorderColor); + aDevice.DrawLine(Point(0,nCenter),Point(0,0)); + aDevice.DrawLine(Point(0,0), Point(nWidth-1,0)); + aDevice.DrawLine(Point(nWidth-1,0),Point(nWidth-1,nCenter)); + aDevice.SetLineColor(aBottomBorderColor); + aDevice.DrawLine(Point(0,nCenter),Point(0,nHeight-1)); + aDevice.DrawLine(Point(0,nHeight-1), Point(nWidth-1,nHeight-1)); + aDevice.DrawLine(Point(nWidth-1,nHeight-1),Point(nWidth-1,nCenter)); + + return aDevice.GetBitmapEx(Point(0,0), Size(nWidth,nHeight)); +} + + + + +Point RectangleBackgroundTheme::GetBackgroundLocation (void) +{ + return Point( + maPreviewBoundingBox.Left()-1, + maPreviewBoundingBox.Bottom() - mnBarHeight + 2); +} + + + + +Rectangle RectangleBackgroundTheme::GetButtonArea (void) +{ + return Rectangle( + maPreviewBoundingBox.Left(), + maPreviewBoundingBox.Bottom() - mnBarHeight + 2, + maPreviewBoundingBox.Right(), + maPreviewBoundingBox.Bottom()); +} + + + + +void RectangleBackgroundTheme::Layout (void) +{ + if (maPreviewBoundingBox.GetWidth() < maMinimumLargeButtonAreaSize.Width()) + if (maPreviewBoundingBox.GetWidth() < maMinimumMediumButtonAreaSize.Width()) + { + meIconSize = Button::IconSize_Small; + mnBarHeight = maMinimumSmallButtonAreaSize.Height(); + } + else + { + meIconSize = Button::IconSize_Medium; + mnBarHeight = maMinimumMediumButtonAreaSize.Height(); + } + else + { + meIconSize = Button::IconSize_Large; + mnBarHeight = maMinimumLargeButtonAreaSize.Height(); + } +} + + + + +//===== BitmapBackgroundTheme ================================================= + +BitmapBackgroundTheme::BitmapBackgroundTheme ( + const ::boost::shared_ptr<Theme>& rpTheme, + const ::std::vector<SharedButton>& rButtons) + : BackgroundTheme(rpTheme, rButtons), + maButtonArea(), + maBackgroundLocation() +{ +} + + + + +BitmapEx BitmapBackgroundTheme::CreateBackground ( + const OutputDevice& rTemplateDevice, + const bool bIsButtonDown) const +{ + (void)rTemplateDevice; + (void)bIsButtonDown; + + OSL_ASSERT(mpTheme); + + // Get images. + switch (meIconSize) + { + case Button::IconSize_Large: + default: + return mpTheme->GetIcon(Theme::Icon_ButtonBarLarge); + + case Button::IconSize_Medium: + return mpTheme->GetIcon(Theme::Icon_ButtonBarMedium); + + case Button::IconSize_Small: + return mpTheme->GetIcon(Theme::Icon_ButtonBarSmall); + } +} + + + + +Point BitmapBackgroundTheme::GetBackgroundLocation (void) +{ + return maBackgroundLocation; +} + + + + +Rectangle BitmapBackgroundTheme::GetButtonArea (void) +{ + return maButtonArea; +} + + + + +void BitmapBackgroundTheme::Layout (void) +{ + Size aImageSize (mpTheme->GetIcon(Theme::Icon_ButtonBarLarge).GetSizePixel()); + if (aImageSize.Width() >= maPreviewBoundingBox.GetWidth()) + { + aImageSize = mpTheme->GetIcon(Theme::Icon_ButtonBarMedium).GetSizePixel(); + if (aImageSize.Width() >= maPreviewBoundingBox.GetWidth()) + { + meIconSize = Button::IconSize_Small; + aImageSize = mpTheme->GetIcon(Theme::Icon_ButtonBarSmall).GetSizePixel(); + } + else + meIconSize = Button::IconSize_Medium; + } + else + { + meIconSize = Button::IconSize_Large; + } + + maBackgroundLocation = Point( + maPreviewBoundingBox.Left() + + (maPreviewBoundingBox.GetWidth()-aImageSize.Width())/2, + maPreviewBoundingBox.Bottom() - aImageSize.Height()); + maButtonArea = Rectangle(maBackgroundLocation, aImageSize); +} + + + + +//===== Button ================================================================ + +Button::Button ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsHelpText) + : mrSlideSorter(rSlideSorter), + meState(State_Normal), + maBoundingBox(), + msHelpText(rsHelpText), + mbIsActive(false), + meIconSize(IconSize_Large) +{ +} + + + + +Button::~Button (void) +{ +} + + + + +bool Button::SetState (const State eState) +{ + if (meState != eState) + { + meState = eState; + return true; + } + else + return false; +} + + + + +Button::State Button::GetState (void) const +{ + return meState; +} + + + + +Rectangle Button::GetBoundingBox (void) const +{ + if (mbIsActive) + return maBoundingBox; + else + return Rectangle(); +} + + + + +::rtl::OUString Button::GetHelpText (void) const +{ + if (mbIsActive) + return msHelpText; + else + return ::rtl::OUString(); +} + + + + +bool Button::IsDown (void) const +{ + return mbIsActive && meState==State_Down; +} + + + + +void Button::SetActiveState (const bool bIsActive) +{ + mbIsActive = bIsActive; +} + + + + +bool Button::IsActive (void) const +{ + return mbIsActive; +} + + + + +void Button::SetIconSize (const IconSize eIconSize) +{ + meIconSize = eIconSize; +} + + + + +Button::IconSize Button::GetIconSize (void) const +{ + return meIconSize; +} + + + + +bool Button::IsEnabled (void) const +{ + return true; +} + + + + +//===== TextButton ============================================================ + +TextButton::TextButton ( + SlideSorter& rSlideSorter, + const ::rtl::OUString& rsText, + const ::rtl::OUString& rsHelpText) + : Button(rSlideSorter, rsHelpText), + msText(rsText) +{ +} + + + + +void TextButton::Place (const Rectangle aButtonBarBox) +{ + maBoundingBox = aButtonBarBox; + SetActiveState(true); +} + + + + +void TextButton::Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const +{ + (void)nAlpha; + + if (mbIsActive) + { + // Paint text over the button background. + if (meState == State_Normal) + rDevice.SetTextColor(rpTheme->GetColor(Theme::Color_ButtonText)); + else + rDevice.SetTextColor(rpTheme->GetColor(Theme::Color_ButtonTextHover)); + Rectangle aBox (maBoundingBox); + aBox += aOffset; + rDevice.DrawText(aBox, msText, TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER); + } +} + + + + +Size TextButton::GetSize (void) const +{ + return Size(); +} + + + + +Size TextButton::GetSize (const Button::IconSize) const +{ + return Size(); +} + + + + +//===== ImageButon ============================================================ + +ImageButton::ImageButton ( + SlideSorter& rSlideSorter, + const BitmapEx& rLargeIcon, + const BitmapEx& rLargeHoverIcon, + const BitmapEx& rMediumIcon, + const BitmapEx& rMediumHoverIcon, + const BitmapEx& rSmallIcon, + const BitmapEx& rSmallHoverIcon, + const ::rtl::OUString& rsHelpText) + : Button(rSlideSorter, rsHelpText), + maLargeIcon(rLargeIcon), + maLargeHoverIcon(rLargeHoverIcon.IsEmpty() ? rLargeIcon : rLargeHoverIcon), + maMediumIcon(rMediumIcon), + maMediumHoverIcon(rMediumHoverIcon.IsEmpty() ? rMediumIcon : rMediumHoverIcon), + maSmallIcon(rSmallIcon), + maSmallHoverIcon(rSmallHoverIcon.IsEmpty() ? rSmallIcon : rSmallHoverIcon) +{ +} + + + + +void ImageButton::Place (const Rectangle aButtonBarBox) +{ + const sal_Int32 nWidth (GetSize().Width()); + maBoundingBox = Rectangle( + aButtonBarBox.Right() - nWidth, + aButtonBarBox.Top(), + aButtonBarBox.Right(), + aButtonBarBox.Bottom()); + SetActiveState(aButtonBarBox.IsInside(maBoundingBox)); +} + + + + +void ImageButton::Paint ( + OutputDevice& rDevice, + const Point aOffset, + const double nAlpha, + const ::boost::shared_ptr<Theme>& rpTheme) const +{ + (void)rpTheme; + + if ( ! mbIsActive) + return; + + const sal_uInt16 nSavedAntialiasingMode (rDevice.GetAntialiasing()); + rDevice.SetAntialiasing(nSavedAntialiasingMode | ANTIALIASING_ENABLE_B2DDRAW); + + rDevice.SetLineColor(); + + // Choose icon. + BitmapEx aIcon; + switch (meIconSize) + { + case IconSize_Large: + default: + if (meState == State_Normal) + aIcon = maLargeIcon; + else + aIcon = maLargeHoverIcon; + break; + + case IconSize_Medium: + if (meState == State_Normal) + aIcon = maMediumIcon; + else + aIcon = maMediumHoverIcon; + break; + + case IconSize_Small: + if (meState == State_Normal) + aIcon = maSmallIcon; + else + aIcon = maSmallHoverIcon; + break; + } + + // Paint icon. + if ( ! aIcon.IsEmpty()) + { + AlphaMask aMask (aIcon.GetSizePixel()); + AdaptTransparency(aMask, aIcon.GetAlpha(), nAlpha); + rDevice.DrawBitmapEx( + Point( + maBoundingBox.Left() + + aOffset.X() + + (maBoundingBox.GetWidth()-aIcon.GetSizePixel().Width())/2, + maBoundingBox.Top() + + aOffset.Y() + + (maBoundingBox.GetHeight()-aIcon.GetSizePixel().Height())/2), + BitmapEx(aIcon.GetBitmap(), aMask)); + } + + rDevice.SetAntialiasing(nSavedAntialiasingMode); +} + + + + +Size ImageButton::GetSize (void) const +{ + return GetSize(meIconSize); +} + + + + +Size ImageButton::GetSize (const Button::IconSize eIconSize) const +{ + switch (eIconSize) + { + case IconSize_Large: + default: + return maLargeIcon.GetSizePixel(); + + case IconSize_Medium: + return maMediumIcon.GetSizePixel(); + + case IconSize_Small: + return maSmallIcon.GetSizePixel(); + } +} + + + + +//===== UnhideButton ========================================================== + +UnhideButton::UnhideButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BLarge), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BLargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BMedium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BMediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BSmall), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2BSmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command2B)) +{ +} + + + + +void UnhideButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + mrSlideSorter.GetController().GetSlotManager()->ChangeSlideExclusionState( + (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) + ? model::SharedPageDescriptor() + : rpDescriptor), + false); +} + + + + +//===== StartSlideShowButton ================================================== + +StartShowButton::StartShowButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Large), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1LargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Medium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1MediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1Small), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command1SmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command1)) +{ +} + + + + +bool StartShowButton::IsEnabled (void) const +{ + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell == NULL) + return false; + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher == NULL) + return false; + + const SfxPoolItem* pState = NULL; + const SfxItemState eState (pDispatcher->QueryState(SID_PRESENTATION, pState)); + return (eState & SFX_ITEM_DISABLED) == 0; +} + + + + +void StartShowButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + // Hide the tool tip early, while the slide show still intializes. + mrSlideSorter.GetView().GetToolTip().SetPage(model::SharedPageDescriptor()); + + Reference< XPresentation2 > xPresentation( + mrSlideSorter.GetModel().GetDocument()->getPresentation()); + if (xPresentation.is()) + { + Sequence<PropertyValue> aProperties (1); + aProperties[0].Name = ::rtl::OUString::createFromAscii("FirstPage"); + const ::rtl::OUString sName (rpDescriptor->GetPage()->GetName()); + aProperties[0].Value = Any(sName); + xPresentation->startWithArguments(aProperties); + } +} + + + + +//===== HideButton ============================================================ + +HideButton::HideButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Large), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2LargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Medium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2MediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2Small), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command2SmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command2)) +{ +} + + + + +void HideButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + mrSlideSorter.GetController().GetSlotManager()->ChangeSlideExclusionState( + (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) + ? model::SharedPageDescriptor() + : rpDescriptor), + true); +} + + + + +//===== DuplicateButton ======================================================= + +DuplicateButton::DuplicateButton (SlideSorter& rSlideSorter) + : ImageButton( + rSlideSorter, + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Large), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3LargeHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Medium), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3MediumHover), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3Small), + rSlideSorter.GetTheme()->GetIcon(Theme::Icon_Command3SmallHover), + rSlideSorter.GetTheme()->GetString(Theme::String_Command3)) +{ +} + + + + +bool DuplicateButton::IsEnabled (void) const +{ + ViewShell* pViewShell = mrSlideSorter.GetViewShell(); + if (pViewShell == NULL) + return false; + SfxDispatcher* pDispatcher = pViewShell->GetDispatcher(); + if (pDispatcher == NULL) + return false; + + const SfxPoolItem* pState = NULL; + const SfxItemState eState (pDispatcher->QueryState( + SID_DUPLICATE_PAGE, + pState)); + return (eState & SFX_ITEM_DISABLED) == 0; +} + + + + +void DuplicateButton::ProcessClick (const model::SharedPageDescriptor& rpDescriptor) +{ + if ( ! rpDescriptor) + return; + + mrSlideSorter.GetView().SetPageUnderMouse(model::SharedPageDescriptor(),false); + + // When the page under the button is not selected then set the + // selection to just this page. + if ( ! rpDescriptor->HasState(model::PageDescriptor::ST_Selected)) + { + mrSlideSorter.GetController().GetPageSelector().DeselectAllPages(); + mrSlideSorter.GetController().GetPageSelector().SelectPage(rpDescriptor); + } + // Duplicate the selected pages. Insert the new pages right + // after the current selection and select them + if (mrSlideSorter.GetViewShell() != NULL + && mrSlideSorter.GetViewShell()->GetDispatcher() != NULL) + { + mrSlideSorter.GetViewShell()->GetDispatcher()->Execute( + SID_DUPLICATE_PAGE, + SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD); + } +} + + + +} } } // 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..f81035e50be1 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsFontProvider.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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(sal_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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/view/SlsFramePainter.cxx b/sd/source/ui/slidesorter/view/SlsFramePainter.cxx new file mode 100644 index 000000000000..c62c32e7d841 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsFramePainter.cxx @@ -0,0 +1,265 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsFramePainter.hxx" +#include <vcl/outdev.hxx> +#include <vcl/bmpacc.hxx> + + +namespace sd { namespace slidesorter { namespace view { + +FramePainter::FramePainter (const BitmapEx& rShadowBitmap) + : maTopLeft(rShadowBitmap,-1,-1), + maTop(rShadowBitmap,0,-1), + maTopRight(rShadowBitmap,+1,-1), + maLeft(rShadowBitmap,-1,0), + maRight(rShadowBitmap,+1,0), + maBottomLeft(rShadowBitmap,-1,+1), + maBottom(rShadowBitmap,0,+1), + maBottomRight(rShadowBitmap,+1,+1), + maCenter(rShadowBitmap,0,0), + mbIsValid(false) +{ + if (rShadowBitmap.GetSizePixel().Width() == rShadowBitmap.GetSizePixel().Height() + && (rShadowBitmap.GetSizePixel().Width()-1)%2 == 0 + && ((rShadowBitmap.GetSizePixel().Width()-1)/2)%2 == 1) + { + mbIsValid = true; + } + else + { + OSL_ASSERT(rShadowBitmap.GetSizePixel().Width() == rShadowBitmap.GetSizePixel().Height()); + OSL_ASSERT((rShadowBitmap.GetSizePixel().Width()-1)%2 == 0); + OSL_ASSERT(((rShadowBitmap.GetSizePixel().Width()-1)/2)%2 == 1); + } +} + + + + +FramePainter::~FramePainter (void) +{ +} + + + + +void FramePainter::PaintFrame ( + OutputDevice& rDevice, + const Rectangle aBox) const +{ + if ( ! mbIsValid) + return; + + // Paint the shadow. + maTopLeft.PaintCorner(rDevice, aBox.TopLeft()); + maTopRight.PaintCorner(rDevice, aBox.TopRight()); + maBottomLeft.PaintCorner(rDevice, aBox.BottomLeft()); + maBottomRight.PaintCorner(rDevice, aBox.BottomRight()); + maLeft.PaintSide(rDevice, aBox.TopLeft(), aBox.BottomLeft(), maTopLeft, maBottomLeft); + maRight.PaintSide(rDevice, aBox.TopRight(), aBox.BottomRight(), maTopRight, maBottomRight); + maTop.PaintSide(rDevice, aBox.TopLeft(), aBox.TopRight(), maTopLeft, maTopRight); + maBottom.PaintSide(rDevice, aBox.BottomLeft(), aBox.BottomRight(), maBottomLeft, maBottomRight); + maCenter.PaintCenter(rDevice,aBox); +} + + + + +void FramePainter::AdaptColor ( + const Color aNewColor, + const bool bEraseCenter) +{ + // Get the source color. + if (maCenter.maBitmap.IsEmpty()) + return; + BitmapReadAccess* pReadAccess = maCenter.maBitmap.GetBitmap().AcquireReadAccess(); + if (pReadAccess == NULL) + return; + const Color aSourceColor = pReadAccess->GetColor(0,0); + maCenter.maBitmap.GetBitmap().ReleaseAccess(pReadAccess); + + // Erase the center bitmap. + if (bEraseCenter) + maCenter.maBitmap.SetEmpty(); + + // Replace the color in all bitmaps. + maTopLeft.maBitmap.Replace(aSourceColor, aNewColor, 0); + maTop.maBitmap.Replace(aSourceColor, aNewColor, 0); + maTopRight.maBitmap.Replace(aSourceColor, aNewColor, 0); + maLeft.maBitmap.Replace(aSourceColor, aNewColor, 0); + maCenter.maBitmap.Replace(aSourceColor, aNewColor, 0); + maRight.maBitmap.Replace(aSourceColor, aNewColor, 0); + maBottomLeft.maBitmap.Replace(aSourceColor, aNewColor, 0); + maBottom.maBitmap.Replace(aSourceColor, aNewColor, 0); + maBottomRight.maBitmap.Replace(aSourceColor, aNewColor, 0); +} + + + + +//===== FramePainter::OffsetBitmap ============================================ + +FramePainter::OffsetBitmap::OffsetBitmap ( + const BitmapEx& rBitmap, + const sal_Int32 nHorizontalPosition, + const sal_Int32 nVerticalPosition) + : maBitmap(), + maOffset() +{ + OSL_ASSERT(nHorizontalPosition>=-1 && nHorizontalPosition<=+1); + OSL_ASSERT(nVerticalPosition>=-1 && nVerticalPosition<=+1); + + const sal_Int32 nS (1); + const sal_Int32 nC (::std::max<sal_Int32>(0,(rBitmap.GetSizePixel().Width()-nS)/2)); + const sal_Int32 nO (nC/2); + + const Point aOrigin( + nHorizontalPosition<0 ? 0 : (nHorizontalPosition == 0 ? nC : nC+nS), + nVerticalPosition<0 ? 0 : (nVerticalPosition == 0 ? nC : nC+nS)); + const Size aSize( + nHorizontalPosition==0 ? nS : nC, + nVerticalPosition==0 ? nS : nC); + maBitmap = BitmapEx(rBitmap, aOrigin, aSize); + if (maBitmap.IsEmpty()) + return; + maOffset = Point( + nHorizontalPosition<0 ? -nO : nHorizontalPosition>0 ? -nO : 0, + nVerticalPosition<0 ? -nO : nVerticalPosition>0 ? -nO : 0); + + // Enlarge the side bitmaps so that painting the frame requires less + // paint calls. + const sal_Int32 nSideBitmapSize (64); + if (nHorizontalPosition == 0 && nVerticalPosition == 0) + { + maBitmap.Scale(Size(nSideBitmapSize,nSideBitmapSize), BMP_SCALE_FAST); + } + else if (nHorizontalPosition == 0) + { + maBitmap.Scale(Size(nSideBitmapSize,aSize.Height()), BMP_SCALE_FAST); + } + else if (nVerticalPosition == 0) + { + maBitmap.Scale(Size(maBitmap.GetSizePixel().Width(), nSideBitmapSize), BMP_SCALE_FAST); + } +} + + + + +void FramePainter::OffsetBitmap::PaintCorner ( + OutputDevice& rDevice, + const Point& rAnchor) const +{ + if ( ! maBitmap.IsEmpty()) + rDevice.DrawBitmapEx(rAnchor+maOffset, maBitmap); +} + + + + +void FramePainter::OffsetBitmap::PaintSide ( + OutputDevice& rDevice, + const Point& rAnchor1, + const Point& rAnchor2, + const OffsetBitmap& rCornerBitmap1, + const OffsetBitmap& rCornerBitmap2) const +{ + if (maBitmap.IsEmpty()) + return; + + const Size aBitmapSize (maBitmap.GetSizePixel()); + if (rAnchor1.Y() == rAnchor2.Y()) + { + // Side is horizontal. + const sal_Int32 nY (rAnchor1.Y() + maOffset.Y()); + const sal_Int32 nLeft ( + rAnchor1.X() + + rCornerBitmap1.maBitmap.GetSizePixel().Width() + + rCornerBitmap1.maOffset.X()); + const sal_Int32 nRight ( + rAnchor2.X() + + rCornerBitmap2.maOffset.X()\ + - 1); + for (sal_Int32 nX=nLeft; nX<=nRight; nX+=aBitmapSize.Width()) + { + rDevice.DrawBitmapEx( + Point(nX,nY), + Size(std::min(aBitmapSize.Width(),static_cast<long>(nRight-nX+1)),aBitmapSize.Height()), + maBitmap); + } + } + else if (rAnchor1.X() == rAnchor2.X()) + { + // Side is vertical. + const sal_Int32 nX (rAnchor1.X() + maOffset.X()); + const sal_Int32 nTop ( + rAnchor1.Y() + + rCornerBitmap1.maBitmap.GetSizePixel().Height() + + rCornerBitmap1.maOffset.Y()); + const sal_Int32 nBottom ( + rAnchor2.Y() + + rCornerBitmap2.maOffset.Y() + - 1); + for (sal_Int32 nY=nTop; nY<=nBottom; nY+=aBitmapSize.Height()) + { + rDevice.DrawBitmapEx( + Point(nX,nY), + Size(aBitmapSize.Width(), std::min(aBitmapSize.Height(), static_cast<long>(nBottom-nY+1))), + maBitmap); + } + } + else + { + // Diagonal sides indicatee an error. + OSL_ASSERT(false); + } +} + + + + +void FramePainter::OffsetBitmap::PaintCenter ( + OutputDevice& rDevice, + const Rectangle& rBox) const +{ + const Size aBitmapSize (maBitmap.GetSizePixel()); + for (sal_Int32 nY=rBox.Top(); nY<=rBox.Bottom(); nY+=aBitmapSize.Height()) + for (sal_Int32 nX=rBox.Left(); nX<=rBox.Right(); nX+=aBitmapSize.Width()) + rDevice.DrawBitmapEx( + Point(nX,nY), + Size( + ::std::min(aBitmapSize.Width(), rBox.Right()-nX+1), + std::min(aBitmapSize.Height(), rBox.Bottom()-nY+1)), + maBitmap); +} + + + +} } } // end of namespace sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsFramePainter.hxx b/sd/source/ui/slidesorter/view/SlsFramePainter.hxx new file mode 100644 index 000000000000..96ccf51c6323 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsFramePainter.hxx @@ -0,0 +1,121 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_FRAME_PAINTER_HXX +#define SD_SLIDESORTER_VIEW_FRAME_PAINTER_HXX + +#include <vcl/bitmapex.hxx> + + +namespace sd { namespace slidesorter { namespace view { + +class FramePainter +{ +public: + FramePainter (const BitmapEx& rBitmap); + ~FramePainter (void); + + /** Paint a border around the given box by using a set of bitmaps for + the corners and sides. + */ + void PaintFrame (OutputDevice&rDevice, const Rectangle aBox) const; + + /** Special functionality that takes the color from the center + bitmap and replaces that color in all bitmaps by the given new + color. Alpha values are not modified. + @param bClearCenterBitmap + When <TRUE/> then the center bitmap is erased. + */ + void AdaptColor (const Color aNewColor, const bool bClearCenterBitmap); + +private: + /** Bitmap with offset that is used when the bitmap is painted. The bitmap + */ + class OffsetBitmap { + public: + BitmapEx maBitmap; + Point maOffset; + + /** Create one of the eight shadow bitmaps from one that combines + them all. This larger bitmap is expected to have dimension NxN + with N=1+2*M. Of this larger bitmap there are created four + corner bitmaps of size 2*M x 2*M and four side bitmaps of sizes + 1xM (top and bottom) and Mx1 (left and right). The corner + bitmaps have each one quadrant of size MxM that is painted under + the interior of the frame. + @param rBitmap + The larger bitmap of which the eight shadow bitmaps are cut + out from. + @param nHorizontalPosition + Valid values are -1 (left), 0 (center), and +1 (right). + @param nVerticalPosition + Valid values are -1 (top), 0 (center), and +1 (bottom). + */ + OffsetBitmap ( + const BitmapEx& rBitmap, + const sal_Int32 nHorizontalPosition, + const sal_Int32 nVerticalPosition); + + /** Use the given device to paint the bitmap at the location that is + the sum of the given anchor and the internal offset. + */ + void PaintCorner (OutputDevice& rDevice, const Point& rAnchor) const; + + /** Use the given device to paint the bitmap stretched between the + two given locations. Offsets of the adjacent corner bitmaps and + the offset of the side bitmap are used to determine the area + that is to be filled with the side bitmap. + */ + void PaintSide ( + OutputDevice& rDevice, + const Point& rAnchor1, + const Point& rAnchor2, + const OffsetBitmap& rCornerBitmap1, + const OffsetBitmap& rCornerBitmap2) const; + + /** Fill the given rectangle with the bitmap. + */ + void PaintCenter ( + OutputDevice& rDevice, + const Rectangle& rBox) const; + }; + OffsetBitmap maTopLeft; + OffsetBitmap maTop; + OffsetBitmap maTopRight; + OffsetBitmap maLeft; + OffsetBitmap maRight; + OffsetBitmap maBottomLeft; + OffsetBitmap maBottom; + OffsetBitmap maBottomRight; + OffsetBitmap maCenter; + bool mbIsValid; +}; + + +} } } // end of namespace sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx b/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx new file mode 100644 index 000000000000..3dd9af11194a --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsInsertAnimator.cxx @@ -0,0 +1,537 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsInsertAnimator.hxx" +#include "controller/SlideSorterController.hxx" +#include "controller/SlsAnimationFunction.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageEnumerationProvider.hxx" + +#include <set> +#include <boost/bind.hpp> +#include <boost/enable_shared_from_this.hpp> + +namespace sd { namespace slidesorter { namespace view { + +namespace { + +class PageObjectRun; + +class AnimatorAccess +{ +public: + virtual void AddRun (const ::boost::shared_ptr<PageObjectRun> pRun) = 0; + virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun) = 0; + virtual model::SlideSorterModel& GetModel (void) const = 0; + virtual view::SlideSorterView& GetView (void) const = 0; + virtual ::boost::shared_ptr<controller::Animator> GetAnimator (void) = 0; + virtual SharedSdWindow GetContentWindow (void) = 0; +}; + + +/** Controller of the position offsets of all page objects in one row or one + column. +*/ +class PageObjectRun : public ::boost::enable_shared_from_this<PageObjectRun> +{ +public: + PageObjectRun ( + AnimatorAccess& rAnimatorAccess, + const sal_Int32 nRunIndex, + const sal_Int32 nStartIndex, + const sal_Int32 nEndIndex); + ~PageObjectRun (void); + + void operator () (const double nTime); + + void UpdateOffsets( + const InsertPosition& rInsertPosition, + const view::Layouter& GetLayouter); + void ResetOffsets (const controller::Animator::AnimationMode eMode); + + /// Index of the row or column that this run represents. + sal_Int32 mnRunIndex; + /// The index at which to make place for the insertion indicator (-1 for + /// no indicator). + sal_Int32 mnLocalInsertIndex; + /// Index of the first page in the run. + sal_Int32 mnStartIndex; + /// Index of the last page in the run. + sal_Int32 mnEndIndex; + /// Offset of each item in the run at the start of the current animation. + ::std::vector<Point> maStartOffset; + /// Target offset of each item in the run at the end of the current animation. + ::std::vector<Point> maEndOffset; + /// Time at which the current animation started. + double mnStartTime; + + class Comparator + { + public: bool operator() ( + const ::boost::shared_ptr<PageObjectRun>& rpRunA, + const ::boost::shared_ptr<PageObjectRun>& rpRunB) const + { + return rpRunA->mnRunIndex < rpRunB->mnRunIndex; + } + }; +private: + controller::Animator::AnimationId mnAnimationId; + AnimatorAccess& mrAnimatorAccess; + ::boost::function<double(double)> maAccelerationFunction; + + Rectangle GetInnerBoundingBox ( + const view::Layouter& rLayouter, + const sal_Int32 nIndex) const; + void RestartAnimation (void); +}; +typedef ::boost::shared_ptr<PageObjectRun> SharedPageObjectRun; + + +Point Blend (const Point& rPointA, const Point& rPointB, const double nT) +{ + return Point( + sal_Int32(rPointA.X() * (1-nT) + rPointB.X() * nT), + sal_Int32(rPointA.Y() * (1-nT) + rPointB.Y() * nT)); +} + +} // end of anonymous namespace + + + +class InsertAnimator::Implementation : public AnimatorAccess +{ +public: + Implementation (SlideSorter& rSlideSorter); + virtual ~Implementation (void); + + void SetInsertPosition ( + const InsertPosition& rInsertPosition, + const controller::Animator::AnimationMode eAnimationMode); + + virtual void AddRun (const ::boost::shared_ptr<PageObjectRun> pRun); + virtual void RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun); + + virtual model::SlideSorterModel& GetModel (void) const { return mrModel; } + virtual view::SlideSorterView& GetView (void) const { return mrView; } + virtual ::boost::shared_ptr<controller::Animator> GetAnimator (void) { return mpAnimator; } + virtual SharedSdWindow GetContentWindow (void) { return mrSlideSorter.GetContentWindow(); } + +private: + model::SlideSorterModel& mrModel; + view::SlideSorterView& mrView; + SlideSorter& mrSlideSorter; + ::boost::shared_ptr<controller::Animator> mpAnimator; + typedef ::std::set<SharedPageObjectRun, PageObjectRun::Comparator> RunContainer; + RunContainer maRuns; + InsertPosition maInsertPosition; + + void StopAnimation (void); + SharedPageObjectRun GetRun ( + view::Layouter& rLayouter, + const InsertPosition& rInsertPosition, + const bool bCreate = true); + RunContainer::const_iterator FindRun (const sal_Int32 nRunIndex) const; +}; + + + + + +//===== InsertAnimator ======================================================== + +InsertAnimator::InsertAnimator (SlideSorter& rSlideSorter) + : mpImplementation(new Implementation(rSlideSorter)) +{ +} + + + + +void InsertAnimator::SetInsertPosition (const InsertPosition& rInsertPosition) +{ + mpImplementation->SetInsertPosition(rInsertPosition, controller::Animator::AM_Animated); +} + + + + +void InsertAnimator::Reset (const controller::Animator::AnimationMode eMode) +{ + mpImplementation->SetInsertPosition(InsertPosition(), eMode); +} + + + + +//===== InsertAnimator::Implementation ======================================== + +InsertAnimator::Implementation::Implementation (SlideSorter& rSlideSorter) + : mrModel(rSlideSorter.GetModel()), + mrView(rSlideSorter.GetView()), + mrSlideSorter(rSlideSorter), + mpAnimator(rSlideSorter.GetController().GetAnimator()), + maRuns(), + maInsertPosition() +{ +} + + + + +InsertAnimator::Implementation::~Implementation (void) +{ + SetInsertPosition(InsertPosition(), controller::Animator::AM_Immediate); +} + + + + +void InsertAnimator::Implementation::SetInsertPosition ( + const InsertPosition& rInsertPosition, + const controller::Animator::AnimationMode eMode) +{ + if (maInsertPosition == rInsertPosition) + return; + + SharedPageObjectRun pOldRun (GetRun(mrView.GetLayouter(), maInsertPosition)); + SharedPageObjectRun pCurrentRun (GetRun(mrView.GetLayouter(), rInsertPosition)); + maInsertPosition = rInsertPosition; + + // When the new insert position is in a different run then move the page + // objects in the old run to their default positions. + if (pOldRun != pCurrentRun) + { + if (pOldRun) + pOldRun->ResetOffsets(eMode); + } + + if (pCurrentRun) + { + pCurrentRun->UpdateOffsets(rInsertPosition, mrView.GetLayouter()); + } +} + + + + +SharedPageObjectRun InsertAnimator::Implementation::GetRun ( + view::Layouter& rLayouter, + const InsertPosition& rInsertPosition, + const bool bCreate) +{ + const sal_Int32 nRow (rInsertPosition.GetRow()); + if (nRow < 0) + return SharedPageObjectRun(); + + RunContainer::const_iterator iRun (maRuns.end()); + if (rLayouter.GetColumnCount() == 1) + { + // There is only one run that contains all slides. + if (maRuns.empty() && bCreate) + maRuns.insert(SharedPageObjectRun(new PageObjectRun( + *this, + 0, + 0, + mrModel.GetPageCount()-1))); + iRun = maRuns.begin(); + } + else + { + iRun = FindRun(nRow); + if (iRun == maRuns.end() && bCreate) + { + // Create a new run. + const sal_Int32 nStartIndex (rLayouter.GetIndex(nRow, 0)); + const sal_Int32 nEndIndex (rLayouter.GetIndex(nRow, rLayouter.GetColumnCount()-1)); + if (nStartIndex <= nEndIndex) + { + iRun = maRuns.insert(SharedPageObjectRun(new PageObjectRun( + *this, + nRow, + nStartIndex, + nEndIndex))).first; + OSL_ASSERT(iRun != maRuns.end()); + } + } + } + + if (iRun != maRuns.end()) + return *iRun; + else + return SharedPageObjectRun(); +} + + + + +InsertAnimator::Implementation::RunContainer::const_iterator + InsertAnimator::Implementation::FindRun (const sal_Int32 nRunIndex) const +{ + return std::find_if( + maRuns.begin(), + maRuns.end(), + ::boost::bind( + ::std::equal_to<sal_Int32>(), + ::boost::bind(&PageObjectRun::mnRunIndex, _1), + nRunIndex)); +} + + + + +void InsertAnimator::Implementation::AddRun (const ::boost::shared_ptr<PageObjectRun> pRun) +{ + if (pRun) + { + maRuns.insert(pRun); + } + else + { + OSL_ASSERT(pRun); + } +} + + + + + +void InsertAnimator::Implementation::RemoveRun (const ::boost::shared_ptr<PageObjectRun> pRun) +{ + if (pRun) + { + // Do not remove runs that show the space for the insertion indicator. + if (pRun->mnLocalInsertIndex == -1) + { + InsertAnimator::Implementation::RunContainer::const_iterator iRun (FindRun(pRun->mnRunIndex)); + if (iRun != maRuns.end()) + { + OSL_ASSERT(*iRun == pRun); + maRuns.erase(iRun); + } + } + } + else + { + OSL_ASSERT(pRun); + } +} + + + + + +//===== PageObjectRun ========================================================= + +PageObjectRun::PageObjectRun ( + AnimatorAccess& rAnimatorAccess, + const sal_Int32 nRunIndex, + const sal_Int32 nStartIndex, + const sal_Int32 nEndIndex) + : mnRunIndex(nRunIndex), + mnLocalInsertIndex(-1), + mnStartIndex(nStartIndex), + mnEndIndex(nEndIndex), + maStartOffset(), + maEndOffset(), + mnStartTime(-1), + mnAnimationId(controller::Animator::NotAnAnimationId), + mrAnimatorAccess(rAnimatorAccess), + maAccelerationFunction( + controller::AnimationParametricFunction( + controller::AnimationBezierFunction (0.1,0.7))) +{ + maStartOffset.resize(nEndIndex - nStartIndex + 1); + maEndOffset.resize(nEndIndex - nStartIndex + 1); +} + + + + +PageObjectRun::~PageObjectRun (void) +{ +} + + + + +Rectangle PageObjectRun::GetInnerBoundingBox ( + const view::Layouter& rLayouter, + const sal_Int32 nIndex) const +{ + model::SharedPageDescriptor pDescriptor ( + mrAnimatorAccess.GetModel().GetPageDescriptor(nIndex)); + if (pDescriptor) + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + return rLayouter.GetPageObjectLayouter()->GetBoundingBox( + pDescriptor, + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem); + else + return rLayouter.GetPageObjectLayouter()->GetBoundingBox( + pDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem); + else + return Rectangle(); +} + + + + +void PageObjectRun::UpdateOffsets( + const InsertPosition& rInsertPosition, + const view::Layouter& rLayouter) +{ + const bool bIsVertical (rLayouter.GetColumnCount()==1); + const sal_Int32 nLocalInsertIndex(bIsVertical + ? rInsertPosition.GetRow() + : rInsertPosition.GetColumn()); + if (nLocalInsertIndex != mnLocalInsertIndex) + { + mnLocalInsertIndex = nLocalInsertIndex; + + model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel()); + const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1); + for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex) + { + model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex)); + if (pDescriptor) + maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset(); + maEndOffset[nIndex] = nIndex < mnLocalInsertIndex + ? rInsertPosition.GetLeadingOffset() + : rInsertPosition.GetTrailingOffset(); + if (bIsVertical) + maEndOffset[nIndex].X() = 0; + else + maEndOffset[nIndex].Y() = 0; + } + RestartAnimation(); + } +} + + + + +void PageObjectRun::ResetOffsets (const controller::Animator::AnimationMode eMode) +{ + mnLocalInsertIndex = -1; + const sal_Int32 nRunLength (mnEndIndex - mnStartIndex + 1); + model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel()); + view::SlideSorterView& rView (mrAnimatorAccess.GetView()); + for (sal_Int32 nIndex=0; nIndex<nRunLength; ++nIndex) + { + model::SharedPageDescriptor pDescriptor(rModel.GetPageDescriptor(nIndex+mnStartIndex)); + if (pDescriptor) + { + if (eMode == controller::Animator::AM_Animated) + maStartOffset[nIndex] = pDescriptor->GetVisualState().GetLocationOffset(); + else + { + const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox()); + pDescriptor->GetVisualState().SetLocationOffset(Point(0,0)); + rView.RequestRepaint(aOldBoundingBox); + rView.RequestRepaint(pDescriptor); + } + } + maEndOffset[nIndex] = Point(0,0); + } + if (eMode == controller::Animator::AM_Animated) + RestartAnimation(); + else + mrAnimatorAccess.RemoveRun(shared_from_this()); +} + + + + +void PageObjectRun::RestartAnimation (void) +{ + // Stop the current animation. + if (mnAnimationId != controller::Animator::NotAnAnimationId) + { + mrAnimatorAccess.GetAnimator()->RemoveAnimation(mnAnimationId); + } + + // Restart the animation. + mrAnimatorAccess.AddRun(shared_from_this()); + mnAnimationId = mrAnimatorAccess.GetAnimator()->AddAnimation( + ::boost::ref(*this), + 0, + 300, + ::boost::bind( + &AnimatorAccess::RemoveRun, + ::boost::ref(mrAnimatorAccess), + shared_from_this())); +} + + + + +void PageObjectRun::operator () (const double nGlobalTime) +{ + if (mnStartTime < 0) + mnStartTime = nGlobalTime; + + double nLocalTime (nGlobalTime - mnStartTime); + if (nLocalTime > 1.0) + nLocalTime = 1.0; + nLocalTime = maAccelerationFunction(nLocalTime); + + model::SlideSorterModel& rModel (mrAnimatorAccess.GetModel()); + view::SlideSorterView& rView (mrAnimatorAccess.GetView()); + for (sal_Int32 nIndex=mnStartIndex; nIndex<=mnEndIndex; ++nIndex) + { + model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + continue; + const Rectangle aOldBoundingBox (pDescriptor->GetBoundingBox()); + pDescriptor->GetVisualState().SetLocationOffset( + Blend( + maStartOffset[nIndex-mnStartIndex], + maEndOffset[nIndex-mnStartIndex], + nLocalTime)); + + // Request a repaint of the old and new bounding box (which largely overlap.) + rView.RequestRepaint(aOldBoundingBox); + rView.RequestRepaint(pDescriptor); + } + + // Call Flush to make + // a) animations a bit more smooth and + // b) on Mac without the Flush a Reset of the page locations is not properly + // visualized when the mouse leaves the window during drag-and-drop. + mrAnimatorAccess.GetContentWindow()->Flush(); +} + + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx new file mode 100644 index 000000000000..abaa5a43b215 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx @@ -0,0 +1,448 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsInsertionIndicatorOverlay.hxx" + +#include "SlideSorter.hxx" +#include "model/SlsPageEnumeration.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsTheme.hxx" +#include "cache/SlsPageCache.hxx" +#include "SlsFramePainter.hxx" +#include "SlsLayeredDevice.hxx" +#include "DrawDocShell.hxx" +#include "drawdoc.hxx" +#include "sdpage.hxx" +#include "sdmod.hxx" + +#include <vcl/virdev.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + + +namespace { + + +static const double gnPreviewOffsetScale = 1.0 / 8.0; + + + +Rectangle GrowRectangle (const Rectangle& rBox, const sal_Int32 nOffset) +{ + return Rectangle ( + rBox.Left() - nOffset, + rBox.Top() - nOffset, + rBox.Right() + nOffset, + rBox.Bottom() + nOffset); +} + +sal_Int32 RoundToInt (const double nValue) { return sal_Int32(::rtl::math::round(nValue)); } + +} // end of anonymous namespace + + +namespace sd { namespace slidesorter { namespace view { + + +//===== InsertionIndicatorOverlay =========================================== + +const static sal_Int32 gnShadowBorder = 3; +const static sal_Int32 gnSuperScaleFactor = 1; + +InsertionIndicatorOverlay::InsertionIndicatorOverlay (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + mbIsVisible(false), + mnLayerIndex(2), + mpLayerInvalidator(), + maLocation(), + maIcon(), + maIconOffset(), + mpShadowPainter( + new FramePainter(mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_RawInsertShadow))) +{ +} + + + + +InsertionIndicatorOverlay::~InsertionIndicatorOverlay (void) +{ + Hide(); +} + + + + +void InsertionIndicatorOverlay::Create (const controller::Transferable* pTransferable) +{ + if (pTransferable == NULL) + return; + + sal_Int32 nSelectionCount (0); + if (pTransferable->HasPageBookmarks()) + nSelectionCount = pTransferable->GetPageBookmarks().Count(); + else + { + DrawDocShell* pDataDocShell = dynamic_cast<DrawDocShell*>(&pTransferable->GetDocShell()); + if (pDataDocShell != NULL) + { + SdDrawDocument* pDataDocument = pDataDocShell->GetDoc(); + if (pDataDocument != NULL) + nSelectionCount = pDataDocument->GetSdPageCount(PK_STANDARD); + } + } + Create(pTransferable->GetRepresentatives(), nSelectionCount); +} + + + + +void InsertionIndicatorOverlay::Create ( + const ::std::vector<controller::Transferable::Representative>& rRepresentatives, + const sal_Int32 nSelectionCount) +{ + view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter()); + ::boost::shared_ptr<view::PageObjectLayouter> pPageObjectLayouter ( + rLayouter.GetPageObjectLayouter()); + ::boost::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme()); + const Size aOriginalPreviewSize (pPageObjectLayouter->GetSize( + PageObjectLayouter::Preview, + PageObjectLayouter::WindowCoordinateSystem)); + + const double nPreviewScale (0.5); + const Size aPreviewSize ( + RoundToInt(aOriginalPreviewSize.Width()*nPreviewScale), + RoundToInt(aOriginalPreviewSize.Height()*nPreviewScale)); + const sal_Int32 nOffset ( + RoundToInt(Min(aPreviewSize.Width(),aPreviewSize.Height()) * gnPreviewOffsetScale)); + + // Determine size and offset depending on the number of previews. + sal_Int32 nCount (rRepresentatives.size()); + if (nCount > 0) + --nCount; + Size aIconSize( + aPreviewSize.Width() + 2 * gnShadowBorder + nCount*nOffset, + aPreviewSize.Height() + 2 * gnShadowBorder + nCount*nOffset); + maIconOffset = Point(gnShadowBorder, gnShadowBorder); + + // Create virtual devices for bitmap and mask whose bitmaps later be + // combined to form the BitmapEx of the icon. + VirtualDevice aContent ( + *mrSlideSorter.GetContentWindow(), + 0, + 0); + aContent.SetOutputSizePixel(aIconSize); + + aContent.SetFillColor(); + aContent.SetLineColor(pTheme->GetColor(Theme::Color_PreviewBorder)); + const Point aOffset = PaintRepresentatives(aContent, aPreviewSize, nOffset, rRepresentatives); + + PaintPageCount(aContent, nSelectionCount, aPreviewSize, aOffset); + + maIcon = aContent.GetBitmapEx(Point(0,0), aIconSize); + maIcon.Scale(aIconSize); +} + + + + +void InsertionIndicatorOverlay::SelectRepresentatives ( + model::PageEnumeration& rSelection, + ::std::vector<model::SharedPageDescriptor>& rDescriptors) const +{ + sal_Int32 nCount (0); + while (rSelection.HasMoreElements()) + { + if (nCount++ >= 3) + break; + rDescriptors.push_back(rSelection.GetNextElement()); + } +} + + + + +Point InsertionIndicatorOverlay::PaintRepresentatives ( + OutputDevice& rContent, + const Size aPreviewSize, + const sal_Int32 nOffset, + const ::std::vector<controller::Transferable::Representative>& rRepresentatives) const +{ + const Point aOffset (0,rRepresentatives.size()==1 ? -nOffset : 0); + + // Paint the pages. + Point aPageOffset (0,0); + double nTransparency (0); + const BitmapEx aExclusionOverlay (mrSlideSorter.GetTheme()->GetIcon(Theme::Icon_HideSlideOverlay)); + for (sal_Int32 nIndex=2; nIndex>=0; --nIndex) + { + if (rRepresentatives.size() <= sal_uInt32(nIndex)) + continue; + switch(nIndex) + { + case 0 : + aPageOffset = Point(0, nOffset); + nTransparency = 0.85; + break; + case 1: + aPageOffset = Point(nOffset, 0); + nTransparency = 0.75; + break; + case 2: + aPageOffset = Point(2*nOffset, 2*nOffset); + nTransparency = 0.65; + break; + } + aPageOffset += aOffset; + aPageOffset.X() += gnShadowBorder; + aPageOffset.Y() += gnShadowBorder; + + // Paint the preview. + Bitmap aPreview (rRepresentatives[nIndex].maBitmap); + const Size aSuperSampleSize( + aPreviewSize.Width()*gnSuperScaleFactor, + aPreviewSize.Height()*gnSuperScaleFactor); + aPreview.Scale(aPreviewSize, BMP_SCALE_INTERPOLATE); + rContent.DrawBitmapEx(aPageOffset, aPreview); + + // When the page is marked as excluded from the slide show then + // paint an overlay that visualizes this. + if (rRepresentatives[nIndex].mbIsExcluded) + { + const Region aSavedClipRegion (rContent.GetClipRegion()); + rContent.IntersectClipRegion(Rectangle(aPageOffset, aPreviewSize)); + // Paint bitmap tiled over the preview to mark it as excluded. + const sal_Int32 nIconWidth (aExclusionOverlay.GetSizePixel().Width()); + const sal_Int32 nIconHeight (aExclusionOverlay.GetSizePixel().Height()); + if (nIconWidth>0 && nIconHeight>0) + { + for (sal_Int32 nX=0; nX<aPreviewSize.Width(); nX+=nIconWidth) + for (sal_Int32 nY=0; nY<aPreviewSize.Height(); nY+=nIconHeight) + rContent.DrawBitmapEx(Point(nX,nY)+aPageOffset, aExclusionOverlay); + } + rContent.SetClipRegion(aSavedClipRegion); + } + + // Tone down the bitmap. The further back the darker it becomes. + Rectangle aBox ( + aPageOffset.X(), + aPageOffset.Y(), + aPageOffset.X()+aPreviewSize.Width()-1, + aPageOffset.Y()+aPreviewSize.Height()-1); + rContent.SetFillColor(COL_BLACK); + rContent.SetLineColor(); + rContent.DrawTransparent( + ::basegfx::B2DPolyPolygon(::basegfx::tools::createPolygonFromRect( + ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1), + 0, + 0)), + nTransparency); + + // Draw border around preview. + Rectangle aBorderBox (GrowRectangle(aBox, 1)); + rContent.SetLineColor(COL_GRAY); + rContent.SetFillColor(); + rContent.DrawRect(aBorderBox); + + // Draw shadow around preview. + mpShadowPainter->PaintFrame(rContent, aBorderBox); + } + + return aPageOffset; +} + + + + +void InsertionIndicatorOverlay::PaintPageCount ( + OutputDevice& rDevice, + const sal_Int32 nSelectionCount, + const Size aPreviewSize, + const Point aFirstPageOffset) const +{ + // Paint the number of slides. + ::boost::shared_ptr<view::Theme> pTheme (mrSlideSorter.GetTheme()); + ::boost::shared_ptr<Font> pFont(Theme::GetFont(Theme::Font_PageCount, rDevice)); + if (pFont) + { + ::rtl::OUString sNumber (::rtl::OUString::valueOf(nSelectionCount)); + + // Determine the size of the (painted) text and create a bounding + // box that centers the text on the first preview. + rDevice.SetFont(*pFont); + Rectangle aTextBox; + rDevice.GetTextBoundRect(aTextBox, sNumber); + Point aTextOffset (aTextBox.TopLeft()); + Size aTextSize (aTextBox.GetSize()); + // Place text inside the first page preview. + Point aTextLocation(aFirstPageOffset); + // Center the text. + aTextLocation += Point( + (aPreviewSize.Width()-aTextBox.GetWidth())/2, + (aPreviewSize.Height()-aTextBox.GetHeight())/2); + aTextBox = Rectangle(aTextLocation, aTextSize); + + // Paint background, border and text. + static const sal_Int32 nBorder = 5; + rDevice.SetFillColor(pTheme->GetColor(Theme::Color_Selection)); + rDevice.SetLineColor(pTheme->GetColor(Theme::Color_Selection)); + rDevice.DrawRect(GrowRectangle(aTextBox, nBorder)); + + rDevice.SetFillColor(); + rDevice.SetLineColor(pTheme->GetColor(Theme::Color_PageCountFontColor)); + rDevice.DrawRect(GrowRectangle(aTextBox, nBorder-1)); + + rDevice.SetTextColor(pTheme->GetColor(Theme::Color_PageCountFontColor)); + rDevice.DrawText(aTextBox.TopLeft()-aTextOffset, sNumber); + } +} + + + + +void InsertionIndicatorOverlay::SetLocation (const Point& rLocation) +{ + const Point aTopLeft ( + rLocation - Point( + maIcon.GetSizePixel().Width()/2, + maIcon.GetSizePixel().Height()/2)); + if (maLocation != aTopLeft) + { + const Rectangle aOldBoundingBox (GetBoundingBox()); + + maLocation = aTopLeft; + + if (mpLayerInvalidator && IsVisible()) + { + mpLayerInvalidator->Invalidate(aOldBoundingBox); + mpLayerInvalidator->Invalidate(GetBoundingBox()); + } + } +} + + + + +void InsertionIndicatorOverlay::Paint ( + OutputDevice& rDevice, + const Rectangle& rRepaintArea) +{ + (void)rRepaintArea; + + if ( ! IsVisible()) + return; + + rDevice.DrawImage(maLocation, maIcon); +} + + + + +void InsertionIndicatorOverlay::SetLayerInvalidator (const SharedILayerInvalidator& rpInvalidator) +{ + mpLayerInvalidator = rpInvalidator; + + if (mbIsVisible && mpLayerInvalidator) + mpLayerInvalidator->Invalidate(GetBoundingBox()); +} + + + + +bool InsertionIndicatorOverlay::IsVisible (void) const +{ + return mbIsVisible; +} + + + + +void InsertionIndicatorOverlay::Show (void) +{ + if ( ! mbIsVisible) + { + mbIsVisible = true; + + ::boost::shared_ptr<LayeredDevice> pLayeredDevice ( + mrSlideSorter.GetView().GetLayeredDevice()); + if (pLayeredDevice) + { + pLayeredDevice->RegisterPainter(shared_from_this(), mnLayerIndex); + if (mpLayerInvalidator) + mpLayerInvalidator->Invalidate(GetBoundingBox()); + } + } +} + + + + +void InsertionIndicatorOverlay::Hide (void) +{ + if (mbIsVisible) + { + mbIsVisible = false; + + ::boost::shared_ptr<LayeredDevice> pLayeredDevice ( + mrSlideSorter.GetView().GetLayeredDevice()); + if (pLayeredDevice) + { + if (mpLayerInvalidator) + mpLayerInvalidator->Invalidate(GetBoundingBox()); + pLayeredDevice->RemovePainter(shared_from_this(), mnLayerIndex); + } + } +} + + + + +Rectangle InsertionIndicatorOverlay::GetBoundingBox (void) const +{ + return Rectangle(maLocation, maIcon.GetSizePixel()); +} + + + + +Size InsertionIndicatorOverlay::GetSize (void) const +{ + return Size( + maIcon.GetSizePixel().Width() + 10, + maIcon.GetSizePixel().Height() + 10); +} + + + +} } } // end of namespace ::sd::slidesorter::view + diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx new file mode 100644 index 000000000000..e3303278111f --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.cxx @@ -0,0 +1,565 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsLayeredDevice.hxx" + +#include <vcl/window.hxx> +#include <vcl/virdev.hxx> + +#include <boost/bind.hpp> +#include <boost/function.hpp> + + +namespace sd { namespace slidesorter { namespace view { + +namespace { +static const sal_Int32 gnMaximumLayerCount = 8; + +class LayerInvalidator : public ILayerInvalidator +{ +public: + LayerInvalidator ( + const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice, + const SharedSdWindow& rpTargetWindow, + const int nLayer) + : mpLayeredDevice(rpLayeredDevice), + mpTargetWindow(rpTargetWindow), + mnLayer(nLayer) + { + } + + virtual void Invalidate (const Rectangle& rInvalidationBox) + { + mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer); + mpTargetWindow->Invalidate(rInvalidationBox); + } + +private: + const ::boost::shared_ptr<LayeredDevice> mpLayeredDevice; + SharedSdWindow mpTargetWindow; + const int mnLayer; +}; + +void DeviceCopy ( + OutputDevice& rTargetDevice, + OutputDevice& rSourceDevice, + const Rectangle& rBox) +{ + rTargetDevice.DrawOutDev( + rBox.TopLeft(), + rBox.GetSize(), + rBox.TopLeft(), + rBox.GetSize(), + rSourceDevice); +} + + +void ForAllRectangles (const Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction) +{ + OSL_ASSERT(aFunction); + + if (rRegion.GetRectCount() <= 1) + { + aFunction(rRegion.GetBoundRect()); + } + else + { + Region aMutableRegionCopy (rRegion); + RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects()); + Rectangle aBox; + while (aMutableRegionCopy.GetNextEnumRect(aHandle, aBox)) + aFunction(aBox); + aMutableRegionCopy.EndEnumRects(aHandle); + } +} + +class Layer : private ::boost::noncopyable +{ +public: + Layer (void); + ~Layer (void); + + void Initialize (const SharedSdWindow& rpTargetWindow); + void InvalidateRectangle (const Rectangle& rInvalidationBox); + void InvalidateRegion (const Region& rInvalidationRegion); + void Validate (const MapMode& rMapMode); + void Repaint ( + OutputDevice& rTargetDevice, + const Rectangle& rRepaintRectangle); + void Resize (const Size& rSize); + void AddPainter (const SharedILayerPainter& rpPainter); + void RemovePainter (const SharedILayerPainter& rpPainter); + bool HasPainter (void) const; + void Dispose (void); + +private: + ::boost::shared_ptr<VirtualDevice> mpLayerDevice; + ::std::vector<SharedILayerPainter> maPainters; + Region maInvalidationRegion; + + void ValidateRectangle (const Rectangle& rBox); +}; +typedef ::boost::shared_ptr<Layer> SharedLayer; + + +} // end of anonymous namespace + + +class LayeredDevice::LayerContainer : public ::std::vector<SharedLayer> +{ +public: + LayerContainer (void) {} + ~LayerContainer (void) {} +}; + + + + +//===== LayeredDevice ========================================================= + +LayeredDevice::LayeredDevice (const SharedSdWindow& rpTargetWindow) + : mpTargetWindow(rpTargetWindow), + mpLayers(new LayerContainer()), + mpBackBuffer(new VirtualDevice(*mpTargetWindow)), + maSavedMapMode(rpTargetWindow->GetMapMode()) +{ + mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel()); +} + + + + +LayeredDevice::~LayeredDevice (void) +{ +} + + + + +void LayeredDevice::Invalidate ( + const Rectangle& rInvalidationArea, + const sal_Int32 nLayer) +{ + if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) + { + OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); + return; + } + + (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); +} + + + + +void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea) +{ + for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) + (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea); +} + + + + +void LayeredDevice::InvalidateAllLayers (const Region& rInvalidationRegion) +{ + for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer) + (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion); +} + + + + +void LayeredDevice::RegisterPainter ( + const SharedILayerPainter& rpPainter, + const sal_Int32 nLayer) +{ + OSL_ASSERT(mpLayers); + if ( ! rpPainter) + { + OSL_ASSERT(rpPainter); + return; + } + if (nLayer<0 || nLayer>=gnMaximumLayerCount) + { + OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount); + return; + } + + // Provide the layers. + if (sal_uInt32(nLayer) >= mpLayers->size()) + { + const sal_Int32 nOldLayerCount (mpLayers->size()); + mpLayers->resize(nLayer+1); + + for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex) + (*mpLayers)[nIndex].reset(new Layer()); + } + + (*mpLayers)[nLayer]->AddPainter(rpPainter); + if (nLayer == 0) + (*mpLayers)[nLayer]->Initialize(mpTargetWindow); + + rpPainter->SetLayerInvalidator( + SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow,nLayer))); +} + + + + +void LayeredDevice::RemovePainter ( + const SharedILayerPainter& rpPainter, + const sal_Int32 nLayer) +{ + if ( ! rpPainter) + { + OSL_ASSERT(rpPainter); + return; + } + if (nLayer<0 || size_t(nLayer)>=mpLayers->size()) + { + OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size()); + return; + } + + rpPainter->SetLayerInvalidator(SharedILayerInvalidator()); + + (*mpLayers)[nLayer]->RemovePainter(rpPainter); + + // Remove top most layers that do not contain any painters. + while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter()) + mpLayers->erase(mpLayers->end()-1); +} + + + + +bool LayeredDevice::HasPainter (const sal_Int32 nLayer) +{ + return nLayer>=0 + && sal_uInt32(nLayer)<mpLayers->size() + && (*mpLayers)[nLayer]->HasPainter(); +} + + + + +void LayeredDevice::Repaint (const Region& rRepaintRegion) +{ + // Validate the contents of all layers (that have their own devices.) + ::std::for_each( + mpLayers->begin(), + mpLayers->end(), + ::boost::bind(&Layer::Validate, _1, mpTargetWindow->GetMapMode())); + + ForAllRectangles(rRepaintRegion, ::boost::bind(&LayeredDevice::RepaintRectangle, this, _1)); +} + + + + +void LayeredDevice::RepaintRectangle (const Rectangle& rRepaintRectangle) +{ + if (mpLayers->size() == 0) + return; + else if (mpLayers->size() == 1) + { + // Just copy the main layer into the target device. + (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle); + } + else + { + // Paint all layers first into the back buffer (to avoid flickering + // due to synchronous paints) and then copy that into the target + // device. + mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode()); + ::std::for_each( + mpLayers->begin(), + mpLayers->end(), + ::boost::bind(&Layer::Repaint, _1, ::boost::ref(*mpBackBuffer), rRepaintRectangle)); + + DeviceCopy(*mpTargetWindow, *mpBackBuffer, rRepaintRectangle); + } +} + + + + +void LayeredDevice::Resize (void) +{ + const Size aSize (mpTargetWindow->GetSizePixel()); + mpBackBuffer->SetOutputSizePixel(aSize); + ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Resize, _1, aSize)); +} + + + + +void LayeredDevice::Dispose (void) +{ + ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Dispose, _1)); + mpLayers->clear(); +} + + + + +bool LayeredDevice::HandleMapModeChange (void) +{ + const MapMode& rMapMode (mpTargetWindow->GetMapMode()); + if (maSavedMapMode == rMapMode) + return false; + + const Rectangle aLogicWindowBox ( + mpTargetWindow->PixelToLogic(Rectangle(Point(0,0), mpTargetWindow->GetSizePixel()))); + if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX() + || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY() + || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit()) + { + // When the scale has changed then we have to paint everything. + InvalidateAllLayers(aLogicWindowBox); + } + else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin()) + { + // Window has been scrolled. Adapt contents of backbuffers and + // layer devices. + const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin()); + mpBackBuffer->CopyArea( + aLogicWindowBox.TopLeft(), + mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode), + aLogicWindowBox.GetSize()); + + // Invalidate the area(s) that have been exposed. + const Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel()); + if (aDelta.Y() < 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Bottom()+aDelta.Y(), + aWindowBox.Right(), + aWindowBox.Bottom()))); + else if (aDelta.Y() > 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Top(), + aWindowBox.Right(), + aWindowBox.Top()+aDelta.Y()))); + if (aDelta.X() < 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Right()+aDelta.X(), + aWindowBox.Top(), + aWindowBox.Right(), + aWindowBox.Bottom()))); + else if (aDelta.X() > 0) + InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle( + aWindowBox.Left(), + aWindowBox.Top(), + aWindowBox.Left()+aDelta.X(), + aWindowBox.Bottom()))); + } + else + { + // Can this happen? Lets trigger a warning when it does. + OSL_ASSERT(false); + } + + maSavedMapMode = rMapMode; + + return true; +} + + + + +//===== Layer ================================================================= + +Layer::Layer (void) + : mpLayerDevice(), + maPainters(), + maInvalidationRegion() +{ +} + + + + +Layer::~Layer (void) +{ +} + + + + +void Layer::Initialize (const SharedSdWindow& rpTargetWindow) +{ +#if 0 + (void)rpTargetWindow; +#else + if ( ! mpLayerDevice) + { + mpLayerDevice.reset(new VirtualDevice(*rpTargetWindow)); + mpLayerDevice->SetOutputSizePixel(rpTargetWindow->GetSizePixel()); + } +#endif +} + + + + +void Layer::InvalidateRectangle (const Rectangle& rInvalidationBox) +{ + maInvalidationRegion.Union(rInvalidationBox); +} + + + + +void Layer::InvalidateRegion (const Region& rInvalidationRegion) +{ + maInvalidationRegion.Union(rInvalidationRegion); +} + + + + +void Layer::Validate (const MapMode& rMapMode) +{ + if (mpLayerDevice && ! maInvalidationRegion.IsEmpty()) + { + Region aRegion (maInvalidationRegion); + maInvalidationRegion.SetEmpty(); + + mpLayerDevice->SetMapMode(rMapMode); + ForAllRectangles( + aRegion, + ::boost::bind(&Layer::ValidateRectangle, this, _1)); + } +} + + + + +void Layer::ValidateRectangle (const Rectangle& rBox) +{ + if ( ! mpLayerDevice) + return; + const Region aSavedClipRegion (mpLayerDevice->GetClipRegion()); + mpLayerDevice->IntersectClipRegion(rBox); + + for (::std::vector<SharedILayerPainter>::const_iterator + iPainter(maPainters.begin()), + iEnd(maPainters.end()); + iPainter!=iEnd; + ++iPainter) + { + (*iPainter)->Paint(*mpLayerDevice, rBox); + } + + mpLayerDevice->SetClipRegion(aSavedClipRegion); +} + + + + +void Layer::Repaint ( + OutputDevice& rTargetDevice, + const Rectangle& rRepaintRectangle) +{ + if (mpLayerDevice) + { + DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle); + } + else + { + ::std::for_each( + maPainters.begin(), + maPainters.end(), + ::boost::bind(&ILayerPainter::Paint, + _1, + ::boost::ref(rTargetDevice), + rRepaintRectangle)); + } +} + + + + +void Layer::Resize (const Size& rSize) +{ + if (mpLayerDevice) + { + mpLayerDevice->SetOutputSizePixel(rSize); + maInvalidationRegion = Rectangle(Point(0,0), rSize); + } +} + + + + +void Layer::AddPainter (const SharedILayerPainter& rpPainter) +{ + OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end()); + + maPainters.push_back(rpPainter); +} + + + + +void Layer::RemovePainter (const SharedILayerPainter& rpPainter) +{ + const ::std::vector<SharedILayerPainter>::iterator iPainter ( + ::std::find(maPainters.begin(), maPainters.end(), rpPainter)); + if (iPainter != maPainters.end()) + { + maPainters.erase(iPainter); + } + else + { + DBG_ASSERT(false,"LayeredDevice::RemovePainter called for painter that is not registered"); + } +} + + + + +bool Layer::HasPainter (void) const +{ + return !maPainters.empty(); +} + + + + +void Layer::Dispose (void) +{ + maPainters.clear(); +} + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx b/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx new file mode 100644 index 000000000000..8b2398221548 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayeredDevice.hxx @@ -0,0 +1,99 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_VIEW_LAYERED_DEVICE_HXX +#define SD_SLIDESORTER_VIEW_LAYERED_DEVICE_HXX + +#include "view/SlsILayerPainter.hxx" +#include "SlideSorter.hxx" + +#include <tools/gen.hxx> +#include <vcl/region.hxx> +#include <vcl/virdev.hxx> + +#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <vector> + +class Window; + +namespace sd { namespace slidesorter { namespace view { + +/** A simple wrapper around an OutputDevice that provides support for + independent layers and buffering. + Each layer may contain any number of painters. +*/ +class LayeredDevice + : public ::boost::enable_shared_from_this<LayeredDevice> + +{ +public: + LayeredDevice (const SharedSdWindow& rpTargetWindow); + ~LayeredDevice (void); + + void Invalidate ( + const Rectangle& rInvalidationBox, + const sal_Int32 nLayer); + void InvalidateAllLayers ( + const Rectangle& rInvalidationBox); + void InvalidateAllLayers ( + const Region& rInvalidationRegion); + + void RegisterPainter ( + const SharedILayerPainter& rPainter, + const sal_Int32 nLayer); + + void RemovePainter ( + const SharedILayerPainter& rPainter, + const sal_Int32 nLayer); + + bool HasPainter (const sal_Int32 nLayer); + + bool HandleMapModeChange (void); + void Repaint (const Region& rRepaintRegion); + + void Resize (void); + + void Dispose (void); + +private: + SharedSdWindow mpTargetWindow; + class LayerContainer; + ::boost::scoped_ptr<LayerContainer> mpLayers; + ::boost::scoped_ptr<VirtualDevice> mpBackBuffer; + MapMode maSavedMapMode; + + void RepaintRectangle (const Rectangle& rRepaintRectangle); +}; + + + +} } } // end of namespace ::sd::slidesorter::view + +#endif diff --git a/sd/source/ui/slidesorter/view/SlsLayouter.cxx b/sd/source/ui/slidesorter/view/SlsLayouter.cxx new file mode 100644 index 000000000000..66f22097993a --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsLayouter.cxx @@ -0,0 +1,1555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsLayouter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "Window.hxx" +#include <rtl/math.hxx> +#include <basegfx/numeric/ftools.hxx> + +namespace { + sal_Int32 RoundToInt (const double nValue) + { + return sal_Int32(::rtl::math::round(nValue)); + } +} + + +namespace sd { namespace slidesorter { namespace view { + +class Layouter::Implementation +{ +public: + SharedSdWindow mpWindow; + sal_Int32 mnRequestedLeftBorder; + sal_Int32 mnRequestedRightBorder; + sal_Int32 mnRequestedTopBorder; + sal_Int32 mnRequestedBottomBorder; + sal_Int32 mnLeftBorder; + sal_Int32 mnRightBorder; + sal_Int32 mnTopBorder; + sal_Int32 mnBottomBorder; + sal_Int32 mnVerticalGap; + sal_Int32 mnHorizontalGap; + Size maMinimalSize; + Size maPreferredSize; + Size maMaximalSize; + sal_Int32 mnMinimalColumnCount; + sal_Int32 mnMaximalColumnCount; + sal_Int32 mnPageCount; + sal_Int32 mnColumnCount; + sal_Int32 mnRowCount; + /// The maximum number of columns. Can only be larger than the current + /// number of columns when there are not enough pages to fill all + /// available columns. + sal_Int32 mnMaxColumnCount; + /// The maximum number of rows. Can only be larger than the current + /// number of rows when there are not enough pages to fill all available + /// rows. + sal_Int32 mnMaxRowCount; + Size maPageObjectSize; + ::boost::shared_ptr<PageObjectLayouter> mpPageObjectLayouter; + ::boost::shared_ptr<view::Theme> mpTheme; + + /** Specify how the gap between two page objects is associated with the + page objects. + */ + enum GapMembership { + GM_NONE, // Gap is not associated with any page object. + GM_PREVIOUS, // The whole gap is associated with the previous page + // object (left or above the gap.) + GM_BOTH, // Half of the gap is associated with previous, half + // with the next page object. + GM_NEXT, // The whole gap is associated with the next page + // object (right or below the gap.) + GM_PAGE_BORDER + }; + + static Implementation* Create ( + const Implementation& rImplementation, + const Layouter::Orientation eOrientation); + + virtual Layouter::Orientation GetOrientation (void) const = 0; + + bool Rearrange ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const sal_uInt32 nPageCount); + + /** 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. + */ + 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 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 nGap) const; + + /** Calculate the logical part of the insert position, i.e. the page + after whicht to insert. + */ + virtual void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const = 0; + + /** Calculate the geometrical part of the insert position, i.e. the + location of where to display the insertion indicator and the + distances about which the leading and trailing pages have to be + moved to make room for the indicator. + */ + void CalculateGeometricPosition ( + InsertPosition& rPosition, + const Size& rIndicatorSize, + const bool bIsVertical, + model::SlideSorterModel& rModel) const; + + /** Return the bounding box of the preview or, when selected, of the page + object. Thus, it returns something like a visual bounding box. + */ + Rectangle GetInnerBoundingBox ( + model::SlideSorterModel& rModel, + const sal_Int32 nIndex) const; + + Range GetValidHorizontalSizeRange (void) const; + Range GetValidVerticalSizeRange (void) const; + + Range GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const; + sal_Int32 GetIndex ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const bool bClampToValidRange) const; + + Rectangle GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap = false) const; + + Rectangle GetPageObjectBox ( + const sal_Int32 nRow, + const sal_Int32 nColumn) const; + + Rectangle AddBorderAndGap ( + const Rectangle& rBoundingBox, + const sal_Int32 nRow, + const sal_Int32 nColumn) const; + + Rectangle GetTotalBoundingBox (void) const; + + virtual ~Implementation (void); + +protected: + Implementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + Implementation (const Implementation& rImplementation); + + virtual void CalculateRowAndColumnCount (const Size& rWindowSize) = 0; + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize) = 0; + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const = 0; + Size GetTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const bool bCalculateWidth, + const bool bCalculateHeight) const; + void CalculateVerticalLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; +}; + + +/** The vertical layouter has one column and as many rows as there are + pages. +*/ +class VerticalImplementation : public Layouter::Implementation +{ +public: + VerticalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + VerticalImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + +/** The horizontal layouter has one row and as many columns as there are + pages. +*/ +class HorizontalImplementation : public Layouter::Implementation +{ +public: + HorizontalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + HorizontalImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + +/** The number of columns of the grid layouter is defined via a control in + the slide sorter tool bar. The number of rows is calculated from the + number of columns and the number of pages. +*/ +class GridImplementation : public Layouter::Implementation +{ +public: + GridImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme); + GridImplementation (const Implementation& rImplementation); + + virtual Layouter::Orientation GetOrientation (void) const; + + void CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const; + +protected: + virtual void CalculateRowAndColumnCount (const Size& rWindowSize); + virtual void CalculateMaxRowAndColumnCount (const Size& rWindowSize); + virtual Size CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const; +}; + + + + +//===== Layouter ============================================================== + +Layouter::Layouter ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<Theme>& rpTheme) + : mpImplementation(new GridImplementation(rpWindow, rpTheme)), + mpWindow(rpWindow) +{ +} + + + + +Layouter::~Layouter (void) +{ +} + + + + +::boost::shared_ptr<PageObjectLayouter> Layouter::GetPageObjectLayouter (void) const +{ + return mpImplementation->mpPageObjectLayouter; +} + + + + +void Layouter::SetBorders ( + sal_Int32 nLeftBorder, + sal_Int32 nRightBorder, + sal_Int32 nTopBorder, + sal_Int32 nBottomBorder) +{ + if (nLeftBorder >= 0) + mpImplementation->mnRequestedLeftBorder = nLeftBorder; + if (nRightBorder >= 0) + mpImplementation->mnRequestedRightBorder = nRightBorder; + if (nTopBorder >= 0) + mpImplementation->mnRequestedTopBorder = nTopBorder; + if (nBottomBorder >= 0) + mpImplementation->mnRequestedBottomBorder = nBottomBorder; +} + + + + +void Layouter::SetColumnCount ( + sal_Int32 nMinimalColumnCount, + sal_Int32 nMaximalColumnCount) +{ + if (nMinimalColumnCount <= nMaximalColumnCount) + { + mpImplementation->mnMinimalColumnCount = nMinimalColumnCount; + mpImplementation->mnMaximalColumnCount = nMaximalColumnCount; + } +} + + + + +bool Layouter::Rearrange ( + const Orientation eOrientation, + const Size& rWindowSize, + const Size& rPageSize, + const sal_uInt32 nPageCount) +{ + OSL_ASSERT(mpWindow); + + if (eOrientation != mpImplementation->GetOrientation()) + mpImplementation.reset(Implementation::Create(*mpImplementation, eOrientation)); + + return mpImplementation->Rearrange(rWindowSize, rPageSize, nPageCount); +} + + + + +void Layouter::_SetZoom (double nZoomFactor) +{ + _SetZoom(Fraction(nZoomFactor)); +} + + + + +void Layouter::_SetZoom (Fraction nZoomFactor) +{ + OSL_ASSERT(mpWindow); + + MapMode aMapMode (mpWindow->GetMapMode()); + aMapMode.SetScaleX (nZoomFactor); + aMapMode.SetScaleY (nZoomFactor); + mpWindow->SetMapMode (aMapMode); +} + + + + +sal_Int32 Layouter::GetColumnCount (void) const +{ + return mpImplementation->mnColumnCount; +} + + + + +sal_Int32 Layouter::GetRowCount (void) const +{ + return mpImplementation->mnRowCount; +} + + + + +sal_Int32 Layouter::GetRow (const sal_Int32 nIndex) const +{ + return nIndex / mpImplementation->mnColumnCount; +} + + + + +sal_Int32 Layouter::GetColumn (const sal_Int32 nIndex) const +{ + return nIndex % mpImplementation->mnColumnCount; +} + + + + +sal_Int32 Layouter::GetIndex (const sal_Int32 nRow, const sal_Int32 nColumn) const +{ + return mpImplementation->GetIndex(nRow,nColumn,true); +} + + + + +Size Layouter::GetPageObjectSize (void) const +{ + return mpImplementation->maPageObjectSize; +} + + + + +Rectangle Layouter::GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap) const +{ + return mpImplementation->GetPageObjectBox(nIndex, bIncludeBorderAndGap); +} + + + + +Rectangle Layouter::GetTotalBoundingBox (void) const +{ + return mpImplementation->GetTotalBoundingBox(); +} + + + + +InsertPosition Layouter::GetInsertPosition ( + const Point& rModelPosition, + const Size& rIndicatorSize, + model::SlideSorterModel& rModel) const +{ + InsertPosition aPosition; + mpImplementation->CalculateLogicalInsertPosition( + rModelPosition, + aPosition); + mpImplementation->CalculateGeometricPosition( + aPosition, + rIndicatorSize, + GetColumnCount()==1, + rModel); + return aPosition; +} + + + + +Range Layouter::GetValidHorizontalSizeRange (void) const +{ + return mpImplementation->GetValidHorizontalSizeRange(); +} + + + + +Range Layouter::GetValidVerticalSizeRange (void) const +{ + return mpImplementation->GetValidVerticalSizeRange(); +} + + + + +Range Layouter::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const +{ + return mpImplementation->GetRangeOfVisiblePageObjects(aVisibleArea); +} + + + + +sal_Int32 Layouter::GetIndexAtPoint ( + const Point& rPosition, + const bool bIncludePageBorders, + const bool bClampToValidRange) const +{ + const sal_Int32 nRow ( + mpImplementation->GetRowAtPosition ( + rPosition.Y(), + bIncludePageBorders, + bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE)); + const sal_Int32 nColumn ( + mpImplementation->GetColumnAtPosition ( + rPosition.X(), + bIncludePageBorders, + bIncludePageBorders ? Implementation::GM_PAGE_BORDER : Implementation::GM_NONE)); + + return mpImplementation->GetIndex(nRow,nColumn,bClampToValidRange); +} + + + + +//===== Layouter::Implementation ============================================== + +Layouter::Implementation* Layouter::Implementation::Create ( + const Implementation& rImplementation, + const Layouter::Orientation eOrientation) +{ + switch (eOrientation) + { + case HORIZONTAL: return new HorizontalImplementation(rImplementation); + case VERTICAL: return new VerticalImplementation(rImplementation); + case GRID: + default: return new GridImplementation(rImplementation); + } +} + + + + +Layouter::Implementation::Implementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : mpWindow(rpWindow), + mnRequestedLeftBorder(5), + mnRequestedRightBorder(5), + mnRequestedTopBorder(5), + mnRequestedBottomBorder(5), + mnLeftBorder(5), + mnRightBorder(5), + mnTopBorder(5), + mnBottomBorder(5), + mnVerticalGap (10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)), + mnHorizontalGap(10 - 2*rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)), + maMinimalSize(132,98), + maPreferredSize(200,150), + maMaximalSize(300,200), + mnMinimalColumnCount(1), + mnMaximalColumnCount(15), + mnPageCount(0), + mnColumnCount(1), + mnRowCount(0), + mnMaxColumnCount(0), + mnMaxRowCount(0), + maPageObjectSize(1,1), + mpPageObjectLayouter(), + mpTheme(rpTheme) +{ +} + + + + +Layouter::Implementation::Implementation (const Implementation& rImplementation) + : mpWindow(rImplementation.mpWindow), + mnRequestedLeftBorder(rImplementation.mnRequestedLeftBorder), + mnRequestedRightBorder(rImplementation.mnRequestedRightBorder), + mnRequestedTopBorder(rImplementation.mnRequestedTopBorder), + mnRequestedBottomBorder(rImplementation.mnRequestedBottomBorder), + mnLeftBorder(rImplementation.mnLeftBorder), + mnRightBorder(rImplementation.mnRightBorder), + mnTopBorder(rImplementation.mnTopBorder), + mnBottomBorder(rImplementation.mnBottomBorder), + mnVerticalGap(rImplementation.mnVerticalGap), + mnHorizontalGap(rImplementation.mnHorizontalGap), + maMinimalSize(rImplementation.maMinimalSize), + maPreferredSize(rImplementation.maPreferredSize), + maMaximalSize(rImplementation.maMaximalSize), + mnMinimalColumnCount(rImplementation.mnMinimalColumnCount), + mnMaximalColumnCount(rImplementation.mnMaximalColumnCount), + mnPageCount(rImplementation.mnPageCount), + mnColumnCount(rImplementation.mnColumnCount), + mnRowCount(rImplementation.mnRowCount), + mnMaxColumnCount(rImplementation.mnMaxColumnCount), + mnMaxRowCount(rImplementation.mnMaxRowCount), + maPageObjectSize(rImplementation.maPageObjectSize), + mpPageObjectLayouter(), + mpTheme(rImplementation.mpTheme) +{ +} + + + + +Layouter::Implementation::~Implementation (void) +{ +} + + + + +bool Layouter::Implementation::Rearrange ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const sal_uInt32 nPageCount) +{ + mnPageCount = nPageCount; + + // Return early when the window or the model have not yet been initialized. + if (rWindowSize.Width()<=0 || rWindowSize.Height()<=0) + return false; + if (rPreviewModelSize.Width()<=0 || rPreviewModelSize.Height()<=0) + return false; + + CalculateRowAndColumnCount(rWindowSize); + + // Update the border values. + mnLeftBorder = mnRequestedLeftBorder; + mnTopBorder = mnRequestedTopBorder; + mnRightBorder = mnRequestedRightBorder; + mnBottomBorder = mnRequestedBottomBorder; + if (mnColumnCount > 1) + { + int nMinimumBorderWidth = mnHorizontalGap/2; + if (mnLeftBorder < nMinimumBorderWidth) + mnLeftBorder = nMinimumBorderWidth; + if (mnRightBorder < nMinimumBorderWidth) + mnRightBorder = nMinimumBorderWidth; + } + else + { + int nMinimumBorderHeight = mnVerticalGap/2; + if (mnTopBorder < nMinimumBorderHeight) + mnTopBorder = nMinimumBorderHeight; + if (mnBottomBorder < nMinimumBorderHeight) + mnBottomBorder = nMinimumBorderHeight; + } + + mpPageObjectLayouter.reset( + new PageObjectLayouter( + mpTheme, + CalculateTargetSize(rWindowSize, rPreviewModelSize), + rPreviewModelSize, + mpWindow, + mnPageCount)); + maPageObjectSize = mpPageObjectLayouter->GetSize( + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::WindowCoordinateSystem); + + CalculateMaxRowAndColumnCount(rWindowSize); + + return true; +} + + + + +sal_Int32 Layouter::Implementation::GetRowAtPosition ( + sal_Int32 nYPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership) const +{ + sal_Int32 nRow = -1; + + const sal_Int32 nY = nYPosition - mnTopBorder; + if (nY >= 0) + { + // Vertical distance from one row to the next. + const sal_Int32 nRowOffset (maPageObjectSize.Height() + mnVerticalGap); + + // Calculate row consisting of page objects and gap below. + nRow = nY / nRowOffset; + + const sal_Int32 nDistanceIntoGap ((nY - nRow*nRowOffset) - maPageObjectSize.Height()); + // When inside the gap below then nYPosition is not over a page + // object. + if (nDistanceIntoGap > 0) + nRow = ResolvePositionInGap ( + nDistanceIntoGap, + eGapMembership, + nRow, + mnVerticalGap); + } + 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::Implementation::GetColumnAtPosition ( + sal_Int32 nXPosition, + bool bIncludeBordersAndGaps, + GapMembership eGapMembership) const +{ + sal_Int32 nColumn = -1; + + sal_Int32 nX = nXPosition - mnLeftBorder; + if (nX >= 0) + { + // Horizontal distance from one column to the next. + const sal_Int32 nColumnOffset (maPageObjectSize.Width() + mnHorizontalGap); + + // 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) - maPageObjectSize.Width()); + // When inside the gap at the right then nXPosition is not over a + // page object. + if (nDistanceIntoGap > 0) + nColumn = ResolvePositionInGap ( + nDistanceIntoGap, + eGapMembership, + nColumn, + mnHorizontalGap); + } + 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::Implementation::ResolvePositionInGap ( + sal_Int32 nDistanceIntoGap, + GapMembership eGapMembership, + sal_Int32 nIndex, + 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 = 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 > 0) + { + if (nDistanceIntoGap > 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; +} + + + + +void Layouter::Implementation::CalculateGeometricPosition ( + InsertPosition& rPosition, + const Size& rIndicatorSize, + const bool bIsVertical, + model::SlideSorterModel& rModel) const +{ + // 1. Determine right/bottom of the leading page and the left/top of the + // trailing page object and how to distribute the missing space. + sal_Int32 nLeadingLocation (0); + sal_Int32 nTrailingLocation (0); + bool bIsLeadingFixed (false); + bool bIsTrailingFixed (false); + sal_Int32 nSecondaryLocation (0); + const sal_Int32 nIndex (rPosition.GetIndex()); + + if (rPosition.IsAtRunStart()) + { + // Place indicator at the top of the column. + const Rectangle aOuterBox (GetPageObjectBox(nIndex)); + const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex)); + if (bIsVertical) + { + nLeadingLocation = aOuterBox.Top(); + nTrailingLocation = aInnerBox.Top(); + nSecondaryLocation = aInnerBox.Center().X(); + } + else + { + nLeadingLocation = aOuterBox.Left(); + nTrailingLocation = aInnerBox.Left(); + nSecondaryLocation = aInnerBox.Center().Y(); + } + bIsLeadingFixed = true; + } + else if (rPosition.IsAtRunEnd()) + { + // Place indicator at the bottom/right of the column/row. + + const Rectangle aOuterBox (GetPageObjectBox(nIndex-1)); + const Rectangle aInnerBox (GetInnerBoundingBox(rModel, nIndex-1)); + if (bIsVertical) + { + nLeadingLocation = aInnerBox.Bottom(); + nTrailingLocation = aOuterBox.Bottom(); + nSecondaryLocation = aInnerBox.Center().X(); + } + else + { + nLeadingLocation = aInnerBox.Right(); + nTrailingLocation = aOuterBox.Right(); + nSecondaryLocation = aInnerBox.Center().Y(); + } + bIsTrailingFixed = true; + if ( ! rPosition.IsExtraSpaceNeeded()) + bIsLeadingFixed = true; + } + else + { + // Place indicator between two rows/columns. + const Rectangle aBox1 (GetInnerBoundingBox(rModel, nIndex-1)); + const Rectangle aBox2 (GetInnerBoundingBox(rModel, nIndex)); + if (bIsVertical) + { + nLeadingLocation = aBox1.Bottom(); + nTrailingLocation = aBox2.Top(); + nSecondaryLocation = (aBox1.Center().X() + aBox2.Center().X()) / 2; + } + else + { + nLeadingLocation = aBox1.Right(); + nTrailingLocation = aBox2.Left(); + nSecondaryLocation = (aBox1.Center().Y() + aBox2.Center().Y()) / 2; + } + } + + // 2. Calculate the location of the insert indicator and the offsets of + // leading and trailing pages. + const sal_Int32 nAvailableSpace (nTrailingLocation - nLeadingLocation); + const sal_Int32 nRequiredSpace (bIsVertical ? rIndicatorSize.Height():rIndicatorSize.Width()); + const sal_Int32 nMissingSpace (::std::max(sal_Int32(0), nRequiredSpace - nAvailableSpace)); + sal_Int32 nPrimaryLocation (0); + sal_Int32 nLeadingOffset (0); + sal_Int32 nTrailingOffset (0); + if (bIsLeadingFixed) + { + nPrimaryLocation = nLeadingLocation + nRequiredSpace/2; + if ( ! bIsTrailingFixed) + nTrailingOffset = nMissingSpace; + } + else if (bIsTrailingFixed) + { + nPrimaryLocation = nTrailingLocation - nRequiredSpace/2; + nLeadingOffset = -nMissingSpace; + } + else + { + nPrimaryLocation = (nLeadingLocation + nTrailingLocation) /2; + nLeadingOffset = -nMissingSpace/2; + nTrailingOffset = nMissingSpace + nLeadingOffset; + } + + if (bIsVertical) + { + rPosition.SetGeometricalPosition( + Point(nSecondaryLocation, nPrimaryLocation), + Point(0, nLeadingOffset), + Point(0, nTrailingOffset)); + } + else + { + rPosition.SetGeometricalPosition( + Point(nPrimaryLocation, nSecondaryLocation), + Point(nLeadingOffset, 0), + Point(nTrailingOffset, 0)); + } +} + + + + +Rectangle Layouter::Implementation::GetInnerBoundingBox ( + model::SlideSorterModel& rModel, + const sal_Int32 nIndex) const +{ + model::SharedPageDescriptor pDescriptor (rModel.GetPageDescriptor(nIndex)); + if ( ! pDescriptor) + return Rectangle(); + + const Point aLocation (pDescriptor->GetLocation(true)); + if (pDescriptor->HasState(model::PageDescriptor::ST_Selected)) + return mpPageObjectLayouter->GetBoundingBox( + aLocation, + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem); + else + return mpPageObjectLayouter->GetBoundingBox( + aLocation, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem); +} + + + + +Range Layouter::Implementation::GetValidHorizontalSizeRange (void) const +{ + return Range( + mnLeftBorder + maMinimalSize.Width() + mnRightBorder, + mnLeftBorder + maMaximalSize.Width() + mnRightBorder); +} + + + + +Range Layouter::Implementation::GetValidVerticalSizeRange (void) const +{ + return Range( + mnTopBorder + maMinimalSize.Height() + mnBottomBorder, + mnTopBorder + maMaximalSize.Height() + mnBottomBorder); +} + + + + +Range Layouter::Implementation::GetRangeOfVisiblePageObjects (const Rectangle& aVisibleArea) const +{ + const sal_Int32 nRow0 (GetRowAtPosition(aVisibleArea.Top(), true, GM_NEXT)); + const sal_Int32 nCol0 (GetColumnAtPosition(aVisibleArea.Left(),true, GM_NEXT)); + const sal_Int32 nRow1 (GetRowAtPosition(aVisibleArea.Bottom(), true, GM_PREVIOUS)); + const sal_Int32 nCol1 (GetColumnAtPosition(aVisibleArea.Right(), true, GM_PREVIOUS)); + + // When start and end lie in different rows then the range may include + // slides outside (left or right of) the given area. + return Range(GetIndex(nRow0,nCol0,true), GetIndex(nRow1,nCol1,true)); +} + + + + +Size Layouter::Implementation::GetTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize, + const bool bCalculateWidth, + const bool bCalculateHeight) const +{ + (void)rPreviewModelSize; + + if (mnColumnCount<=0 || mnRowCount<=0) + return maPreferredSize; + if ( ! (bCalculateWidth || bCalculateHeight)) + { + OSL_ASSERT(bCalculateWidth || bCalculateHeight); + return maPreferredSize; + } + + // Calculate the width of each page object. + Size aTargetSize (0,0); + if (bCalculateWidth) + aTargetSize.setWidth( + (rWindowSize.Width() - mnLeftBorder - mnRightBorder + - (mnColumnCount-1) * mnHorizontalGap) + / mnColumnCount); + else if (bCalculateHeight) + aTargetSize.setHeight( + (rWindowSize.Height() - mnTopBorder - mnBottomBorder + - (mnRowCount-1) * mnVerticalGap) + / mnRowCount); + + if (bCalculateWidth) + { + if (aTargetSize.Width() < maMinimalSize.Width()) + aTargetSize.setWidth(maMinimalSize.Width()); + else if (aTargetSize.Width() > maMaximalSize.Width()) + aTargetSize.setWidth(maMaximalSize.Width()); + } + else if (bCalculateHeight) + { + if (aTargetSize.Height() < maMinimalSize.Height()) + aTargetSize.setHeight(maMinimalSize.Height()); + else if (aTargetSize.Height() > maMaximalSize.Height()) + aTargetSize.setHeight(maMaximalSize.Height()); + } + + return aTargetSize; +} + + + + +sal_Int32 Layouter::Implementation::GetIndex ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const bool bClampToValidRange) const +{ + if (nRow >= 0 && nColumn >= 0) + { + const sal_Int32 nIndex (nRow * mnColumnCount + nColumn); + if (nIndex >= mnPageCount) + if (bClampToValidRange) + return mnPageCount-1; + else + return -1; + else + return nIndex; + } + else if (bClampToValidRange) + return 0; + else + return -1; +} + + + + +Rectangle Layouter::Implementation::GetPageObjectBox ( + const sal_Int32 nIndex, + const bool bIncludeBorderAndGap) const +{ + const sal_Int32 nRow (nIndex / mnColumnCount); + const sal_Int32 nColumn (nIndex % mnColumnCount); + + const Rectangle aBoundingBox (GetPageObjectBox(nRow,nColumn)); + if (bIncludeBorderAndGap) + return AddBorderAndGap(aBoundingBox, nRow, nColumn); + else + return aBoundingBox; +} + + + + +Rectangle Layouter::Implementation::GetPageObjectBox ( + const sal_Int32 nRow, + const sal_Int32 nColumn) const +{ + return Rectangle( + Point (mnLeftBorder + + nColumn * maPageObjectSize.Width() + + (nColumn>0 ? nColumn : 0) * mnHorizontalGap, + mnTopBorder + + nRow * maPageObjectSize.Height() + + (nRow>0 ? nRow : 0) * mnVerticalGap), + maPageObjectSize); +} + + + + + +Rectangle Layouter::Implementation::AddBorderAndGap ( + const Rectangle& rBoundingBox, + const sal_Int32 nRow, + const sal_Int32 nColumn) const +{ + Rectangle aBoundingBox (rBoundingBox); + + if (nColumn == 0) + aBoundingBox.Left() = 0; + else + aBoundingBox.Left() -= mnHorizontalGap/2; + if (nColumn == mnColumnCount-1) + aBoundingBox.Right() += mnRightBorder; + else + aBoundingBox.Right() += mnHorizontalGap/2; + if (nRow == 0) + aBoundingBox.Top() = 0; + else + aBoundingBox.Top() -= mnVerticalGap/2; + if (nRow == mnRowCount-1) + aBoundingBox.Bottom() += mnBottomBorder; + else + aBoundingBox.Bottom() += mnVerticalGap/2; + return aBoundingBox; +} + + + + +Rectangle Layouter::Implementation::GetTotalBoundingBox (void) const +{ + sal_Int32 nHorizontalSize = 0; + sal_Int32 nVerticalSize = 0; + if (mnColumnCount > 0) + { + sal_Int32 nRowCount = (mnPageCount+mnColumnCount-1) / mnColumnCount; + nHorizontalSize = + mnLeftBorder + + mnRightBorder + + mnColumnCount * maPageObjectSize.Width(); + if (mnColumnCount > 1) + nHorizontalSize += (mnColumnCount-1) * mnHorizontalGap; + nVerticalSize = + mnTopBorder + + mnBottomBorder + + nRowCount * maPageObjectSize.Height(); + if (nRowCount > 1) + nVerticalSize += (nRowCount-1) * mnVerticalGap; + } + + return Rectangle ( + Point(0,0), + Size (nHorizontalSize, nVerticalSize) + ); +} + + + + +void Layouter::Implementation::CalculateVerticalLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + const sal_Int32 nY = rModelPosition.Y() - mnTopBorder + maPageObjectSize.Height()/2; + const sal_Int32 nRowHeight (maPageObjectSize.Height() + mnVerticalGap); + const sal_Int32 nRow (::std::min(mnPageCount, nY / nRowHeight)); + rPosition.SetLogicalPosition ( + nRow, + 0, + nRow, + (nRow == 0), + (nRow == mnRowCount), + (nRow >= mnMaxRowCount)); +} + + + + +//===== HorizontalImplementation ================================================ + +HorizontalImplementation::HorizontalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +HorizontalImplementation::HorizontalImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation HorizontalImplementation::GetOrientation (void) const +{ + return Layouter::HORIZONTAL; +} + + + + +void HorizontalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + (void)rWindowSize; + + // Row and column count are fixed (for a given page count.) + mnColumnCount = mnPageCount; + mnRowCount = 1; +} + + + + +void HorizontalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder) + / (maPageObjectSize.Width() + mnHorizontalGap); + mnMaxRowCount = 1; +} + + + + +Size HorizontalImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, false, true); +} + + + + +void HorizontalImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2; + const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap); + const sal_Int32 nColumn (::std::min(mnPageCount, nX / nColumnWidth)); + rPosition.SetLogicalPosition ( + 0, + nColumn, + nColumn, + (nColumn == 0), + (nColumn == mnColumnCount), + (nColumn >= mnMaxColumnCount)); +} + + + + +//===== VerticalImplementation ================================================ + +VerticalImplementation::VerticalImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +VerticalImplementation::VerticalImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation VerticalImplementation::GetOrientation (void) const +{ + return Layouter::VERTICAL; +} + + + + +void VerticalImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + (void)rWindowSize; + + // Row and column count are fixed (for a given page count.) + mnRowCount = mnPageCount; + mnColumnCount = 1; + +} + + + + +void VerticalImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder) + / (maPageObjectSize.Height() + mnVerticalGap); + mnMaxColumnCount = 1; +} + + + + +Size VerticalImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, false); +} + + + + +void VerticalImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + return CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition); +} + + + + +//===== GridImplementation ================================================ + +GridImplementation::GridImplementation ( + const SharedSdWindow& rpWindow, + const ::boost::shared_ptr<view::Theme>& rpTheme) + : Implementation(rpWindow, rpTheme) +{ +} + + + + +GridImplementation::GridImplementation (const Implementation& rImplementation) + : Implementation(rImplementation) +{ +} + + + + +Layouter::Orientation GridImplementation::GetOrientation (void) const +{ + return Layouter::GRID; +} + + + + +void GridImplementation::CalculateRowAndColumnCount (const Size& rWindowSize) +{ + // Calculate the column count. + mnColumnCount + = (rWindowSize.Width() - mnRequestedLeftBorder - mnRequestedRightBorder) + / (maPreferredSize.Width() + mnHorizontalGap); + if (mnColumnCount < mnMinimalColumnCount) + mnColumnCount = mnMinimalColumnCount; + if (mnColumnCount > mnMaximalColumnCount) + mnColumnCount = mnMaximalColumnCount; + mnRowCount = (mnPageCount + mnColumnCount-1)/mnColumnCount; +} + + + + +void GridImplementation::CalculateMaxRowAndColumnCount (const Size& rWindowSize) +{ + mnMaxColumnCount = (rWindowSize.Width() - mnLeftBorder - mnRightBorder) + / (maPageObjectSize.Width() + mnHorizontalGap); + mnMaxRowCount = (rWindowSize.Height() - mnTopBorder - mnBottomBorder) + / (maPageObjectSize.Height() + mnVerticalGap); +} + + + + + +Size GridImplementation::CalculateTargetSize ( + const Size& rWindowSize, + const Size& rPreviewModelSize) const +{ + return Implementation::GetTargetSize(rWindowSize, rPreviewModelSize, true, true); +} + + + + +void GridImplementation::CalculateLogicalInsertPosition ( + const Point& rModelPosition, + InsertPosition& rPosition) const +{ + if (mnColumnCount == 1) + { + CalculateVerticalLogicalInsertPosition(rModelPosition, rPosition); + } + else + { + // Handle the general case of more than one column. + sal_Int32 nRow (::std::min( + mnRowCount-1, + GetRowAtPosition (rModelPosition.Y(), true, GM_BOTH))); + const sal_Int32 nX = rModelPosition.X() - mnLeftBorder + maPageObjectSize.Width()/2; + const sal_Int32 nColumnWidth (maPageObjectSize.Width() + mnHorizontalGap); + sal_Int32 nColumn (::std::min(mnColumnCount, nX / nColumnWidth)); + sal_Int32 nIndex (nRow * mnColumnCount + nColumn); + bool bIsAtRunEnd (nColumn == mnColumnCount); + + if (nIndex >= mnPageCount) + { + nIndex = mnPageCount; + nRow = mnRowCount-1; + nColumn = ::std::min(::std::min(mnPageCount, mnColumnCount), nColumn); + bIsAtRunEnd = true; + } + + rPosition.SetLogicalPosition ( + nRow, + nColumn, + nIndex, + (nColumn == 0), + bIsAtRunEnd, + (nColumn >= mnMaxColumnCount)); + } +} + + + + +//===== InsertPosition ======================================================== + +InsertPosition::InsertPosition (void) + : mnRow(-1), + mnColumn(-1), + mnIndex(-1), + mbIsAtRunStart(false), + mbIsAtRunEnd(false), + mbIsExtraSpaceNeeded(false), + maLocation(0,0), + maLeadingOffset(0,0), + maTrailingOffset(0,0) +{ +} + + + + +InsertPosition& InsertPosition::operator= (const InsertPosition& rInsertPosition) +{ + if (this != &rInsertPosition) + { + mnRow = rInsertPosition.mnRow; + mnColumn = rInsertPosition.mnColumn; + mnIndex = rInsertPosition.mnIndex; + mbIsAtRunStart = rInsertPosition.mbIsAtRunStart; + mbIsAtRunEnd = rInsertPosition.mbIsAtRunEnd; + mbIsExtraSpaceNeeded = rInsertPosition.mbIsExtraSpaceNeeded; + maLocation = rInsertPosition.maLocation; + maLeadingOffset = rInsertPosition.maLeadingOffset; + maTrailingOffset = rInsertPosition.maTrailingOffset; + } + return *this; +} + + + + +bool InsertPosition::operator== (const InsertPosition& rInsertPosition) const +{ + // Do not compare the geometrical information (maLocation). + return mnRow==rInsertPosition.mnRow + && mnColumn==rInsertPosition.mnColumn + && mnIndex==rInsertPosition.mnIndex + && mbIsAtRunStart==rInsertPosition.mbIsAtRunStart + && mbIsAtRunEnd==rInsertPosition.mbIsAtRunEnd + && mbIsExtraSpaceNeeded==rInsertPosition.mbIsExtraSpaceNeeded; +} + + + + +bool InsertPosition::operator!= (const InsertPosition& rInsertPosition) const +{ + return !operator==(rInsertPosition); +} + + + + +void InsertPosition::SetLogicalPosition ( + const sal_Int32 nRow, + const sal_Int32 nColumn, + const sal_Int32 nIndex, + const bool bIsAtRunStart, + const bool bIsAtRunEnd, + const bool bIsExtraSpaceNeeded) +{ + mnRow = nRow; + mnColumn = nColumn; + mnIndex = nIndex; + mbIsAtRunStart = bIsAtRunStart; + mbIsAtRunEnd = bIsAtRunEnd; + mbIsExtraSpaceNeeded = bIsExtraSpaceNeeded; +} + + + + +void InsertPosition::SetGeometricalPosition( + const Point aLocation, + const Point aLeadingOffset, + const Point aTrailingOffset) +{ + maLocation = aLocation; + maLeadingOffset = aLeadingOffset; + maTrailingOffset = aTrailingOffset; +} + + + +} } } // end of namespace ::sd::slidesorter::namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/view/SlsPageObject.cxx b/sd/source/ui/slidesorter/view/SlsPageObject.cxx new file mode 100644 index 000000000000..3e9b0aa94b35 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObject.cxx @@ -0,0 +1,83 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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() +{ + if (mpDescriptor.get() != NULL) + return mpDescriptor->GetPageObjectFactory().CreateViewContact(this, mpDescriptor); + else + return NULL; +} + + + +} } } // end of namespace ::sd::slidesorter::view + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx new file mode 100644 index 000000000000..d798fa27accb --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectLayouter.cxx @@ -0,0 +1,287 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsPageObjectLayouter.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "view/SlsFontProvider.hxx" +#include "view/SlsTheme.hxx" +#include "tools/IconCache.hxx" +#include "Window.hxx" +#include "res_bmp.hrc" + +namespace sd { namespace slidesorter { namespace view { + +namespace { +const static sal_Int32 gnLeftPageNumberOffset = 2; +const static sal_Int32 gnRightPageNumberOffset = 5; +const static sal_Int32 gnOuterBorderWidth = 5; +const static sal_Int32 gnInfoAreaMinWidth = 26; +} + +PageObjectLayouter::PageObjectLayouter ( + const ::boost::shared_ptr<Theme>& rpTheme, + const Size& rPageObjectWindowSize, + const Size& rPageSize, + const SharedSdWindow& rpWindow, + const sal_Int32 nPageCount) + : mpWindow(rpWindow), + maPageObjectSize(rPageObjectWindowSize.Width(), rPageObjectWindowSize.Height()), + mnModelToWindowScale(1), + maPageObjectBoundingBox(), + maPageNumberAreaBoundingBox(), + maPreviewBoundingBox(), + maTransitionEffectBoundingBox(), + maTransitionEffectIcon(IconCache::Instance().GetIcon(BMP_FADE_EFFECT_INDICATOR)), + mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rpWindow)) +{ + const Size aPageNumberAreaSize (GetPageNumberAreaSize(nPageCount)); + + const int nMaximumBorderWidth (gnOuterBorderWidth); + const int nFocusIndicatorWidth (rpTheme->GetIntegerValue(Theme::Integer_FocusIndicatorWidth)); + + maPreviewBoundingBox = CalculatePreviewBoundingBox( + maPageObjectSize, + Size(rPageSize.Width(), rPageSize.Height()), + aPageNumberAreaSize.Width(), + nFocusIndicatorWidth); + maFocusIndicatorBoundingBox = Rectangle(Point(0,0), maPageObjectSize); + maPageObjectBoundingBox = Rectangle( + Point( + nFocusIndicatorWidth, + nFocusIndicatorWidth), + Size( + maPageObjectSize.Width()-2*nFocusIndicatorWidth, + maPageObjectSize.Height()-2*nFocusIndicatorWidth)); + + maPageNumberAreaBoundingBox = Rectangle( + Point( + std::max(gnLeftPageNumberOffset, + sal_Int32(maPreviewBoundingBox.Left() + - gnRightPageNumberOffset + - aPageNumberAreaSize.Width())), + nMaximumBorderWidth), + aPageNumberAreaSize); + + const Size aIconSize (maTransitionEffectIcon.GetSizePixel()); + maTransitionEffectBoundingBox = Rectangle( + Point( + (maPreviewBoundingBox.Left() - aIconSize.Width()) / 2, + maPreviewBoundingBox.Bottom() - aIconSize.Height()), + aIconSize); +} + + + + +PageObjectLayouter::~PageObjectLayouter(void) +{ +} + + + + +Rectangle PageObjectLayouter::CalculatePreviewBoundingBox ( + Size& rPageObjectSize, + const Size& rPageSize, + const sal_Int32 nPageNumberAreaWidth, + const sal_Int32 nFocusIndicatorWidth) +{ + const sal_Int32 nIconWidth (maTransitionEffectIcon.GetSizePixel().Width()); + const sal_Int32 nLeftAreaWidth ( + ::std::max( + gnInfoAreaMinWidth, + gnRightPageNumberOffset + + ::std::max( + nPageNumberAreaWidth, + nIconWidth))); + sal_Int32 nPreviewWidth; + sal_Int32 nPreviewHeight; + const double nPageAspectRatio (double(rPageSize.Width()) / double(rPageSize.Height())); + if (rPageObjectSize.Height() == 0) + { + // Calculate height so that the preview fills the available + // horizontal space completely while observing the aspect ratio of + // the preview. + nPreviewWidth = rPageObjectSize.Width() + - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio); + rPageObjectSize.setHeight(nPreviewHeight + 2*gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1); + } + else if (rPageObjectSize.Width() == 0) + { + // Calculate the width of the page object so that the preview fills + // the available vertical space completely while observing the + // aspect ratio of the preview. + nPreviewHeight = rPageObjectSize.Height() - 2*gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio); + rPageObjectSize.setWidth(nPreviewWidth + + nLeftAreaWidth + gnOuterBorderWidth + 2*nFocusIndicatorWidth + 1); + + } + else + { + // The size of the page object is given. Calculate the size of the + // preview. + nPreviewWidth = rPageObjectSize.Width() + - nLeftAreaWidth - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + nPreviewHeight = rPageObjectSize.Height() + - gnOuterBorderWidth - 2*nFocusIndicatorWidth - 1; + if (double(nPreviewWidth)/double(nPreviewHeight) > nPageAspectRatio) + nPreviewWidth = ::basegfx::fround(nPreviewHeight * nPageAspectRatio); + else + nPreviewHeight = ::basegfx::fround(nPreviewWidth / nPageAspectRatio); + } + // When the preview does not fill the available space completely then + // place it flush right and vertically centered. + const int nLeft (rPageObjectSize.Width() + - gnOuterBorderWidth - nPreviewWidth - nFocusIndicatorWidth - 1); + const int nTop ((rPageObjectSize.Height() - nPreviewHeight)/2); + return Rectangle( + nLeft, + nTop, + nLeft + nPreviewWidth, + nTop + nPreviewHeight); +} + + + + +Rectangle PageObjectLayouter::GetBoundingBox ( + const model::SharedPageDescriptor& rpPageDescriptor, + const Part ePart, + const CoordinateSystem eCoordinateSystem) +{ + OSL_ASSERT(rpPageDescriptor); + Point aLocation (rpPageDescriptor ? rpPageDescriptor->GetLocation() : Point(0,0)); + return GetBoundingBox(aLocation, ePart, eCoordinateSystem); +} + + + + +Rectangle PageObjectLayouter::GetBoundingBox ( + const Point& rPageObjectLocation, + const Part ePart, + const CoordinateSystem eCoordinateSystem) +{ + Rectangle aBoundingBox; + switch (ePart) + { + case FocusIndicator: + aBoundingBox = maFocusIndicatorBoundingBox; + break; + + case PageObject: + case MouseOverIndicator: + aBoundingBox = maPageObjectBoundingBox; + break; + + case Preview: + aBoundingBox = maPreviewBoundingBox; + break; + + case PageNumber: + aBoundingBox = maPageNumberAreaBoundingBox; + break; + + case Name: + aBoundingBox = maPageNumberAreaBoundingBox; + break; + + case TransitionEffectIndicator: + aBoundingBox = maTransitionEffectBoundingBox; + break; + } + + // Adapt coordinates to the requested coordinate system. + Point aLocation (rPageObjectLocation); + if (eCoordinateSystem == WindowCoordinateSystem) + aLocation += mpWindow->GetMapMode().GetOrigin(); + + return Rectangle( + aBoundingBox.TopLeft() + aLocation, + aBoundingBox.BottomRight() + aLocation); +} + + + + +Size PageObjectLayouter::GetSize ( + const Part ePart, + const CoordinateSystem eCoordinateSystem) +{ + return GetBoundingBox(Point(0,0), ePart, eCoordinateSystem).GetSize(); +} + + + + +Size PageObjectLayouter::GetPageNumberAreaSize (const int nPageCount) +{ + OSL_ASSERT(mpWindow); + + // Set the correct font. + Font aOriginalFont (mpWindow->GetFont()); + if (mpPageNumberFont) + mpWindow->SetFont(*mpPageNumberFont); + + 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. + + const Size aSize ( + mpWindow->GetTextWidth(sPageNumberTemplate), + mpWindow->GetTextHeight()); + + mpWindow->SetFont(aOriginalFont); + + return aSize; +} + + + + +Image PageObjectLayouter::GetTransitionEffectIcon (void) const +{ + return maTransitionEffectIcon; +} + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx new file mode 100644 index 000000000000..cb78c1a12f71 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsPageObjectPainter.cxx @@ -0,0 +1,584 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsPageObjectPainter.hxx" + +#include "model/SlsPageDescriptor.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsPageObjectLayouter.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsTheme.hxx" +#include "view/SlsButtonBar.hxx" +#include "SlsFramePainter.hxx" +#include "cache/SlsPageCache.hxx" +#include "controller/SlsProperties.hxx" +#include "Window.hxx" +#include "sdpage.hxx" +#include "sdresid.hxx" +#include <vcl/svapp.hxx> +#include <vcl/vclenum.hxx> +#include <vcl/virdev.hxx> +#include <boost/scoped_ptr.hpp> + +using namespace ::drawinglayer::primitive2d; + +namespace sd { namespace slidesorter { namespace view { + +namespace { + +sal_uInt8 Blend ( + const sal_uInt8 nValue1, + const sal_uInt8 nValue2, + const double nWeight) +{ + const double nValue (nValue1*(1-nWeight) + nValue2 * nWeight); + if (nValue < 0) + return 0; + else if (nValue > 255) + return 255; + else + return (sal_uInt8)nValue; +} + +sal_uInt8 ClampColorChannel (const double nValue) +{ + if (nValue <= 0) + return 0; + else if (nValue >= 255) + return 255; + else + return sal_uInt8(nValue); +} + +sal_uInt8 CalculateColorChannel( + const double nColor1, + const double nColor2, + const double nAlpha1, + const double nAlpha2, + const double nAlpha0) +{ + if (nAlpha0 == 0) + return 0; + + const double nColor0 ((nAlpha1*nColor1 + nAlpha1*nAlpha2*nColor1 + nAlpha2*nColor2) / nAlpha0); + return ClampColorChannel(255 * nColor0); +} + +} // end of anonymous namespace + + + + +//===== PageObjectPainter ===================================================== + +PageObjectPainter::PageObjectPainter ( + const SlideSorter& rSlideSorter) + : mrLayouter(rSlideSorter.GetView().GetLayouter()), + mpPageObjectLayouter(), + mpCache(rSlideSorter.GetView().GetPreviewCache()), + mpProperties(rSlideSorter.GetProperties()), + mpTheme(rSlideSorter.GetTheme()), + mpPageNumberFont(Theme::GetFont(Theme::Font_PageNumber, *rSlideSorter.GetContentWindow())), + mpShadowPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_RawShadow))), + mpFocusBorderPainter(new FramePainter(mpTheme->GetIcon(Theme::Icon_FocusBorder))), + maNormalBackground(), + maSelectionBackground(), + maFocusedSelectionBackground(), + maMouseOverBackground(), + maMouseOverFocusedBackground(), + msUnhideString(mpTheme->GetString(Theme::String_Unhide)), + mrButtonBar(rSlideSorter.GetView().GetButtonBar()) +{ + // Replace the color (not the alpha values) in the focus border with a + // color derived from the current selection color. + Color aColor (mpTheme->GetColor(Theme::Color_Selection)); + sal_uInt16 nHue, nSat, nBri; + aColor.RGBtoHSB(nHue, nSat, nBri); + aColor = Color::HSBtoRGB(nHue, 28, 65); + mpFocusBorderPainter->AdaptColor(aColor, true); +} + + + + +PageObjectPainter::~PageObjectPainter (void) +{ +} + + + + +void PageObjectPainter::PaintPageObject ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + // The page object layouter is quite volatile. It may have been replaced + // since the last call. Update it now. + mpPageObjectLayouter = mrLayouter.GetPageObjectLayouter(); + if ( ! mpPageObjectLayouter) + { + OSL_ASSERT(mpPageObjectLayouter); + return; + } + + // Turn off antialiasing to avoid the bitmaps from being shifted by + // fractions of a pixel and thus show blurry edges. + const sal_uInt16 nSavedAntialiasingMode (rDevice.GetAntialiasing()); + rDevice.SetAntialiasing(nSavedAntialiasingMode & ~ANTIALIASING_ENABLE_B2DDRAW); + + PaintBackground(rDevice, rpDescriptor); + PaintPreview(rDevice, rpDescriptor); + PaintPageNumber(rDevice, rpDescriptor); + PaintTransitionEffect(rDevice, rpDescriptor); + mrButtonBar.Paint(rDevice, rpDescriptor); + + rDevice.SetAntialiasing(nSavedAntialiasingMode); +} + + + + +void PageObjectPainter::NotifyResize (const bool bForce) +{ + (void)bForce; + maNormalBackground.SetEmpty(); + maSelectionBackground.SetEmpty(); + maFocusedSelectionBackground.SetEmpty(); + maFocusedBackground.SetEmpty(); + maMouseOverBackground.SetEmpty(); + maMouseOverFocusedBackground.SetEmpty(); + maMouseOverSelectedAndFocusedBackground.SetEmpty(); +} + + + + +void PageObjectPainter::SetTheme (const ::boost::shared_ptr<view::Theme>& rpTheme) +{ + mpTheme = rpTheme; + NotifyResize(true); +} + + + + +void PageObjectPainter::PaintBackground ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::ModelCoordinateSystem)); + + const Bitmap& rBackground (GetBackgroundForState(rpDescriptor, rDevice)); + rDevice.DrawBitmap(aBox.TopLeft(), rBackground); + + // Fill the interior of the preview area with the default background + // color of the page. + SdPage* pPage = rpDescriptor->GetPage(); + if (pPage != NULL) + { + rDevice.SetFillColor(pPage->GetPageBackgroundColor(NULL)); + rDevice.SetLineColor(pPage->GetPageBackgroundColor(NULL)); + const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + rDevice.DrawRect(aPreviewBox); + } +} + + + + +void PageObjectPainter::PaintPreview ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + + if (mpCache != NULL) + { + const SdrPage* pPage = rpDescriptor->GetPage(); + mpCache->SetPreciousFlag(pPage, true); + + const Bitmap aPreview (GetPreviewBitmap(rpDescriptor, &rDevice)); + if ( ! aPreview.IsEmpty()) + { + if (aPreview.GetSizePixel() != aBox.GetSize()) + rDevice.DrawBitmap(aBox.TopLeft(), aBox.GetSize(), aPreview); + else + rDevice.DrawBitmap(aBox.TopLeft(), aPreview); + } + } +} + + + + +Bitmap PageObjectPainter::CreateMarkedPreview ( + const Size& rSize, + const Bitmap& rPreview, + const BitmapEx& rOverlay, + const OutputDevice* pReferenceDevice) const +{ + ::boost::scoped_ptr<VirtualDevice> pDevice; + if (pReferenceDevice != NULL) + pDevice.reset(new VirtualDevice(*pReferenceDevice)); + else + pDevice.reset(new VirtualDevice()); + pDevice->SetOutputSizePixel(rSize); + + pDevice->DrawBitmap(Point(0,0), rSize, rPreview); + + // Paint bitmap tiled over the preview to mark it as excluded. + const sal_Int32 nIconWidth (rOverlay.GetSizePixel().Width()); + const sal_Int32 nIconHeight (rOverlay.GetSizePixel().Height()); + if (nIconWidth>0 && nIconHeight>0) + { + for (sal_Int32 nX=0; nX<rSize.Width(); nX+=nIconWidth) + for (sal_Int32 nY=0; nY<rSize.Height(); nY+=nIconHeight) + pDevice->DrawBitmapEx(Point(nX,nY), rOverlay); + } + return pDevice->GetBitmap(Point(0,0), rSize); +} + + + + +Bitmap PageObjectPainter::GetPreviewBitmap ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice* pReferenceDevice) const +{ + const SdrPage* pPage = rpDescriptor->GetPage(); + const bool bIsExcluded (rpDescriptor->HasState(model::PageDescriptor::ST_Excluded)); + + if (bIsExcluded) + { + Bitmap aMarkedPreview (mpCache->GetMarkedPreviewBitmap(pPage,false)); + const Rectangle aPreviewBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + if (aMarkedPreview.IsEmpty() || aMarkedPreview.GetSizePixel()!=aPreviewBox.GetSize()) + { + aMarkedPreview = CreateMarkedPreview( + aPreviewBox.GetSize(), + mpCache->GetPreviewBitmap(pPage,true), + mpTheme->GetIcon(Theme::Icon_HideSlideOverlay), + pReferenceDevice); + mpCache->SetMarkedPreviewBitmap(pPage, aMarkedPreview); + } + return aMarkedPreview; + } + else + { + return mpCache->GetPreviewBitmap(pPage,false); + } +} + + + + +void PageObjectPainter::PaintPageNumber ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::PageNumber, + PageObjectLayouter::ModelCoordinateSystem)); + + // Determine the color of the page number. + Color aPageNumberColor (mpTheme->GetColor(Theme::Color_PageNumberDefault)); + if (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) || + rpDescriptor->HasState(model::PageDescriptor::ST_Selected)) + { + // Page number is painted on background for hover or selection or + // both. Each of these background colors has a predefined luminance + // which is compatible with the PageNumberHover color. + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHover)); + } + else + { + const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background)); + const sal_Int32 nBackgroundLuminance (aBackgroundColor.GetLuminance()); + // When the background color is black then this is interpreted as + // high contrast mode and the font color is set to white. + if (nBackgroundLuminance == 0) + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberHighContrast)); + else + { + // Compare luminance of default page number color and background + // color. When the two are similar then use a darker + // (preferred) or brighter font color. + const sal_Int32 nFontLuminance (aPageNumberColor.GetLuminance()); + if (abs(nBackgroundLuminance - nFontLuminance) < 60) + { + if (nBackgroundLuminance > nFontLuminance-30) + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberBrightBackground)); + else + aPageNumberColor = Color(mpTheme->GetColor(Theme::Color_PageNumberDarkBackground)); + } + } + } + + // Paint the page number. + OSL_ASSERT(rpDescriptor->GetPage()!=NULL); + const sal_Int32 nPageNumber ((rpDescriptor->GetPage()->GetPageNum() - 1) / 2 + 1); + const String sPageNumber (String::CreateFromInt32(nPageNumber)); + rDevice.SetFont(*mpPageNumberFont); + rDevice.SetTextColor(aPageNumberColor); + rDevice.DrawText(aBox, sPageNumber, TEXT_DRAW_RIGHT | TEXT_DRAW_VCENTER); +} + + + + +void PageObjectPainter::PaintTransitionEffect ( + OutputDevice& rDevice, + const model::SharedPageDescriptor& rpDescriptor) const +{ + const SdPage* pPage = rpDescriptor->GetPage(); + if (pPage!=NULL && pPage->getTransitionType() > 0) + { + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + rpDescriptor, + PageObjectLayouter::TransitionEffectIndicator, + PageObjectLayouter::ModelCoordinateSystem)); + + rDevice.DrawBitmapEx( + aBox.TopLeft(), + mpPageObjectLayouter->GetTransitionEffectIcon().GetBitmapEx()); + } +} + + + + +Bitmap& PageObjectPainter::GetBackgroundForState ( + const model::SharedPageDescriptor& rpDescriptor, + const OutputDevice& rReferenceDevice) +{ + enum State { None = 0x00, Selected = 0x01, MouseOver = 0x02, Focused = 0x04 }; + const int eState = + (rpDescriptor->HasState(model::PageDescriptor::ST_Selected) ? Selected : None) + | (rpDescriptor->HasState(model::PageDescriptor::ST_MouseOver) ? MouseOver : None) + | (rpDescriptor->HasState(model::PageDescriptor::ST_Focused) ? Focused : None); + + switch (eState) + { + case MouseOver | Selected | Focused: + return GetBackground( + maMouseOverSelectedAndFocusedBackground, + Theme::Gradient_MouseOverSelectedAndFocusedPage, + rReferenceDevice, + true); + + case MouseOver | Selected: + case MouseOver: + return GetBackground( + maMouseOverBackground, + Theme::Gradient_MouseOverPage, + rReferenceDevice, + false); + + case MouseOver | Focused: + return GetBackground( + maMouseOverFocusedBackground, + Theme::Gradient_MouseOverPage, + rReferenceDevice, + true); + + case Selected | Focused: + return GetBackground( + maFocusedSelectionBackground, + Theme::Gradient_SelectedAndFocusedPage, + rReferenceDevice, + true); + + case Selected: + return GetBackground( + maSelectionBackground, + Theme::Gradient_SelectedPage, + rReferenceDevice, + false); + + case Focused: + return GetBackground( + maFocusedBackground, + Theme::Gradient_FocusedPage, + rReferenceDevice, + true); + + case None: + default: + return GetBackground( + maNormalBackground, + Theme::Gradient_NormalPage, + rReferenceDevice, + false); + } +} + + + + +Bitmap& PageObjectPainter::GetBackground( + Bitmap& rBackground, + Theme::GradientColorType eType, + const OutputDevice& rReferenceDevice, + const bool bHasFocusBorder) +{ + if (rBackground.IsEmpty()) + rBackground = CreateBackgroundBitmap(rReferenceDevice, eType, bHasFocusBorder); + return rBackground; +} + + + + +Bitmap PageObjectPainter::CreateBackgroundBitmap( + const OutputDevice& rReferenceDevice, + const Theme::GradientColorType eColorType, + const bool bHasFocusBorder) const +{ + const Size aSize (mpPageObjectLayouter->GetSize( + PageObjectLayouter::FocusIndicator, + PageObjectLayouter::WindowCoordinateSystem)); + const Rectangle aPageObjectBox (mpPageObjectLayouter->GetBoundingBox( + Point(0,0), + PageObjectLayouter::PageObject, + PageObjectLayouter::ModelCoordinateSystem)); + VirtualDevice aBitmapDevice (rReferenceDevice); + aBitmapDevice.SetOutputSizePixel(aSize); + + // Fill the background with the background color of the slide sorter. + const Color aBackgroundColor (mpTheme->GetColor(Theme::Color_Background)); + OSL_TRACE("filling background of page object bitmap with color %x", aBackgroundColor.GetColor()); + aBitmapDevice.SetFillColor(aBackgroundColor); + aBitmapDevice.SetLineColor(aBackgroundColor); + aBitmapDevice.DrawRect(Rectangle(Point(0,0), aSize)); + + // Paint the slide area with a linear gradient that starts some pixels + // below the top and ends some pixels above the bottom. + const Color aTopColor(mpTheme->GetGradientColor(eColorType, Theme::Fill1)); + const Color aBottomColor(mpTheme->GetGradientColor(eColorType, Theme::Fill2)); + if (aTopColor != aBottomColor) + { + const sal_Int32 nHeight (aPageObjectBox.GetHeight()); + const sal_Int32 nDefaultConstantSize(nHeight/4); + const sal_Int32 nMinimalGradientSize(40); + const sal_Int32 nY1 ( + ::std::max<sal_Int32>( + 0, + ::std::min<sal_Int32>( + nDefaultConstantSize, + (nHeight - nMinimalGradientSize)/2))); + const sal_Int32 nY2 (nHeight-nY1); + const sal_Int32 nTop (aPageObjectBox.Top()); + for (sal_Int32 nY=0; nY<nHeight; ++nY) + { + if (nY<=nY1) + aBitmapDevice.SetLineColor(aTopColor); + else if (nY>=nY2) + aBitmapDevice.SetLineColor(aBottomColor); + else + { + Color aColor (aTopColor); + aColor.Merge(aBottomColor, 255 * (nY2-nY) / (nY2-nY1)); + aBitmapDevice.SetLineColor(aColor); + } + aBitmapDevice.DrawLine( + Point(aPageObjectBox.Left(), nY+nTop), + Point(aPageObjectBox.Right(), nY+nTop)); + } + } + else + { + aBitmapDevice.SetFillColor(aTopColor); + aBitmapDevice.DrawRect(aPageObjectBox); + } + + // Paint the simple border and, for some backgrounds, the focus border. + if (bHasFocusBorder) + mpFocusBorderPainter->PaintFrame(aBitmapDevice, aPageObjectBox); + else + PaintBorder(aBitmapDevice, eColorType, aPageObjectBox); + + // Get bounding box of the preview around which a shadow is painted. + // Compensate for the border around the preview. + const Rectangle aBox (mpPageObjectLayouter->GetBoundingBox( + Point(0,0), + PageObjectLayouter::Preview, + PageObjectLayouter::ModelCoordinateSystem)); + Rectangle aFrameBox (aBox.Left()-1,aBox.Top()-1,aBox.Right()+1,aBox.Bottom()+1); + mpShadowPainter->PaintFrame(aBitmapDevice, aFrameBox); + + return aBitmapDevice.GetBitmap (Point(0,0),aSize); +} + + + + +void PageObjectPainter::PaintBorder ( + OutputDevice& rDevice, + const Theme::GradientColorType eColorType, + const Rectangle& rBox) const +{ + rDevice.SetFillColor(); + const sal_Int32 nBorderWidth (1); + for (int nIndex=0; nIndex<nBorderWidth; ++nIndex) + { + const int nDelta (nIndex); + rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border2)); + rDevice.DrawLine( + Point(rBox.Left()-nDelta, rBox.Top()-nDelta), + Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta)); + rDevice.DrawLine( + Point(rBox.Left()-nDelta, rBox.Bottom()+nDelta), + Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta)); + rDevice.DrawLine( + Point(rBox.Right()+nDelta, rBox.Bottom()+nDelta), + Point(rBox.Right()+nDelta, rBox.Top()-nDelta)); + + rDevice.SetLineColor(mpTheme->GetGradientColor(eColorType, Theme::Border1)); + rDevice.DrawLine( + Point(rBox.Left()-nDelta, rBox.Top()-nDelta), + Point(rBox.Right()+nDelta, rBox.Top()-nDelta)); + } +} + + + +} } } // end of namespace sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsResource.hxx b/sd/source/ui/slidesorter/view/SlsResource.hxx new file mode 100644 index 000000000000..9ba3e33b2422 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsResource.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SD_SLIDESORTER_RESOURCE_HXX +#define SD_SLIDESORTER_RESOURCE_HXX + +#include "view/SlsResource.hrc" +#include "sdresid.hxx" +#include <tools/rc.hxx> + +namespace sd { namespace slidesorter { namespace view { + +class LocalResource : public Resource +{ +public: + LocalResource (const sal_uInt16 nResourceId) : Resource(SdResId(nResourceId)){} + ~LocalResource (void) { FreeResource(); } +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/view/SlsResource.src b/sd/source/ui/slidesorter/view/SlsResource.src new file mode 100644 index 000000000000..13f6cd08c775 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsResource.src @@ -0,0 +1,314 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "view/SlsResource.hrc" + +Resource RID_SLIDESORTER_ICONS +{ + Image IMAGE_COMMAND1_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large.png" ; }; + }; + Image IMAGE_COMMAND1_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large_hover.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND1_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large_hc.png" ; }; + }; + Image IMAGE_COMMAND1_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND1_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small_hc.png" ; }; + }; + Image IMAGE_COMMAND1_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command1_small_hover_hc.png" ; }; + }; + + + Image IMAGE_COMMAND2_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large.png" ; }; + }; + Image IMAGE_COMMAND2_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large_hover.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND2_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large_hc.png" ; }; + }; + Image IMAGE_COMMAND2_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND2_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small_hc.png" ; }; + }; + Image IMAGE_COMMAND2_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2_small_hover_hc.png" ; }; + }; + + + Image IMAGE_COMMAND2B_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large.png" ; }; + }; + Image IMAGE_COMMAND2B_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large_hover.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND2B_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small_hc.png" ; }; + }; + Image IMAGE_COMMAND2B_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command2b_small_hover_hc.png" ; }; + }; + + + Image IMAGE_COMMAND3_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large.png" ; }; + }; + Image IMAGE_COMMAND3_LARGE_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large_hover.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium_hover.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL_HOVER + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small_hover.png" ; }; + }; + + Image IMAGE_COMMAND3_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large_hc.png" ; }; + }; + Image IMAGE_COMMAND3_LARGE_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_large_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium_hc.png" ; }; + }; + Image IMAGE_COMMAND3_MEDIUM_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_medium_hover_hc.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small_hc.png" ; }; + }; + Image IMAGE_COMMAND3_SMALL_HOVER_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command3_small_hover_hc.png" ; }; + }; + + + Image IMAGE_BUTTONBAR_LARGE + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_large.png" ; }; + }; + Image IMAGE_BUTTONBAR_MEDIUM + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_medium.png" ; }; + }; + Image IMAGE_BUTTONBAR_SMALL + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_small.png" ; }; + }; + + Image IMAGE_BUTTONBAR_LARGE_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_large_hc.png" ; }; + }; + Image IMAGE_BUTTONBAR_MEDIUM_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_medium_hc.png" ; }; + }; + Image IMAGE_BUTTONBAR_SMALL_HC + { + ImageBitmap = Bitmap { File = "slide_sorter_command_background_small_hc.png" ; }; + }; + + + + Image IMAGE_SHADOW + { + ImageBitmap = Bitmap { File = "slide_sorter_shadow.png" ; }; + }; + + Image IMAGE_INSERT_SHADOW + { + ImageBitmap = Bitmap { File = "slide_sorter_insert_shadow.png" ; }; + }; + + Image IMAGE_HIDE_SLIDE_OVERLAY + { + ImageBitmap = Bitmap { File = "slide_sorter_hide_slide_overlay.png" ; }; + }; + + Image IMAGE_FOCUS_BORDER + { + ImageBitmap = Bitmap { File = "slide_sorter_focus_border.png" ; }; + }; + + + String STRING_DRAG_AND_DROP_PAGES + { + Text [ en-US ] = "Drag and Drop Pages" ; + }; + + String STRING_DRAG_AND_DROP_SLIDES + { + Text [ en-US ] = "Drag and Drop Slides" ; + }; + + String STRING_COMMAND1 + { + Text [ en-US ] = "Start Slide Show" ; + }; + + String STRING_COMMAND2_A + { + Text [ en-US ] = "Hide Slide" ; + }; + + String STRING_COMMAND2_B + { + Text [ en-US ] = "Show Slide" ; + }; + + String STRING_COMMAND3 + { + Text [ en-US ] = "Duplicate Slide" ; + }; +}; diff --git a/sd/source/ui/slidesorter/view/SlsTheme.cxx b/sd/source/ui/slidesorter/view/SlsTheme.cxx new file mode 100644 index 000000000000..5cc06eadae04 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsTheme.cxx @@ -0,0 +1,536 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsTheme.hxx" +#include "SlsResource.hxx" +#include "controller/SlsProperties.hxx" +#include "sdresid.hxx" +#include <tools/color.hxx> +#include <vcl/outdev.hxx> +#include <vcl/image.hxx> +#include <vcl/svapp.hxx> +#include <svtools/colorcfg.hxx> + +namespace sd { namespace slidesorter { namespace view { + +const static ColorData Black = 0x000000; +const static ColorData White = 0xffffff; + + + +ColorData ChangeLuminance (const ColorData aColorData, const int nValue) +{ + Color aColor (aColorData); + if (nValue > 0) + aColor.IncreaseLuminance(nValue); + else + aColor.DecreaseLuminance(-nValue); + return aColor.GetColor(); +} + +ColorData HGBAdapt ( + const ColorData aColorData, + const sal_Int32 nNewSaturation, + const sal_Int32 nNewBrightness) +{ + sal_uInt16 nHue (0); + sal_uInt16 nSaturation (0); + sal_uInt16 nBrightness (0); + Color(aColorData).RGBtoHSB(nHue, nSaturation, nBrightness); + return Color::HSBtoRGB( + nHue, + nNewSaturation>=0 ? nNewSaturation : nSaturation, + nNewBrightness>=0 ? nNewBrightness : nBrightness); +} + + + + +Theme::Theme (const ::boost::shared_ptr<controller::Properties>& rpProperties) + : mbIsHighContrastMode(false), + maBackgroundColor(rpProperties->GetBackgroundColor().GetColor()), + maPageBackgroundColor(COL_WHITE), + maGradients(), + maIcons(), + maColor(), + maIntegerValues() +{ + { + LocalResource aResource (RID_SLIDESORTER_ICONS); + + maStrings.resize(_StringType_Size_); + maStrings[String_DragAndDropPages] = String(SdResId(STRING_DRAG_AND_DROP_PAGES)); + maStrings[String_DragAndDropSlides] = String(SdResId(STRING_DRAG_AND_DROP_SLIDES)); + maStrings[String_Command1] = String(SdResId(STRING_COMMAND1)); + maStrings[String_Command2] = String(SdResId(STRING_COMMAND2_A)); + maStrings[String_Command2B] = String(SdResId(STRING_COMMAND2_B)); + maStrings[String_Command3] = String(SdResId(STRING_COMMAND3)); + + maColor.resize(_ColorType_Size_); + maColor[Color_Background] = maBackgroundColor; + maColor[Color_ButtonBackground] = Black; + maColor[Color_ButtonText] = 0xc0c0c0; + maColor[Color_ButtonTextHover] = White; + maColor[Color_PageNumberDefault] = 0x0808080; + maColor[Color_PageNumberHover] = 0x4c4c4c; + maColor[Color_PageNumberHighContrast] = White; + maColor[Color_PageNumberBrightBackground] = 0x333333; + maColor[Color_PageNumberDarkBackground] = 0xcccccc; + maColor[Color_PreviewBorder] = 0x949599; + + maIntegerValues.resize(_IntegerValueType_Size_); + maIntegerValues[Integer_ButtonCornerRadius] = 3; + maIntegerValues[Integer_ButtonMaxAlpha] = 0; + maIntegerValues[Integer_ButtonBarMaxAlpha] = 0; + maIntegerValues[Integer_ButtonPaintType] = 1; + maIntegerValues[Integer_ButtonBorder] = 4; + maIntegerValues[Integer_ButtonGap] = 0; + maIntegerValues[Integer_ButtonFadeInDelay] = 800; + maIntegerValues[Integer_ButtonFadeInDuration] = 100; + maIntegerValues[Integer_ButtonFadeOutDelay] = 0; + maIntegerValues[Integer_ButtonFadeOutDuration] = 100; + maIntegerValues[Integer_ToolTipDelay] = 1000; + maIntegerValues[Integer_FocusIndicatorWidth] = 3; + } + + Update(rpProperties); +} + + + + +void Theme::Update (const ::boost::shared_ptr<controller::Properties>& rpProperties) +{ + const bool bSavedHighContrastMode (mbIsHighContrastMode); + mbIsHighContrastMode = rpProperties->IsHighContrastModeActive(); + + // Set up colors. + maBackgroundColor = rpProperties->GetBackgroundColor().GetColor(); + maPageBackgroundColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; + + maColor[Color_Background] = maBackgroundColor; + + maGradients.resize(_GradientColorType_Size_); + + maColor[Color_Background] = maBackgroundColor; + const ColorData aSelectionColor (rpProperties->GetSelectionColor().GetColor()); + maColor[Color_Selection] = aSelectionColor; + if (Color(aSelectionColor).IsBright()) + maColor[Color_PageCountFontColor] = Black; + else + maColor[Color_PageCountFontColor] = White; + + // Set up gradients. + SetGradient(Gradient_SelectedPage, aSelectionColor, 50, 50, +100,+100, +50,+25); + SetGradient(Gradient_MouseOverPage, aSelectionColor, 75, 75, +100,+100, +50,+25); + SetGradient(Gradient_SelectedAndFocusedPage, aSelectionColor, 50, 50, +100,+100, -50,-75); + SetGradient(Gradient_MouseOverSelectedAndFocusedPage, aSelectionColor, 75, 75, +100,+100, -50,-75); + SetGradient(Gradient_FocusedPage, aSelectionColor, -1,-1, 0,0, -50,-75); + + SetGradient(Gradient_ButtonBackground, Black, -1,-1, 0,0, 0,0); + SetGradient(Gradient_NormalPage, maBackgroundColor, -1,-1, 0,0, 0,0); + + // The focused gradient needs special handling because its fill color is + // like that of the NormalPage gradient. + GetGradient(Gradient_FocusedPage).maFillColor1 = GetGradient(Gradient_NormalPage).maFillColor1; + GetGradient(Gradient_FocusedPage).maFillColor2 = GetGradient(Gradient_NormalPage).maFillColor2; + + // Set up icons. + if (bSavedHighContrastMode != mbIsHighContrastMode || maIcons.empty()) + { + LocalResource aResource (RID_SLIDESORTER_ICONS); + + maIcons.resize(_IconType_Size_); + if (mbIsHighContrastMode) + { + InitializeIcon(Icon_RawShadow, IMAGE_SHADOW); + InitializeIcon(Icon_RawInsertShadow, IMAGE_INSERT_SHADOW); + InitializeIcon(Icon_HideSlideOverlay, IMAGE_HIDE_SLIDE_OVERLAY); + + InitializeIcon(Icon_ButtonBarLarge, IMAGE_BUTTONBAR_LARGE_HC); + InitializeIcon(Icon_ButtonBarMedium, IMAGE_BUTTONBAR_MEDIUM_HC); + InitializeIcon(Icon_ButtonBarSmall, IMAGE_BUTTONBAR_SMALL_HC); + + InitializeIcon(Icon_Command1Large, IMAGE_COMMAND1_LARGE_HC); + InitializeIcon(Icon_Command1LargeHover, IMAGE_COMMAND1_LARGE_HOVER_HC); + InitializeIcon(Icon_Command1Medium, IMAGE_COMMAND1_MEDIUM_HC); + InitializeIcon(Icon_Command1MediumHover, IMAGE_COMMAND1_MEDIUM_HOVER_HC); + InitializeIcon(Icon_Command1Small, IMAGE_COMMAND1_SMALL_HC); + InitializeIcon(Icon_Command1SmallHover, IMAGE_COMMAND1_SMALL_HOVER_HC); + + InitializeIcon(Icon_Command2Large, IMAGE_COMMAND2_LARGE_HC); + InitializeIcon(Icon_Command2LargeHover, IMAGE_COMMAND2_LARGE_HOVER_HC); + InitializeIcon(Icon_Command2Medium, IMAGE_COMMAND2_MEDIUM_HC); + InitializeIcon(Icon_Command2MediumHover, IMAGE_COMMAND2_MEDIUM_HOVER_HC); + InitializeIcon(Icon_Command2Small, IMAGE_COMMAND2_SMALL_HC); + InitializeIcon(Icon_Command2SmallHover, IMAGE_COMMAND2_SMALL_HOVER_HC); + + InitializeIcon(Icon_Command2BLarge, IMAGE_COMMAND2B_LARGE_HC); + InitializeIcon(Icon_Command2BLargeHover, IMAGE_COMMAND2B_LARGE_HOVER_HC); + InitializeIcon(Icon_Command2BMedium, IMAGE_COMMAND2B_MEDIUM_HC); + InitializeIcon(Icon_Command2BMediumHover, IMAGE_COMMAND2B_MEDIUM_HOVER_HC); + InitializeIcon(Icon_Command2BSmall, IMAGE_COMMAND2B_SMALL_HC); + InitializeIcon(Icon_Command2BSmallHover, IMAGE_COMMAND2B_SMALL_HOVER_HC); + + InitializeIcon(Icon_Command3Large, IMAGE_COMMAND3_LARGE_HC); + InitializeIcon(Icon_Command3LargeHover, IMAGE_COMMAND3_LARGE_HOVER_HC); + InitializeIcon(Icon_Command3Medium, IMAGE_COMMAND3_SMALL_HC); + InitializeIcon(Icon_Command3MediumHover, IMAGE_COMMAND3_SMALL_HOVER_HC); + InitializeIcon(Icon_Command3Small, IMAGE_COMMAND3_SMALL_HC); + InitializeIcon(Icon_Command3SmallHover, IMAGE_COMMAND3_SMALL_HOVER_HC); + } + else + { + InitializeIcon(Icon_RawShadow, IMAGE_SHADOW); + InitializeIcon(Icon_RawInsertShadow, IMAGE_INSERT_SHADOW); + InitializeIcon(Icon_HideSlideOverlay, IMAGE_HIDE_SLIDE_OVERLAY); + + InitializeIcon(Icon_ButtonBarLarge, IMAGE_BUTTONBAR_LARGE); + InitializeIcon(Icon_ButtonBarMedium, IMAGE_BUTTONBAR_MEDIUM); + InitializeIcon(Icon_ButtonBarSmall, IMAGE_BUTTONBAR_SMALL); + + InitializeIcon(Icon_Command1Large, IMAGE_COMMAND1_LARGE); + InitializeIcon(Icon_Command1LargeHover, IMAGE_COMMAND1_LARGE_HOVER); + InitializeIcon(Icon_Command1Medium, IMAGE_COMMAND1_MEDIUM); + InitializeIcon(Icon_Command1MediumHover, IMAGE_COMMAND1_MEDIUM_HOVER); + InitializeIcon(Icon_Command1Small, IMAGE_COMMAND1_SMALL); + InitializeIcon(Icon_Command1SmallHover, IMAGE_COMMAND1_SMALL_HOVER); + + InitializeIcon(Icon_Command2Large, IMAGE_COMMAND2_LARGE); + InitializeIcon(Icon_Command2LargeHover, IMAGE_COMMAND2_LARGE_HOVER); + InitializeIcon(Icon_Command2Medium, IMAGE_COMMAND2_MEDIUM); + InitializeIcon(Icon_Command2MediumHover, IMAGE_COMMAND2_MEDIUM_HOVER); + InitializeIcon(Icon_Command2Small, IMAGE_COMMAND2_SMALL); + InitializeIcon(Icon_Command2SmallHover, IMAGE_COMMAND2_SMALL_HOVER); + + InitializeIcon(Icon_Command2BLarge, IMAGE_COMMAND2B_LARGE); + InitializeIcon(Icon_Command2BLargeHover, IMAGE_COMMAND2B_LARGE_HOVER); + InitializeIcon(Icon_Command2BMedium, IMAGE_COMMAND2B_MEDIUM); + InitializeIcon(Icon_Command2BMediumHover, IMAGE_COMMAND2B_MEDIUM_HOVER); + InitializeIcon(Icon_Command2BSmall, IMAGE_COMMAND2B_SMALL); + InitializeIcon(Icon_Command2BSmallHover, IMAGE_COMMAND2B_SMALL_HOVER); + + InitializeIcon(Icon_Command3Large, IMAGE_COMMAND3_LARGE); + InitializeIcon(Icon_Command3LargeHover, IMAGE_COMMAND3_LARGE_HOVER); + InitializeIcon(Icon_Command3Medium, IMAGE_COMMAND3_MEDIUM); + InitializeIcon(Icon_Command3MediumHover, IMAGE_COMMAND3_MEDIUM_HOVER); + InitializeIcon(Icon_Command3Small, IMAGE_COMMAND3_SMALL); + InitializeIcon(Icon_Command3SmallHover, IMAGE_COMMAND3_SMALL_HOVER); + } + InitializeIcon(Icon_FocusBorder, IMAGE_FOCUS_BORDER); + } +} + + + + +::boost::shared_ptr<Font> Theme::GetFont ( + const FontType eType, + const OutputDevice& rDevice) +{ + ::boost::shared_ptr<Font> pFont; + + switch (eType) + { + case Font_PageNumber: + pFont.reset(new Font(Application::GetSettings().GetStyleSettings().GetAppFont())); + pFont->SetTransparent(sal_True); + pFont->SetWeight(WEIGHT_BOLD); + break; + + case Font_PageCount: + pFont.reset(new Font(Application::GetSettings().GetStyleSettings().GetAppFont())); + pFont->SetTransparent(sal_True); + pFont->SetWeight(WEIGHT_NORMAL); + { + const Size aSize (pFont->GetSize()); + pFont->SetSize(Size(aSize.Width()*5/3, aSize.Height()*5/3)); + } + break; + + case Font_Button: + pFont.reset(new Font(Application::GetSettings().GetStyleSettings().GetAppFont())); + pFont->SetTransparent(sal_True); + pFont->SetWeight(WEIGHT_BOLD); + { + const Size aSize (pFont->GetSize()); + pFont->SetSize(Size(aSize.Width()*4/3, aSize.Height()*4/3)); + } + break; + } + + if (pFont) + { + // Transform the point size to pixel size. + const MapMode aFontMapMode (MAP_POINT); + const Size aFontSize (rDevice.LogicToPixel(pFont->GetSize(), aFontMapMode)); + + // Transform the font size to the logical coordinates of the device. + pFont->SetSize(rDevice.PixelToLogic(aFontSize)); + } + + return pFont; +} + + + + +ColorData Theme::GetColor (const ColorType eType) +{ + if (eType>=0 && sal_uInt32(eType)<maColor.size()) + return maColor[eType]; + else + return 0; +} + + + + +void Theme::SetColor ( + const ColorType eType, + const ColorData aData) +{ + if (eType>=0 && sal_uInt32(eType)<maColor.size()) + maColor[eType] = aData; +} + + + + +ColorData Theme::GetGradientColor ( + const GradientColorType eType, + const GradientColorClass eClass) +{ + GradientDescriptor& rDescriptor (GetGradient(eType)); + + switch (eClass) + { + case Border1: return rDescriptor.maBorderColor1; + case Border2: return rDescriptor.maBorderColor2; + case Fill1: return rDescriptor.maFillColor1; + case Fill2: return rDescriptor.maFillColor2; + default: OSL_ASSERT(false); // fall through + case Base: return rDescriptor.maBaseColor; + } +} + + + + +sal_Int32 Theme::GetGradientOffset ( + const GradientColorType eType, + const GradientColorClass eClass) +{ + GradientDescriptor& rDescriptor (GetGradient(eType)); + + switch (eClass) + { + case Border1: return rDescriptor.mnBorderOffset1; + case Border2: return rDescriptor.mnBorderOffset2; + case Fill1: return rDescriptor.mnFillOffset1; + case Fill2: return rDescriptor.mnFillOffset2; + default: OSL_ASSERT(false); // fall through + case Base: return 0; + } +} + + + + +void Theme::SetGradient ( + const GradientColorType eType, + const ColorData aBaseColor, + const sal_Int32 nSaturationOverride, + const sal_Int32 nBrightnessOverride, + const sal_Int32 nFillStartOffset, + const sal_Int32 nFillEndOffset, + const sal_Int32 nBorderStartOffset, + const sal_Int32 nBorderEndOffset) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + + rGradient.maBaseColor = aBaseColor; + + rGradient.mnSaturationOverride = nSaturationOverride; + rGradient.mnBrightnessOverride = nBrightnessOverride; + const ColorData aColor (nSaturationOverride>=0 || nBrightnessOverride>=0 + ? HGBAdapt(aBaseColor, nSaturationOverride, nBrightnessOverride) + : aBaseColor); + + rGradient.maFillColor1 = ChangeLuminance(aColor, nFillStartOffset); + rGradient.maFillColor2 = ChangeLuminance(aColor, nFillEndOffset); + rGradient.maBorderColor1 = ChangeLuminance(aColor, nBorderStartOffset); + rGradient.maBorderColor2 = ChangeLuminance(aColor, nBorderEndOffset); + + rGradient.mnFillOffset1 = nFillStartOffset; + rGradient.mnFillOffset2 = nFillEndOffset; + rGradient.mnBorderOffset1 = nBorderStartOffset; + rGradient.mnBorderOffset2 = nBorderEndOffset; +} + + + + +sal_Int32 Theme::GetGradientSaturationOverride (const GradientColorType eType) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + return rGradient.mnSaturationOverride; +} + + + + +sal_Int32 Theme::GetGradientBrightnessOverride (const GradientColorType eType) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + return rGradient.mnBrightnessOverride; +} + + + + +void Theme::SetGradientSaturationOverride (const GradientColorType eType, const sal_Int32 nValue) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + SetGradient( + eType, + rGradient.maBaseColor, + nValue, + rGradient.mnBrightnessOverride, + rGradient.mnFillOffset1, + rGradient.mnFillOffset2, + rGradient.mnBorderOffset1, + rGradient.mnBorderOffset2); +} + + + + +void Theme::SetGradientBrightnessOverride (const GradientColorType eType, const sal_Int32 nValue) +{ + GradientDescriptor& rGradient (GetGradient(eType)); + SetGradient(eType, + rGradient.maBaseColor, + rGradient.mnSaturationOverride, + nValue, + rGradient.mnFillOffset1, + rGradient.mnFillOffset2, + rGradient.mnBorderOffset1, + rGradient.mnBorderOffset2); +} + + + + +const BitmapEx& Theme::GetIcon (const IconType eType) +{ + if (eType>=0 && size_t(eType)<maIcons.size()) + return maIcons[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIcons.size()); + return maIcons[0]; + } +} + + + + +sal_Int32 Theme::GetIntegerValue (const IntegerValueType eType) const +{ + if (eType>=0 && size_t(eType)<maIntegerValues.size()) + return maIntegerValues[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIntegerValues.size()); + return 0; + } +} + + + + +void Theme::SetIntegerValue (const IntegerValueType eType, const sal_Int32 nValue) +{ + if (eType>=0 && size_t(eType)<maIntegerValues.size()) + maIntegerValues[eType] = nValue; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIntegerValues.size()); + } +} + + + + +::rtl::OUString Theme::GetString (const StringType eType) const +{ + if (eType>=0 && size_t(eType)<maStrings.size()) + return maStrings[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maStrings.size()); + return ::rtl::OUString(); + } +} + + + + +Theme::GradientDescriptor& Theme::GetGradient (const GradientColorType eType) +{ + if (eType>=0 && size_t(eType)<maGradients.size()) + return maGradients[eType]; + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maGradients.size()); + return maGradients[0]; + } +} + + + + +void Theme::InitializeIcon (const IconType eType, sal_uInt16 nResourceId) +{ + if (eType>=0 && size_t(eType)<maIcons.size()) + { + const BitmapEx aIcon (Image(SdResId(nResourceId)).GetBitmapEx()); + maIcons[eType] = aIcon; + } + else + { + OSL_ASSERT(eType>=0 && size_t(eType)<maIcons.size()); + } +} + + + + +} } } // end of namespace ::sd::slidesorter::view diff --git a/sd/source/ui/slidesorter/view/SlsToolTip.cxx b/sd/source/ui/slidesorter/view/SlsToolTip.cxx new file mode 100644 index 000000000000..211760ef2002 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsToolTip.cxx @@ -0,0 +1,230 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "view/SlsToolTip.hxx" +#include "view/SlideSorterView.hxx" +#include "view/SlsLayouter.hxx" +#include "view/SlsTheme.hxx" +#include "sdpage.hxx" +#include "sdresid.hxx" +#include "glob.hrc" +#include <vcl/help.hxx> + +using ::rtl::OUString; + +namespace sd { namespace slidesorter { namespace view { + +ToolTip::ToolTip (SlideSorter& rSlideSorter) + : mrSlideSorter(rSlideSorter), + msDefaultHelpText(), + msCurrentHelpText(), + mnHelpWindowHandle(0), + maTimer() +{ + maTimer.SetTimeout(rSlideSorter.GetTheme()->GetIntegerValue(Theme::Integer_ToolTipDelay)); + maTimer.SetTimeoutHdl(LINK(this, ToolTip, DelayTrigger)); +} + + + + +ToolTip::~ToolTip (void) +{ + maTimer.Stop(); + Hide(); +} + + + + +void ToolTip::SetPage (const model::SharedPageDescriptor& rpDescriptor) +{ + if (mpDescriptor != rpDescriptor) + { + maTimer.Stop(); + Hide(); + + mpDescriptor = rpDescriptor; + + if (mpDescriptor) + { + SdPage* pPage = mpDescriptor->GetPage(); + OUString sHelpText; + if (pPage != NULL) + sHelpText = pPage->GetName(); + else + { + OSL_ASSERT(mpDescriptor->GetPage() != NULL); + } + if (sHelpText.getLength() == 0) + { + sHelpText = String(SdResId(STR_PAGE)); + sHelpText += String::CreateFromInt32(mpDescriptor->GetPageIndex()+1); + } + + msDefaultHelpText = sHelpText; + msCurrentHelpText = sHelpText; + Show(false); + } + else + { + msDefaultHelpText = OUString(); + msCurrentHelpText = OUString(); + } + } +} + + + + +void ToolTip::ShowDefaultHelpText (const ::rtl::OUString& rsHelpText) +{ + if (msDefaultHelpText != rsHelpText) + { + const bool bIsVisible (Hide()); + + msDefaultHelpText = rsHelpText; + msCurrentHelpText = rsHelpText; + + Show(bIsVisible); + } +} + + + + +void ToolTip::ShowDefaultHelpText (void) +{ + if (msCurrentHelpText != msDefaultHelpText) + { + const bool bIsVisible (Hide()); + + msCurrentHelpText = msDefaultHelpText; + + Show(bIsVisible); + } +} + + + + +void ToolTip::ShowHelpText (const ::rtl::OUString& rsHelpText) +{ + if (msCurrentHelpText != rsHelpText) + { + const bool bIsVisible (Hide()); + + msCurrentHelpText = rsHelpText; + + Show(bIsVisible); + } +} + + + + +void ToolTip::Show (const bool bNoDelay) +{ + if (bNoDelay) + DoShow(); + else + maTimer.Start(); +} + + + + +void ToolTip::DoShow (void) +{ + if (maTimer.IsActive()) + { + // The delay timer is active. Wait for it to trigger the showing of + // the tool tip. + return; + } + + SharedSdWindow pWindow (mrSlideSorter.GetContentWindow()); + if (msCurrentHelpText.getLength()>0 && pWindow) + { + Rectangle aBox ( + mrSlideSorter.GetView().GetLayouter().GetPageObjectLayouter()->GetBoundingBox( + mpDescriptor, + PageObjectLayouter::Preview, + PageObjectLayouter::WindowCoordinateSystem)); + + // Do not show the help text when the (lower edge of the ) preview + // is not visible. The tool tip itself may still be outside the + // window. + if (aBox.Bottom() >= pWindow->GetSizePixel().Height()) + return; + + ::Window* pParent (pWindow.get()); + while (pParent!=NULL && pParent->GetParent()!=NULL) + pParent = pParent->GetParent(); + const Point aOffset (pWindow->GetWindowExtentsRelative(pParent).TopLeft()); + + // We do not know how high the tool tip will be but want its top + // edge not its bottom to be at a specific position (a little below + // the preview). Therefore we use a little trick and place the tool + // tip at the top of a rectangle that is placed below the preview. + aBox.Move(aOffset.X(), aOffset.Y() + aBox.GetHeight() + 3); + mnHelpWindowHandle = Help::ShowTip( + pWindow.get(), + aBox, + msCurrentHelpText, + QUICKHELP_CENTER | QUICKHELP_TOP); + } +} + + + + +bool ToolTip::Hide (void) +{ + if (mnHelpWindowHandle>0) + { + Help::HideTip(mnHelpWindowHandle); + mnHelpWindowHandle = 0; + return true; + } + else + return false; +} + + + + +IMPL_LINK(ToolTip, DelayTrigger, void*, EMPTYARG) +{ + DoShow(); + + return 0; +} + +} } } // 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..76da9c1a4f15 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.cxx @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sd.hxx" + +#include "SlsViewCacheContext.hxx" + +#include "SlideSorter.hxx" +#include "model/SlideSorterModel.hxx" +#include "model/SlsPageDescriptor.hxx" +#include "model/SlsPageEnumerationProvider.hxx" +#include "view/SlideSorterView.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 (SlideSorter& rSlideSorter) + : mrModel(rSlideSorter.GetModel()), + mrSlideSorter(rSlideSorter) +{ +} + + + + +ViewCacheContext::~ViewCacheContext (void) +{ +} + + + + +void ViewCacheContext::NotifyPreviewCreation ( + cache::CacheKey aKey, + const Bitmap&) +{ + const model::SharedPageDescriptor pDescriptor (GetDescriptor(aKey)); + if (pDescriptor.get() != NULL) + { + // Force a repaint that will trigger their re-creation. + mrSlideSorter.GetView().RequestRepaint(pDescriptor); + } + else + { + OSL_ASSERT(pDescriptor); + } +} + + + + +bool ViewCacheContext::IsIdle (void) +{ + sal_Int32 nIdleState (tools::IdleDetection::GetIdleState(mrSlideSorter.GetContentWindow().get())); + if (nIdleState == tools::IdleDetection::IDET_IDLE) + return true; + else + return false; +} + + + + +bool ViewCacheContext::IsVisible (cache::CacheKey aKey) +{ + const model::SharedPageDescriptor pDescriptor (GetDescriptor(aKey)); + return pDescriptor && pDescriptor->HasState(model::PageDescriptor::ST_Visible); +} + + + + +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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx new file mode 100644 index 000000000000..886e36c82210 --- /dev/null +++ b/sd/source/ui/slidesorter/view/SlsViewCacheContext.hxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <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 { +class SlideSorter; +} } + +namespace sd { namespace slidesorter { namespace view { + +/** 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 (SlideSorter& rSlideSorter); + virtual ~ViewCacheContext (void); + virtual void NotifyPreviewCreation (cache::CacheKey aKey, const Bitmap& 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; + SlideSorter& mrSlideSorter; + + model::SharedPageDescriptor GetDescriptor (cache::CacheKey aKey); +}; + + +} } } // end of namespace ::sd::slidesorter::view + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/source/ui/slidesorter/view/makefile.mk b/sd/source/ui/slidesorter/view/makefile.mk new file mode 100755 index 000000000000..3c5fc39c3ede --- /dev/null +++ b/sd/source/ui/slidesorter/view/makefile.mk @@ -0,0 +1,69 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/..$/.. + +PROJECTPCH=sd +PROJECTPCHSOURCE=$(PRJ)$/util$/sd +PRJNAME=sd +TARGET=slsview +ENABLE_EXCEPTIONS=TRUE +AUTOSEG=true +PRJINC=..$/.. + +IMGLST_SRS=$(SRS)$/$(TARGET).srs + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SRS1NAME=$(TARGET) +SRC1FILES = \ + SlsResource.src + +SLOFILES = \ + $(SLO)$/SlideSorterView.obj \ + $(SLO)$/SlsButtonBar.obj \ + $(SLO)$/SlsFontProvider.obj \ + $(SLO)$/SlsFramePainter.obj \ + $(SLO)$/SlsInsertAnimator.obj \ + $(SLO)$/SlsInsertionIndicatorOverlay.obj\ + $(SLO)$/SlsLayeredDevice.obj \ + $(SLO)$/SlsLayouter.obj \ + $(SLO)$/SlsPageObjectLayouter.obj \ + $(SLO)$/SlsPageObjectPainter.obj \ + $(SLO)$/SlsTheme.obj \ + $(SLO)$/SlsToolTip.obj \ + $(SLO)$/SlsViewCacheContext.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + |