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 <swmodule.hxx>
26 #include <dbconfig.hxx>
28 #include <o3tl/string_view.hxx>
30 #define USER_DATA_VERSION_1 "1"
31 #define USER_DATA_VERSION USER_DATA_VERSION_1
33 SwFieldDBPage::SwFieldDBPage(weld::Container
* pPage
, weld::DialogController
* pController
, const SfxItemSet
*const pCoreSet
)
34 : SwFieldPage(pPage
, pController
, u
"modules/swriter/ui/flddbpage.ui"_ustr
, u
"FieldDbPage"_ustr
, pCoreSet
)
37 , m_xTypeLB(m_xBuilder
->weld_tree_view(u
"type"_ustr
))
38 , m_xDatabaseTLB(new SwDBTreeList(m_xBuilder
->weld_tree_view(u
"select"_ustr
)))
39 , m_xAddDBPB(m_xBuilder
->weld_button(u
"browse"_ustr
))
40 , m_xCondition(m_xBuilder
->weld_widget(u
"condgroup"_ustr
))
41 , m_xConditionED(new ConditionEdit
<weld::Entry
>(m_xBuilder
->weld_entry(u
"condition"_ustr
)))
42 , m_xValue(m_xBuilder
->weld_widget(u
"recgroup"_ustr
))
43 , m_xValueED(m_xBuilder
->weld_entry(u
"recnumber"_ustr
))
44 , m_xDBFormatRB(m_xBuilder
->weld_radio_button(u
"fromdatabasecb"_ustr
))
45 , m_xNewFormatRB(m_xBuilder
->weld_radio_button(u
"userdefinedcb"_ustr
))
46 , m_xNumFormatLB(new NumFormatListBox(m_xBuilder
->weld_combo_box(u
"numformat"_ustr
)))
47 , m_xFormatLB(m_xBuilder
->weld_combo_box(u
"format"_ustr
))
48 , m_xFormat(m_xBuilder
->weld_widget(u
"formatframe"_ustr
))
50 SetTypeSel(-1); //TODO
52 m_xTypeLB
->make_sorted();
53 m_xFormatLB
->make_sorted();
55 auto nWidth
= m_xTypeLB
->get_approximate_digit_width() * FIELD_COLUMN_WIDTH
;
56 auto nHeight
= m_xTypeLB
->get_height_rows(10);
57 m_xTypeLB
->set_size_request(nWidth
, nHeight
);
58 m_xDatabaseTLB
->set_size_request(nWidth
*2, nHeight
);
60 m_xNumFormatLB
->connect_changed(LINK(this, SwFieldDBPage
, NumSelectHdl
));
61 m_xDatabaseTLB
->connect_changed(LINK(this, SwFieldDBPage
, TreeSelectHdl
));
62 m_xDatabaseTLB
->connect_row_activated(LINK(this, SwFieldDBPage
, TreeViewInsertHdl
));
64 m_xValueED
->connect_changed(LINK(this, SwFieldDBPage
, ModifyHdl
));
65 m_xAddDBPB
->connect_clicked(LINK(this, SwFieldDBPage
, AddDBHdl
));
68 m_xTypeLB
->set_buildable_name(m_xTypeLB
->get_buildable_name() + "-db");
69 m_xNumFormatLB
->set_buildable_name(m_xNumFormatLB
->get_buildable_name() + "-db");
70 m_xFormatLB
->set_buildable_name(m_xFormatLB
->get_buildable_name() + "-db");
73 SwFieldDBPage::~SwFieldDBPage()
75 // If we have no stored SwWrtShell, it means we didn't do anything useful - no need to revoke.
76 if (SwWrtShell
* pSh
= CheckAndGetWrtShell())
78 // This would cleanup in the case of cancelled dialog
79 SwDBManager
* pDbManager
= pSh
->GetDoc()->GetDBManager();
81 pDbManager
->RevokeLastRegistrations();
86 void SwFieldDBPage::Reset(const SfxItemSet
*)
88 Init(); // general initialization
90 const sal_Int32 nOldPos
= m_xTypeLB
->get_selected_index();
92 m_sOldDBName
= m_xDatabaseTLB
->GetDBName(m_sOldTableName
, m_sOldColumnName
);
98 // initialise TypeListBox
99 const SwFieldGroupRgn
& rRg
= SwFieldMgr::GetGroupRange(IsFieldDlgHtmlMode(), GetGroup());
101 for(sal_uInt16 i
= rRg
.nStart
; i
< rRg
.nEnd
; ++i
)
103 const SwFieldTypesEnum nTypeId
= SwFieldMgr::GetTypeId(i
);
104 m_xTypeLB
->append(OUString::number(static_cast<sal_uInt16
>(nTypeId
)), SwFieldMgr::GetTypeStr(i
));
109 const SwFieldTypesEnum nTypeId
= GetCurField()->GetTypeId();
110 m_xTypeLB
->append(OUString::number(static_cast<sal_uInt16
>(nTypeId
)),
111 SwFieldMgr::GetTypeStr(SwFieldMgr::GetPos(nTypeId
)));
117 if (GetTypeSel() != -1)
118 m_xTypeLB
->select(GetTypeSel());
120 m_xFormatLB
->clear();
122 const sal_uInt16 nSize
= GetFieldMgr().GetFormatCount(SwFieldTypesEnum::DatabaseSetNumber
, IsFieldDlgHtmlMode());
123 for( sal_uInt16 i
= 0; i
< nSize
; ++i
)
125 const sal_uInt16 nFormatId
= GetFieldMgr().GetFormatId( SwFieldTypesEnum::DatabaseSetNumber
, i
);
126 OUString
sId(OUString::number(nFormatId
));
127 m_xFormatLB
->append(sId
, GetFieldMgr().GetFormatStr(SwFieldTypesEnum::DatabaseSetNumber
, i
));
128 if (SVX_NUM_ARABIC
== nFormatId
)
129 m_xFormatLB
->set_active_id(sId
);
135 m_xTypeLB
->select(nOldPos
);
137 if (!m_sOldDBName
.isEmpty())
139 m_xDatabaseTLB
->Select(m_sOldDBName
, m_sOldTableName
, m_sOldColumnName
);
143 if (SwWrtShell
*pSh
= CheckAndGetWrtShell())
145 SwDBData
aTmp(pSh
->GetDBData());
146 m_xDatabaseTLB
->Select(aTmp
.sDataSource
, aTmp
.sCommand
, u
"");
153 const OUString sUserData
= GetUserData();
155 if (o3tl::equalsIgnoreAsciiCase(o3tl::getToken(sUserData
, 0, ';', nIdx
), u
"" USER_DATA_VERSION_1
))
157 const sal_uInt16 nVal
= o3tl::narrowing
<sal_uInt16
>(o3tl::toInt32(o3tl::getToken(sUserData
, 0, ';', nIdx
)));
158 if (nVal
!= USHRT_MAX
)
160 for (sal_Int32 i
= 0, nEntryCount
= m_xTypeLB
->n_children(); i
< nEntryCount
; ++i
)
162 if (nVal
== m_xTypeLB
->get_id(i
).toUInt32())
164 m_xTypeLB
->select(i
);
173 m_xTypeLB
->connect_selection_changed(LINK(this, SwFieldDBPage
, TypeListBoxHdl
));
174 m_xTypeLB
->connect_row_activated(LINK(this, SwFieldDBPage
, TreeViewInsertHdl
));
178 m_xConditionED
->save_value();
179 m_xValueED
->save_value();
180 m_sOldDBName
= m_xDatabaseTLB
->GetDBName(m_sOldTableName
, m_sOldColumnName
);
181 m_nOldFormat
= GetCurField()->GetFormat();
182 m_nOldSubType
= GetCurField()->GetSubType();
186 // SwFieldDBPage may ask for password to select current document's data source,
187 // so only do that when activating the page, not when dialog is creating all pages
188 bool SwFieldDBPage::DeferResetToFirstActivation() { return true; }
190 bool SwFieldDBPage::FillItemSet(SfxItemSet
* )
193 OUString sColumnName
;
196 aData
.sDataSource
= m_xDatabaseTLB
->GetDBName(sTableName
, sColumnName
, &bIsTable
);
197 aData
.sCommand
= sTableName
;
198 aData
.nCommandType
= bIsTable
? 0 : 1;
200 if (SwWrtShell
*pSh
= CheckAndGetWrtShell())
202 SwDBManager
* pDbManager
= pSh
->GetDoc()->GetDBManager();
204 pDbManager
->CommitLastRegistrations();
206 if (aData
.sDataSource
.isEmpty())
207 aData
= pSh
->GetDBData();
210 if(!aData
.sDataSource
.isEmpty()) // without database no new field command
212 const SwFieldTypesEnum nTypeId
= static_cast<SwFieldTypesEnum
>(m_xTypeLB
->get_id(GetTypeSel()).toUInt32());
213 sal_uInt32 nFormat
= 0;
214 sal_uInt16 nSubType
= 0;
216 OUString sDBName
= aData
.sDataSource
217 + OUStringChar(DB_DELIM
)
219 + OUStringChar(DB_DELIM
)
220 + OUString::number(aData
.nCommandType
)
221 + OUStringChar(DB_DELIM
);
222 if (!sColumnName
.isEmpty())
224 sDBName
+= sColumnName
+ OUStringChar(DB_DELIM
);
226 OUString aName
= sDBName
+ m_xConditionED
->get_text();
230 case SwFieldTypesEnum::Database
:
231 nFormat
= m_xNumFormatLB
->GetFormat();
232 if (m_xNewFormatRB
->get_sensitive() && m_xNewFormatRB
->get_active())
233 nSubType
= nsSwExtendedSubType::SUB_OWN_FMT
;
237 case SwFieldTypesEnum::DatabaseSetNumber
:
238 nFormat
= m_xFormatLB
->get_active_id().toUInt32();
243 const OUString
aVal(m_xValueED
->get_text());
244 OUString sTempTableName
;
245 OUString sTempColumnName
;
246 OUString sTempDBName
= m_xDatabaseTLB
->GetDBName(sTempTableName
, sTempColumnName
);
247 bool bDBListBoxChanged
= m_sOldDBName
!= sTempDBName
||
248 m_sOldTableName
!= sTempTableName
|| m_sOldColumnName
!= sTempColumnName
;
249 if (!IsFieldEdit() ||
250 m_xConditionED
->get_value_changed_from_saved() ||
251 m_xValueED
->get_saved_value() != aVal
||
253 m_nOldFormat
!= nFormat
|| m_nOldSubType
!= nSubType
)
255 InsertField( nTypeId
, nSubType
, aName
, aVal
, nFormat
);
262 std::unique_ptr
<SfxTabPage
> SwFieldDBPage::Create( weld::Container
* pPage
, weld::DialogController
* pController
,
263 const SfxItemSet
*const pAttrSet
)
265 return std::make_unique
<SwFieldDBPage
>( pPage
, pController
, pAttrSet
);
268 sal_uInt16
SwFieldDBPage::GetGroup()
273 IMPL_LINK( SwFieldDBPage
, TypeListBoxHdl
, weld::TreeView
&, rBox
, void )
278 void SwFieldDBPage::TypeHdl(const weld::TreeView
* pBox
)
280 // save old ListBoxPos
281 const sal_Int32 nOld
= GetTypeSel();
283 // current ListBoxPos
284 SetTypeSel(m_xTypeLB
->get_selected_index());
286 if (GetTypeSel() == -1)
289 m_xTypeLB
->select(0);
292 if (nOld
== GetTypeSel())
295 bool bCond
= false, bSetNo
= false, bFormat
= false, bDBFormat
= false;
296 const SwFieldTypesEnum nTypeId
= static_cast<SwFieldTypesEnum
>(m_xTypeLB
->get_id(GetTypeSel()).toUInt32());
298 m_xDatabaseTLB
->ShowColumns(nTypeId
== SwFieldTypesEnum::Database
);
303 OUString sColumnName
;
304 if (nTypeId
== SwFieldTypesEnum::Database
)
306 if (auto const*const pField
= dynamic_cast<SwDBField
*>(GetCurField()))
308 aData
= pField
->GetDBData();
309 sColumnName
= static_cast<SwDBFieldType
*>(GetCurField()->GetTyp())->GetColumnName();
314 if (auto *const pField
= dynamic_cast<SwDBNameInfField
*>(GetCurField()))
316 if(SwWrtShell
*pSh
= CheckAndGetWrtShell())
317 aData
= pField
->GetDBData(pSh
->GetDoc());
320 m_xDatabaseTLB
->Select(aData
.sDataSource
, aData
.sCommand
, sColumnName
);
325 case SwFieldTypesEnum::Database
:
329 m_xNumFormatLB
->show();
332 weld::Widget
& rWidget
= m_xNumFormatLB
->get_widget();
333 rWidget
.set_accessible_relation_labeled_by(m_xNewFormatRB
.get());
335 if (pBox
) // type was changed by user
336 m_xDBFormatRB
->set_active(true);
340 if (GetCurField()->GetFormat() != 0 && GetCurField()->GetFormat() != SAL_MAX_UINT32
)
341 m_xNumFormatLB
->SetDefFormat(GetCurField()->GetFormat());
343 if (GetCurField()->GetSubType() & nsSwExtendedSubType::SUB_OWN_FMT
)
344 m_xNewFormatRB
->set_active(true);
346 m_xDBFormatRB
->set_active(true);
350 case SwFieldTypesEnum::DatabaseNumberSet
:
353 case SwFieldTypesEnum::DatabaseNextSet
:
357 m_xConditionED
->set_text(GetCurField()->GetPar1());
358 m_xValueED
->set_text(GetCurField()->GetPar2());
362 case SwFieldTypesEnum::DatabaseName
:
365 case SwFieldTypesEnum::DatabaseSetNumber
:
368 m_xNewFormatRB
->set_active(true);
369 m_xNumFormatLB
->hide();
372 m_xFormatLB
->set_accessible_relation_labeled_by(m_xNewFormatRB
.get());
376 for (sal_Int32 nI
= m_xFormatLB
->get_count(); nI
;)
378 if (GetCurField()->GetFormat() == m_xFormatLB
->get_id(--nI
).toUInt32())
380 m_xFormatLB
->set_active( nI
);
390 m_xCondition
->set_sensitive(bCond
);
391 m_xValue
->set_sensitive(bSetNo
);
392 if (nTypeId
!= SwFieldTypesEnum::Database
)
394 m_xDBFormatRB
->set_sensitive(bDBFormat
);
395 m_xNewFormatRB
->set_sensitive(bDBFormat
|| bFormat
);
396 m_xNumFormatLB
->set_sensitive(bDBFormat
);
397 m_xFormatLB
->set_sensitive(bFormat
);
399 m_xFormat
->set_sensitive(bDBFormat
|| bFormat
);
403 m_xValueED
->set_text(OUString());
405 m_xConditionED
->set_text(u
"TRUE"_ustr
);
407 m_xConditionED
->set_text(OUString());
413 IMPL_LINK_NOARG(SwFieldDBPage
, NumSelectHdl
, weld::ComboBox
&, void)
415 m_xNewFormatRB
->set_active(true);
416 m_xNumFormatLB
->CallSelectHdl();
419 void SwFieldDBPage::CheckInsert()
422 const SwFieldTypesEnum nTypeId
= static_cast<SwFieldTypesEnum
>(m_xTypeLB
->get_id(GetTypeSel()).toUInt32());
424 std::unique_ptr
<weld::TreeIter
> xIter(m_xDatabaseTLB
->make_iterator());
425 if (m_xDatabaseTLB
->get_selected(xIter
.get()))
427 bool bEntry
= m_xDatabaseTLB
->iter_parent(*xIter
);
429 if (nTypeId
== SwFieldTypesEnum::Database
&& bEntry
)
430 bEntry
= m_xDatabaseTLB
->iter_parent(*xIter
);
437 if (nTypeId
== SwFieldTypesEnum::DatabaseNumberSet
)
439 bool bHasValue
= !m_xValueED
->get_text().isEmpty();
441 bInsert
&= bHasValue
;
444 EnableInsert(bInsert
, IsCurrentPage());
447 IMPL_LINK(SwFieldDBPage
, TreeSelectHdl
, weld::TreeView
&, rBox
, void)
449 std::unique_ptr
<weld::TreeIter
> xIter(rBox
.make_iterator());
450 if (!rBox
.get_selected(xIter
.get()))
453 const SwFieldTypesEnum nTypeId
= static_cast<SwFieldTypesEnum
>(m_xTypeLB
->get_id(GetTypeSel()).toUInt32());
455 bool bEntry
= m_xDatabaseTLB
->iter_parent(*xIter
);
457 if (nTypeId
== SwFieldTypesEnum::Database
&& bEntry
)
458 bEntry
= m_xDatabaseTLB
->iter_parent(*xIter
);
462 if (nTypeId
!= SwFieldTypesEnum::Database
)
465 bool bNumFormat
= false;
470 OUString sColumnName
;
472 OUString sDBName
= m_xDatabaseTLB
->GetDBName(sTableName
, sColumnName
, &bIsTable
);
473 bNumFormat
= GetFieldMgr().IsDBNumeric(sDBName
,
478 m_xDBFormatRB
->set_active(true);
481 m_xDBFormatRB
->set_sensitive(bNumFormat
);
482 m_xNewFormatRB
->set_sensitive(bNumFormat
);
483 m_xNumFormatLB
->set_sensitive(bNumFormat
);
484 m_xFormat
->set_sensitive(bNumFormat
);
487 IMPL_LINK_NOARG(SwFieldDBPage
, AddDBHdl
, weld::Button
&, void)
489 if (SwWrtShell
* pSh
= CheckAndGetWrtShell())
492 = SwDBManager::LoadAndRegisterDataSource(GetFrameWeld(), pSh
->GetDoc()->GetDocShell());
493 if (!sNewDB
.isEmpty())
495 m_xDatabaseTLB
->AddDataSource(sNewDB
);
501 IMPL_LINK_NOARG(SwFieldDBPage
, ModifyHdl
, weld::Entry
&, void)
506 void SwFieldDBPage::FillUserData()
508 const sal_Int32 nEntryPos
= m_xTypeLB
->get_selected_index();
509 const sal_uInt16 nTypeSel
= ( -1 == nEntryPos
)
510 ? USHRT_MAX
: m_xTypeLB
->get_id(nEntryPos
).toUInt32();
511 SetUserData(USER_DATA_VERSION
";" + OUString::number( nTypeSel
));
514 void SwFieldDBPage::ActivateMailMergeAddress()
516 m_xTypeLB
->select_id(OUString::number(static_cast<sal_uInt16
>(SwFieldTypesEnum::Database
)));
517 TypeListBoxHdl(*m_xTypeLB
);
518 const SwDBData
& rData
= SwModule::get()->GetDBConfig()->GetAddressSource();
519 m_xDatabaseTLB
->Select(rData
.sDataSource
, rData
.sCommand
, u
"");
522 void SwFieldDBPage::SetWrtShell(SwWrtShell
& rSh
)
524 // We need to remember the shell to be able to call correct SwDBManager
525 SwFieldPage::SetWrtShell(&rSh
);
526 m_xDatabaseTLB
->SetWrtShell(rSh
);
529 SwWrtShell
* SwFieldDBPage::CheckAndGetWrtShell()
531 SwWrtShell
* pSh
= GetWrtShell();
534 pSh
= ::GetActiveWrtShell();
535 if (pSh
) // this is not guaranteed: e.g., activating print preview with dialog active
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */