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