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