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