Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/sd/source/ui/dlg/TemplateScanner.cxx
Line
Count
Source (jump to first uncovered line)
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:
45
    FolderDescriptor (
46
        int nPriority,
47
        OUString sContentIdentifier,
48
        const Reference<css::ucb::XCommandEnvironment>& rxFolderEnvironment)
49
0
        : mnPriority(nPriority),
50
0
          msContentIdentifier(std::move(sContentIdentifier)),
51
0
          mxFolderEnvironment(rxFolderEnvironment)
52
0
    { }
53
    int mnPriority;
54
    OUString msContentIdentifier;
55
    //    Reference<sdbc::XResultSet> mxFolderResultSet;
56
    Reference<css::ucb::XCommandEnvironment> mxFolderEnvironment;
57
58
    class Comparator
59
    {
60
    public:
61
        bool operator() (const FolderDescriptor& r1, const FolderDescriptor& r2) const
62
0
            { 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
*/
69
int Classify (std::u16string_view rsURL)
70
0
{
71
0
    int nPriority (0);
72
73
0
    if (rsURL.empty())
74
0
        nPriority = 100;
75
0
    else if (rsURL.find(u"presnt") != std::u16string_view::npos)
76
0
    {
77
0
        nPriority = 30;
78
0
    }
79
0
    else if (rsURL.find(u"layout") != std::u16string_view::npos)
80
0
    {
81
0
        nPriority = 20;
82
0
    }
83
0
    else if (rsURL.find(u"educate") != std::u16string_view::npos)
84
0
    {
85
0
        nPriority = 40;
86
0
    }
87
0
    else if (rsURL.find(u"finance")  != std::u16string_view::npos)
88
0
    {
89
0
        nPriority = 40;
90
0
    }
91
0
    else
92
0
    {
93
        // All other folders are taken for user supplied and have the
94
        // highest priority.
95
0
        nPriority = 10;
96
0
    }
97
98
0
    return nPriority;
99
0
}
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
111
TemplateScanner::TemplateScanner()
112
0
    : meState(INITIALIZE_SCANNING),
113
0
      mpFolderDescriptors(new FolderDescriptorList)
114
0
{
115
    //  empty;
116
0
}
117
118
TemplateScanner::~TemplateScanner()
119
0
{
120
0
}
121
122
TemplateScanner::State TemplateScanner::GetTemplateRoot()
123
0
{
124
0
    const Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
125
0
    Reference<frame::XDocumentTemplates> xTemplates = frame::DocumentTemplates::create(xContext);
126
0
    mxTemplateRoot = xTemplates->getContent();
127
128
0
    return INITIALIZE_FOLDER_SCANNING;
129
0
}
130
131
TemplateScanner::State TemplateScanner::InitializeEntryScanning()
132
0
{
133
0
    State eNextState (SCAN_ENTRY);
134
135
0
    if (maFolderContent.isFolder())
136
0
    {
137
0
        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
0
        mxEntryResultSet.set( maFolderContent.createCursor({ TITLE, u"TargetURL"_ustr, u"TypeDescription"_ustr }, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY));
143
0
    }
144
0
    else
145
0
        eNextState = ERROR;
146
147
0
    return eNextState;
148
0
}
149
150
TemplateScanner::State TemplateScanner::ScanEntry()
151
0
{
152
0
    State eNextState (ERROR);
153
154
0
    Reference<css::ucb::XContentAccess> xContentAccess (mxEntryResultSet, UNO_QUERY);
155
0
    Reference<css::sdbc::XRow> xRow (mxEntryResultSet, UNO_QUERY);
156
157
0
    if (xContentAccess.is() && xRow.is() && mxEntryResultSet.is())
158
0
    {
159
0
        if (mxEntryResultSet->next())
160
0
        {
161
0
            OUString sTitle (xRow->getString (1));
162
0
            OUString sTargetURL (xRow->getString (2));
163
0
            OUString sContentType (xRow->getString (3));
164
165
0
            OUString aId = xContentAccess->queryContentIdentifierString();
166
0
            ::ucbhelper::Content aContent(aId, mxEntryEnvironment, comphelper::getProcessComponentContext());
167
0
            if (aContent.isDocument ())
168
0
            {
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
0
                if (    (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII)
175
0
                    ||  (sContentType == MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII)
176
0
                    ||  (sContentType == "application/vnd.stardivision.impress")
177
0
                    ||  (sContentType == MIMETYPE_VND_SUN_XML_IMPRESS_ASCII)
178
                        // The following id comes from the bugdoc in #i2764#.
179
0
                    ||  (sContentType == "Impress 2.0"))
180
0
                {
181
0
                    OUString sLocalisedTitle = SfxDocumentTemplates::ConvertResourceString(sTitle);
182
0
                    mpTemplateEntries.push_back(std::make_unique<TemplateEntry>(sLocalisedTitle, sTargetURL));
183
0
                }
184
0
            }
185
186
            // Continue scanning entries.
187
0
            eNextState = SCAN_ENTRY;
188
0
        }
189
0
        else
190
0
        {
191
            // Continue with scanning the next folder.
192
0
            eNextState = SCAN_FOLDER;
193
0
        }
194
0
    }
195
196
0
    return eNextState;
197
0
}
198
199
TemplateScanner::State TemplateScanner::InitializeFolderScanning()
200
0
{
201
0
    State eNextState (ERROR);
202
203
0
    mxFolderResultSet.clear();
204
205
0
    try
206
0
    {
207
        //  Create content for template folders.
208
0
        mxFolderEnvironment.clear();
209
0
        ::ucbhelper::Content aTemplateDir (mxTemplateRoot, mxFolderEnvironment, comphelper::getProcessComponentContext());
210
211
        //  Create a cursor to iterate over the template folders.
212
0
        mxFolderResultSet.set( aTemplateDir.createCursor({ TITLE, u"TargetDirURL"_ustr }, ::ucbhelper::INCLUDE_FOLDERS_ONLY));
213
0
        if (mxFolderResultSet.is())
214
0
            eNextState = GATHER_FOLDER_LIST;
215
0
    }
216
0
    catch (css::uno::Exception&)
217
0
    {
218
0
       eNextState = ERROR;
219
0
    }
220
221
0
    return eNextState;
222
0
}
223
224
TemplateScanner::State TemplateScanner::GatherFolderList()
225
0
{
226
0
    State eNextState (ERROR);
227
228
0
    Reference<css::ucb::XContentAccess> xContentAccess (mxFolderResultSet, UNO_QUERY);
229
0
    if (xContentAccess.is() && mxFolderResultSet.is())
230
0
    {
231
0
        while (mxFolderResultSet->next())
232
0
        {
233
0
            Reference<sdbc::XRow> xRow (mxFolderResultSet, UNO_QUERY);
234
0
            if (xRow.is())
235
0
            {
236
0
                OUString sTargetDir (xRow->getString (2));
237
238
0
                mpFolderDescriptors->insert(
239
0
                    FolderDescriptor(
240
0
                        Classify(sTargetDir),
241
0
                        xContentAccess->queryContentIdentifierString(),
242
0
                        mxFolderEnvironment));
243
0
            }
244
0
        }
245
246
0
        eNextState = SCAN_FOLDER;
247
0
    }
248
249
0
    return eNextState;
250
0
}
251
252
TemplateScanner::State TemplateScanner::ScanFolder()
253
0
{
254
0
    State eNextState (ERROR);
255
256
0
    if (!mpFolderDescriptors->empty())
257
0
    {
258
0
        FolderDescriptor aDescriptor (*mpFolderDescriptors->begin());
259
0
        mpFolderDescriptors->erase(mpFolderDescriptors->begin());
260
261
0
        OUString aId (aDescriptor.msContentIdentifier);
262
263
0
        maFolderContent = ::ucbhelper::Content (aId, aDescriptor.mxFolderEnvironment, comphelper::getProcessComponentContext());
264
0
        if (maFolderContent.isFolder())
265
0
        {
266
            // Scan the folder and insert it into the list of template
267
            // folders.
268
            // Continue with scanning all entries in the folder.
269
0
            mpTemplateEntries.clear();
270
0
            eNextState = INITIALIZE_ENTRY_SCAN;
271
0
        }
272
0
    }
273
0
    else
274
0
    {
275
0
        eNextState = DONE;
276
0
    }
277
278
0
    return eNextState;
279
0
}
280
281
void TemplateScanner::RunNextStep()
282
0
{
283
0
    switch (meState)
284
0
    {
285
0
        case INITIALIZE_SCANNING:
286
0
            meState = GetTemplateRoot();
287
0
            break;
288
289
0
        case INITIALIZE_FOLDER_SCANNING:
290
0
            meState = InitializeFolderScanning();
291
0
            break;
292
293
0
        case SCAN_FOLDER:
294
0
            meState = ScanFolder();
295
0
            break;
296
297
0
        case GATHER_FOLDER_LIST:
298
0
            meState = GatherFolderList();
299
0
            break;
300
301
0
        case INITIALIZE_ENTRY_SCAN:
302
0
            meState = InitializeEntryScanning();
303
0
            break;
304
305
0
        case SCAN_ENTRY:
306
0
            meState = ScanEntry();
307
0
            break;
308
0
        default:
309
0
            break;
310
0
    }
311
312
0
    switch (meState)
313
0
    {
314
0
        case DONE:
315
0
        case ERROR:
316
0
            mxTemplateRoot.clear();
317
0
            mxFolderEnvironment.clear();
318
0
            mxEntryEnvironment.clear();
319
0
            mxFolderResultSet.clear();
320
0
            mxEntryResultSet.clear();
321
0
            break;
322
0
        default:
323
0
            break;
324
0
    }
325
0
}
326
327
bool TemplateScanner::HasNextStep()
328
0
{
329
0
    switch (meState)
330
0
    {
331
0
        case DONE:
332
0
        case ERROR:
333
0
            return false;
334
335
0
        default:
336
0
            return true;
337
0
    }
338
0
}
339
340
}
341
342
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */