1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <contentcontroldlg.hxx>
22 #include <vcl/weld.hxx>
23 #include <cui/cuicharmap.hxx>
24 #include <svl/numformat.hxx>
25 #include <svl/zformat.hxx>
29 #include <textcontentcontrol.hxx>
30 #include <IDocumentState.hxx>
31 #include <swuiexp.hxx>
32 #include <numfmtlb.hxx>
34 using namespace com::sun::star
;
36 SwContentControlDlg::SwContentControlDlg(weld::Window
* pParent
, SwWrtShell
& rWrtShell
)
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"))
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
));
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 });
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
));
78 const SwPosition
* pStart
= rWrtShell
.GetCursor()->Start();
79 SwTextNode
* pTextNode
= pStart
->GetNode().GetTextNode();
85 SwTextAttr
* pAttr
= pTextNode
->GetTextAttrAt(
86 pStart
->GetContentIndex(), RES_TXTATR_CONTENTCONTROL
, ::sw::GetTextAttrMode::Parent
);
92 SwTextContentControl
* pTextContentControl
= static_txtattr_cast
<SwTextContentControl
*>(pAttr
);
93 const SwFormatContentControl
& rFormatContentControl
= pTextContentControl
->GetContentControl();
94 m_pContentControl
= rFormatContentControl
.GetContentControl();
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();
101 if (!m_pContentControl
->GetAlias().isEmpty())
103 m_xAlias
->set_text(m_pContentControl
->GetAlias());
104 m_xAlias
->save_value();
107 if (!m_pContentControl
->GetTag().isEmpty())
109 m_xTag
->set_text(m_pContentControl
->GetTag());
110 m_xTag
->save_value();
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.
124 m_xId
->set_editable(false); // still available for copy/paste
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.
129 m_xTabIndex
->set_range(SAL_MIN_INT32
, SAL_MAX_INT32
);
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();
135 if (m_pContentControl
->GetCheckbox())
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();
144 m_xCheckboxFrame
->set_visible(false);
147 if (m_pContentControl
->GetComboBox() || m_pContentControl
->GetDropDown())
149 for (const auto& rListItem
: m_pContentControl
->GetListItems())
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);
155 m_aSavedListItems
= m_pContentControl
->GetListItems();
159 m_xListItemsFrame
->set_visible(false);
160 m_xListItemButtons
->set_visible(false);
163 if (m_pContentControl
->GetDate())
165 m_xDateFormat
->SetFormatType(SvNumFormatType::DATE
);
166 m_xDateFormat
->SetShowLanguageControl(true);
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));
173 OUString sFormatString
= m_pContentControl
->GetDateFormat();
174 OUString sLang
= m_pContentControl
->GetDateLanguage();
175 if (!sFormatString
.isEmpty() && !sLang
.isEmpty())
177 SvNumberFormatter
* pNumberFormatter
= m_rWrtShell
.GetNumberFormatter();
178 LanguageType aLangType
= LanguageTag(sLang
).getLanguageType();
179 sal_uInt32 nFormat
= pNumberFormatter
->GetEntryKey(sFormatString
, aLangType
);
180 if (nFormat
== NUMBERFORMAT_ENTRY_NOT_FOUND
)
182 sal_Int32 nCheckPos
= 0;
183 SvNumFormatType nType
;
184 pNumberFormatter
->PutEntry(sFormatString
, nCheckPos
, nType
, nFormat
,
185 LanguageTag(sLang
).getLanguageType());
188 if (aLangType
!= LANGUAGE_DONTKNOW
&& nFormat
!= NUMBERFORMAT_ENTRY_NOT_FOUND
)
190 m_xDateFormat
->SetDefFormat(nFormat
);
196 m_xDateFrame
->set_visible(false);
200 SwContentControlDlg::~SwContentControlDlg()
202 if (m_xListItemDialog
)
203 m_xListItemDialog
.disposeAndClear();
206 IMPL_LINK_NOARG(SwContentControlDlg
, OkHdl
, weld::Button
&, void)
208 if (!m_pContentControl
)
213 bool bChanged
= false;
214 if (m_xShowingPlaceHolderCB
->get_state_changed_from_saved())
216 bool bShowingPlaceHolder
= m_xShowingPlaceHolderCB
->get_state() == TRISTATE_TRUE
;
217 m_pContentControl
->SetShowingPlaceHolder(bShowingPlaceHolder
);
221 if (m_xAlias
->get_value_changed_from_saved())
223 m_pContentControl
->SetAlias(m_xAlias
->get_text());
227 if (m_xTag
->get_value_changed_from_saved())
229 m_pContentControl
->SetTag(m_xTag
->get_text());
233 if (m_xId
->get_value_changed_from_saved())
235 m_pContentControl
->SetId(o3tl::narrowing
<sal_Int32
>(m_xId
->get_value()));
239 if (m_xTabIndex
->get_value_changed_from_saved())
241 m_pContentControl
->SetTabIndex(o3tl::narrowing
<sal_uInt32
>(m_xTabIndex
->get_value()));
245 if (m_xCheckedState
->get_value_changed_from_saved())
247 m_pContentControl
->SetCheckedState(m_xCheckedState
->get_text());
250 if (m_xUncheckedState
->get_value_changed_from_saved())
252 m_pContentControl
->SetUncheckedState(m_xUncheckedState
->get_text());
255 std::vector
<SwContentControlListItem
> aItems
;
256 for (int i
= 0; i
< m_xListItems
->n_children(); ++i
)
258 SwContentControlListItem aItem
;
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
);
263 if (aItems
!= m_aSavedListItems
)
265 m_pContentControl
->SetListItems(aItems
);
269 if (m_pContentControl
->GetDate())
271 SvNumberFormatter
* pNumberFormatter
= m_rWrtShell
.GetNumberFormatter();
272 const SvNumberformat
* pFormat
= pNumberFormatter
->GetEntry(m_xDateFormat
->GetFormat());
275 if (pFormat
->GetFormatstring() != m_pContentControl
->GetDateFormat())
277 m_pContentControl
->SetDateFormat(pFormat
->GetFormatstring());
281 OUString aLanguage
= LanguageTag(pFormat
->GetLanguage()).getBcp47();
282 if (aLanguage
!= m_pContentControl
->GetDateLanguage())
284 m_pContentControl
->SetDateLanguage(aLanguage
);
292 m_rWrtShell
.GetDoc()->getIDocumentState().SetModified();
294 // Make sure that the cursor gets updated with the new list items.
295 m_rWrtShell
.HideCursor();
296 m_rWrtShell
.ShowCursor();
299 m_xDialog
->response(RET_OK
);
302 IMPL_LINK(SwContentControlDlg
, SelectCharHdl
, weld::Button
&, rButton
, void)
304 SvxCharacterMap
aMap(m_xDialog
.get(), nullptr, nullptr);
305 sal_UCS4 cBullet
= 0;
306 sal_Int32 nIndex
= 0;
307 if (&rButton
== m_xCheckedStateBtn
.get())
309 cBullet
= m_pContentControl
->GetCheckedState().iterateCodePoints(&nIndex
);
311 else if (&rButton
== m_xUncheckedStateBtn
.get())
313 cBullet
= m_pContentControl
->GetUncheckedState().iterateCodePoints(&nIndex
);
315 aMap
.SetChar(cBullet
);
316 if (aMap
.run() != RET_OK
)
321 cBullet
= aMap
.GetChar();
322 if (&rButton
== m_xCheckedStateBtn
.get())
324 m_xCheckedState
->set_text(OUString(&cBullet
, 1));
326 else if (&rButton
== m_xUncheckedStateBtn
.get())
328 m_xUncheckedState
->set_text(OUString(&cBullet
, 1));
332 IMPL_LINK_NOARG(SwContentControlDlg
, InsertHdl
, weld::Button
&, void)
334 std::shared_ptr
<SwContentControlListItem
> aItem
= std::make_shared
<SwContentControlListItem
>();
335 SwAbstractDialogFactory
& rFact
= swui::GetFactory();
336 m_xListItemDialog
= rFact
.CreateSwContentControlListItemDlg(m_xDialog
.get(), *aItem
);
337 m_xListItemDialog
->StartExecuteAsync([this, aItem
](sal_Int32 nResult
) {
338 if (nResult
== RET_OK
)
340 if (aItem
->m_aDisplayText
.isEmpty() && aItem
->m_aValue
.isEmpty())
342 // Maintain the invariant that value can't be empty.
346 if (aItem
->m_aValue
.isEmpty())
348 aItem
->m_aValue
= aItem
->m_aDisplayText
;
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);
356 m_xListItemDialog
.disposeAndClear();
360 IMPL_LINK_NOARG(SwContentControlDlg
, RenameHdl
, weld::Button
&, void)
362 int nRow
= m_xListItems
->get_selected_index();
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);
371 SwAbstractDialogFactory
& rFact
= swui::GetFactory();
372 m_xListItemDialog
= rFact
.CreateSwContentControlListItemDlg(m_xDialog
.get(), *aItem
);
373 m_xListItemDialog
->StartExecuteAsync([this, aItem
, nRow
](sal_Int32 nResult
) {
374 if (nResult
== RET_OK
)
376 if (aItem
->m_aDisplayText
.isEmpty() && aItem
->m_aValue
.isEmpty())
378 // Maintain the invariant that value can't be empty.
382 if (aItem
->m_aValue
.isEmpty())
384 aItem
->m_aValue
= aItem
->m_aDisplayText
;
387 m_xListItems
->set_text(nRow
, aItem
->m_aDisplayText
, 0);
388 m_xListItems
->set_text(nRow
, aItem
->m_aValue
, 1);
391 m_xListItemDialog
.disposeAndClear();
395 IMPL_LINK_NOARG(SwContentControlDlg
, DeleteHdl
, weld::Button
&, void)
397 int nRow
= m_xListItems
->get_selected_index();
403 m_xListItems
->remove(nRow
);
406 IMPL_LINK_NOARG(SwContentControlDlg
, MoveUpHdl
, weld::Button
&, void)
408 int nRow
= m_xListItems
->get_selected_index();
414 SwContentControlListItem aItem
;
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
);
419 m_xListItems
->insert_text(nRow
, aItem
.m_aDisplayText
);
420 m_xListItems
->set_text(nRow
, aItem
.m_aValue
, 1);
421 m_xListItems
->select(nRow
);
424 IMPL_LINK_NOARG(SwContentControlDlg
, MoveDownHdl
, weld::Button
&, void)
426 int nRow
= m_xListItems
->get_selected_index();
427 int nEndPos
= m_xListItems
->n_children() - 1;
428 if (nRow
< 0 || nRow
>= nEndPos
)
433 SwContentControlListItem aItem
;
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
);
438 m_xListItems
->insert_text(nRow
, aItem
.m_aDisplayText
);
439 m_xListItems
->set_text(nRow
, aItem
.m_aValue
, 1);
440 m_xListItems
->select(nRow
);
443 IMPL_LINK_NOARG(SwContentControlDlg
, SelectionChangedHdl
, weld::TreeView
&, void)
445 int nRow
= m_xListItems
->get_selected_index();
448 m_xRenameBtn
->set_sensitive(false);
449 m_xDeleteBtn
->set_sensitive(false);
453 m_xRenameBtn
->set_sensitive(true);
454 m_xDeleteBtn
->set_sensitive(true);
459 m_xMoveUpBtn
->set_sensitive(false);
463 m_xMoveUpBtn
->set_sensitive(true);
466 int nEndPos
= m_xListItems
->n_children() - 1;
467 if (nRow
< 0 || nRow
>= nEndPos
)
469 m_xMoveDownBtn
->set_sensitive(false);
473 m_xMoveDownBtn
->set_sensitive(true);
477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */