LibreOffice Module sw (master) 1
contentcontroldlg.cxx
Go to the documentation of this file.
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 <contentcontroldlg.hxx>
21
22#include <vcl/weld.hxx>
23#include <cui/cuicharmap.hxx>
24#include <svl/numformat.hxx>
25#include <svl/zformat.hxx>
26
27#include <wrtsh.hxx>
28#include <ndtxt.hxx>
30#include <IDocumentState.hxx>
31#include <swuiexp.hxx>
32#include <numfmtlb.hxx>
33
34using namespace com::sun::star;
35
37 : SfxDialogController(pParent, "modules/swriter/ui/contentcontroldlg.ui",
38 "ContentControlDialog")
39 , m_rWrtShell(rWrtShell)
40 , m_xShowingPlaceHolderCB(m_xBuilder->weld_check_button("showing_place_holder"))
41 , m_xAlias(m_xBuilder->weld_entry("aliasentry"))
42 , m_xTag(m_xBuilder->weld_entry("tagentry"))
43 , m_xId(m_xBuilder->weld_spin_button("idspinbutton"))
44 , m_xTabIndex(m_xBuilder->weld_spin_button("tabindexspinbutton"))
45 , m_xCheckboxFrame(m_xBuilder->weld_frame("checkboxframe"))
46 , m_xCheckedState(m_xBuilder->weld_entry("checkboxcheckedentry"))
47 , m_xCheckedStateBtn(m_xBuilder->weld_button("btncheckboxchecked"))
48 , m_xUncheckedState(m_xBuilder->weld_entry("checkboxuncheckedentry"))
49 , m_xUncheckedStateBtn(m_xBuilder->weld_button("btncheckboxunchecked"))
50 , m_xListItemsFrame(m_xBuilder->weld_frame("listitemsframe"))
51 , m_xListItems(m_xBuilder->weld_tree_view("listitems"))
52 , m_xListItemButtons(m_xBuilder->weld_box("listitembuttons"))
53 , m_xInsertBtn(m_xBuilder->weld_button("add"))
54 , m_xRenameBtn(m_xBuilder->weld_button("modify"))
55 , m_xDeleteBtn(m_xBuilder->weld_button("remove"))
56 , m_xMoveUpBtn(m_xBuilder->weld_button("moveup"))
57 , m_xMoveDownBtn(m_xBuilder->weld_button("movedown"))
58 , m_xDateFrame(m_xBuilder->weld_frame("dateframe"))
59 , m_xDateFormat(new SwNumFormatTreeView(m_xBuilder->weld_tree_view("date_formats_treeview")))
60 , m_xOk(m_xBuilder->weld_button("ok"))
61{
62 m_xCheckedStateBtn->connect_clicked(LINK(this, SwContentControlDlg, SelectCharHdl));
63 m_xUncheckedStateBtn->connect_clicked(LINK(this, SwContentControlDlg, SelectCharHdl));
64 m_xListItems->connect_changed(LINK(this, SwContentControlDlg, SelectionChangedHdl));
65 m_xOk->connect_clicked(LINK(this, SwContentControlDlg, OkHdl));
66
67 // Only 2 items would be visible by default.
68 m_xListItems->set_size_request(-1, m_xListItems->get_height_rows(8));
69 // Only the first column would have a non-zero size by default in the SvHeaderTabListBox case.
70 m_xListItems->set_column_fixed_widths({ 100, 100 });
71
72 m_xInsertBtn->connect_clicked(LINK(this, SwContentControlDlg, InsertHdl));
73 m_xRenameBtn->connect_clicked(LINK(this, SwContentControlDlg, RenameHdl));
74 m_xDeleteBtn->connect_clicked(LINK(this, SwContentControlDlg, DeleteHdl));
75 m_xMoveUpBtn->connect_clicked(LINK(this, SwContentControlDlg, MoveUpHdl));
76 m_xMoveDownBtn->connect_clicked(LINK(this, SwContentControlDlg, MoveDownHdl));
77
78 const SwPosition* pStart = rWrtShell.GetCursor()->Start();
79 SwTextNode* pTextNode = pStart->GetNode().GetTextNode();
80 if (!pTextNode)
81 {
82 return;
83 }
84
85 SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
87 if (!pAttr)
88 {
89 return;
90 }
91
92 SwTextContentControl* pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
93 const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
94 m_pContentControl = rFormatContentControl.GetContentControl();
95
96 bool bShowingPlaceHolder = m_pContentControl->GetShowingPlaceHolder();
97 TriState eShowingPlaceHolder = bShowingPlaceHolder ? TRISTATE_TRUE : TRISTATE_FALSE;
98 m_xShowingPlaceHolderCB->set_state(eShowingPlaceHolder);
99 m_xShowingPlaceHolderCB->save_state();
100
101 if (!m_pContentControl->GetAlias().isEmpty())
102 {
103 m_xAlias->set_text(m_pContentControl->GetAlias());
104 m_xAlias->save_value();
105 }
106
107 if (!m_pContentControl->GetTag().isEmpty())
108 {
109 m_xTag->set_text(m_pContentControl->GetTag());
110 m_xTag->save_value();
111 }
112
113 // The ID is supposed to be a unique ID, but it isn't really used for much
114 // and in MS Word it (supposedly) is automatically made unique if it is a duplicate.
115 // The main purpose for having it here is lookup, not modification,
116 // since AFAIK the only use of the ID is for VBA macro name lookup.
117 // Since it is used as unsigned in VBA, make the UI display the unsigned values too.
118 m_xId->set_range(0, SAL_MAX_UINT32);
119 m_xId->set_increments(1, 10);
120 const sal_uInt32 nId = static_cast<sal_uInt32>(m_pContentControl->GetId());
121 m_xId->set_value(nId);
122 // a one-time chance to set the ID - only allow setting it when it is undefined.
123 if (nId)
124 m_xId->set_editable(false); // still available for copy/paste
125 m_xId->save_value();
126
127 // And on the contrary, the tabIndex is stored as unsigned,
128 // even though humanly speaking it is much nicer to use -1 to indicate a no tab stop. Oh well.
130 m_xTabIndex->set_increments(1, 10);
131 const sal_Int32 nTabIndex = static_cast<sal_Int32>(m_pContentControl->GetTabIndex());
132 m_xTabIndex->set_value(nTabIndex);
133 m_xTabIndex->save_value();
134
135 if (m_pContentControl->GetCheckbox())
136 {
137 m_xCheckedState->set_text(m_pContentControl->GetCheckedState());
138 m_xCheckedState->save_value();
139 m_xUncheckedState->set_text(m_pContentControl->GetUncheckedState());
140 m_xUncheckedState->save_value();
141 }
142 else
143 {
144 m_xCheckboxFrame->set_visible(false);
145 }
146
147 if (m_pContentControl->GetComboBox() || m_pContentControl->GetDropDown())
148 {
149 for (const auto& rListItem : m_pContentControl->GetListItems())
150 {
151 int nRow = m_xListItems->n_children();
152 m_xListItems->append_text(rListItem.m_aDisplayText);
153 m_xListItems->set_text(nRow, rListItem.m_aValue, 1);
154 }
155 m_aSavedListItems = m_pContentControl->GetListItems();
156 }
157 else
158 {
159 m_xListItemsFrame->set_visible(false);
160 m_xListItemButtons->set_visible(false);
161 }
162
163 if (m_pContentControl->GetDate())
164 {
165 m_xDateFormat->SetFormatType(SvNumFormatType::DATE);
166 m_xDateFormat->SetShowLanguageControl(true);
167
168 // Set height to double of the default.
169 weld::TreeView& rTreeView = dynamic_cast<weld::TreeView&>(m_xDateFormat->get_widget());
170 rTreeView.set_size_request(rTreeView.get_preferred_size().Width(),
171 rTreeView.get_height_rows(10));
172
173 OUString sFormatString = m_pContentControl->GetDateFormat();
174 OUString sLang = m_pContentControl->GetDateLanguage();
175 if (!sFormatString.isEmpty() && !sLang.isEmpty())
176 {
178 LanguageType aLangType = LanguageTag(sLang).getLanguageType();
179 sal_uInt32 nFormat = pNumberFormatter->GetEntryKey(sFormatString, aLangType);
180 if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
181 {
182 sal_Int32 nCheckPos = 0;
184 pNumberFormatter->PutEntry(sFormatString, nCheckPos, nType, nFormat,
185 LanguageTag(sLang).getLanguageType());
186 }
187
188 if (aLangType != LANGUAGE_DONTKNOW && nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
189 {
190 m_xDateFormat->SetDefFormat(nFormat);
191 }
192 }
193 }
194 else
195 {
196 m_xDateFrame->set_visible(false);
197 }
198}
199
201{
204}
205
207{
208 if (!m_pContentControl)
209 {
210 return;
211 }
212
213 bool bChanged = false;
214 if (m_xShowingPlaceHolderCB->get_state_changed_from_saved())
215 {
216 bool bShowingPlaceHolder = m_xShowingPlaceHolderCB->get_state() == TRISTATE_TRUE;
217 m_pContentControl->SetShowingPlaceHolder(bShowingPlaceHolder);
218 bChanged = true;
219 }
220
221 if (m_xAlias->get_value_changed_from_saved())
222 {
223 m_pContentControl->SetAlias(m_xAlias->get_text());
224 bChanged = true;
225 }
226
227 if (m_xTag->get_value_changed_from_saved())
228 {
229 m_pContentControl->SetTag(m_xTag->get_text());
230 bChanged = true;
231 }
232
233 if (m_xId->get_value_changed_from_saved())
234 {
235 m_pContentControl->SetId(o3tl::narrowing<sal_Int32>(m_xId->get_value()));
236 bChanged = true;
237 }
238
239 if (m_xTabIndex->get_value_changed_from_saved())
240 {
241 m_pContentControl->SetTabIndex(o3tl::narrowing<sal_uInt32>(m_xTabIndex->get_value()));
242 bChanged = true;
243 }
244
245 if (m_xCheckedState->get_value_changed_from_saved())
246 {
247 m_pContentControl->SetCheckedState(m_xCheckedState->get_text());
248 }
249
250 if (m_xUncheckedState->get_value_changed_from_saved())
251 {
252 m_pContentControl->SetUncheckedState(m_xUncheckedState->get_text());
253 }
254
255 std::vector<SwContentControlListItem> aItems;
256 for (int i = 0; i < m_xListItems->n_children(); ++i)
257 {
259 aItem.m_aDisplayText = m_xListItems->get_text(i, 0);
260 aItem.m_aValue = m_xListItems->get_text(i, 1);
261 aItems.push_back(aItem);
262 }
263 if (aItems != m_aSavedListItems)
264 {
265 m_pContentControl->SetListItems(aItems);
266 bChanged = true;
267 }
268
269 if (m_pContentControl->GetDate())
270 {
271 SvNumberFormatter* pNumberFormatter = m_rWrtShell.GetNumberFormatter();
272 const SvNumberformat* pFormat = pNumberFormatter->GetEntry(m_xDateFormat->GetFormat());
273 if (pFormat)
274 {
275 if (pFormat->GetFormatstring() != m_pContentControl->GetDateFormat())
276 {
277 m_pContentControl->SetDateFormat(pFormat->GetFormatstring());
278 bChanged = true;
279 }
280
281 OUString aLanguage = LanguageTag(pFormat->GetLanguage()).getBcp47();
282 if (aLanguage != m_pContentControl->GetDateLanguage())
283 {
284 m_pContentControl->SetDateLanguage(aLanguage);
285 bChanged = true;
286 }
287 }
288 }
289
290 if (bChanged)
291 {
292 m_rWrtShell.GetDoc()->getIDocumentState().SetModified();
293
294 // Make sure that the cursor gets updated with the new list items.
295 m_rWrtShell.HideCursor();
296 m_rWrtShell.ShowCursor();
297 }
298
299 m_xDialog->response(RET_OK);
300}
301
302IMPL_LINK(SwContentControlDlg, SelectCharHdl, weld::Button&, rButton, void)
303{
304 SvxCharacterMap aMap(m_xDialog.get(), nullptr, nullptr);
305 sal_UCS4 cBullet = 0;
306 sal_Int32 nIndex = 0;
307 if (&rButton == m_xCheckedStateBtn.get())
308 {
309 cBullet = m_pContentControl->GetCheckedState().iterateCodePoints(&nIndex);
310 }
311 else if (&rButton == m_xUncheckedStateBtn.get())
312 {
313 cBullet = m_pContentControl->GetUncheckedState().iterateCodePoints(&nIndex);
314 }
315 aMap.SetChar(cBullet);
316 if (aMap.run() != RET_OK)
317 {
318 return;
319 }
320
321 cBullet = aMap.GetChar();
322 if (&rButton == m_xCheckedStateBtn.get())
323 {
324 m_xCheckedState->set_text(OUString(&cBullet, 1));
325 }
326 else if (&rButton == m_xUncheckedStateBtn.get())
327 {
328 m_xUncheckedState->set_text(OUString(&cBullet, 1));
329 }
330}
331
333{
334 std::shared_ptr<SwContentControlListItem> aItem = std::make_shared<SwContentControlListItem>();
336 m_xListItemDialog = rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), *aItem);
337 m_xListItemDialog->StartExecuteAsync([this, aItem](sal_Int32 nResult) {
338 if (nResult == RET_OK)
339 {
340 if (aItem->m_aDisplayText.isEmpty() && aItem->m_aValue.isEmpty())
341 {
342 // Maintain the invariant that value can't be empty.
343 return;
344 }
345
346 if (aItem->m_aValue.isEmpty())
347 {
348 aItem->m_aValue = aItem->m_aDisplayText;
349 }
350
351 int nRow = m_xListItems->n_children();
352 m_xListItems->append_text(aItem->m_aDisplayText);
353 m_xListItems->set_text(nRow, aItem->m_aValue, 1);
354 }
355
356 m_xListItemDialog.disposeAndClear();
357 });
358}
359
361{
362 int nRow = m_xListItems->get_selected_index();
363 if (nRow < 0)
364 {
365 return;
366 }
367
368 std::shared_ptr<SwContentControlListItem> aItem = std::make_shared<SwContentControlListItem>();
369 aItem->m_aDisplayText = m_xListItems->get_text(nRow, 0);
370 aItem->m_aValue = m_xListItems->get_text(nRow, 1);
372 m_xListItemDialog = rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), *aItem);
373 m_xListItemDialog->StartExecuteAsync([this, aItem, nRow](sal_Int32 nResult) {
374 if (nResult == RET_OK)
375 {
376 if (aItem->m_aDisplayText.isEmpty() && aItem->m_aValue.isEmpty())
377 {
378 // Maintain the invariant that value can't be empty.
379 return;
380 }
381
382 if (aItem->m_aValue.isEmpty())
383 {
384 aItem->m_aValue = aItem->m_aDisplayText;
385 }
386
387 m_xListItems->set_text(nRow, aItem->m_aDisplayText, 0);
388 m_xListItems->set_text(nRow, aItem->m_aValue, 1);
389 }
390
391 m_xListItemDialog.disposeAndClear();
392 });
393}
394
396{
397 int nRow = m_xListItems->get_selected_index();
398 if (nRow < 0)
399 {
400 return;
401 }
402
403 m_xListItems->remove(nRow);
404}
405
407{
408 int nRow = m_xListItems->get_selected_index();
409 if (nRow <= 0)
410 {
411 return;
412 }
413
415 aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0);
416 aItem.m_aValue = m_xListItems->get_text(nRow, 1);
417 m_xListItems->remove(nRow);
418 --nRow;
419 m_xListItems->insert_text(nRow, aItem.m_aDisplayText);
420 m_xListItems->set_text(nRow, aItem.m_aValue, 1);
421 m_xListItems->select(nRow);
422}
423
425{
426 int nRow = m_xListItems->get_selected_index();
427 int nEndPos = m_xListItems->n_children() - 1;
428 if (nRow < 0 || nRow >= nEndPos)
429 {
430 return;
431 }
432
434 aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0);
435 aItem.m_aValue = m_xListItems->get_text(nRow, 1);
436 m_xListItems->remove(nRow);
437 ++nRow;
438 m_xListItems->insert_text(nRow, aItem.m_aDisplayText);
439 m_xListItems->set_text(nRow, aItem.m_aValue, 1);
440 m_xListItems->select(nRow);
441}
442
444{
445 int nRow = m_xListItems->get_selected_index();
446 if (nRow < 0)
447 {
448 m_xRenameBtn->set_sensitive(false);
449 m_xDeleteBtn->set_sensitive(false);
450 }
451 else
452 {
453 m_xRenameBtn->set_sensitive(true);
454 m_xDeleteBtn->set_sensitive(true);
455 }
456
457 if (nRow <= 0)
458 {
459 m_xMoveUpBtn->set_sensitive(false);
460 }
461 else
462 {
463 m_xMoveUpBtn->set_sensitive(true);
464 }
465
466 int nEndPos = m_xListItems->n_children() - 1;
467 if (nRow < 0 || nRow >= nEndPos)
468 {
469 m_xMoveDownBtn->set_sensitive(false);
470 }
471 else
472 {
473 m_xMoveDownBtn->set_sensitive(true);
474 }
475}
476
477/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XExecutableDialog > m_xDialog
LanguageType getLanguageType(bool bResolveSystem=true) const
const OUString & getBcp47(bool bResolveSystem=true) const
constexpr tools::Long Width() const
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bReplaceBooleanEquivalent=true)
sal_uInt32 GetEntryKey(std::u16string_view sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
LanguageType GetLanguage() const
const OUString & GetFormatstring() const
virtual VclPtr< AbstractSwContentControlListItemDlg > CreateSwContentControlListItemDlg(weld::Window *pParent, SwContentControlListItem &rItem)=0
The content control dialog allows editing the properties of the content control under the cursor.
std::unique_ptr< weld::Box > m_xListItemButtons
std::unique_ptr< weld::Button > m_xUncheckedStateBtn
std::unique_ptr< weld::Button > m_xRenameBtn
std::vector< SwContentControlListItem > m_aSavedListItems
std::unique_ptr< weld::Frame > m_xDateFrame
std::shared_ptr< SwContentControl > m_pContentControl
std::unique_ptr< weld::Button > m_xMoveUpBtn
std::unique_ptr< weld::SpinButton > m_xTabIndex
std::unique_ptr< weld::Button > m_xInsertBtn
std::unique_ptr< weld::TreeView > m_xListItems
std::unique_ptr< weld::Frame > m_xListItemsFrame
std::unique_ptr< weld::CheckButton > m_xShowingPlaceHolderCB
std::unique_ptr< weld::Button > m_xMoveDownBtn
std::unique_ptr< weld::SpinButton > m_xId
std::unique_ptr< weld::Frame > m_xCheckboxFrame
std::unique_ptr< weld::Entry > m_xAlias
std::unique_ptr< weld::Entry > m_xUncheckedState
SwContentControlDlg(weld::Window *pParent, SwWrtShell &rSh)
std::unique_ptr< weld::Button > m_xCheckedStateBtn
std::unique_ptr< weld::Button > m_xDeleteBtn
virtual ~SwContentControlDlg() override
std::unique_ptr< weld::Entry > m_xTag
std::unique_ptr< SwNumFormatTreeView > m_xDateFormat
std::unique_ptr< weld::Button > m_xOk
std::unique_ptr< weld::Entry > m_xCheckedState
VclPtr< VclAbstractDialog > m_xListItemDialog
Represents one list item in a content control dropdown list.
OUString m_aValue
This must not be empty.
OUString m_aDisplayText
This may be empty, ToString() falls back to m_aValue.
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:194
SvNumberFormatter * GetNumberFormatter()
Query NumberFormatter from document.
Definition: editsh.cxx:756
SfxPoolItem subclass that wraps an SwContentControl.
const std::shared_ptr< SwContentControl > & GetContentControl() const
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:901
const SwPosition * Start() const
Definition: pam.hxx:258
A wrapper around SfxPoolItem to store the start position of (usually) a text portion,...
Definition: txatbase.hxx:44
const SwFormatContentControl & GetContentControl() const
Definition: txatbase.hxx:220
SwTextAttr subclass that tracks the location of the wrapped SwFormatContentControl.
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:112
SwTextAttr * GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich, ::sw::GetTextAttrMode const eMode=::sw::GetTextAttrMode::Default) const
get the innermost text attribute covering position nIndex.
Definition: ndtxt.cxx:1804
Used by the UI to modify the document model.
Definition: wrtsh.hxx:97
void disposeAndClear()
virtual int get_height_rows(int nRows) const=0
virtual void set_size_request(int nWidth, int nHeight)=0
virtual Size get_preferred_size() const=0
IMPL_LINK_NOARG(SwContentControlDlg, OkHdl, weld::Button &, void)
IMPL_LINK(SwContentControlDlg, SelectCharHdl, weld::Button &, rButton, void)
TriState
TRISTATE_FALSE
TRISTATE_TRUE
constexpr TypedWhichId< SwFormatContentControl > RES_TXTATR_CONTENTCONTROL(56)
sal_Int32 nIndex
#define LANGUAGE_DONTKNOW
if(aStr !=aBuf) UpdateName_Impl(m_xFollowLb.get()
int i
@ Parent
EXPAND : (Start < nIndex <= End)
SwAbstractDialogFactory & GetFactory()
Definition: swuiexp.cxx:26
HashMap_OWString_Interface aMap
sal_Int16 nId
QPRO_FUNC_TYPE nType
Marks a position in the document model.
Definition: pam.hxx:38
SwNode & GetNode() const
Definition: pam.hxx:81
sal_Int32 GetContentIndex() const
Definition: pam.hxx:85
#define SAL_MAX_INT32
#define SAL_MIN_INT32
#define SAL_MAX_UINT32
RET_OK
sal_uInt32 sal_UCS4
SvNumFormatType
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND