xref: /core/sd/source/ui/dlg/TemplateScanner.cxx (revision ed0b12f4eadf1f2242f06cbd56804f75376274b1)
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 #include <TemplateScanner.hxx>
21 
22 #include <comphelper/processfactory.hxx>
23 #include <comphelper/documentconstants.hxx>
24 
25 #include <sfx2/doctempl.hxx>
26 #include <com/sun/star/frame/DocumentTemplates.hpp>
27 #include <com/sun/star/frame/XDocumentTemplates.hpp>
28 #include <com/sun/star/ucb/XContentAccess.hpp>
29 #include <com/sun/star/sdbc/XResultSet.hpp>
30 #include <com/sun/star/sdbc/XRow.hpp>
31 
32 #include <set>
33 #include <utility>
34 
35 using namespace ::com::sun::star;
36 using namespace ::com::sun::star::uno;
37 
38 namespace {
39 
40 constexpr OUString TITLE = u"Title"_ustr;
41 
42 class FolderDescriptor
43 {
44 public:
FolderDescriptor(int nPriority,OUString sContentIdentifier,const Reference<css::ucb::XCommandEnvironment> & rxFolderEnvironment)45     FolderDescriptor (
46         int nPriority,
47         OUString sContentIdentifier,
48         const Reference<css::ucb::XCommandEnvironment>& rxFolderEnvironment)
49         : mnPriority(nPriority),
50           msContentIdentifier(std::move(sContentIdentifier)),
51           mxFolderEnvironment(rxFolderEnvironment)
52     { }
53     int mnPriority;
54     OUString msContentIdentifier;
55     //    Reference<sdbc::XResultSet> mxFolderResultSet;
56     Reference<css::ucb::XCommandEnvironment> mxFolderEnvironment;
57 
58     class Comparator
59     {
60     public:
operator ()(const FolderDescriptor & r1,const FolderDescriptor & r2) const61         bool operator() (const FolderDescriptor& r1, const FolderDescriptor& r2) const
62             { return r1.mnPriority < r2.mnPriority; }
63     };
64 };
65 
66 /** Use a heuristic based on the URL of a top-level template folder to
67     assign a priority that is used to sort the folders.
68 */
Classify(std::u16string_view rsURL)69 int Classify (std::u16string_view rsURL)
70 {
71     int nPriority (0);
72 
73     if (rsURL.empty())
74         nPriority = 100;
75     else if (rsURL.find(u"presnt") != std::u16string_view::npos)
76     {
77         nPriority = 30;
78     }
79     else if (rsURL.find(u"layout") != std::u16string_view::npos)
80     {
81         nPriority = 20;
82     }
83     else if (rsURL.find(u"educate") != std::u16string_view::npos)
84     {
85         nPriority = 40;
86     }
87     else if (rsURL.find(u"finance")  != std::u16string_view::npos)
88     {
89         nPriority = 40;
90     }
91     else
92     {
93         // All other folders are taken for user supplied and have the
94         // highest priority.
95         nPriority = 10;
96     }
97 
98     return nPriority;
99 }
100 
101 } // end of anonymous namespace
102 
103 namespace sd
104 {
105 
106 class TemplateScanner::FolderDescriptorList
107     : public ::std::multiset<FolderDescriptor,FolderDescriptor::Comparator>
108 {
109 };
110 
TemplateScanner()111 TemplateScanner::TemplateScanner()
112     : meState(INITIALIZE_SCANNING),
113       mpFolderDescriptors(new FolderDescriptorList)
114 {
115     //  empty;
116 }
117 
~TemplateScanner()118 TemplateScanner::~TemplateScanner()
119 {
120 }
121 
GetTemplateRoot()122 TemplateScanner::State TemplateScanner::GetTemplateRoot()
123 {
124     const Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
125     Reference<frame::XDocumentTemplates> xTemplates = frame::DocumentTemplates::create(xContext);
126     mxTemplateRoot = xTemplates->getContent();
127 
128     return INITIALIZE_FOLDER_SCANNING;
129 }
130 
InitializeEntryScanning()131 TemplateScanner::State TemplateScanner::InitializeEntryScanning()
132 {
133     State eNextState (SCAN_ENTRY);
134 
135     if (maFolderContent.isFolder())
136     {
137         mxEntryEnvironment.clear();
138 
139         //  Create a cursor to iterate over the templates in this folders.
140         //  We are interested only in three properties: the entry's name,
141         //  its URL, and its content type.
142         mxEntryResultSet.set( maFolderContent.createCursor({ TITLE, u"TargetURL"_ustr, u"TypeDescription"_ustr }, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY));
143     }
144     else
145         eNextState = ERROR;
146 
147     return eNextState;
148 }
149 
ScanEntry()150 TemplateScanner::State TemplateScanner::ScanEntry()
151 {
152     State eNextState (ERROR);
153 
154     Reference<css::ucb::XContentAccess> xContentAccess (mxEntryResultSet, UNO_QUERY);
155     Reference<css::sdbc::XRow> xRow (mxEntryResultSet, UNO_QUERY);
156 
157     if (xContentAccess.is() && xRow.is() && mxEntryResultSet.is())
158     {
159         if (mxEntryResultSet->next())
160         {
161             OUString sTitle (xRow->getString (1));
162             OUString sTargetURL (xRow->getString (2));
163             OUString sContentType (xRow->getString (3));
164 
165             OUString aId = xContentAccess->queryContentIdentifierString();
166             ::ucbhelper::Content aContent(aId, mxEntryEnvironment, comphelper::getProcessComponentContext());
167             if (aContent.isDocument ())
168             {
169                 //  Check whether the entry is an impress template.  If so
170                 //  add a new entry to the resulting list (which is created
171                 //  first if necessary).
172                 //  These strings are used to find impress templates in the tree of
173                 //  template files.  Should probably be determined dynamically.
174                 if (    (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII)
175                     ||  (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII)
176                     ||  (sContentType == "application/vnd.stardivision.impress")
177                     ||  (sContentType == MIMETYPE_VND_SUN_XML_IMPRESS_ASCII)
178                         // The following id comes from the bugdoc in #i2764#.
179                     ||  (sContentType == "Impress 2.0"))
180                 {
181                     OUString sLocalisedTitle = SfxDocumentTemplates::ConvertResourceString(sTitle);
182                     mpTemplateEntries.push_back(std::make_unique<TemplateEntry>(sLocalisedTitle, sTargetURL));
183                 }
184             }
185 
186             // Continue scanning entries.
187             eNextState = SCAN_ENTRY;
188         }
189         else
190         {
191             // Continue with scanning the next folder.
192             eNextState = SCAN_FOLDER;
193         }
194     }
195 
196     return eNextState;
197 }
198 
InitializeFolderScanning()199 TemplateScanner::State TemplateScanner::InitializeFolderScanning()
200 {
201     State eNextState (ERROR);
202 
203     mxFolderResultSet.clear();
204 
205     try
206     {
207         //  Create content for template folders.
208         mxFolderEnvironment.clear();
209         ::ucbhelper::Content aTemplateDir (mxTemplateRoot, mxFolderEnvironment, comphelper::getProcessComponentContext());
210 
211         //  Create a cursor to iterate over the template folders.
212         mxFolderResultSet.set( aTemplateDir.createCursor({ TITLE, u"TargetDirURL"_ustr }, ::ucbhelper::INCLUDE_FOLDERS_ONLY));
213         if (mxFolderResultSet.is())
214             eNextState = GATHER_FOLDER_LIST;
215     }
216     catch (css::uno::Exception&)
217     {
218        eNextState = ERROR;
219     }
220 
221     return eNextState;
222 }
223 
GatherFolderList()224 TemplateScanner::State TemplateScanner::GatherFolderList()
225 {
226     State eNextState (ERROR);
227 
228     Reference<css::ucb::XContentAccess> xContentAccess (mxFolderResultSet, UNO_QUERY);
229     if (xContentAccess.is() && mxFolderResultSet.is())
230     {
231         while (mxFolderResultSet->next())
232         {
233             Reference<sdbc::XRow> xRow (mxFolderResultSet, UNO_QUERY);
234             if (xRow.is())
235             {
236                 OUString sTargetDir (xRow->getString (2));
237 
238                 mpFolderDescriptors->insert(
239                     FolderDescriptor(
240                         Classify(sTargetDir),
241                         xContentAccess->queryContentIdentifierString(),
242                         mxFolderEnvironment));
243             }
244         }
245 
246         eNextState = SCAN_FOLDER;
247     }
248 
249     return eNextState;
250 }
251 
ScanFolder()252 TemplateScanner::State TemplateScanner::ScanFolder()
253 {
254     State eNextState (ERROR);
255 
256     if (!mpFolderDescriptors->empty())
257     {
258         FolderDescriptor aDescriptor (*mpFolderDescriptors->begin());
259         mpFolderDescriptors->erase(mpFolderDescriptors->begin());
260 
261         OUString aId (aDescriptor.msContentIdentifier);
262 
263         maFolderContent = ::ucbhelper::Content (aId, aDescriptor.mxFolderEnvironment, comphelper::getProcessComponentContext());
264         if (maFolderContent.isFolder())
265         {
266             // Scan the folder and insert it into the list of template
267             // folders.
268             // Continue with scanning all entries in the folder.
269             mpTemplateEntries.clear();
270             eNextState = INITIALIZE_ENTRY_SCAN;
271         }
272     }
273     else
274     {
275         eNextState = DONE;
276     }
277 
278     return eNextState;
279 }
280 
RunNextStep()281 void TemplateScanner::RunNextStep()
282 {
283     switch (meState)
284     {
285         case INITIALIZE_SCANNING:
286             meState = GetTemplateRoot();
287             break;
288 
289         case INITIALIZE_FOLDER_SCANNING:
290             meState = InitializeFolderScanning();
291             break;
292 
293         case SCAN_FOLDER:
294             meState = ScanFolder();
295             break;
296 
297         case GATHER_FOLDER_LIST:
298             meState = GatherFolderList();
299             break;
300 
301         case INITIALIZE_ENTRY_SCAN:
302             meState = InitializeEntryScanning();
303             break;
304 
305         case SCAN_ENTRY:
306             meState = ScanEntry();
307             break;
308         default:
309             break;
310     }
311 
312     switch (meState)
313     {
314         case DONE:
315         case ERROR:
316             mxTemplateRoot.clear();
317             mxFolderEnvironment.clear();
318             mxEntryEnvironment.clear();
319             mxFolderResultSet.clear();
320             mxEntryResultSet.clear();
321             break;
322         default:
323             break;
324     }
325 }
326 
HasNextStep()327 bool TemplateScanner::HasNextStep()
328 {
329     switch (meState)
330     {
331         case DONE:
332         case ERROR:
333             return false;
334 
335         default:
336             return true;
337     }
338 }
339 
340 }
341 
342 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
343