1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "TemplateScanner.hxx"
23 #include <comphelper/processfactory.hxx>
24 #include <comphelper/componentcontext.hxx>
25 #include <comphelper/documentconstants.hxx>
26 #include <comphelper/string.hxx>
28 #include <tools/debug.hxx>
29 #include <osl/mutex.hxx>
30 #include <vcl/svapp.hxx>
31 #include <sfx2/doctempl.hxx>
32 #include <sfx2/templatelocnames.hrc>
33 #include <com/sun/star/frame/DocumentTemplates.hpp>
34 #include <com/sun/star/frame/XDocumentTemplates.hpp>
35 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
36 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
37 #include <com/sun/star/ucb/XContentAccess.hpp>
38 #include <com/sun/star/sdbc/XResultSet.hpp>
39 #include <com/sun/star/sdbc/XRow.hpp>
43 using namespace ::com::sun::star
;
44 using namespace ::com::sun::star::uno
;
48 const char TITLE
[] = "Title";
49 const char TARGET_DIR_URL
[] = "TargetDirURL";
50 const char DESCRIPTION
[] = "TypeDescription";
51 const char TARGET_URL
[] = "TargetURL";
53 const char DOCTEMPLATES
[] = "com.sun.star.frame.DocumentTemplates";
55 // These strings are used to find impress templates in the tree of
56 // template files. Should probably be determined dynamically.
57 const char IMPRESS_BIN_TEMPLATE
[] = "application/vnd.stardivision.impress";
58 const char IMPRESS_XML_TEMPLATE
[] = MIMETYPE_VND_SUN_XML_IMPRESS_ASCII
;
59 // The following id comes from the bugdoc in #i2764#.
60 const char IMPRESS_XML_TEMPLATE_B
[] = "Impress 2.0";
61 const char IMPRESS_XML_TEMPLATE_OASIS
[] = MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII
;
64 class FolderDescriptor
69 const OUString
& rsTitle
,
70 const OUString
& rsTargetDir
,
71 const OUString
& rsContentIdentifier
,
72 const Reference
<com::sun::star::ucb::XCommandEnvironment
>& rxFolderEnvironment
)
73 : mnPriority(nPriority
),
75 msTargetDir(rsTargetDir
),
76 msContentIdentifier(rsContentIdentifier
),
77 mxFolderEnvironment(rxFolderEnvironment
)
82 OUString msContentIdentifier
;
83 // Reference<sdbc::XResultSet> mxFolderResultSet;
84 Reference
<com::sun::star::ucb::XCommandEnvironment
> mxFolderEnvironment
;
89 bool operator() (const FolderDescriptor
& r1
, const FolderDescriptor
& r2
) const
90 { return r1
.mnPriority
< r2
.mnPriority
; }
94 /** Use a heuristic based on the URL of a top-level template folder to
95 assign a priority that is used to sort the folders.
97 int Classify (const OUString
&, const OUString
& rsURL
)
103 else if (rsURL
.indexOf("presnt")>=0)
107 else if (rsURL
.indexOf("layout")>=0)
111 else if (rsURL
.indexOf("educate")>=0)
115 else if (rsURL
.indexOf("finance")>=0)
121 // All other folders are taken for user supplied and have the
129 } // end of anonymous namespace
137 TemplateEntryCompare::TemplateEntryCompare():
138 mpStringSorter(new comphelper::string::NaturalStringSorter(
139 ::comphelper::getProcessComponentContext(),
140 Application::GetSettings().GetLanguageTag().getLocale())) {}
142 bool TemplateEntryCompare::operator()(TemplateEntry
* pA
, TemplateEntry
* pB
) const
144 return 0 > mpStringSorter
->compare(pA
->msTitle
, pB
->msTitle
);
147 void TemplateDir::EnableSorting(bool bSortingEnabled
)
149 mbSortingEnabled
= bSortingEnabled
;
150 if (mbSortingEnabled
)
152 if (mpEntryCompare
.get() == NULL
)
153 mpEntryCompare
.reset(new TemplateEntryCompare
);
155 ::std::sort(maEntries
.begin(), maEntries
.end(), *mpEntryCompare
);
159 void TemplateDir::InsertEntry(TemplateEntry
* pNewEntry
)
161 if (mbSortingEnabled
)
163 ::std::vector
<TemplateEntry
*>::iterator aPlaceToInsert
=
164 ::std::upper_bound(maEntries
.begin(), maEntries
.end(), pNewEntry
, *mpEntryCompare
);
165 maEntries
.insert(aPlaceToInsert
, pNewEntry
);
168 maEntries
.push_back(pNewEntry
);
171 class TemplateScanner::FolderDescriptorList
172 : public ::std::multiset
<FolderDescriptor
,FolderDescriptor::Comparator
>
176 TemplateScanner::TemplateScanner (void)
177 : meState(INITIALIZE_SCANNING
),
179 mpTemplateDirectory(NULL
),
181 mbEntrySortingEnabled(false),
182 mpLastAddedEntry(NULL
),
183 mpFolderDescriptors(new FolderDescriptorList()),
185 mxFolderEnvironment(),
186 mxEntryEnvironment(),
196 TemplateScanner::~TemplateScanner (void)
198 mpFolderDescriptors
.reset();
200 // Delete all entries of the template list that have not been
201 // transferred to another object.
202 std::vector
<TemplateDir
*>::iterator I
;
203 for (I
=maFolderList
.begin(); I
!=maFolderList
.end(); ++I
)
211 TemplateScanner::State
TemplateScanner::GetTemplateRoot (void)
213 State
eNextState (INITIALIZE_FOLDER_SCANNING
);
215 Reference
< XComponentContext
> xContext
= ::comphelper::getProcessComponentContext();
216 Reference
<frame::XDocumentTemplates
> xTemplates
= frame::DocumentTemplates::create(xContext
);
217 mxTemplateRoot
= xTemplates
->getContent();
225 TemplateScanner::State
TemplateScanner::InitializeEntryScanning (void)
227 State
eNextState (SCAN_ENTRY
);
229 if (maFolderContent
.isFolder())
231 mxEntryEnvironment
= Reference
<com::sun::star::ucb::XCommandEnvironment
>();
233 // We are interested only in three properties: the entry's name,
234 // its URL, and its content type.
235 Sequence
<OUString
> aProps (3);
236 aProps
[0] = OUString(TITLE
);
237 aProps
[1] = OUString(TARGET_URL
);
238 aProps
[2] = OUString(DESCRIPTION
);
240 // Create a cursor to iterate over the templates in this folders.
241 ::ucbhelper::ResultSetInclude eInclude
= ::ucbhelper::INCLUDE_DOCUMENTS_ONLY
;
242 mxEntryResultSet
= Reference
<com::sun::star::sdbc::XResultSet
>(
243 maFolderContent
.createCursor(aProps
, eInclude
));
254 TemplateScanner::State
TemplateScanner::ScanEntry (void)
256 State
eNextState (ERROR
);
258 Reference
<com::sun::star::ucb::XContentAccess
> xContentAccess (mxEntryResultSet
, UNO_QUERY
);
259 Reference
<com::sun::star::sdbc::XRow
> xRow (mxEntryResultSet
, UNO_QUERY
);
261 if (xContentAccess
.is() && xRow
.is() && mxEntryResultSet
.is())
263 if (mxEntryResultSet
->next())
265 OUString
sTitle (xRow
->getString (1));
266 OUString
sTargetURL (xRow
->getString (2));
267 OUString
sContentType (xRow
->getString (3));
269 OUString aId
= xContentAccess
->queryContentIdentifierString();
270 ::ucbhelper::Content aContent
= ::ucbhelper::Content (aId
, mxEntryEnvironment
, comphelper::getProcessComponentContext());
271 if (aContent
.isDocument ())
273 // Check whether the entry is an impress template. If so
274 // add a new entry to the resulting list (which is created
275 // first if necessary).
276 if ( (sContentType
== MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE
)
277 || (sContentType
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(IMPRESS_XML_TEMPLATE_OASIS
)))
278 || (sContentType
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(IMPRESS_BIN_TEMPLATE
)))
279 || (sContentType
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(IMPRESS_XML_TEMPLATE
)))
280 || (sContentType
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(IMPRESS_XML_TEMPLATE_B
))))
282 OUString sLocalisedTitle
= SfxDocumentTemplates::ConvertResourceString(
283 STR_TEMPLATE_NAME1_DEF
, STR_TEMPLATE_NAME1
, NUM_TEMPLATE_NAMES
, sTitle
);
284 mpLastAddedEntry
= new TemplateEntry(sLocalisedTitle
, sTargetURL
);
285 mpTemplateDirectory
->InsertEntry(mpLastAddedEntry
);
289 // Continue scanning entries.
290 eNextState
= SCAN_ENTRY
;
294 if (mpTemplateDirectory
->maEntries
.empty())
296 delete mpTemplateDirectory
;
297 mpTemplateDirectory
= NULL
;
301 SolarMutexGuard aGuard
;
302 maFolderList
.push_back(mpTemplateDirectory
);
305 // Continue with scanning the next folder.
306 eNextState
= SCAN_FOLDER
;
316 TemplateScanner::State
TemplateScanner::InitializeFolderScanning (void)
318 State
eNextState (ERROR
);
320 mxFolderResultSet
= Reference
<sdbc::XResultSet
>();
324 // Create content for template folders.
325 mxFolderEnvironment
= Reference
<com::sun::star::ucb::XCommandEnvironment
>();
326 ::ucbhelper::Content
aTemplateDir (mxTemplateRoot
, mxFolderEnvironment
, comphelper::getProcessComponentContext());
328 // Define the list of properties we are interested in.
329 Sequence
<OUString
> aProps (2);
330 aProps
[0] = OUString(TITLE
);
331 aProps
[1] = OUString(TARGET_DIR_URL
);
333 // Create an cursor to iterate over the template folders.
334 ::ucbhelper::ResultSetInclude eInclude
= ::ucbhelper::INCLUDE_FOLDERS_ONLY
;
335 mxFolderResultSet
= Reference
<sdbc::XResultSet
>(
336 aTemplateDir
.createCursor(aProps
, eInclude
));
337 if (mxFolderResultSet
.is())
338 eNextState
= GATHER_FOLDER_LIST
;
340 catch (::com::sun::star::uno::Exception
&)
351 TemplateScanner::State
TemplateScanner::GatherFolderList (void)
353 State
eNextState (ERROR
);
355 Reference
<com::sun::star::ucb::XContentAccess
> xContentAccess (mxFolderResultSet
, UNO_QUERY
);
356 if (xContentAccess
.is() && mxFolderResultSet
.is())
358 while (mxFolderResultSet
->next())
360 Reference
<sdbc::XRow
> xRow (mxFolderResultSet
, UNO_QUERY
);
363 OUString
sTitle (xRow
->getString (1));
364 OUString
sTargetDir (xRow
->getString (2));
365 OUString aId
= xContentAccess
->queryContentIdentifierString();
367 mpFolderDescriptors
->insert(
369 Classify(sTitle
,sTargetDir
),
373 mxFolderEnvironment
));
377 eNextState
= SCAN_FOLDER
;
386 TemplateScanner::State
TemplateScanner::ScanFolder (void)
388 State
eNextState (ERROR
);
390 if (mpFolderDescriptors
->size() > 0)
392 FolderDescriptor
aDescriptor (*mpFolderDescriptors
->begin());
393 mpFolderDescriptors
->erase(mpFolderDescriptors
->begin());
395 OUString
sTitle (aDescriptor
.msTitle
);
396 OUString
sTargetDir (aDescriptor
.msTargetDir
);
397 OUString
aId (aDescriptor
.msContentIdentifier
);
399 maFolderContent
= ::ucbhelper::Content (aId
, aDescriptor
.mxFolderEnvironment
, comphelper::getProcessComponentContext());
400 if (maFolderContent
.isFolder())
402 // Scan the folder and insert it into the list of template
404 mpTemplateDirectory
= new TemplateDir (sTitle
, sTargetDir
);
405 if (mpTemplateDirectory
!= NULL
)
407 mpTemplateDirectory
->EnableSorting(mbEntrySortingEnabled
);
408 // Continue with scanning all entries in the folder.
409 eNextState
= INITIALIZE_ENTRY_SCAN
;
424 void TemplateScanner::Scan (void)
426 while (HasNextStep())
433 std::vector
<TemplateDir
*>& TemplateScanner::GetFolderList (void)
441 void TemplateScanner::RunNextStep (void)
445 case INITIALIZE_SCANNING
:
446 meState
= GetTemplateRoot();
449 case INITIALIZE_FOLDER_SCANNING
:
450 meState
= InitializeFolderScanning();
454 meState
= ScanFolder();
457 case GATHER_FOLDER_LIST
:
458 meState
= GatherFolderList();
461 case INITIALIZE_ENTRY_SCAN
:
462 meState
= InitializeEntryScanning();
466 meState
= ScanEntry();
476 mxTemplateRoot
.clear();
477 mxTemplateRoot
.clear();
478 mxFolderEnvironment
.clear();
479 mxEntryEnvironment
.clear();
480 mxFolderResultSet
.clear();
481 mxEntryResultSet
.clear();
482 mpLastAddedEntry
= NULL
;
492 bool TemplateScanner::HasNextStep (void)
508 const TemplateEntry
* TemplateScanner::GetLastAddedEntry (void) const
510 return mpLastAddedEntry
;
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */