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