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