Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/dialog/ClassificationDialog.cxx
Line
Count
Source
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
 */
10
11
#include <svx/ClassificationDialog.hxx>
12
#include <svx/ClassificationCommon.hxx>
13
14
#include <editeng/flditem.hxx>
15
#include <editeng/eeitem.hxx>
16
#include <editeng/section.hxx>
17
#include <editeng/editobj.hxx>
18
#include <editeng/wghtitem.hxx>
19
#include <svl/itemset.hxx>
20
#include <osl/file.hxx>
21
#include <rtl/bootstrap.hxx>
22
#include <config_folders.h>
23
#include <tools/stream.hxx>
24
#include <tools/XmlWriter.hxx>
25
#include <tools/XmlWalker.hxx>
26
#include <utility>
27
#include <vcl/event.hxx>
28
#include <vcl/svapp.hxx>
29
#include <vcl/weld/Builder.hxx>
30
#include <vcl/weld/Dialog.hxx>
31
#include <vcl/weld/customweld.hxx>
32
33
#include <officecfg/Office/Common.hxx>
34
35
#include "ClassificationEditView.hxx"
36
37
namespace svx {
38
39
IMPL_STATIC_LINK(ClassificationDialog, KeyInput, const KeyEvent&, rKeyEvent, bool)
40
0
{
41
0
    bool bTextIsFreeForm = officecfg::Office::Common::Classification::IntellectualPropertyTextInputIsFreeForm::get();
42
43
0
    if (!bTextIsFreeForm)
44
0
    {
45
        // Ignore key combination with modifier keys
46
0
        if (rKeyEvent.GetKeyCode().IsMod3()
47
0
         || rKeyEvent.GetKeyCode().IsMod2()
48
0
         || rKeyEvent.GetKeyCode().IsMod1())
49
0
        {
50
0
            return true;
51
0
        }
52
53
0
        switch (rKeyEvent.GetKeyCode().GetCode())
54
0
        {
55
            // Allowed characters
56
0
            case KEY_BACKSPACE:
57
0
            case KEY_DELETE:
58
0
            case KEY_DIVIDE:
59
0
            case KEY_SEMICOLON:
60
0
            case KEY_SPACE:
61
0
                return false;
62
            // Anything else is ignored
63
0
            default:
64
0
                return true;
65
0
        }
66
0
    }
67
68
0
    return false;
69
0
}
70
71
namespace {
72
73
constexpr size_t RECENTLY_USED_LIMIT = 5;
74
75
constexpr OUString constRecentlyUsedFileName(u"recentlyUsed.xml"_ustr);
76
77
OUString lcl_getClassificationUserPath()
78
0
{
79
0
    OUString sPath(u"${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/user/classification/"_ustr);
80
0
    rtl::Bootstrap::expandMacros(sPath);
81
0
    return sPath;
82
0
}
83
84
const SvxFieldItem* findField(editeng::Section const & rSection)
85
0
{
86
0
    for (SfxPoolItem const * pPool : rSection.maAttributes)
87
0
    {
88
0
        if (pPool->Which() == EE_FEATURE_FIELD)
89
0
            return static_cast<const SvxFieldItem*>(pPool);
90
0
    }
91
0
    return nullptr;
92
0
}
93
94
bool fileExists(OUString const & sFilename)
95
0
{
96
0
    osl::File aFile(sFilename);
97
0
    osl::FileBase::RC eRC = aFile.open(osl_File_OpenFlag_Read);
98
0
    return osl::FileBase::E_None == eRC;
99
0
}
100
101
bool stringToClassificationType(std::string_view rsType, svx::ClassificationType & reType)
102
0
{
103
0
    if (rsType == "CATEGORY")
104
0
        reType = svx::ClassificationType::CATEGORY;
105
0
    else if (rsType == "INTELLECTUAL_PROPERTY_PART")
106
0
        reType = svx::ClassificationType::INTELLECTUAL_PROPERTY_PART;
107
0
    else if (rsType == "MARKING")
108
0
        reType = svx::ClassificationType::MARKING;
109
0
    else if (rsType == "PARAGRAPH")
110
0
        reType = svx::ClassificationType::PARAGRAPH;
111
0
    else if (rsType == "TEXT")
112
0
        reType = svx::ClassificationType::TEXT;
113
0
    else
114
0
        return false;
115
0
    return true;
116
0
}
117
118
OUString classificationTypeToString(svx::ClassificationType const & reType)
119
0
{
120
0
    switch(reType)
121
0
    {
122
0
        case svx::ClassificationType::CATEGORY:
123
0
            return u"CATEGORY"_ustr; break;
124
0
        case svx::ClassificationType::MARKING:
125
0
            return u"MARKING"_ustr; break;
126
0
        case svx::ClassificationType::TEXT:
127
0
            return u"TEXT"_ustr; break;
128
0
        case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
129
0
            return u"INTELLECTUAL_PROPERTY_PART"_ustr; break;
130
0
        case svx::ClassificationType::PARAGRAPH:
131
0
            return u"PARAGRAPH"_ustr; break;
132
0
    }
133
0
    return OUString();
134
0
}
135
136
void writeResultToXml(tools::XmlWriter & rXmlWriter,
137
                      std::vector<ClassificationResult> const & rResultCollection)
138
0
{
139
0
    for (ClassificationResult const & rResult : rResultCollection)
140
0
    {
141
0
        rXmlWriter.startElement("element");
142
0
        OUString sType = classificationTypeToString(rResult.meType);
143
0
        rXmlWriter.attribute("type", sType);
144
0
        rXmlWriter.startElement("string");
145
0
        rXmlWriter.content(rResult.msName);
146
0
        rXmlWriter.endElement();
147
0
        rXmlWriter.startElement("abbreviatedString");
148
0
        rXmlWriter.content(rResult.msAbbreviatedName);
149
0
        rXmlWriter.endElement();
150
0
        rXmlWriter.startElement("identifier");
151
0
        rXmlWriter.content(rResult.msIdentifier);
152
0
        rXmlWriter.endElement();
153
0
        rXmlWriter.endElement();
154
0
    }
155
0
}
156
157
} // end anonymous namespace
158
159
ClassificationDialog::ClassificationDialog(weld::Window* pParent, const css::uno::Reference<css::document::XDocumentProperties>& rDocProps,
160
                                           const bool bPerParagraph, std::function<void()> aParagraphSignHandler)
161
0
    : GenericDialogController(pParent, u"svx/ui/classificationdialog.ui"_ustr, u"AdvancedDocumentClassificationDialog"_ustr)
162
0
    , maHelper(rDocProps)
163
0
    , maInternationalHelper(rDocProps, /*bUseLocalizedPolicy*/ false)
164
0
    , m_bPerParagraph(bPerParagraph)
165
0
    , m_aParagraphSignHandler(std::move(aParagraphSignHandler))
166
0
    , m_nCurrentSelectedCategory(-1)
167
0
    , m_xOkButton(m_xBuilder->weld_button(u"ok"_ustr))
168
0
    , m_xSignButton(m_xBuilder->weld_button(u"signButton"_ustr))
169
0
    , m_xToolBox(m_xBuilder->weld_toggle_button(u"toolbox"_ustr))
170
0
    , m_xRecentlyUsedListBox(m_xBuilder->weld_combo_box(u"recentlyUsedCB"_ustr))
171
0
    , m_xClassificationListBox(m_xBuilder->weld_combo_box(u"classificationCB"_ustr))
172
0
    , m_xInternationalClassificationListBox(m_xBuilder->weld_combo_box(u"internationalClassificationCB"_ustr))
173
0
    , m_xMarkingLabel(m_xBuilder->weld_label(u"markingLabel"_ustr))
174
0
    , m_xMarkingListBox(m_xBuilder->weld_tree_view(u"markingLB"_ustr))
175
0
    , m_xIntellectualPropertyPartListBox(m_xBuilder->weld_tree_view(u"intellectualPropertyPartLB"_ustr))
176
0
    , m_xIntellectualPropertyPartNumberListBox(m_xBuilder->weld_tree_view(u"intellectualPropertyPartNumberLB"_ustr))
177
0
    , m_xIntellectualPropertyPartAddButton(m_xBuilder->weld_button(u"intellectualPropertyPartAddButton"_ustr))
178
0
    , m_xIntellectualPropertyPartEdit(m_xBuilder->weld_entry(u"intellectualPropertyPartEntry"_ustr))
179
0
    , m_xIntellectualPropertyExpander(m_xBuilder->weld_expander(u"intellectualPropertyExpander"_ustr))
180
0
    , m_xEditWindow(new ClassificationEditView)
181
0
    , m_xEditWindowWeld(new weld::CustomWeld(*m_xBuilder, u"classificationEditWindow"_ustr, *m_xEditWindow))
182
0
{
183
0
    m_xOkButton->connect_clicked(LINK(this, ClassificationDialog, OkHdl));
184
0
    m_xSignButton->connect_clicked(LINK(this, ClassificationDialog, ButtonClicked));
185
0
    m_xSignButton->set_visible(m_bPerParagraph);
186
187
0
    m_xIntellectualPropertyPartEdit->connect_key_press(LINK(this, ClassificationDialog, KeyInput));
188
189
    // no need for BOLD if we do paragraph classification
190
0
    if (m_bPerParagraph)
191
0
    {
192
0
        m_xToolBox->hide();
193
0
    }
194
0
    else
195
0
    {
196
0
        m_xToolBox->connect_toggled(LINK(this, ClassificationDialog, SelectToolboxHdl));
197
0
    }
198
199
0
    m_xIntellectualPropertyPartAddButton->connect_clicked(LINK(this, ClassificationDialog, ButtonClicked));
200
201
0
    m_xClassificationListBox->set_size_request(m_xClassificationListBox->get_approximate_digit_width() * 20, -1);
202
0
    m_xClassificationListBox->connect_changed(LINK(this, ClassificationDialog, SelectClassificationHdl));
203
0
    for (const OUString& rName : maHelper.GetBACNames())
204
0
        m_xClassificationListBox->append_text(rName);
205
206
0
    m_xInternationalClassificationListBox->set_size_request(m_xInternationalClassificationListBox->get_approximate_digit_width() * 20, -1);
207
0
    m_xInternationalClassificationListBox->connect_changed(LINK(this, ClassificationDialog, SelectClassificationHdl));
208
0
    for (const OUString& rName : maInternationalHelper.GetBACNames())
209
0
        m_xInternationalClassificationListBox->append_text(rName);
210
211
0
    if (!maHelper.GetMarkings().empty())
212
0
    {
213
0
        m_xMarkingListBox->set_size_request(m_xMarkingListBox->get_approximate_digit_width() * 10,
214
0
                                            m_xMarkingListBox->get_height_rows(4));
215
0
        m_xMarkingListBox->connect_item_activated(
216
0
            LINK(this, ClassificationDialog, SelectMarkingHdl));
217
218
0
        for (const OUString& rName : maHelper.GetMarkings())
219
0
            m_xMarkingListBox->append_text(rName);
220
0
    }
221
0
    else
222
0
    {
223
0
        m_xMarkingListBox->hide();
224
0
        m_xMarkingLabel->hide();
225
0
    }
226
227
0
    m_xIntellectualPropertyPartNumberListBox->set_size_request(m_xIntellectualPropertyPartNumberListBox->get_approximate_digit_width() * 10,
228
0
                                                               m_xIntellectualPropertyPartNumberListBox->get_height_rows(5));
229
0
    m_xIntellectualPropertyPartNumberListBox->connect_item_activated(
230
0
        LINK(this, ClassificationDialog, SelectIPPartNumbersHdl));
231
0
    for (const OUString& rName : maHelper.GetIntellectualPropertyPartNumbers())
232
0
        m_xIntellectualPropertyPartNumberListBox->append_text(rName);
233
234
0
    m_xIntellectualPropertyPartNumberListBox->set_size_request(m_xIntellectualPropertyPartNumberListBox->get_approximate_digit_width() * 20,
235
0
                                                               m_xIntellectualPropertyPartListBox->get_height_rows(5));
236
0
    m_xIntellectualPropertyPartListBox->connect_item_activated(
237
0
        LINK(this, ClassificationDialog, SelectIPPartHdl));
238
0
    for (const OUString& rName : maHelper.GetIntellectualPropertyParts())
239
0
        m_xIntellectualPropertyPartListBox->append_text(rName);
240
241
0
    m_xRecentlyUsedListBox->set_size_request(m_xRecentlyUsedListBox->get_approximate_digit_width() * 5, -1);
242
0
    m_xRecentlyUsedListBox->connect_changed(LINK(this, ClassificationDialog, SelectRecentlyUsedHdl));
243
244
0
    m_xIntellectualPropertyExpander->connect_expanded(LINK(this, ClassificationDialog, ExpandedHdl));
245
0
    if (officecfg::Office::Common::Classification::IntellectualPropertySectionExpanded::get())
246
0
        m_nAsyncExpandEvent = Application::PostUserEvent(LINK(this, ClassificationDialog, OnAsyncExpandHdl));
247
0
    else
248
0
        m_nAsyncExpandEvent = nullptr;
249
250
0
    m_xEditWindow->SetModifyHdl(LINK(this, ClassificationDialog, EditWindowModifiedHdl));
251
252
0
    readRecentlyUsed();
253
0
    toggleWidgetsDependingOnCategory();
254
255
0
    int nNumber = 1;
256
0
    if (m_aRecentlyUsedValuesCollection.empty())
257
0
    {
258
0
        m_xRecentlyUsedListBox->set_sensitive(false);
259
0
    }
260
0
    else
261
0
    {
262
0
        for (std::vector<ClassificationResult> const & rResults : m_aRecentlyUsedValuesCollection)
263
0
        {
264
0
            OUString rContentRepresentation = svx::classification::convertClassificationResultToString(rResults);
265
0
            OUString rDescription = OUString::number(nNumber) + ": " + rContentRepresentation;
266
0
            nNumber++;
267
268
0
            m_xRecentlyUsedListBox->append_text(rDescription);
269
0
        }
270
0
    }
271
0
}
272
273
//do it async so gtk has a chance to shrink it to best size, otherwise it's larger than min
274
IMPL_LINK_NOARG(ClassificationDialog, OnAsyncExpandHdl, void*, void)
275
0
{
276
0
    m_nAsyncExpandEvent = nullptr;
277
0
    m_xIntellectualPropertyExpander->set_expanded(true);
278
0
}
279
280
ClassificationDialog::~ClassificationDialog()
281
0
{
282
0
    if (m_nAsyncExpandEvent)
283
0
        Application::RemoveUserEvent(m_nAsyncExpandEvent);
284
0
}
285
286
void ClassificationDialog::insertCategoryField(sal_Int32 nID)
287
0
{
288
0
    const OUString aFullString = maHelper.GetBACNames()[nID];
289
0
    const OUString aAbbreviatedString = maHelper.GetAbbreviatedBACNames()[nID];
290
0
    const OUString aIdentifierString = maHelper.GetBACIdentifiers()[nID];
291
0
    insertField(ClassificationType::CATEGORY, aAbbreviatedString, aFullString, aIdentifierString);
292
0
}
293
294
void ClassificationDialog::insertField(ClassificationType eType, OUString const & rString, OUString const & rFullString, OUString const & rIdentifier)
295
0
{
296
0
    ClassificationField aField(eType, rString, rFullString, rIdentifier);
297
0
    m_xEditWindow->InsertField(SvxFieldItem(aField, EE_FEATURE_FIELD));
298
0
}
299
300
void ClassificationDialog::setupValues(std::vector<ClassificationResult> && rInput)
301
0
{
302
0
    m_aInitialValues = std::move(rInput);
303
0
    readIn(m_aInitialValues);
304
0
}
305
306
void ClassificationDialog::readRecentlyUsed()
307
0
{
308
0
    OUString sPath = lcl_getClassificationUserPath();
309
0
    OUString sFilePath(sPath + constRecentlyUsedFileName);
310
311
0
    if (!fileExists(sFilePath))
312
0
        return;
313
314
0
    SvFileStream aFileStream(sFilePath, StreamMode::READ);
315
0
    tools::XmlWalker aWalker;
316
0
    if (!aWalker.open(&aFileStream))
317
0
        return;
318
319
0
    if (aWalker.name() != "recentlyUsedClassifications")
320
0
        return;
321
322
0
    aWalker.children();
323
0
    while (aWalker.isValid())
324
0
    {
325
0
        if (aWalker.name() == "elementGroup")
326
0
        {
327
0
            std::vector<ClassificationResult> aResults;
328
329
0
            aWalker.children();
330
331
0
            while (aWalker.isValid())
332
0
            {
333
0
                if (aWalker.name() == "element")
334
0
                {
335
0
                    svx::ClassificationType eType = svx::ClassificationType::TEXT;
336
0
                    OUString sString;
337
0
                    OUString sAbbreviatedString;
338
0
                    OUString sIdentifier;
339
340
                    // Convert string to classification type, but continue only if
341
                    // conversion was successful.
342
0
                    if (stringToClassificationType(aWalker.attribute("type"_ostr), eType))
343
0
                    {
344
0
                        aWalker.children();
345
346
0
                        while (aWalker.isValid())
347
0
                        {
348
0
                            if (aWalker.name() == "string")
349
0
                            {
350
0
                                sString = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
351
0
                            }
352
0
                            else if (aWalker.name() == "abbreviatedString")
353
0
                            {
354
0
                                sAbbreviatedString = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
355
0
                            }
356
0
                            else if (aWalker.name() == "identifier")
357
0
                            {
358
0
                                sIdentifier = OStringToOUString(aWalker.content(), RTL_TEXTENCODING_UTF8);
359
0
                            }
360
0
                            aWalker.next();
361
0
                        }
362
0
                        aWalker.parent();
363
364
0
                        aResults.emplace_back(eType, sString, sAbbreviatedString, sIdentifier);
365
0
                    }
366
0
                }
367
0
                aWalker.next();
368
0
            }
369
0
            aWalker.parent();
370
0
            m_aRecentlyUsedValuesCollection.push_back(std::move(aResults));
371
0
        }
372
0
        aWalker.next();
373
0
    }
374
0
    aWalker.parent();
375
0
}
376
377
void ClassificationDialog::writeRecentlyUsed()
378
0
{
379
0
    OUString sPath = lcl_getClassificationUserPath();
380
0
    osl::Directory::createPath(sPath);
381
0
    OUString sFilePath(sPath + constRecentlyUsedFileName);
382
383
0
    std::unique_ptr<SvStream> pStream;
384
0
    pStream.reset(new SvFileStream(sFilePath, StreamMode::STD_READWRITE | StreamMode::TRUNC));
385
386
0
    tools::XmlWriter aXmlWriter(pStream.get());
387
388
0
    if (!aXmlWriter.startDocument())
389
0
        return;
390
391
0
    aXmlWriter.startElement("recentlyUsedClassifications");
392
393
0
    aXmlWriter.startElement("elementGroup");
394
395
0
    writeResultToXml(aXmlWriter, getResult());
396
397
0
    aXmlWriter.endElement();
398
399
0
    if (m_aRecentlyUsedValuesCollection.size() >= RECENTLY_USED_LIMIT)
400
0
        m_aRecentlyUsedValuesCollection.pop_back();
401
402
0
    for (std::vector<ClassificationResult> const & rResultCollection : m_aRecentlyUsedValuesCollection)
403
0
    {
404
0
        aXmlWriter.startElement("elementGroup");
405
406
0
        writeResultToXml(aXmlWriter, rResultCollection);
407
408
0
        aXmlWriter.endElement();
409
0
    }
410
411
0
    aXmlWriter.endElement();
412
413
0
    aXmlWriter.endDocument();
414
0
}
415
416
void ClassificationDialog::readIn(std::vector<ClassificationResult> const & rInput)
417
0
{
418
0
    sal_Int32 nParagraph = -1;
419
420
0
    for (ClassificationResult const & rClassificationResult : rInput)
421
0
    {
422
423
0
        switch (rClassificationResult.meType)
424
0
        {
425
0
            case svx::ClassificationType::TEXT:
426
0
            {
427
0
                m_xEditWindow->getEditView().InsertText(rClassificationResult.msName);
428
0
            }
429
0
            break;
430
431
0
            case svx::ClassificationType::CATEGORY:
432
0
            {
433
0
                OUString sName;
434
0
                if (rClassificationResult.msName.isEmpty())
435
0
                    sName = maHelper.GetBACNameForIdentifier(rClassificationResult.msIdentifier);
436
0
                else
437
0
                    sName = rClassificationResult.msName;
438
439
0
                OUString sAbbreviatedName = rClassificationResult.msAbbreviatedName;
440
0
                if (sAbbreviatedName.isEmpty())
441
0
                    sAbbreviatedName = maHelper.GetAbbreviatedBACName(sName);
442
443
0
                m_xClassificationListBox->set_active_text(sName);
444
0
                m_nCurrentSelectedCategory = m_xClassificationListBox->get_active();
445
0
                m_xInternationalClassificationListBox->set_active(m_xClassificationListBox->get_active());
446
447
0
                insertField(rClassificationResult.meType, sAbbreviatedName, sName, rClassificationResult.msIdentifier);
448
0
            }
449
0
            break;
450
451
0
            case svx::ClassificationType::MARKING:
452
0
            {
453
0
                m_xMarkingListBox->select_text(rClassificationResult.msName);
454
0
                insertField(rClassificationResult.meType, rClassificationResult.msName, rClassificationResult.msName, rClassificationResult.msIdentifier);
455
0
            }
456
0
            break;
457
458
0
            case svx::ClassificationType::INTELLECTUAL_PROPERTY_PART:
459
0
            {
460
0
                insertField(rClassificationResult.meType, rClassificationResult.msName, rClassificationResult.msName, rClassificationResult.msIdentifier);
461
0
            }
462
0
            break;
463
464
0
            case svx::ClassificationType::PARAGRAPH:
465
0
            {
466
0
                nParagraph++;
467
468
0
                if (nParagraph != 0)
469
0
                    m_xEditWindow->getEditView().InsertParaBreak();
470
471
                // Set paragraph font weight
472
0
                FontWeight eWeight = (rClassificationResult.msName == "BOLD") ? WEIGHT_BOLD : WEIGHT_NORMAL;
473
474
0
                ClassificationEditEngine& rEdEngine = m_xEditWindow->getEditEngine();
475
0
                SfxItemSet aSet(rEdEngine.GetParaAttribs(nParagraph));
476
0
                aSet.Put(SvxWeightItem(eWeight, EE_CHAR_WEIGHT));
477
0
                rEdEngine.SetParaAttribs(nParagraph, aSet);
478
0
            }
479
0
            break;
480
481
0
            default:
482
0
            break;
483
0
        }
484
0
    }
485
0
    toggleWidgetsDependingOnCategory();
486
0
}
487
488
void ClassificationDialog::toggleWidgetsDependingOnCategory()
489
0
{
490
0
    const EditEngine& rEditEngine = m_xEditWindow->getEditEngine();
491
492
0
    for (sal_Int32 nParagraph = 0; nParagraph < rEditEngine.GetParagraphCount(); ++nParagraph)
493
0
    {
494
0
        for (const EFieldInfo& rFieldInfo : rEditEngine.GetFieldInfo(nParagraph))
495
0
        {
496
0
            if (rFieldInfo.pFieldItem)
497
0
            {
498
0
                const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(rFieldInfo.pFieldItem->GetField());
499
0
                if (pClassificationField && pClassificationField->meType == ClassificationType::CATEGORY)
500
0
                {
501
0
                    m_xOkButton->set_sensitive(true);
502
0
                    return;
503
0
                }
504
0
            }
505
0
        }
506
0
    }
507
508
    // Category field in the text edit has been deleted, so reset the list boxes
509
0
    m_xOkButton->set_sensitive(false);
510
0
    m_xClassificationListBox->set_active(-1);
511
0
    m_xInternationalClassificationListBox->set_active(-1);
512
0
}
513
514
std::vector<ClassificationResult> ClassificationDialog::getResult()
515
0
{
516
0
    std::vector<ClassificationResult> aClassificationResults;
517
518
0
    ClassificationEditEngine& rEdEngine = m_xEditWindow->getEditEngine();
519
0
    EditTextObject aEditText(rEdEngine.CreateTextObject());
520
521
0
    sal_Int32 nCurrentParagraph = -1;
522
523
0
    std::vector<editeng::Section> aSections;
524
0
    aEditText.GetAllSections(aSections);
525
0
    for (editeng::Section const & rSection : aSections)
526
0
    {
527
0
        while (nCurrentParagraph < rSection.mnParagraph)
528
0
        {
529
0
            nCurrentParagraph++;
530
531
            // Get Weight of current paragraph
532
0
            FontWeight eFontWeight = WEIGHT_NORMAL;
533
0
            SfxItemSet aItemSet(rEdEngine.GetParaAttribs(nCurrentParagraph));
534
0
            if (const SfxPoolItem* pItem = aItemSet.GetItem(EE_CHAR_WEIGHT, false))
535
0
            {
536
0
                const SvxWeightItem* pWeightItem = dynamic_cast<const SvxWeightItem*>(pItem);
537
0
                if (pWeightItem && pWeightItem->GetWeight() == WEIGHT_BOLD)
538
0
                    eFontWeight = WEIGHT_BOLD;
539
0
            }
540
            // Font weight to string
541
0
            OUString sWeightProperty = u"NORMAL"_ustr;
542
0
            if (eFontWeight == WEIGHT_BOLD)
543
0
                sWeightProperty = "BOLD";
544
            // Insert into collection
545
0
            OUString sBlank;
546
0
            aClassificationResults.emplace_back(ClassificationType::PARAGRAPH, sWeightProperty, sBlank, sBlank);
547
0
        }
548
549
0
        const SvxFieldItem* pFieldItem = findField(rSection);
550
551
0
        ESelection aSelection(rSection.mnParagraph, rSection.mnStart, rSection.mnParagraph, rSection.mnEnd);
552
0
        const OUString sDisplayString = rEdEngine.GetText(aSelection);
553
0
        if (!sDisplayString.isEmpty())
554
0
        {
555
0
            const ClassificationField* pClassificationField = pFieldItem ? dynamic_cast<const ClassificationField*>(pFieldItem->GetField()) : nullptr;
556
557
0
            if (pClassificationField)
558
0
            {
559
0
                aClassificationResults.emplace_back(pClassificationField->meType, pClassificationField->msFullClassName,
560
0
                                                   pClassificationField->msDescription, pClassificationField->msIdentifier);
561
0
            }
562
0
            else
563
0
            {
564
0
                aClassificationResults.emplace_back(ClassificationType::TEXT, sDisplayString, sDisplayString, OUString());
565
0
            }
566
0
        }
567
0
    }
568
569
0
    return aClassificationResults;
570
0
}
571
572
IMPL_LINK(ClassificationDialog, SelectClassificationHdl, weld::ComboBox&, rBox, void)
573
0
{
574
0
    const sal_Int32 nSelected = rBox.get_active();
575
0
    if (nSelected < 0 || m_nCurrentSelectedCategory == nSelected)
576
0
        return;
577
578
0
    EditTextObject aEditText(m_xEditWindow->getEditEngine().CreateTextObject());
579
0
    std::vector<editeng::Section> aSections;
580
0
    aEditText.GetAllSections(aSections);
581
582
    // if we are replacing an existing field
583
0
    bool bReplaceExisting = false;
584
    // selection of the existing field, which will be replaced
585
0
    ESelection aExistingFieldSelection;
586
587
0
    for (editeng::Section const & rSection : aSections)
588
0
    {
589
0
        const SvxFieldItem* pFieldItem = findField(rSection);
590
0
        if (pFieldItem)
591
0
        {
592
0
            const ClassificationField* pClassificationField = dynamic_cast<const ClassificationField*>(pFieldItem->GetField());
593
0
            if (pClassificationField && pClassificationField->meType == ClassificationType::CATEGORY)
594
0
            {
595
0
                aExistingFieldSelection = ESelection(rSection.mnParagraph, rSection.mnStart,
596
0
                                                     rSection.mnParagraph, rSection.mnEnd);
597
0
                bReplaceExisting = true;
598
0
            }
599
0
        }
600
0
    }
601
602
0
    if (bReplaceExisting)
603
0
        m_xEditWindow->getEditView().SetSelection(aExistingFieldSelection);
604
605
0
    insertCategoryField(nSelected);
606
607
    // Change category to the new selection
608
0
    m_xInternationalClassificationListBox->set_active(nSelected);
609
0
    m_xClassificationListBox->set_active(nSelected);
610
0
    m_nCurrentSelectedCategory = nSelected;
611
0
}
612
613
IMPL_LINK_NOARG(ClassificationDialog, SelectMarkingHdl, const weld::TreeIter&, bool)
614
0
{
615
0
    sal_Int32 nSelected = m_xMarkingListBox->get_selected_index();
616
0
    if (nSelected >= 0)
617
0
    {
618
0
        const OUString aString = maHelper.GetMarkings()[nSelected];
619
0
        insertField(ClassificationType::MARKING, aString, aString);
620
0
    }
621
0
    return true;
622
0
}
623
624
IMPL_LINK_NOARG(ClassificationDialog, SelectIPPartNumbersHdl, const weld::TreeIter&, bool)
625
0
{
626
0
    sal_Int32 nSelected = m_xIntellectualPropertyPartNumberListBox->get_selected_index();
627
0
    if (nSelected >= 0)
628
0
    {
629
0
        OUString sString = maHelper.GetIntellectualPropertyPartNumbers()[nSelected];
630
0
        m_xIntellectualPropertyPartEdit->replace_selection(sString);
631
0
        m_xIntellectualPropertyPartEdit->grab_focus();
632
0
    }
633
0
    return true;
634
0
}
635
636
IMPL_LINK(ClassificationDialog, SelectRecentlyUsedHdl, weld::ComboBox&, rBox, void)
637
0
{
638
0
    sal_Int32 nSelected = rBox.get_active();
639
0
    if (nSelected >= 0)
640
0
    {
641
0
        m_xEditWindow->getEditEngine().Clear();
642
0
        readIn(m_aRecentlyUsedValuesCollection[nSelected]);
643
0
    }
644
0
}
645
646
IMPL_LINK_NOARG(ClassificationDialog, SelectIPPartHdl, const weld::TreeIter&, bool)
647
0
{
648
0
    const sal_Int32 nSelected = m_xIntellectualPropertyPartListBox->get_selected_index();
649
0
    if (nSelected >= 0)
650
0
    {
651
0
        const OUString sString = maHelper.GetIntellectualPropertyParts()[nSelected];
652
0
        m_xIntellectualPropertyPartEdit->replace_selection(sString);
653
0
        m_xIntellectualPropertyPartEdit->grab_focus();
654
0
    }
655
0
    return true;
656
0
}
657
658
IMPL_LINK(ClassificationDialog, ButtonClicked, weld::Button&, rButton, void)
659
0
{
660
0
    if (&rButton == m_xSignButton.get())
661
0
    {
662
0
        m_aParagraphSignHandler();
663
0
    }
664
0
    else if (&rButton == m_xIntellectualPropertyPartAddButton.get())
665
0
    {
666
0
        const OUString sString = m_xIntellectualPropertyPartEdit->get_text();
667
0
        insertField(ClassificationType::INTELLECTUAL_PROPERTY_PART, sString, sString);
668
0
    }
669
0
}
670
671
IMPL_LINK_NOARG(ClassificationDialog, OkHdl, weld::Button&, void)
672
0
{
673
0
    writeRecentlyUsed();
674
0
    m_xDialog->response(RET_OK);
675
0
}
676
677
IMPL_LINK_NOARG(ClassificationDialog, SelectToolboxHdl, weld::Toggleable&, void)
678
0
{
679
0
    m_xEditWindow->InvertSelectionWeight();
680
0
}
681
682
IMPL_LINK_NOARG(ClassificationDialog, EditWindowModifiedHdl, LinkParamNone*, void)
683
0
{
684
0
    toggleWidgetsDependingOnCategory();
685
0
}
686
687
IMPL_STATIC_LINK(ClassificationDialog, ExpandedHdl, weld::Expander&, rExpander, void)
688
0
{
689
0
    std::shared_ptr<comphelper::ConfigurationChanges> aConfigurationChanges(comphelper::ConfigurationChanges::create());
690
0
    officecfg::Office::Common::Classification::IntellectualPropertySectionExpanded::set(rExpander.get_expanded(), aConfigurationChanges);
691
0
    aConfigurationChanges->commit();
692
0
}
693
694
} // end svx
695
696
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */