| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| #include "precompiled_sd.hxx" |
| |
| #include "RecentlyUsedMasterPages.hxx" |
| #include "MasterPageObserver.hxx" |
| #include "MasterPagesSelector.hxx" |
| #include "MasterPageDescriptor.hxx" |
| #include "tools/ConfigurationAccess.hxx" |
| #include "drawdoc.hxx" |
| #include "sdpage.hxx" |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include <comphelper/processfactory.hxx> |
| #include "unomodel.hxx" |
| #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> |
| #include <com/sun/star/drawing/XDrawPages.hpp> |
| #include <com/sun/star/frame/XComponentLoader.hpp> |
| #include <com/sun/star/container/XNameAccess.hpp> |
| #include <com/sun/star/container/XHierarchicalNameAccess.hpp> |
| #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
| #include <com/sun/star/beans/PropertyValue.hpp> |
| #include <com/sun/star/beans/PropertyState.hpp> |
| #include <tools/urlobj.hxx> |
| #include <unotools/confignode.hxx> |
| #include <osl/doublecheckedlocking.h> |
| #include <osl/getglobalmutex.hxx> |
| |
| using namespace ::std; |
| using ::rtl::OUString; |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| |
| |
| namespace { |
| |
| static const OUString& GetPathToImpressConfigurationRoot (void) |
| { |
| static const OUString sPathToImpressConfigurationRoot ( |
| RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.Office.Impress/")); |
| return sPathToImpressConfigurationRoot; |
| } |
| static const OUString& GetPathToSetNode (void) |
| { |
| static const OUString sPathToSetNode( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "MultiPaneGUI/ToolPanel/RecentlyUsedMasterPages")); |
| return sPathToSetNode; |
| } |
| |
| |
| class Descriptor |
| { |
| public: |
| ::rtl::OUString msURL; |
| ::rtl::OUString msName; |
| ::sd::sidebar::MasterPageContainer::Token maToken; |
| Descriptor (const ::rtl::OUString& rsURL, const ::rtl::OUString& rsName) |
| : msURL(rsURL), |
| msName(rsName), |
| maToken(::sd::sidebar::MasterPageContainer::NIL_TOKEN) |
| {} |
| Descriptor (::sd::sidebar::MasterPageContainer::Token aToken, |
| const ::rtl::OUString& rsURL, const ::rtl::OUString& rsName) |
| : msURL(rsURL), |
| msName(rsName), |
| maToken(aToken) |
| {} |
| class TokenComparator |
| { public: |
| TokenComparator(::sd::sidebar::MasterPageContainer::Token aToken) |
| : maToken(aToken) {} |
| bool operator () (const Descriptor& rDescriptor) |
| { return maToken==rDescriptor.maToken; } |
| private: ::sd::sidebar::MasterPageContainer::Token maToken; |
| }; |
| }; |
| |
| } // end of anonymous namespace |
| |
| |
| |
| |
| namespace sd { namespace sidebar { |
| |
| class RecentlyUsedMasterPages::MasterPageList : public ::std::vector<Descriptor> |
| { |
| public: |
| MasterPageList (void) {} |
| }; |
| |
| |
| RecentlyUsedMasterPages* RecentlyUsedMasterPages::mpInstance = NULL; |
| |
| |
| RecentlyUsedMasterPages& RecentlyUsedMasterPages::Instance (void) |
| { |
| if (mpInstance == NULL) |
| { |
| ::osl::GetGlobalMutex aMutexFunctor; |
| ::osl::MutexGuard aGuard (aMutexFunctor()); |
| if (mpInstance == NULL) |
| { |
| RecentlyUsedMasterPages* pInstance = new RecentlyUsedMasterPages(); |
| pInstance->LateInit(); |
| SdGlobalResourceContainer::Instance().AddResource ( |
| ::std::auto_ptr<SdGlobalResource>(pInstance)); |
| OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
| mpInstance = pInstance; |
| } |
| } |
| else { |
| OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); |
| } |
| |
| return *mpInstance; |
| } |
| |
| |
| |
| |
| RecentlyUsedMasterPages::RecentlyUsedMasterPages (void) |
| : maListeners(), |
| mpMasterPages(new MasterPageList()), |
| mnMaxListSize(8), |
| mpContainer(new MasterPageContainer()) |
| { |
| } |
| |
| |
| |
| |
| RecentlyUsedMasterPages::~RecentlyUsedMasterPages (void) |
| { |
| Link aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener)); |
| mpContainer->RemoveChangeListener(aLink); |
| |
| MasterPageObserver::Instance().RemoveEventListener( |
| LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener)); |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::LateInit (void) |
| { |
| Link aLink (LINK(this,RecentlyUsedMasterPages,MasterPageContainerChangeListener)); |
| mpContainer->AddChangeListener(aLink); |
| |
| LoadPersistentValues (); |
| MasterPageObserver::Instance().AddEventListener( |
| LINK(this,RecentlyUsedMasterPages,MasterPageChangeListener)); |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::LoadPersistentValues (void) |
| { |
| try |
| { |
| do |
| { |
| tools::ConfigurationAccess aConfiguration ( |
| GetPathToImpressConfigurationRoot(), |
| tools::ConfigurationAccess::READ_ONLY); |
| Reference<container::XNameAccess> xSet ( |
| aConfiguration.GetConfigurationNode(GetPathToSetNode()), |
| UNO_QUERY); |
| if ( ! xSet.is()) |
| break; |
| |
| const String sURLMemberName (OUString::createFromAscii("URL")); |
| const String sNameMemberName (OUString::createFromAscii("Name")); |
| OUString sURL; |
| OUString sName; |
| |
| // Read the names and URLs of the master pages. |
| Sequence<OUString> aKeys (xSet->getElementNames()); |
| mpMasterPages->clear(); |
| mpMasterPages->reserve(aKeys.getLength()); |
| for (int i=0; i<aKeys.getLength(); i++) |
| { |
| Reference<container::XNameAccess> xSetItem ( |
| xSet->getByName(aKeys[i]), UNO_QUERY); |
| if (xSetItem.is()) |
| { |
| Any aURL (xSetItem->getByName(sURLMemberName)); |
| Any aName (xSetItem->getByName(sNameMemberName)); |
| aURL >>= sURL; |
| aName >>= sName; |
| SharedMasterPageDescriptor pDescriptor (new MasterPageDescriptor( |
| MasterPageContainer::TEMPLATE, |
| -1, |
| sURL, |
| String(), |
| sName, |
| false, |
| ::boost::shared_ptr<PageObjectProvider>( |
| new TemplatePageObjectProvider(sURL)), |
| ::boost::shared_ptr<PreviewProvider>( |
| new TemplatePreviewProvider(sURL)))); |
| // For user supplied templates we use a different |
| // preview provider: The preview in the document shows |
| // not only shapes on the master page but also shapes on |
| // the foreground. This is misleading and therefore |
| // these previews are discarded and created directly |
| // from the page objects. |
| if (pDescriptor->GetURLClassification() == MasterPageDescriptor::URLCLASS_USER) |
| pDescriptor->mpPreviewProvider = ::boost::shared_ptr<PreviewProvider>( |
| new PagePreviewProvider()); |
| MasterPageContainer::Token aToken (mpContainer->PutMasterPage(pDescriptor)); |
| mpMasterPages->push_back(Descriptor(aToken,sURL,sName)); |
| } |
| } |
| |
| ResolveList(); |
| } |
| while (false); |
| } |
| catch (Exception&) |
| { |
| // Ignore exception. |
| } |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::SavePersistentValues (void) |
| { |
| try |
| { |
| do |
| { |
| tools::ConfigurationAccess aConfiguration ( |
| GetPathToImpressConfigurationRoot(), |
| tools::ConfigurationAccess::READ_WRITE); |
| Reference<container::XNameContainer> xSet ( |
| aConfiguration.GetConfigurationNode(GetPathToSetNode()), |
| UNO_QUERY); |
| if ( ! xSet.is()) |
| break; |
| |
| // Clear the set. |
| Sequence<OUString> aKeys (xSet->getElementNames()); |
| sal_Int32 i; |
| for (i=0; i<aKeys.getLength(); i++) |
| xSet->removeByName (aKeys[i]); |
| |
| // Fill it with the URLs of this object. |
| const String sURLMemberName (OUString::createFromAscii("URL")); |
| const String sNameMemberName (OUString::createFromAscii("Name")); |
| Any aValue; |
| Reference<lang::XSingleServiceFactory> xChildFactory ( |
| xSet, UNO_QUERY); |
| if ( ! xChildFactory.is()) |
| break; |
| MasterPageList::const_iterator iDescriptor; |
| sal_Int32 nIndex(0); |
| for (iDescriptor=mpMasterPages->begin(); |
| iDescriptor!=mpMasterPages->end(); |
| ++iDescriptor,++nIndex) |
| { |
| // Create new child. |
| OUString sKey (OUString::createFromAscii("index_")); |
| sKey += OUString::valueOf(nIndex); |
| Reference<container::XNameReplace> xChild( |
| xChildFactory->createInstance(), UNO_QUERY); |
| if (xChild.is()) |
| { |
| xSet->insertByName (sKey, makeAny(xChild)); |
| |
| aValue <<= OUString(iDescriptor->msURL); |
| xChild->replaceByName (sURLMemberName, aValue); |
| |
| aValue <<= OUString(iDescriptor->msName); |
| xChild->replaceByName (sNameMemberName, aValue); |
| } |
| } |
| |
| // Write the data back to disk. |
| aConfiguration.CommitChanges(); |
| } |
| while (false); |
| } |
| catch (Exception&) |
| { |
| // Ignore exception. |
| } |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::AddEventListener (const Link& rEventListener) |
| { |
| if (::std::find ( |
| maListeners.begin(), |
| maListeners.end(), |
| rEventListener) == maListeners.end()) |
| { |
| maListeners.push_back (rEventListener); |
| } |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::RemoveEventListener (const Link& rEventListener) |
| { |
| maListeners.erase ( |
| ::std::find ( |
| maListeners.begin(), |
| maListeners.end(), |
| rEventListener)); |
| } |
| |
| |
| |
| |
| int RecentlyUsedMasterPages::GetMasterPageCount (void) const |
| { |
| return mpMasterPages->size(); |
| } |
| |
| |
| |
| |
| MasterPageContainer::Token RecentlyUsedMasterPages::GetTokenForIndex (sal_uInt32 nIndex) const |
| { |
| if(nIndex<mpMasterPages->size()) |
| return (*mpMasterPages)[nIndex].maToken; |
| else |
| return MasterPageContainer::NIL_TOKEN; |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::SendEvent (void) |
| { |
| ::std::vector<Link>::iterator aLink (maListeners.begin()); |
| ::std::vector<Link>::iterator aEnd (maListeners.end()); |
| while (aLink!=aEnd) |
| { |
| aLink->Call (NULL); |
| ++aLink; |
| } |
| } |
| |
| |
| |
| |
| IMPL_LINK(RecentlyUsedMasterPages, MasterPageChangeListener, |
| MasterPageObserverEvent*, pEvent) |
| { |
| switch (pEvent->meType) |
| { |
| case MasterPageObserverEvent::ET_MASTER_PAGE_ADDED: |
| case MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS: |
| AddMasterPage( |
| mpContainer->GetTokenForStyleName(pEvent->mrMasterPageName)); |
| break; |
| |
| case MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED: |
| // Do not change the list of recently master pages (the deleted |
| // page was recently used) but tell the listeners. They may want |
| // to update their lists. |
| SendEvent(); |
| break; |
| } |
| return 0; |
| } |
| |
| |
| |
| |
| IMPL_LINK(RecentlyUsedMasterPages, MasterPageContainerChangeListener, |
| MasterPageContainerChangeEvent*, pEvent) |
| { |
| if (pEvent != NULL) |
| switch (pEvent->meEventType) |
| { |
| case MasterPageContainerChangeEvent::CHILD_ADDED: |
| case MasterPageContainerChangeEvent::CHILD_REMOVED: |
| case MasterPageContainerChangeEvent::INDEX_CHANGED: |
| case MasterPageContainerChangeEvent::INDEXES_CHANGED: |
| ResolveList(); |
| break; |
| |
| default: |
| // Ignored. |
| break; |
| } |
| return 0; |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::AddMasterPage ( |
| MasterPageContainer::Token aToken, |
| bool bMakePersistent) |
| { |
| // For the page to be inserted the token has to be valid and the page |
| // has to have a valid URL. This excludes master pages that do not come |
| // from template files. |
| if (aToken != MasterPageContainer::NIL_TOKEN |
| && mpContainer->GetURLForToken(aToken).Len()>0) |
| { |
| |
| MasterPageList::iterator aIterator ( |
| ::std::find_if(mpMasterPages->begin(),mpMasterPages->end(), |
| Descriptor::TokenComparator(aToken))); |
| if (aIterator != mpMasterPages->end()) |
| { |
| // When an entry for the given token already exists then remove |
| // it now and insert it later at the head of the list. |
| mpMasterPages->erase (aIterator); |
| } |
| |
| mpMasterPages->insert(mpMasterPages->begin(), |
| Descriptor( |
| aToken, |
| mpContainer->GetURLForToken(aToken), |
| mpContainer->GetStyleNameForToken(aToken))); |
| |
| // Shorten list to maximal size. |
| while (mpMasterPages->size() > mnMaxListSize) |
| { |
| mpMasterPages->pop_back (); |
| } |
| |
| if (bMakePersistent) |
| SavePersistentValues (); |
| SendEvent(); |
| } |
| } |
| |
| |
| |
| |
| void RecentlyUsedMasterPages::ResolveList (void) |
| { |
| bool bNotify (false); |
| |
| MasterPageList::iterator iDescriptor; |
| for (iDescriptor=mpMasterPages->begin(); iDescriptor!=mpMasterPages->end(); ++iDescriptor) |
| { |
| if (iDescriptor->maToken == MasterPageContainer::NIL_TOKEN) |
| { |
| MasterPageContainer::Token aToken (mpContainer->GetTokenForURL(iDescriptor->msURL)); |
| iDescriptor->maToken = aToken; |
| if (aToken != MasterPageContainer::NIL_TOKEN) |
| bNotify = true; |
| } |
| else |
| { |
| if ( ! mpContainer->HasToken(iDescriptor->maToken)) |
| { |
| iDescriptor->maToken = MasterPageContainer::NIL_TOKEN; |
| bNotify = true; |
| } |
| } |
| } |
| |
| if (bNotify) |
| SendEvent(); |
| } |
| |
| |
| } } // end of namespace sd::sidebar |