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>
29 #include <textcontentcontrol.hxx>
30 #include <IDocumentState.hxx>
31 #include <swuiexp.hxx>
32 #include <numfmtlb.hxx>
33 
34 using 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_xCheckboxFrame(m_xBuilder->weld_frame("checkboxframe"))
42  , m_xCheckedState(m_xBuilder->weld_entry("checkboxcheckedentry"))
43  , m_xCheckedStateBtn(m_xBuilder->weld_button("btncheckboxchecked"))
44  , m_xUncheckedState(m_xBuilder->weld_entry("checkboxuncheckedentry"))
45  , m_xUncheckedStateBtn(m_xBuilder->weld_button("btncheckboxunchecked"))
46  , m_xListItemsFrame(m_xBuilder->weld_frame("listitemsframe"))
47  , m_xListItems(m_xBuilder->weld_tree_view("listitems"))
48  , m_xListItemButtons(m_xBuilder->weld_box("listitembuttons"))
49  , m_xInsertBtn(m_xBuilder->weld_button("add"))
50  , m_xRenameBtn(m_xBuilder->weld_button("modify"))
51  , m_xDeleteBtn(m_xBuilder->weld_button("remove"))
52  , m_xMoveUpBtn(m_xBuilder->weld_button("moveup"))
53  , m_xMoveDownBtn(m_xBuilder->weld_button("movedown"))
54  , m_xDateFrame(m_xBuilder->weld_frame("dateframe"))
55  , m_xDateFormat(new SwNumFormatTreeView(m_xBuilder->weld_tree_view("date_formats_treeview")))
56  , m_xOk(m_xBuilder->weld_button("ok"))
57 {
58  m_xCheckedStateBtn->connect_clicked(LINK(this, SwContentControlDlg, SelectCharHdl));
59  m_xUncheckedStateBtn->connect_clicked(LINK(this, SwContentControlDlg, SelectCharHdl));
60  m_xListItems->connect_changed(LINK(this, SwContentControlDlg, SelectionChangedHdl));
61  m_xOk->connect_clicked(LINK(this, SwContentControlDlg, OkHdl));
62 
63  // Only 2 items would be visible by default.
64  m_xListItems->set_size_request(-1, m_xListItems->get_height_rows(8));
65  // Only the first column would have a non-zero size by default in the SvHeaderTabListBox case.
66  m_xListItems->set_column_fixed_widths({ 100, 100 });
67 
68  m_xInsertBtn->connect_clicked(LINK(this, SwContentControlDlg, InsertHdl));
69  m_xRenameBtn->connect_clicked(LINK(this, SwContentControlDlg, RenameHdl));
70  m_xDeleteBtn->connect_clicked(LINK(this, SwContentControlDlg, DeleteHdl));
71  m_xMoveUpBtn->connect_clicked(LINK(this, SwContentControlDlg, MoveUpHdl));
72  m_xMoveDownBtn->connect_clicked(LINK(this, SwContentControlDlg, MoveDownHdl));
73 
74  const SwPosition* pStart = rWrtShell.GetCursor()->Start();
75  SwTextNode* pTextNode = pStart->nNode.GetNode().GetTextNode();
76  if (!pTextNode)
77  {
78  return;
79  }
80 
81  SwTextAttr* pAttr = pTextNode->GetTextAttrAt(pStart->nContent.GetIndex(),
83  if (!pAttr)
84  {
85  return;
86  }
87 
88  SwTextContentControl* pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
89  const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
90  m_pContentControl = rFormatContentControl.GetContentControl();
91 
92  bool bShowingPlaceHolder = m_pContentControl->GetShowingPlaceHolder();
93  TriState eShowingPlaceHolder = bShowingPlaceHolder ? TRISTATE_TRUE : TRISTATE_FALSE;
94  m_xShowingPlaceHolderCB->set_state(eShowingPlaceHolder);
95  m_xShowingPlaceHolderCB->save_state();
96 
97  if (m_pContentControl->GetCheckbox())
98  {
99  m_xCheckedState->set_text(m_pContentControl->GetCheckedState());
100  m_xCheckedState->save_value();
101  m_xUncheckedState->set_text(m_pContentControl->GetUncheckedState());
102  m_xUncheckedState->save_value();
103  }
104  else
105  {
106  m_xCheckboxFrame->set_visible(false);
107  }
108 
109  if (m_pContentControl->HasListItems())
110  {
111  for (const auto& rListItem : m_pContentControl->GetListItems())
112  {
113  int nRow = m_xListItems->n_children();
114  m_xListItems->append_text(rListItem.m_aDisplayText);
115  m_xListItems->set_text(nRow, rListItem.m_aValue, 1);
116  }
117  m_aSavedListItems = m_pContentControl->GetListItems();
118  }
119  else
120  {
121  m_xListItemsFrame->set_visible(false);
122  m_xListItemButtons->set_visible(false);
123  }
124 
125  if (m_pContentControl->GetDate())
126  {
127  m_xDateFormat->SetFormatType(SvNumFormatType::DATE);
128  m_xDateFormat->SetShowLanguageControl(true);
129 
130  // Set height to double of the default.
131  weld::TreeView& rTreeView = dynamic_cast<weld::TreeView&>(m_xDateFormat->get_widget());
132  rTreeView.set_size_request(rTreeView.get_preferred_size().Width(),
133  rTreeView.get_height_rows(10));
134 
135  OUString sFormatString = m_pContentControl->GetDateFormat();
136  OUString sLang = m_pContentControl->GetDateLanguage();
137  if (!sFormatString.isEmpty() && !sLang.isEmpty())
138  {
139  SvNumberFormatter* pNumberFormatter = m_rWrtShell.GetNumberFormatter();
140  LanguageType aLangType = LanguageTag(sLang).getLanguageType();
141  sal_uInt32 nFormat = pNumberFormatter->GetEntryKey(sFormatString, aLangType);
142  if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
143  {
144  sal_Int32 nCheckPos = 0;
146  pNumberFormatter->PutEntry(sFormatString, nCheckPos, nType, nFormat,
147  LanguageTag(sLang).getLanguageType());
148  }
149 
150  if (aLangType != LANGUAGE_DONTKNOW && nFormat != NUMBERFORMAT_ENTRY_NOT_FOUND)
151  {
152  m_xDateFormat->SetDefFormat(nFormat);
153  }
154  }
155  }
156  else
157  {
158  m_xDateFrame->set_visible(false);
159  }
160 }
161 
163 
165 {
166  if (!m_pContentControl)
167  {
168  return;
169  }
170 
171  bool bChanged = false;
172  if (m_xShowingPlaceHolderCB->get_state_changed_from_saved())
173  {
174  bool bShowingPlaceHolder = m_xShowingPlaceHolderCB->get_state() == TRISTATE_TRUE;
175  m_pContentControl->SetShowingPlaceHolder(bShowingPlaceHolder);
176  bChanged = true;
177  }
178 
179  if (m_xCheckedState->get_value_changed_from_saved())
180  {
181  m_pContentControl->SetCheckedState(m_xCheckedState->get_text());
182  }
183 
184  if (m_xUncheckedState->get_value_changed_from_saved())
185  {
186  m_pContentControl->SetUncheckedState(m_xUncheckedState->get_text());
187  }
188 
189  std::vector<SwContentControlListItem> aItems;
190  for (int i = 0; i < m_xListItems->n_children(); ++i)
191  {
193  aItem.m_aDisplayText = m_xListItems->get_text(i, 0);
194  aItem.m_aValue = m_xListItems->get_text(i, 1);
195  aItems.push_back(aItem);
196  }
197  if (aItems != m_aSavedListItems)
198  {
199  m_pContentControl->SetListItems(aItems);
200  bChanged = true;
201  }
202 
203  if (m_pContentControl->GetDate())
204  {
205  SvNumberFormatter* pNumberFormatter = m_rWrtShell.GetNumberFormatter();
206  const SvNumberformat* pFormat = pNumberFormatter->GetEntry(m_xDateFormat->GetFormat());
207  if (pFormat)
208  {
209  if (pFormat->GetFormatstring() != m_pContentControl->GetDateFormat())
210  {
211  m_pContentControl->SetDateFormat(pFormat->GetFormatstring());
212  bChanged = true;
213  }
214 
215  OUString aLanguage = LanguageTag(pFormat->GetLanguage()).getBcp47();
216  if (aLanguage != m_pContentControl->GetDateLanguage())
217  {
218  m_pContentControl->SetDateLanguage(aLanguage);
219  bChanged = true;
220  }
221  }
222  }
223 
224  if (bChanged)
225  {
226  m_rWrtShell.GetDoc()->getIDocumentState().SetModified();
227 
228  // Make sure that the cursor gets updated with the new list items.
229  m_rWrtShell.HideCursor();
230  m_rWrtShell.ShowCursor();
231  }
232 
233  m_xDialog->response(RET_OK);
234 }
235 
236 IMPL_LINK(SwContentControlDlg, SelectCharHdl, weld::Button&, rButton, void)
237 {
238  SvxCharacterMap aMap(m_xDialog.get(), nullptr, nullptr);
239  sal_UCS4 cBullet = 0;
240  sal_Int32 nIndex = 0;
241  if (&rButton == m_xCheckedStateBtn.get())
242  {
243  cBullet = m_pContentControl->GetCheckedState().iterateCodePoints(&nIndex);
244  }
245  else if (&rButton == m_xUncheckedStateBtn.get())
246  {
247  cBullet = m_pContentControl->GetUncheckedState().iterateCodePoints(&nIndex);
248  }
249  aMap.SetChar(cBullet);
250  if (aMap.run() != RET_OK)
251  {
252  return;
253  }
254 
255  cBullet = aMap.GetChar();
256  if (&rButton == m_xCheckedStateBtn.get())
257  {
258  m_xCheckedState->set_text(OUString(&cBullet, 1));
259  }
260  else if (&rButton == m_xUncheckedStateBtn.get())
261  {
262  m_xUncheckedState->set_text(OUString(&cBullet, 1));
263  }
264 }
265 
267 {
271  rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), aItem));
272  if (!pDlg->Execute())
273  {
274  return;
275  }
276 
277  if (aItem.m_aDisplayText.isEmpty() && aItem.m_aValue.isEmpty())
278  {
279  // Maintain the invariant that value can't be empty.
280  return;
281  }
282 
283  if (aItem.m_aValue.isEmpty())
284  {
285  aItem.m_aValue = aItem.m_aDisplayText;
286  }
287 
288  int nRow = m_xListItems->n_children();
289  m_xListItems->append_text(aItem.m_aDisplayText);
290  m_xListItems->set_text(nRow, aItem.m_aValue, 1);
291 }
292 
294 {
295  int nRow = m_xListItems->get_selected_index();
296  if (nRow < 0)
297  {
298  return;
299  }
300 
302  aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0);
303  aItem.m_aValue = m_xListItems->get_text(nRow, 1);
306  rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), aItem));
307  if (!pDlg->Execute())
308  {
309  return;
310  }
311 
312  if (aItem.m_aDisplayText.isEmpty() && aItem.m_aValue.isEmpty())
313  {
314  // Maintain the invariant that value can't be empty.
315  return;
316  }
317 
318  if (aItem.m_aValue.isEmpty())
319  {
320  aItem.m_aValue = aItem.m_aDisplayText;
321  }
322 
323  m_xListItems->set_text(nRow, aItem.m_aDisplayText, 0);
324  m_xListItems->set_text(nRow, aItem.m_aValue, 1);
325 }
326 
328 {
329  int nRow = m_xListItems->get_selected_index();
330  if (nRow < 0)
331  {
332  return;
333  }
334 
335  m_xListItems->remove(nRow);
336 }
337 
339 {
340  int nRow = m_xListItems->get_selected_index();
341  if (nRow <= 0)
342  {
343  return;
344  }
345 
347  aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0);
348  aItem.m_aValue = m_xListItems->get_text(nRow, 1);
349  m_xListItems->remove(nRow);
350  --nRow;
351  m_xListItems->insert_text(nRow, aItem.m_aDisplayText);
352  m_xListItems->set_text(nRow, aItem.m_aValue, 1);
353  m_xListItems->select(nRow);
354 }
355 
357 {
358  int nRow = m_xListItems->get_selected_index();
359  int nEndPos = m_xListItems->n_children() - 1;
360  if (nRow < 0 || nRow >= nEndPos)
361  {
362  return;
363  }
364 
366  aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0);
367  aItem.m_aValue = m_xListItems->get_text(nRow, 1);
368  m_xListItems->remove(nRow);
369  ++nRow;
370  m_xListItems->insert_text(nRow, aItem.m_aDisplayText);
371  m_xListItems->set_text(nRow, aItem.m_aValue, 1);
372  m_xListItems->select(nRow);
373 }
374 
376 {
377  if (!m_xListItems->has_focus())
378  {
379  return;
380  }
381 
382  int nRow = m_xListItems->get_selected_index();
383  if (nRow < 0)
384  {
385  m_xRenameBtn->set_sensitive(false);
386  m_xDeleteBtn->set_sensitive(false);
387  }
388  else
389  {
390  m_xRenameBtn->set_sensitive(true);
391  m_xDeleteBtn->set_sensitive(true);
392  }
393 
394  if (nRow <= 0)
395  {
396  m_xMoveUpBtn->set_sensitive(false);
397  }
398  else
399  {
400  m_xMoveUpBtn->set_sensitive(true);
401  }
402 
403  int nEndPos = m_xListItems->n_children() - 1;
404  if (nRow < 0 || nRow >= nEndPos)
405  {
406  m_xMoveDownBtn->set_sensitive(false);
407  }
408  else
409  {
410  m_xMoveDownBtn->set_sensitive(true);
411  }
412 }
413 
414 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::unique_ptr< weld::Frame > m_xListItemsFrame
std::shared_ptr< SwContentControl > m_pContentControl
std::unique_ptr< weld::Button > m_xRenameBtn
sal_Int32 nIndex
Marks a position in the document model.
Definition: pam.hxx:36
std::unique_ptr< weld::CheckButton > m_xShowingPlaceHolderCB
std::unique_ptr< weld::Entry > m_xCheckedState
sal_uInt32 sal_UCS4
The content control dialog allows editing the properties of the content control under the cursor...
SwNodeIndex nNode
Definition: pam.hxx:38
LanguageType getLanguageType(bool bResolveSystem=true) const
std::unique_ptr< weld::Button > m_xOk
SfxPoolItem subclass that wraps an SwContentControl.
SwNode & GetNode() const
Definition: ndindex.hxx:128
std::unique_ptr< weld::Button > m_xInsertBtn
std::unique_ptr< weld::Frame > m_xDateFrame
std::unique_ptr< weld::Button > m_xCheckedStateBtn
SwTextAttr * GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich, enum GetTextAttrMode const eMode=DEFAULT) const
get the innermost text attribute covering position nIndex.
Definition: ndtxt.cxx:1746
virtual short Execute()=0
TRISTATE_TRUE
const OUString & GetFormatstring() const
SwContentControlDlg(weld::Window *pParent, SwWrtShell &rSh)
Used by the UI to modify the document model.
Definition: wrtsh.hxx:96
constexpr tools::Long Width() const
HashMap_OWString_Interface aMap
std::unique_ptr< weld::Button > m_xMoveUpBtn
IMPL_LINK(SwContentControlDlg, SelectCharHdl, weld::Button &, rButton, void)
virtual VclPtr< AbstractSwContentControlListItemDlg > CreateSwContentControlListItemDlg(weld::Window *pParent, SwContentControlListItem &rItem)=0
Represents one list item in a content control dropdown list.
SwIndex nContent
Definition: pam.hxx:39
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bReplaceBooleanEquivalent=true)
A wrapper around SfxPoolItem to store the start position of (usually) a text portion, with an optional end.
Definition: txatbase.hxx:43
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND
std::unique_ptr< SwNumFormatTreeView > m_xDateFormat
std::vector< SwContentControlListItem > m_aSavedListItems
virtual ~SwContentControlDlg() override
int i
SwAbstractDialogFactory & GetFactory()
Definition: swuiexp.cxx:26
const SwFormatContentControl & GetContentControl() const
Definition: txatbase.hxx:220
TRISTATE_FALSE
#define LANGUAGE_DONTKNOW
std::unique_ptr< weld::Frame > m_xCheckboxFrame
SvNumFormatType
T static_txtattr_cast(S *s)
Definition: txatbase.hxx:257
sal_uInt32 GetEntryKey(std::u16string_view sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
virtual Size get_preferred_size() const =0
const SwPosition * Start() const
Definition: pam.hxx:213
EXPAND : (Start < nIndex <= End)
Definition: ndtxt.hxx:371
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
constexpr TypedWhichId< SwFormatContentControl > RES_TXTATR_CONTENTCONTROL(56)
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:195
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
SwTextAttr subclass that tracks the location of the wrapped SwFormatContentControl.
sal_Int32 GetIndex() const
Definition: index.hxx:91
RET_OK
Reference< XExecutableDialog > m_xDialog
std::unique_ptr< weld::Button > m_xMoveDownBtn
virtual int get_height_rows(int nRows) const =0
QPRO_FUNC_TYPE nType
std::unique_ptr< weld::TreeView > m_xListItems
OUString m_aValue
This must not be empty.
std::unique_ptr< weld::Box > m_xListItemButtons
std::unique_ptr< weld::Button > m_xDeleteBtn
OUString m_aDisplayText
This may be empty, ToString() falls back to m_aValue.
IMPL_LINK_NOARG(SwContentControlDlg, OkHdl, weld::Button &, void)
std::unique_ptr< weld::Entry > m_xUncheckedState
TriState
virtual void set_size_request(int nWidth, int nHeight)=0
std::unique_ptr< weld::Button > m_xUncheckedStateBtn
SvNumberFormatter * GetNumberFormatter()
Query NumberFormatter from document.
Definition: editsh.cxx:757
LanguageType GetLanguage() const
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:864