/************************************************************** * * 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 #endif #include #include #include #include #include #include #include #include #include #include #include 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& rxFolderEnvironment) : mnPriority(nPriority), msTitle(rsTitle), msTargetDir(rsTargetDir), msContentIdentifier(rsContentIdentifier), mxFolderEnvironment(rxFolderEnvironment) { } int mnPriority; ::rtl::OUString msTitle; ::rtl::OUString msTargetDir; ::rtl::OUString msContentIdentifier; // Reference mxFolderResultSet; Reference 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 { }; 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::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 xFactory = ::comphelper::getProcessServiceFactory (); DBG_ASSERT (xFactory.is(), "TemplateScanner::GetTemplateRoot: xFactory is NULL"); if (xFactory.is()) { Reference 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(); // We are interested only in three properties: the entry's name, // its URL, and its content type. Sequence 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( maFolderContent.createCursor(aProps, eInclude)); } else eNextState = ERROR; return eNextState; } TemplateScanner::State TemplateScanner::ScanEntry (void) { State eNextState (ERROR); Reference xContentAccess (mxEntryResultSet, UNO_QUERY); Reference 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(); try { // Create content for template folders. mxFolderEnvironment = Reference(); ::ucbhelper::Content aTemplateDir (mxTemplateRoot, mxFolderEnvironment); // Define the list of properties we are interested in. Sequence 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( 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 xContentAccess (mxFolderResultSet, UNO_QUERY); if (xContentAccess.is() && mxFolderResultSet.is()) { while (mxFolderResultSet->next()) { Reference 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& 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; } }