Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 :
21 : #include "TemplateScanner.hxx"
22 :
23 : #include <comphelper/processfactory.hxx>
24 : #include <comphelper/documentconstants.hxx>
25 : #include <comphelper/string.hxx>
26 :
27 : #include <tools/debug.hxx>
28 : #include <osl/mutex.hxx>
29 : #include <vcl/svapp.hxx>
30 : #include <sfx2/doctempl.hxx>
31 : #include <sfx2/templatelocnames.hrc>
32 : #include <com/sun/star/frame/DocumentTemplates.hpp>
33 : #include <com/sun/star/frame/XDocumentTemplates.hpp>
34 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
35 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
36 : #include <com/sun/star/ucb/XContentAccess.hpp>
37 : #include <com/sun/star/sdbc/XResultSet.hpp>
38 : #include <com/sun/star/sdbc/XRow.hpp>
39 :
40 : #include <set>
41 :
42 : using namespace ::com::sun::star;
43 : using namespace ::com::sun::star::uno;
44 :
45 : namespace {
46 :
47 : const char TITLE[] = "Title";
48 : const char TARGET_DIR_URL[] = "TargetDirURL";
49 : const char DESCRIPTION[] = "TypeDescription";
50 : const char TARGET_URL[] = "TargetURL";
51 :
52 : const char DOCTEMPLATES[] = "com.sun.star.frame.DocumentTemplates";
53 :
54 : // These strings are used to find impress templates in the tree of
55 : // template files. Should probably be determined dynamically.
56 : const char IMPRESS_BIN_TEMPLATE[] = "application/vnd.stardivision.impress";
57 : const char IMPRESS_XML_TEMPLATE[] = MIMETYPE_VND_SUN_XML_IMPRESS_ASCII;
58 : // The following id comes from the bugdoc in #i2764#.
59 : const char IMPRESS_XML_TEMPLATE_B[] = "Impress 2.0";
60 : const char IMPRESS_XML_TEMPLATE_OASIS[] = MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII;
61 :
62 :
63 0 : class FolderDescriptor
64 : {
65 : public:
66 0 : FolderDescriptor (
67 : int nPriority,
68 : const OUString& rsTitle,
69 : const OUString& rsTargetDir,
70 : const OUString& rsContentIdentifier,
71 : const Reference<com::sun::star::ucb::XCommandEnvironment>& rxFolderEnvironment)
72 : : mnPriority(nPriority),
73 : msTitle(rsTitle),
74 : msTargetDir(rsTargetDir),
75 : msContentIdentifier(rsContentIdentifier),
76 0 : mxFolderEnvironment(rxFolderEnvironment)
77 0 : { }
78 : int mnPriority;
79 : OUString msTitle;
80 : OUString msTargetDir;
81 : OUString msContentIdentifier;
82 : // Reference<sdbc::XResultSet> mxFolderResultSet;
83 : Reference<com::sun::star::ucb::XCommandEnvironment> mxFolderEnvironment;
84 :
85 : class Comparator
86 : {
87 : public:
88 0 : bool operator() (const FolderDescriptor& r1, const FolderDescriptor& r2) const
89 0 : { return r1.mnPriority < r2.mnPriority; }
90 : };
91 : };
92 :
93 : /** Use a heuristic based on the URL of a top-level template folder to
94 : assign a priority that is used to sort the folders.
95 : */
96 0 : int Classify (const OUString&, const OUString& rsURL)
97 : {
98 0 : int nPriority (0);
99 :
100 0 : if (rsURL.isEmpty())
101 0 : nPriority = 100;
102 0 : else if (rsURL.indexOf("presnt")>=0)
103 : {
104 0 : nPriority = 30;
105 : }
106 0 : else if (rsURL.indexOf("layout")>=0)
107 : {
108 0 : nPriority = 20;
109 : }
110 0 : else if (rsURL.indexOf("educate")>=0)
111 : {
112 0 : nPriority = 40;
113 : }
114 0 : else if (rsURL.indexOf("finance")>=0)
115 : {
116 0 : nPriority = 40;
117 : }
118 : else
119 : {
120 : // All other folders are taken for user supplied and have the
121 : // highest priority.
122 0 : nPriority = 10;
123 : }
124 :
125 0 : return nPriority;
126 : }
127 :
128 : } // end of anonymous namespace
129 :
130 :
131 :
132 :
133 : namespace sd
134 : {
135 :
136 0 : TemplateEntryCompare::TemplateEntryCompare():
137 : mpStringSorter(new comphelper::string::NaturalStringSorter(
138 : ::comphelper::getProcessComponentContext(),
139 0 : Application::GetSettings().GetLanguageTag().getLocale())) {}
140 :
141 0 : bool TemplateEntryCompare::operator()(TemplateEntry* pA, TemplateEntry* pB) const
142 : {
143 0 : return 0 > mpStringSorter->compare(pA->msTitle, pB->msTitle);
144 : }
145 :
146 0 : void TemplateDir::EnableSorting(bool bSortingEnabled)
147 : {
148 0 : mbSortingEnabled = bSortingEnabled;
149 0 : if (mbSortingEnabled)
150 : {
151 0 : if (mpEntryCompare.get() == NULL)
152 0 : mpEntryCompare.reset(new TemplateEntryCompare);
153 :
154 0 : ::std::sort(maEntries.begin(), maEntries.end(), *mpEntryCompare);
155 : }
156 0 : }
157 :
158 0 : void TemplateDir::InsertEntry(TemplateEntry* pNewEntry)
159 : {
160 0 : if (mbSortingEnabled)
161 : {
162 : ::std::vector<TemplateEntry*>::iterator aPlaceToInsert =
163 0 : ::std::upper_bound(maEntries.begin(), maEntries.end(), pNewEntry, *mpEntryCompare);
164 0 : maEntries.insert(aPlaceToInsert, pNewEntry);
165 : }
166 : else
167 0 : maEntries.push_back(pNewEntry);
168 0 : }
169 :
170 0 : class TemplateScanner::FolderDescriptorList
171 : : public ::std::multiset<FolderDescriptor,FolderDescriptor::Comparator>
172 : {
173 : };
174 :
175 0 : TemplateScanner::TemplateScanner (void)
176 : : meState(INITIALIZE_SCANNING),
177 : maFolderContent(),
178 : mpTemplateDirectory(NULL),
179 : maFolderList(),
180 : mbEntrySortingEnabled(false),
181 : mpLastAddedEntry(NULL),
182 0 : mpFolderDescriptors(new FolderDescriptorList()),
183 : mxTemplateRoot(),
184 : mxFolderEnvironment(),
185 : mxEntryEnvironment(),
186 : mxFolderResultSet(),
187 0 : mxEntryResultSet()
188 : {
189 : // empty;
190 0 : }
191 :
192 :
193 :
194 :
195 0 : TemplateScanner::~TemplateScanner (void)
196 : {
197 0 : mpFolderDescriptors.reset();
198 :
199 : // Delete all entries of the template list that have not been
200 : // transferred to another object.
201 0 : std::vector<TemplateDir*>::iterator I;
202 0 : for (I=maFolderList.begin(); I!=maFolderList.end(); ++I)
203 0 : if (*I != NULL)
204 0 : delete *I;
205 0 : }
206 :
207 :
208 :
209 :
210 0 : TemplateScanner::State TemplateScanner::GetTemplateRoot (void)
211 : {
212 0 : State eNextState (INITIALIZE_FOLDER_SCANNING);
213 :
214 0 : Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
215 0 : Reference<frame::XDocumentTemplates> xTemplates = frame::DocumentTemplates::create(xContext);
216 0 : mxTemplateRoot = xTemplates->getContent();
217 :
218 0 : return eNextState;
219 : }
220 :
221 :
222 :
223 :
224 0 : TemplateScanner::State TemplateScanner::InitializeEntryScanning (void)
225 : {
226 0 : State eNextState (SCAN_ENTRY);
227 :
228 0 : if (maFolderContent.isFolder())
229 : {
230 0 : mxEntryEnvironment = Reference<com::sun::star::ucb::XCommandEnvironment>();
231 :
232 : // We are interested only in three properties: the entry's name,
233 : // its URL, and its content type.
234 0 : Sequence<OUString> aProps (3);
235 0 : aProps[0] = OUString(TITLE);
236 0 : aProps[1] = OUString(TARGET_URL);
237 0 : aProps[2] = OUString(DESCRIPTION);
238 :
239 : // Create a cursor to iterate over the templates in this folders.
240 0 : ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_DOCUMENTS_ONLY;
241 0 : mxEntryResultSet = Reference<com::sun::star::sdbc::XResultSet>(
242 0 : maFolderContent.createCursor(aProps, eInclude));
243 : }
244 : else
245 0 : eNextState = ERROR;
246 :
247 0 : return eNextState;
248 : }
249 :
250 :
251 :
252 :
253 0 : TemplateScanner::State TemplateScanner::ScanEntry (void)
254 : {
255 0 : State eNextState (ERROR);
256 :
257 0 : Reference<com::sun::star::ucb::XContentAccess> xContentAccess (mxEntryResultSet, UNO_QUERY);
258 0 : Reference<com::sun::star::sdbc::XRow> xRow (mxEntryResultSet, UNO_QUERY);
259 :
260 0 : if (xContentAccess.is() && xRow.is() && mxEntryResultSet.is())
261 : {
262 0 : if (mxEntryResultSet->next())
263 : {
264 0 : OUString sTitle (xRow->getString (1));
265 0 : OUString sTargetURL (xRow->getString (2));
266 0 : OUString sContentType (xRow->getString (3));
267 :
268 0 : OUString aId = xContentAccess->queryContentIdentifierString();
269 0 : ::ucbhelper::Content aContent = ::ucbhelper::Content (aId, mxEntryEnvironment, comphelper::getProcessComponentContext());
270 0 : if (aContent.isDocument ())
271 : {
272 : // Check whether the entry is an impress template. If so
273 : // add a new entry to the resulting list (which is created
274 : // first if necessary).
275 0 : if ( (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE)
276 0 : || (sContentType == IMPRESS_XML_TEMPLATE_OASIS)
277 0 : || (sContentType == IMPRESS_BIN_TEMPLATE)
278 0 : || (sContentType == IMPRESS_XML_TEMPLATE)
279 0 : || (sContentType == IMPRESS_XML_TEMPLATE_B))
280 : {
281 : OUString sLocalisedTitle = SfxDocumentTemplates::ConvertResourceString(
282 0 : STR_TEMPLATE_NAME1_DEF, STR_TEMPLATE_NAME1, NUM_TEMPLATE_NAMES, sTitle );
283 0 : mpLastAddedEntry = new TemplateEntry(sLocalisedTitle, sTargetURL);
284 0 : mpTemplateDirectory->InsertEntry(mpLastAddedEntry);
285 : }
286 : }
287 :
288 : // Continue scanning entries.
289 0 : eNextState = SCAN_ENTRY;
290 : }
291 : else
292 : {
293 0 : if (mpTemplateDirectory->maEntries.empty())
294 : {
295 0 : delete mpTemplateDirectory;
296 0 : mpTemplateDirectory = NULL;
297 : }
298 : else
299 : {
300 0 : SolarMutexGuard aGuard;
301 0 : maFolderList.push_back(mpTemplateDirectory);
302 : }
303 :
304 : // Continue with scanning the next folder.
305 0 : eNextState = SCAN_FOLDER;
306 : }
307 : }
308 :
309 0 : return eNextState;
310 : }
311 :
312 :
313 :
314 :
315 0 : TemplateScanner::State TemplateScanner::InitializeFolderScanning (void)
316 : {
317 0 : State eNextState (ERROR);
318 :
319 0 : mxFolderResultSet = Reference<sdbc::XResultSet>();
320 :
321 : try
322 : {
323 : // Create content for template folders.
324 0 : mxFolderEnvironment = Reference<com::sun::star::ucb::XCommandEnvironment>();
325 0 : ::ucbhelper::Content aTemplateDir (mxTemplateRoot, mxFolderEnvironment, comphelper::getProcessComponentContext());
326 :
327 : // Define the list of properties we are interested in.
328 0 : Sequence<OUString> aProps (2);
329 0 : aProps[0] = OUString(TITLE);
330 0 : aProps[1] = OUString(TARGET_DIR_URL);
331 :
332 : // Create an cursor to iterate over the template folders.
333 0 : ::ucbhelper::ResultSetInclude eInclude = ::ucbhelper::INCLUDE_FOLDERS_ONLY;
334 0 : mxFolderResultSet = Reference<sdbc::XResultSet>(
335 0 : aTemplateDir.createCursor(aProps, eInclude));
336 0 : if (mxFolderResultSet.is())
337 0 : eNextState = GATHER_FOLDER_LIST;
338 : }
339 0 : catch (::com::sun::star::uno::Exception&)
340 : {
341 0 : eNextState = ERROR;
342 : }
343 :
344 0 : return eNextState;
345 : }
346 :
347 :
348 :
349 :
350 0 : TemplateScanner::State TemplateScanner::GatherFolderList (void)
351 : {
352 0 : State eNextState (ERROR);
353 :
354 0 : Reference<com::sun::star::ucb::XContentAccess> xContentAccess (mxFolderResultSet, UNO_QUERY);
355 0 : if (xContentAccess.is() && mxFolderResultSet.is())
356 : {
357 0 : while (mxFolderResultSet->next())
358 : {
359 0 : Reference<sdbc::XRow> xRow (mxFolderResultSet, UNO_QUERY);
360 0 : if (xRow.is())
361 : {
362 0 : OUString sTitle (xRow->getString (1));
363 0 : OUString sTargetDir (xRow->getString (2));
364 0 : OUString aId = xContentAccess->queryContentIdentifierString();
365 :
366 0 : mpFolderDescriptors->insert(
367 : FolderDescriptor(
368 : Classify(sTitle,sTargetDir),
369 : sTitle,
370 : sTargetDir,
371 : aId,
372 0 : mxFolderEnvironment));
373 : }
374 0 : }
375 :
376 0 : eNextState = SCAN_FOLDER;
377 : }
378 :
379 0 : return eNextState;
380 : }
381 :
382 :
383 :
384 :
385 0 : TemplateScanner::State TemplateScanner::ScanFolder (void)
386 : {
387 0 : State eNextState (ERROR);
388 :
389 0 : if (mpFolderDescriptors->size() > 0)
390 : {
391 0 : FolderDescriptor aDescriptor (*mpFolderDescriptors->begin());
392 0 : mpFolderDescriptors->erase(mpFolderDescriptors->begin());
393 :
394 0 : OUString sTitle (aDescriptor.msTitle);
395 0 : OUString sTargetDir (aDescriptor.msTargetDir);
396 0 : OUString aId (aDescriptor.msContentIdentifier);
397 :
398 0 : maFolderContent = ::ucbhelper::Content (aId, aDescriptor.mxFolderEnvironment, comphelper::getProcessComponentContext());
399 0 : if (maFolderContent.isFolder())
400 : {
401 : // Scan the folder and insert it into the list of template
402 : // folders.
403 0 : mpTemplateDirectory = new TemplateDir (sTitle, sTargetDir);
404 0 : if (mpTemplateDirectory != NULL)
405 : {
406 0 : mpTemplateDirectory->EnableSorting(mbEntrySortingEnabled);
407 : // Continue with scanning all entries in the folder.
408 0 : eNextState = INITIALIZE_ENTRY_SCAN;
409 : }
410 0 : }
411 : }
412 : else
413 : {
414 0 : eNextState = DONE;
415 : }
416 :
417 0 : return eNextState;
418 : }
419 :
420 :
421 :
422 :
423 0 : void TemplateScanner::Scan (void)
424 : {
425 0 : while (HasNextStep())
426 0 : RunNextStep();
427 0 : }
428 :
429 :
430 :
431 :
432 0 : std::vector<TemplateDir*>& TemplateScanner::GetFolderList (void)
433 : {
434 0 : return maFolderList;
435 : }
436 :
437 :
438 :
439 :
440 0 : void TemplateScanner::RunNextStep (void)
441 : {
442 0 : switch (meState)
443 : {
444 : case INITIALIZE_SCANNING:
445 0 : meState = GetTemplateRoot();
446 0 : break;
447 :
448 : case INITIALIZE_FOLDER_SCANNING:
449 0 : meState = InitializeFolderScanning();
450 0 : break;
451 :
452 : case SCAN_FOLDER:
453 0 : meState = ScanFolder();
454 0 : break;
455 :
456 : case GATHER_FOLDER_LIST:
457 0 : meState = GatherFolderList();
458 0 : break;
459 :
460 : case INITIALIZE_ENTRY_SCAN:
461 0 : meState = InitializeEntryScanning();
462 0 : break;
463 :
464 : case SCAN_ENTRY:
465 0 : meState = ScanEntry();
466 0 : break;
467 : default:
468 0 : break;
469 : }
470 :
471 0 : switch (meState)
472 : {
473 : case DONE:
474 : case ERROR:
475 0 : mxTemplateRoot.clear();
476 0 : mxTemplateRoot.clear();
477 0 : mxFolderEnvironment.clear();
478 0 : mxEntryEnvironment.clear();
479 0 : mxFolderResultSet.clear();
480 0 : mxEntryResultSet.clear();
481 0 : mpLastAddedEntry = NULL;
482 0 : break;
483 : default:
484 0 : break;
485 : }
486 0 : }
487 :
488 :
489 :
490 :
491 0 : bool TemplateScanner::HasNextStep (void)
492 : {
493 0 : switch (meState)
494 : {
495 : case DONE:
496 : case ERROR:
497 0 : return false;
498 :
499 : default:
500 0 : return true;
501 : }
502 : }
503 :
504 :
505 :
506 :
507 0 : const TemplateEntry* TemplateScanner::GetLastAddedEntry (void) const
508 : {
509 0 : return mpLastAddedEntry;
510 : }
511 :
512 33 : }
513 :
514 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|