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 <swmodule.hxx>
21 #include <wrtsh.hxx>
22 #include <dbfld.hxx>
23 #include <doc.hxx>
24
25 #include "flddb.hxx"
26 #include <dbconfig.hxx>
27 #include <dbmgr.hxx>
28
29 #define USER_DATA_VERSION_1 "1"
30 #define USER_DATA_VERSION USER_DATA_VERSION_1
31
SwFieldDBPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * const pCoreSet)32 SwFieldDBPage::SwFieldDBPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *const pCoreSet)
33 : SwFieldPage(pPage, pController, "modules/swriter/ui/flddbpage.ui", "FieldDbPage", pCoreSet)
34 , m_nOldFormat(0)
35 , m_nOldSubType(0)
36 , m_xTypeLB(m_xBuilder->weld_tree_view("type"))
37 , m_xDatabaseTLB(new SwDBTreeList(m_xBuilder->weld_tree_view("select")))
38 , m_xAddDBPB(m_xBuilder->weld_button("browse"))
39 , m_xCondition(m_xBuilder->weld_widget("condgroup"))
40 , m_xConditionED(new ConditionEdit(m_xBuilder->weld_entry("condition")))
41 , m_xValue(m_xBuilder->weld_widget("recgroup"))
42 , m_xValueED(m_xBuilder->weld_entry("recnumber"))
43 , m_xDBFormatRB(m_xBuilder->weld_radio_button("fromdatabasecb"))
44 , m_xNewFormatRB(m_xBuilder->weld_radio_button("userdefinedcb"))
45 , m_xNumFormatLB(new NumFormatListBox(m_xBuilder->weld_combo_box("numformat")))
46 , m_xFormatLB(m_xBuilder->weld_combo_box("format"))
47 , m_xFormat(m_xBuilder->weld_widget("formatframe"))
48 {
49 SetTypeSel(-1); //TODO
50
51 m_xTypeLB->make_sorted();
52 m_xFormatLB->make_sorted();
53
54 auto nWidth = m_xTypeLB->get_approximate_digit_width() * FIELD_COLUMN_WIDTH;
55 auto nHeight = m_xTypeLB->get_height_rows(10);
56 m_xTypeLB->set_size_request(nWidth, nHeight);
57 m_xDatabaseTLB->set_size_request(nWidth*2, nHeight);
58
59 m_xNumFormatLB->connect_changed(LINK(this, SwFieldDBPage, NumSelectHdl));
60 m_xDatabaseTLB->connect_changed(LINK(this, SwFieldDBPage, TreeSelectHdl));
61 m_xDatabaseTLB->connect_row_activated(LINK(this, SwFieldDBPage, TreeViewInsertHdl));
62
63 m_xValueED->connect_changed(LINK(this, SwFieldDBPage, ModifyHdl));
64 m_xAddDBPB->connect_clicked(LINK(this, SwFieldDBPage, AddDBHdl));
65 }
66
~SwFieldDBPage()67 SwFieldDBPage::~SwFieldDBPage()
68 {
69 // If we have no stored SwWrtShell, it means we didn't do anything useful - no need to revoke.
70 if (SwWrtShell* pSh = GetWrtShell())
71 {
72 // This would cleanup in the case of cancelled dialog
73 SwDBManager* pDbManager = pSh->GetDoc()->GetDBManager();
74 if (pDbManager)
75 pDbManager->RevokeLastRegistrations();
76 }
77 }
78
79 // initialise TabPage
Reset(const SfxItemSet *)80 void SwFieldDBPage::Reset(const SfxItemSet*)
81 {
82 Init(); // general initialization
83
84 const sal_Int32 nOldPos = m_xTypeLB->get_selected_index();
85 m_xTypeLB->freeze();
86 m_sOldDBName = m_xDatabaseTLB->GetDBName(m_sOldTableName, m_sOldColumnName);
87
88 m_xTypeLB->clear();
89
90 if (!IsFieldEdit())
91 {
92 // initialise TypeListBox
93 const SwFieldGroupRgn& rRg = SwFieldMgr::GetGroupRange(IsFieldDlgHtmlMode(), GetGroup());
94
95 for(sal_uInt16 i = rRg.nStart; i < rRg.nEnd; ++i)
96 {
97 const SwFieldTypesEnum nTypeId = SwFieldMgr::GetTypeId(i);
98 m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)), SwFieldMgr::GetTypeStr(i));
99 }
100 }
101 else
102 {
103 const SwFieldTypesEnum nTypeId = GetCurField()->GetTypeId();
104 m_xTypeLB->append(OUString::number(static_cast<sal_uInt16>(nTypeId)),
105 SwFieldMgr::GetTypeStr(SwFieldMgr::GetPos(nTypeId)));
106 }
107
108 m_xTypeLB->thaw();
109
110 // select old Pos
111 if (GetTypeSel() != -1)
112 m_xTypeLB->select(GetTypeSel());
113
114 m_xFormatLB->clear();
115
116 const sal_uInt16 nSize = GetFieldMgr().GetFormatCount(SwFieldTypesEnum::DatabaseSetNumber, IsFieldDlgHtmlMode());
117 for( sal_uInt16 i = 0; i < nSize; ++i )
118 {
119 const sal_uInt16 nFormatId = GetFieldMgr().GetFormatId( SwFieldTypesEnum::DatabaseSetNumber, i );
120 OUString sId(OUString::number(nFormatId));
121 m_xFormatLB->append(sId, GetFieldMgr().GetFormatStr(SwFieldTypesEnum::DatabaseSetNumber, i));
122 if (SVX_NUM_ARABIC == nFormatId)
123 m_xFormatLB->set_active_id(sId);
124 }
125
126 if (!IsFieldEdit())
127 {
128 if (nOldPos != -1)
129 m_xTypeLB->select(nOldPos);
130
131 if (!m_sOldDBName.isEmpty())
132 {
133 m_xDatabaseTLB->Select(m_sOldDBName, m_sOldTableName, m_sOldColumnName);
134 }
135 else
136 {
137 SwWrtShell *pSh = CheckAndGetWrtShell();
138 if(pSh)
139 {
140 SwDBData aTmp(pSh->GetDBData());
141 m_xDatabaseTLB->Select(aTmp.sDataSource, aTmp.sCommand, u"");
142 }
143 }
144 }
145
146 if( !IsRefresh() )
147 {
148 const OUString sUserData = GetUserData();
149 sal_Int32 nIdx{ 0 };
150 if (sUserData.getToken(0, ';', nIdx).equalsIgnoreAsciiCase(USER_DATA_VERSION_1))
151 {
152 const sal_uInt16 nVal = o3tl::narrowing<sal_uInt16>(sUserData.getToken(0, ';', nIdx).toInt32());
153 if (nVal != USHRT_MAX)
154 {
155 for (sal_Int32 i = 0, nEntryCount = m_xTypeLB->n_children(); i < nEntryCount; ++i)
156 {
157 if (nVal == m_xTypeLB->get_id(i).toUInt32())
158 {
159 m_xTypeLB->select(i);
160 break;
161 }
162 }
163 }
164 }
165 }
166 TypeHdl(nullptr);
167
168 m_xTypeLB->connect_changed(LINK(this, SwFieldDBPage, TypeListBoxHdl));
169 m_xTypeLB->connect_row_activated(LINK(this, SwFieldDBPage, TreeViewInsertHdl));
170
171 if (IsFieldEdit())
172 {
173 m_xConditionED->save_value();
174 m_xValueED->save_value();
175 m_sOldDBName = m_xDatabaseTLB->GetDBName(m_sOldTableName, m_sOldColumnName);
176 m_nOldFormat = GetCurField()->GetFormat();
177 m_nOldSubType = GetCurField()->GetSubType();
178 }
179 }
180
181 // SwFieldDBPage may ask for password to select current document's data source,
182 // so only do that when activating the page, not when dialog is creating all pages
DeferResetToFirstActivation()183 bool SwFieldDBPage::DeferResetToFirstActivation() { return true; }
184
FillItemSet(SfxItemSet *)185 bool SwFieldDBPage::FillItemSet(SfxItemSet* )
186 {
187 OUString sTableName;
188 OUString sColumnName;
189 SwDBData aData;
190 sal_Bool bIsTable;
191 aData.sDataSource = m_xDatabaseTLB->GetDBName(sTableName, sColumnName, &bIsTable);
192 aData.sCommand = sTableName;
193 aData.nCommandType = bIsTable ? 0 : 1;
194 SwWrtShell *pSh = CheckAndGetWrtShell();
195 assert(pSh);
196
197 SwDBManager* pDbManager = pSh->GetDoc()->GetDBManager();
198 if (pDbManager)
199 pDbManager->CommitLastRegistrations();
200
201 if (aData.sDataSource.isEmpty())
202 aData = pSh->GetDBData();
203
204 if(!aData.sDataSource.isEmpty()) // without database no new field command
205 {
206 const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32());
207 sal_uLong nFormat = 0;
208 sal_uInt16 nSubType = 0;
209
210 OUString sDBName = aData.sDataSource
211 + OUStringChar(DB_DELIM)
212 + aData.sCommand
213 + OUStringChar(DB_DELIM)
214 + OUString::number(aData.nCommandType)
215 + OUStringChar(DB_DELIM);
216 if (!sColumnName.isEmpty())
217 {
218 sDBName += sColumnName + OUStringChar(DB_DELIM);
219 }
220 OUString aName = sDBName + m_xConditionED->get_text();
221
222 switch (nTypeId)
223 {
224 case SwFieldTypesEnum::Database:
225 nFormat = m_xNumFormatLB->GetFormat();
226 if (m_xNewFormatRB->get_sensitive() && m_xNewFormatRB->get_active())
227 nSubType = nsSwExtendedSubType::SUB_OWN_FMT;
228 aName = sDBName;
229 break;
230
231 case SwFieldTypesEnum::DatabaseSetNumber:
232 nFormat = m_xFormatLB->get_active_id().toUInt32();
233 break;
234 default: break;
235 }
236
237 const OUString aVal(m_xValueED->get_text());
238 OUString sTempTableName;
239 OUString sTempColumnName;
240 OUString sTempDBName = m_xDatabaseTLB->GetDBName(sTempTableName, sTempColumnName);
241 bool bDBListBoxChanged = m_sOldDBName != sTempDBName ||
242 m_sOldTableName != sTempTableName || m_sOldColumnName != sTempColumnName;
243 if (!IsFieldEdit() ||
244 m_xConditionED->get_value_changed_from_saved() ||
245 m_xValueED->get_saved_value() != aVal ||
246 bDBListBoxChanged ||
247 m_nOldFormat != nFormat || m_nOldSubType != nSubType)
248 {
249 InsertField( nTypeId, nSubType, aName, aVal, nFormat);
250 }
251 }
252
253 return false;
254 }
255
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * const pAttrSet)256 std::unique_ptr<SfxTabPage> SwFieldDBPage::Create( weld::Container* pPage, weld::DialogController* pController,
257 const SfxItemSet *const pAttrSet )
258 {
259 return std::make_unique<SwFieldDBPage>( pPage, pController, pAttrSet );
260 }
261
GetGroup()262 sal_uInt16 SwFieldDBPage::GetGroup()
263 {
264 return GRP_DB;
265 }
266
IMPL_LINK(SwFieldDBPage,TypeListBoxHdl,weld::TreeView &,rBox,void)267 IMPL_LINK( SwFieldDBPage, TypeListBoxHdl, weld::TreeView&, rBox, void )
268 {
269 TypeHdl(&rBox);
270 }
271
TypeHdl(const weld::TreeView * pBox)272 void SwFieldDBPage::TypeHdl(const weld::TreeView* pBox)
273 {
274 // save old ListBoxPos
275 const sal_Int32 nOld = GetTypeSel();
276
277 // current ListBoxPos
278 SetTypeSel(m_xTypeLB->get_selected_index());
279
280 if (GetTypeSel() == -1)
281 {
282 SetTypeSel(0);
283 m_xTypeLB->select(0);
284 }
285
286 if (nOld == GetTypeSel())
287 return;
288
289 SwWrtShell *pSh = CheckAndGetWrtShell();
290 assert(pSh);
291 bool bCond = false, bSetNo = false, bFormat = false, bDBFormat = false;
292 const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32());
293
294 m_xDatabaseTLB->ShowColumns(nTypeId == SwFieldTypesEnum::Database);
295
296 if (IsFieldEdit())
297 {
298 SwDBData aData;
299 OUString sColumnName;
300 if (nTypeId == SwFieldTypesEnum::Database)
301 {
302 aData = static_cast<SwDBField*>(GetCurField())->GetDBData();
303 sColumnName = static_cast<SwDBFieldType*>(GetCurField()->GetTyp())->GetColumnName();
304 }
305 else
306 {
307 aData = static_cast<SwDBNameInfField*>(GetCurField())->GetDBData(pSh->GetDoc());
308 }
309 m_xDatabaseTLB->Select(aData.sDataSource, aData.sCommand, sColumnName);
310 }
311
312 switch (nTypeId)
313 {
314 case SwFieldTypesEnum::Database:
315 {
316 bFormat = true;
317 bDBFormat = true;
318 m_xNumFormatLB->show();
319 m_xFormatLB->hide();
320
321 weld::Widget& rWidget = m_xNumFormatLB->get_widget();
322 m_xNewFormatRB->set_accessible_relation_label_for(&rWidget);
323 rWidget.set_accessible_relation_labeled_by(m_xNewFormatRB.get());
324 m_xFormatLB->set_accessible_relation_label_for(nullptr);
325
326 if (pBox) // type was changed by user
327 m_xDBFormatRB->set_active(true);
328
329 if (IsFieldEdit())
330 {
331 if (GetCurField()->GetFormat() != 0 && GetCurField()->GetFormat() != SAL_MAX_UINT32)
332 m_xNumFormatLB->SetDefFormat(GetCurField()->GetFormat());
333
334 if (GetCurField()->GetSubType() & nsSwExtendedSubType::SUB_OWN_FMT)
335 m_xNewFormatRB->set_active(true);
336 else
337 m_xDBFormatRB->set_active(true);
338 }
339 break;
340 }
341 case SwFieldTypesEnum::DatabaseNumberSet:
342 bSetNo = true;
343 [[fallthrough]];
344 case SwFieldTypesEnum::DatabaseNextSet:
345 bCond = true;
346 if (IsFieldEdit())
347 {
348 m_xConditionED->set_text(GetCurField()->GetPar1());
349 m_xValueED->set_text(GetCurField()->GetPar2());
350 }
351 break;
352
353 case SwFieldTypesEnum::DatabaseName:
354 break;
355
356 case SwFieldTypesEnum::DatabaseSetNumber:
357 {
358 bFormat = true;
359 m_xNewFormatRB->set_active(true);
360 m_xNumFormatLB->hide();
361 m_xFormatLB->show();
362
363 m_xNewFormatRB->set_accessible_relation_label_for(m_xFormatLB.get());
364 m_xFormatLB->set_accessible_relation_labeled_by(m_xNewFormatRB.get());
365 weld::Widget& rWidget = m_xNumFormatLB->get_widget();
366 rWidget.set_accessible_relation_label_for(nullptr);
367
368 if( IsFieldEdit() )
369 {
370 for (sal_Int32 nI = m_xFormatLB->get_count(); nI;)
371 {
372 if (GetCurField()->GetFormat() == m_xFormatLB->get_id(--nI).toUInt32())
373 {
374 m_xFormatLB->set_active( nI );
375 break;
376 }
377 }
378 }
379 break;
380 }
381 default: break;
382 }
383
384 m_xCondition->set_sensitive(bCond);
385 m_xValue->set_sensitive(bSetNo);
386 if (nTypeId != SwFieldTypesEnum::Database)
387 {
388 m_xDBFormatRB->set_sensitive(bDBFormat);
389 m_xNewFormatRB->set_sensitive(bDBFormat || bFormat);
390 m_xNumFormatLB->set_sensitive(bDBFormat);
391 m_xFormatLB->set_sensitive(bFormat);
392 }
393 m_xFormat->set_sensitive(bDBFormat || bFormat);
394
395 if (!IsFieldEdit())
396 {
397 m_xValueED->set_text(OUString());
398 if (bCond)
399 m_xConditionED->set_text("TRUE");
400 else
401 m_xConditionED->set_text(OUString());
402 }
403
404 CheckInsert();
405 }
406
IMPL_LINK_NOARG(SwFieldDBPage,NumSelectHdl,weld::ComboBox &,void)407 IMPL_LINK_NOARG(SwFieldDBPage, NumSelectHdl, weld::ComboBox&, void)
408 {
409 m_xNewFormatRB->set_active(true);
410 m_xNumFormatLB->CallSelectHdl();
411 }
412
CheckInsert()413 void SwFieldDBPage::CheckInsert()
414 {
415 bool bInsert = true;
416 const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32());
417
418 std::unique_ptr<weld::TreeIter> xIter(m_xDatabaseTLB->make_iterator());
419 if (m_xDatabaseTLB->get_selected(xIter.get()))
420 {
421 bool bEntry = m_xDatabaseTLB->iter_parent(*xIter);
422
423 if (nTypeId == SwFieldTypesEnum::Database && bEntry)
424 bEntry = m_xDatabaseTLB->iter_parent(*xIter);
425
426 bInsert &= bEntry;
427 }
428 else
429 bInsert = false;
430
431 if (nTypeId == SwFieldTypesEnum::DatabaseNumberSet)
432 {
433 bool bHasValue = !m_xValueED->get_text().isEmpty();
434
435 bInsert &= bHasValue;
436 }
437
438 EnableInsert(bInsert);
439 }
440
IMPL_LINK(SwFieldDBPage,TreeSelectHdl,weld::TreeView &,rBox,void)441 IMPL_LINK(SwFieldDBPage, TreeSelectHdl, weld::TreeView&, rBox, void)
442 {
443 std::unique_ptr<weld::TreeIter> xIter(rBox.make_iterator());
444 if (!rBox.get_selected(xIter.get()))
445 return;
446
447 const SwFieldTypesEnum nTypeId = static_cast<SwFieldTypesEnum>(m_xTypeLB->get_id(GetTypeSel()).toUInt32());
448
449 bool bEntry = m_xDatabaseTLB->iter_parent(*xIter);
450
451 if (nTypeId == SwFieldTypesEnum::Database && bEntry)
452 bEntry = m_xDatabaseTLB->iter_parent(*xIter);
453
454 CheckInsert();
455
456 if (nTypeId != SwFieldTypesEnum::Database)
457 return;
458
459 bool bNumFormat = false;
460
461 if (bEntry)
462 {
463 OUString sTableName;
464 OUString sColumnName;
465 sal_Bool bIsTable;
466 OUString sDBName = m_xDatabaseTLB->GetDBName(sTableName, sColumnName, &bIsTable);
467 bNumFormat = GetFieldMgr().IsDBNumeric(sDBName,
468 sTableName,
469 bIsTable,
470 sColumnName);
471 if (!IsFieldEdit())
472 m_xDBFormatRB->set_active(true);
473 }
474
475 m_xDBFormatRB->set_sensitive(bNumFormat);
476 m_xNewFormatRB->set_sensitive(bNumFormat);
477 m_xNumFormatLB->set_sensitive(bNumFormat);
478 m_xFormat->set_sensitive(bNumFormat);
479 }
480
IMPL_LINK_NOARG(SwFieldDBPage,AddDBHdl,weld::Button &,void)481 IMPL_LINK_NOARG(SwFieldDBPage, AddDBHdl, weld::Button&, void)
482 {
483 if (SwWrtShell* pSh = CheckAndGetWrtShell())
484 {
485 OUString sNewDB
486 = SwDBManager::LoadAndRegisterDataSource(GetFrameWeld(), pSh->GetDoc()->GetDocShell());
487 if (!sNewDB.isEmpty())
488 {
489 m_xDatabaseTLB->AddDataSource(sNewDB);
490 }
491 }
492 }
493
494 // Modify
IMPL_LINK_NOARG(SwFieldDBPage,ModifyHdl,weld::Entry &,void)495 IMPL_LINK_NOARG(SwFieldDBPage, ModifyHdl, weld::Entry&, void)
496 {
497 CheckInsert();
498 }
499
FillUserData()500 void SwFieldDBPage::FillUserData()
501 {
502 const sal_Int32 nEntryPos = m_xTypeLB->get_selected_index();
503 const sal_uInt16 nTypeSel = ( -1 == nEntryPos )
504 ? USHRT_MAX : m_xTypeLB->get_id(nEntryPos).toUInt32();
505 SetUserData(USER_DATA_VERSION ";" + OUString::number( nTypeSel ));
506 }
507
ActivateMailMergeAddress()508 void SwFieldDBPage::ActivateMailMergeAddress()
509 {
510 m_xTypeLB->select_id(OUString::number(static_cast<sal_uInt16>(SwFieldTypesEnum::Database)));
511 TypeListBoxHdl(*m_xTypeLB);
512 const SwDBData& rData = SW_MOD()->GetDBConfig()->GetAddressSource();
513 m_xDatabaseTLB->Select(rData.sDataSource, rData.sCommand, u"");
514 }
515
SetWrtShell(SwWrtShell & rSh)516 void SwFieldDBPage::SetWrtShell(SwWrtShell& rSh)
517 {
518 // We need to remember the shell to be able to call correct SwDBManager
519 SwFieldPage::SetWrtShell(&rSh);
520 m_xDatabaseTLB->SetWrtShell(rSh);
521 }
522
CheckAndGetWrtShell()523 SwWrtShell* SwFieldDBPage::CheckAndGetWrtShell()
524 {
525 SwWrtShell* pSh = GetWrtShell();
526 if (!pSh)
527 {
528 pSh = ::GetActiveWrtShell();
529 if (pSh) // this is not guaranteed: e.g., activating print preview with dialog active
530 SetWrtShell(*pSh);
531 }
532 return pSh;
533 }
534
535 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
536