| /************************************************************** |
| * |
| * 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. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sd.hxx" |
| |
| #include "TemplateScanner.hxx" |
| |
| #ifndef _COMPHELPER_SERVICEFACTORY_HXX |
| #include <comphelper/processfactory.hxx> |
| #endif |
| #include <comphelper/documentconstants.hxx> |
| |
| #include <tools/debug.hxx> |
| #include <vos/mutex.hxx> |
| #include <vcl/svapp.hxx> |
| #include <com/sun/star/frame/XDocumentTemplates.hpp> |
| #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
| #include <com/sun/star/ucb/XCommandEnvironment.hpp> |
| #include <com/sun/star/ucb/XContentAccess.hpp> |
| #include <com/sun/star/sdbc/XResultSet.hpp> |
| #include <com/sun/star/sdbc/XRow.hpp> |
| |
| #include <set> |
| |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| |
| namespace { |
| |
| const ::rtl::OUString TITLE = ::rtl::OUString::createFromAscii ("Title"); |
| const ::rtl::OUString TARGET_DIR_URL = ::rtl::OUString::createFromAscii ("TargetDirURL"); |
| const ::rtl::OUString DESCRIPTION = ::rtl::OUString::createFromAscii ("TypeDescription"); |
| const ::rtl::OUString TARGET_URL = ::rtl::OUString::createFromAscii ("TargetURL"); |
| |
| const ::rtl::OUString DOCTEMPLATES = ::rtl::OUString::createFromAscii ("com.sun.star.frame.DocumentTemplates"); |
| |
| // These strings are used to find impress templates in the tree of |
| // template files. Should probably be determined dynamically. |
| const ::rtl::OUString IMPRESS_BIN_TEMPLATE = ::rtl::OUString::createFromAscii ("application/vnd.stardivision.impress"); |
| const ::rtl::OUString IMPRESS_XML_TEMPLATE = MIMETYPE_VND_SUN_XML_IMPRESS; |
| // The following id comes from the bugdoc in #i2764#. |
| const ::rtl::OUString IMPRESS_XML_TEMPLATE_B = ::rtl::OUString::createFromAscii ("Impress 2.0"); |
| const ::rtl::OUString IMPRESS_XML_TEMPLATE_OASIS = MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION; |
| |
| |
| class FolderDescriptor |
| { |
| public: |
| FolderDescriptor ( |
| int nPriority, |
| const ::rtl::OUString& rsTitle, |
| const ::rtl::OUString& rsTargetDir, |
| const ::rtl::OUString& rsContentIdentifier, |
| const Reference<com::sun::star::ucb::XCommandEnvironment>& rxFolderEnvironment) |
| : mnPriority(nPriority), |
| msTitle(rsTitle), |
| msTargetDir(rsTargetDir), |
| msContentIdentifier(rsContentIdentifier), |
| mxFolderEnvironment(rxFolderEnvironment) |
| { } |
| int mnPriority; |
| ::rtl::OUString msTitle; |
| ::rtl::OUString msTargetDir; |
| ::rtl::OUString msContentIdentifier; |
| // Reference<sdbc::XResultSet> mxFolderResultSet; |
| Reference<com::sun::star::ucb::XCommandEnvironment> mxFolderEnvironment; |
| |
| class Comparator { public: |
| bool operator() (const FolderDescriptor& r1, const FolderDescriptor& r2) |
| { return r1.mnPriority < r2.mnPriority; } |
| }; |
| }; |
| |
| /** Use a heuristic based on the URL of a top-level template folder to |
| assign a priority that is used to sort the folders. |
| */ |
| int Classify (const ::rtl::OUString&, const ::rtl::OUString& rsURL) |
| { |
| int nPriority (0); |
| |
| if (rsURL.getLength() == 0) |
| nPriority = 100; |
| else if (rsURL.indexOf(::rtl::OUString::createFromAscii("presnt"))>=0) |
| { |
| nPriority = 30; |
| } |
| else if (rsURL.indexOf(::rtl::OUString::createFromAscii("layout"))>=0) |
| { |
| nPriority = 20; |
| } |
| else if (rsURL.indexOf(::rtl::OUString::createFromAscii("educate"))>=0) |
| { |
| nPriority = 40; |
| } |
| else if (rsURL.indexOf(::rtl::OUString::createFromAscii("finance"))>=0) |
| { |
| nPriority = 40; |
| } |
| else |
| { |
| // All other folders are taken for user supplied and have the |
| // highest priority. |
| nPriority = 10; |
| } |
| |
| return nPriority; |
| } |
| |
| } // end of anonymous namespace |
| |
| |
| |
| |
| namespace sd |
| { |
| |
| class TemplateScanner::FolderDescriptorList |
| : public ::std::multiset<FolderDescriptor,FolderDescriptor::Comparator> |
| { |
| }; |
| |
| TemplateScanner::TemplateScanner (void) |
| : meState(INITIALIZE_SCANNING), |
| maFolderContent(), |
| mpTemplateDirectory(NULL), |
| maFolderList(), |
| mpLastAddedEntry(NULL), |
| mpFolderDescriptors(new FolderDescriptorList()), |
| mxTemplateRoot(), |
| mxFolderEnvironment(), |
| mxEntryEnvironment(), |
| mxFolderResultSet(), |
| mxEntryResultSet() |
| { |
| // empty; |
| } |
| |
| |
| |
| |
| TemplateScanner::~TemplateScanner (void) |
| { |
| mpFolderDescriptors.reset(); |
| |
| // Delete all entries of the template list that have not been |
| // transferred to another object. |
| std::vector<TemplateDir*>::iterator I; |
| for (I=maFolderList.begin(); I!=maFolderList.end(); I++) |
| if (*I != NULL) |
| delete *I; |
| } |
| |
| |
| |
| |
| TemplateScanner::State TemplateScanner::GetTemplateRoot (void) |
| { |
| State eNextState (INITIALIZE_FOLDER_SCANNING); |
| |
| Reference<lang::XMultiServiceFactory> xFactory = ::comphelper::getProcessServiceFactory (); |
| DBG_ASSERT (xFactory.is(), "TemplateScanner::GetTemplateRoot: xFactory is NULL"); |
| |
| if (xFactory.is()) |
| { |
| Reference<frame::XDocumentTemplates> xTemplates ( |
| xFactory->createInstance (DOCTEMPLATES), UNO_QUERY); |
| DBG_ASSERT (xTemplates.is(), "TemplateScanner::GetTemplateRoot: xTemplates is NULL"); |
| |
| if (xTemplates.is()) |
| mxTemplateRoot = xTemplates->getContent(); |
| else |
| eNextState = ERROR; |
| } |
| else |
| eNextState = ERROR; |
| |
| return eNextState; |
| } |
| |
| |
| |
| |
| TemplateScanner::State TemplateScanner::InitializeEntryScanning (void) |
| { |
| State eNextState (SCAN_ENTRY); |
| |
| if (maFolderContent.isFolder()) |
| { |
| mxEntryEnvironment = Reference<com::sun::star::ucb::XCommandEnvironment>(); |
| |
| // We are interested only in three properties: the entry's name, |
| // its URL, and its content type. |
| Sequence<rtl::OUString> aProps (3); |
| aProps[0] = TITLE; |
| aProps[1] = TARGET_URL; |
| aProps[2] = DESCRIPTION; |
| |
| // Create a cursor to iterate over the templates in this folders. |
| ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_DOCUMENTS_ONLY; |
| mxEntryResultSet = Reference<com::sun::star::sdbc::XResultSet>( |
| maFolderContent.createCursor(aProps, eInclude)); |
| } |
| else |
| eNextState = ERROR; |
| |
| return eNextState; |
| } |
| |
| |
| |
| |
| TemplateScanner::State TemplateScanner::ScanEntry (void) |
| { |
| State eNextState (ERROR); |
| |
| Reference<com::sun::star::ucb::XContentAccess> xContentAccess (mxEntryResultSet, UNO_QUERY); |
| Reference<com::sun::star::sdbc::XRow> xRow (mxEntryResultSet, UNO_QUERY); |
| |
| if (xContentAccess.is() && xRow.is() && mxEntryResultSet.is()) |
| { |
| if (mxEntryResultSet->next()) |
| { |
| ::rtl::OUString sTitle (xRow->getString (1)); |
| ::rtl::OUString sTargetURL (xRow->getString (2)); |
| ::rtl::OUString sContentType (xRow->getString (3)); |
| |
| ::rtl::OUString aId = xContentAccess->queryContentIdentifierString(); |
| ::ucbhelper::Content aContent = ::ucbhelper::Content (aId, mxEntryEnvironment); |
| if (aContent.isDocument ()) |
| { |
| // Check wether the entry is an impress template. If so |
| // add a new entry to the resulting list (which is created |
| // first if necessary). |
| if ( (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE) |
| || (sContentType == IMPRESS_XML_TEMPLATE_OASIS) |
| || (sContentType == IMPRESS_BIN_TEMPLATE) |
| || (sContentType == IMPRESS_XML_TEMPLATE) |
| || (sContentType == IMPRESS_XML_TEMPLATE_B)) |
| { |
| mpLastAddedEntry = new TemplateEntry(sTitle, sTargetURL); |
| mpTemplateDirectory->maEntries.push_back(mpLastAddedEntry); |
| } |
| } |
| |
| // Continue scanning entries. |
| eNextState = SCAN_ENTRY; |
| } |
| else |
| { |
| if (mpTemplateDirectory->maEntries.empty()) |
| { |
| delete mpTemplateDirectory; |
| mpTemplateDirectory = NULL; |
| } |
| else |
| { |
| ::vos::OGuard aGuard(Application::GetSolarMutex()); |
| maFolderList.push_back(mpTemplateDirectory); |
| } |
| |
| // Continue with scanning the next folder. |
| eNextState = SCAN_FOLDER; |
| } |
| } |
| |
| return eNextState; |
| } |
| |
| |
| |
| |
| TemplateScanner::State TemplateScanner::InitializeFolderScanning (void) |
| { |
| State eNextState (ERROR); |
| |
| mxFolderResultSet = Reference<sdbc::XResultSet>(); |
| |
| try |
| { |
| // Create content for template folders. |
| mxFolderEnvironment = Reference<com::sun::star::ucb::XCommandEnvironment>(); |
| ::ucbhelper::Content aTemplateDir (mxTemplateRoot, mxFolderEnvironment); |
| |
| // Define the list of properties we are interested in. |
| Sequence<rtl::OUString> aProps (2); |
| aProps[0] = TITLE; |
| aProps[1] = TARGET_DIR_URL; |
| |
| // Create an cursor to iterate over the template folders. |
| ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_ONLY; |
| mxFolderResultSet = Reference<sdbc::XResultSet>( |
| aTemplateDir.createCursor(aProps, eInclude)); |
| if (mxFolderResultSet.is()) |
| eNextState = GATHER_FOLDER_LIST; |
| } |
| catch (::com::sun::star::uno::Exception&) |
| { |
| eNextState = ERROR; |
| } |
| |
| return eNextState; |
| } |
| |
| |
| |
| |
| TemplateScanner::State TemplateScanner::GatherFolderList (void) |
| { |
| State eNextState (ERROR); |
| |
| Reference<com::sun::star::ucb::XContentAccess> xContentAccess (mxFolderResultSet, UNO_QUERY); |
| if (xContentAccess.is() && mxFolderResultSet.is()) |
| { |
| while (mxFolderResultSet->next()) |
| { |
| Reference<sdbc::XRow> xRow (mxFolderResultSet, UNO_QUERY); |
| if (xRow.is()) |
| { |
| ::rtl::OUString sTitle (xRow->getString (1)); |
| ::rtl::OUString sTargetDir (xRow->getString (2)); |
| ::rtl::OUString aId = xContentAccess->queryContentIdentifierString(); |
| |
| mpFolderDescriptors->insert( |
| FolderDescriptor( |
| Classify(sTitle,sTargetDir), |
| sTitle, |
| sTargetDir, |
| aId, |
| mxFolderEnvironment)); |
| } |
| } |
| |
| eNextState = SCAN_FOLDER; |
| } |
| |
| return eNextState; |
| } |
| |
| |
| |
| |
| TemplateScanner::State TemplateScanner::ScanFolder (void) |
| { |
| State eNextState (ERROR); |
| |
| if (mpFolderDescriptors->size() > 0) |
| { |
| FolderDescriptor aDescriptor (*mpFolderDescriptors->begin()); |
| mpFolderDescriptors->erase(mpFolderDescriptors->begin()); |
| |
| ::rtl::OUString sTitle (aDescriptor.msTitle); |
| ::rtl::OUString sTargetDir (aDescriptor.msTargetDir); |
| ::rtl::OUString aId (aDescriptor.msContentIdentifier); |
| |
| maFolderContent = ::ucbhelper::Content (aId, aDescriptor.mxFolderEnvironment); |
| if (maFolderContent.isFolder()) |
| { |
| // Scan the folder and insert it into the list of template |
| // folders. |
| mpTemplateDirectory = new TemplateDir (sTitle, sTargetDir); |
| if (mpTemplateDirectory != NULL) |
| { |
| // Continue with scanning all entries in the folder. |
| eNextState = INITIALIZE_ENTRY_SCAN; |
| } |
| } |
| } |
| else |
| { |
| eNextState = DONE; |
| } |
| |
| return eNextState; |
| } |
| |
| |
| |
| |
| void TemplateScanner::Scan (void) |
| { |
| while (HasNextStep()) |
| RunNextStep(); |
| } |
| |
| |
| |
| |
| std::vector<TemplateDir*>& TemplateScanner::GetFolderList (void) |
| { |
| return maFolderList; |
| } |
| |
| |
| |
| |
| void TemplateScanner::RunNextStep (void) |
| { |
| switch (meState) |
| { |
| case INITIALIZE_SCANNING: |
| meState = GetTemplateRoot(); |
| break; |
| |
| case INITIALIZE_FOLDER_SCANNING: |
| meState = InitializeFolderScanning(); |
| break; |
| |
| case SCAN_FOLDER: |
| meState = ScanFolder(); |
| break; |
| |
| case GATHER_FOLDER_LIST: |
| meState = GatherFolderList(); |
| break; |
| |
| case INITIALIZE_ENTRY_SCAN: |
| meState = InitializeEntryScanning(); |
| break; |
| |
| case SCAN_ENTRY: |
| meState = ScanEntry(); |
| break; |
| default: |
| break; |
| } |
| |
| switch (meState) |
| { |
| case DONE: |
| case ERROR: |
| mxTemplateRoot.clear(); |
| mxTemplateRoot.clear(); |
| mxFolderEnvironment.clear(); |
| mxEntryEnvironment.clear(); |
| mxFolderResultSet.clear(); |
| mxEntryResultSet.clear(); |
| mpLastAddedEntry = NULL; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| |
| |
| |
| bool TemplateScanner::HasNextStep (void) |
| { |
| switch (meState) |
| { |
| case DONE: |
| case ERROR: |
| return false; |
| |
| default: |
| return true; |
| } |
| } |
| |
| |
| |
| |
| const TemplateEntry* TemplateScanner::GetLastAddedEntry (void) const |
| { |
| return mpLastAddedEntry; |
| } |
| |
| } |