ITEM: Refactor ItemType
[LibreOffice.git] / sw / source / ui / dbui / dbinsdlg.cxx
blob1139bf27e3a744eb910c71961db738c1b71337fe
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <dbinsdlg.hxx>
22 #include <float.h>
24 #include <hintids.hxx>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/sdbc/XDataSource.hpp>
27 #include <com/sun/star/sdbc/XRow.hpp>
28 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
29 #include <com/sun/star/sdbcx/XRowLocate.hpp>
30 #include <com/sun/star/sdb/XQueriesSupplier.hpp>
31 #include <com/sun/star/sdb/XColumn.hpp>
32 #include <com/sun/star/sdbc/DataType.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/util/NumberFormatter.hpp>
35 #include <com/sun/star/util/XNumberFormatTypes.hpp>
36 #include <comphelper/processfactory.hxx>
37 #include <comphelper/sequence.hxx>
38 #include <comphelper/types.hxx>
39 #include <svl/numuno.hxx>
40 #include <svl/numformat.hxx>
41 #include <svl/stritem.hxx>
42 #include <comphelper/diagnose_ex.hxx>
43 #include <utility>
44 #include <vcl/mnemonic.hxx>
45 #include <svl/style.hxx>
46 #include <svl/zformat.hxx>
47 #include <sfx2/htmlmode.hxx>
48 #include <svl/itemset.hxx>
49 #include <editeng/brushitem.hxx>
50 #include <editeng/boxitem.hxx>
51 #include <unotools/collatorwrapper.hxx>
52 #include <fmtclds.hxx>
53 #include <tabcol.hxx>
54 #include <uiitems.hxx>
55 #include <viewopt.hxx>
56 #include <wrtsh.hxx>
57 #include <view.hxx>
58 #include <docsh.hxx>
59 #include <dbmgr.hxx>
60 #include <tblafmt.hxx>
61 #include <cellatr.hxx>
62 #include <swtablerep.hxx>
63 #include <dbfld.hxx>
64 #include <fmtcol.hxx>
65 #include <swwait.hxx>
66 #include <modcfg.hxx>
67 #include <swmodule.hxx>
68 #include <poolfmt.hxx>
69 #include <connectivity/dbtools.hxx>
71 #include <cmdid.h>
72 #include <SwStyleNameMapper.hxx>
73 #include <tabsh.hxx>
74 #include <swabstdlg.hxx>
75 #include <strings.hrc>
76 #include <IDocumentMarkAccess.hxx>
78 #include <o3tl/any.hxx>
80 #include <memory>
81 #include <string_view>
83 #include <swuiexp.hxx>
85 using namespace ::dbtools;
86 using namespace ::com::sun::star;
87 using namespace ::com::sun::star::beans;
88 using namespace ::com::sun::star::container;
89 using namespace ::com::sun::star::lang;
90 using namespace ::com::sun::star::sdb;
91 using namespace ::com::sun::star::sdbc;
92 using namespace ::com::sun::star::sdbcx;
93 using namespace ::com::sun::star::uno;
95 const char cDBFieldStart = '<';
96 const char cDBFieldEnd = '>';
98 // Helper structure for adding database rows as fields or text
99 struct DB_Column
101 const enum class Type { FILLTEXT, COL_FIELD, COL_TEXT, SPLITPARA } eColType;
103 union {
104 OUString* pText;
105 SwField* pField;
106 sal_uInt32 nFormat;
108 const SwInsDBColumn* pColInfo;
110 DB_Column() : eColType(Type::SPLITPARA),
111 pText(nullptr),
112 pColInfo(nullptr)
115 explicit DB_Column( const OUString& rText )
116 : eColType(Type::FILLTEXT),
117 pText(new OUString(rText)),
118 pColInfo(nullptr)
121 DB_Column( const SwInsDBColumn& rInfo, sal_uInt32 nFormat_ )
122 : eColType(Type::COL_TEXT),
123 nFormat(nFormat_),
124 pColInfo(&rInfo)
127 DB_Column( const SwInsDBColumn& rInfo, SwDBField& rField )
128 : eColType(Type::COL_FIELD),
129 pField(&rField),
130 pColInfo(&rInfo)
133 ~DB_Column()
135 if( Type::COL_FIELD == eColType )
136 delete pField;
137 else if( Type::FILLTEXT == eColType )
138 delete pText;
142 namespace {
144 struct DB_ColumnConfigData
146 SwInsDBColumns aDBColumns;
147 OUString sEdit;
148 OUString sTableList;
149 OUString sTmplNm;
150 OUString sTAutoFormatNm;
151 bool bIsTable : 1,
152 bIsField : 1,
153 bIsHeadlineOn : 1,
154 bIsEmptyHeadln : 1;
156 DB_ColumnConfigData(DB_ColumnConfigData const&) = delete;
157 DB_ColumnConfigData& operator=(DB_ColumnConfigData const&) = delete;
159 DB_ColumnConfigData()
161 bIsTable = bIsHeadlineOn = true;
162 bIsField = bIsEmptyHeadln = false;
168 bool SwInsDBColumn::operator<( const SwInsDBColumn& rCmp ) const
170 return 0 > GetAppCollator().compareString( sColumn, rCmp.sColumn );
173 SwInsertDBColAutoPilot::SwInsertDBColAutoPilot( SwView& rView,
174 Reference<XDataSource> const & xDataSource,
175 Reference<sdbcx::XColumnsSupplier> const & xColSupp,
176 SwDBData aData )
177 : SfxDialogController(rView.GetWindow()->GetFrameWeld(), u"modules/swriter/ui/insertdbcolumnsdialog.ui"_ustr, u"InsertDbColumnsDialog"_ustr)
178 , ConfigItem(u"Office.Writer/InsertData/DataSet"_ustr, ConfigItemMode::NONE)
179 , m_aDBData(std::move(aData))
180 , m_sNoTmpl(SwResId(SW_STR_NONE))
181 , m_pView(&rView)
182 , m_xRbAsTable(m_xBuilder->weld_radio_button(u"astable"_ustr))
183 , m_xRbAsField(m_xBuilder->weld_radio_button(u"asfields"_ustr))
184 , m_xRbAsText(m_xBuilder->weld_radio_button(u"astext"_ustr))
185 , m_xHeadFrame(m_xBuilder->weld_frame(u"dbframe"_ustr))
186 , m_xLbTableDbColumn(m_xBuilder->weld_tree_view(u"tabledbcols"_ustr))
187 , m_xLbTextDbColumn(m_xBuilder->weld_tree_view(u"tabletxtcols"_ustr))
188 , m_xFormatFrame(m_xBuilder->weld_frame(u"formatframe"_ustr))
189 , m_xRbDbFormatFromDb(m_xBuilder->weld_radio_button(u"fromdatabase"_ustr))
190 , m_xRbDbFormatFromUsr(m_xBuilder->weld_radio_button(u"userdefined"_ustr))
191 , m_xLbDbFormatFromUsr(new NumFormatListBox(m_xBuilder->weld_combo_box(u"numformat"_ustr)))
192 , m_xIbDbcolToEdit(m_xBuilder->weld_button(u"toedit"_ustr))
193 , m_xEdDbText(m_xBuilder->weld_text_view(u"textview"_ustr))
194 , m_xFtDbParaColl(m_xBuilder->weld_label(u"parastylelabel"_ustr))
195 , m_xLbDbParaColl(m_xBuilder->weld_combo_box(u"parastyle"_ustr))
196 , m_xIbDbcolAllTo(m_xBuilder->weld_button(u"oneright"_ustr))
197 , m_xIbDbcolOneTo(m_xBuilder->weld_button(u"allright"_ustr))
198 , m_xIbDbcolOneFrom(m_xBuilder->weld_button(u"oneleft"_ustr))
199 , m_xIbDbcolAllFrom(m_xBuilder->weld_button(u"allleft"_ustr))
200 , m_xFtTableCol(m_xBuilder->weld_label(u"tablecolft"_ustr))
201 , m_xLbTableCol(m_xBuilder->weld_tree_view(u"tablecols"_ustr))
202 , m_xCbTableHeadon(m_xBuilder->weld_check_button(u"tableheading"_ustr))
203 , m_xRbHeadlColnms(m_xBuilder->weld_radio_button(u"columnname"_ustr))
204 , m_xRbHeadlEmpty(m_xBuilder->weld_radio_button(u"rowonly"_ustr))
205 , m_xPbTableFormat(m_xBuilder->weld_button(u"tableformat"_ustr))
206 , m_xPbTableAutofmt(m_xBuilder->weld_button(u"autoformat"_ustr))
208 m_xEdDbText->set_size_request(m_xEdDbText->get_approximate_digit_width() * 40, -1);
209 m_xLbDbParaColl->make_sorted();
211 m_nGBFormatLen = m_xFormatFrame->get_label().getLength();
213 if (xColSupp.is())
215 SwWrtShell& rSh = m_pView->GetWrtShell();
216 SvNumberFormatter* pNumFormatr = rSh.GetNumberFormatter();
217 rtl::Reference<SvNumberFormatsSupplierObj> pNumFormat = new SvNumberFormatsSupplierObj( pNumFormatr );
218 Reference< util::XNumberFormats > xDocNumberFormats = pNumFormat->getNumberFormats();
219 Reference< util::XNumberFormatTypes > xDocNumberFormatTypes(xDocNumberFormats, UNO_QUERY);
221 Reference<XPropertySet> xSourceProps(xDataSource, UNO_QUERY);
222 Reference< util::XNumberFormats > xNumberFormats;
223 if(xSourceProps.is())
225 Any aFormats = xSourceProps->getPropertyValue(u"NumberFormatsSupplier"_ustr);
226 if(aFormats.hasValue())
228 Reference< util::XNumberFormatsSupplier> xSuppl;
229 aFormats >>= xSuppl;
230 if(xSuppl.is())
232 xNumberFormats = xSuppl->getNumberFormats( );
236 Reference <XNameAccess> xCols = xColSupp->getColumns();
237 const Sequence<OUString> aColNames = xCols->getElementNames();
238 for (const OUString& rColName : aColNames)
240 std::unique_ptr<SwInsDBColumn> pNew(new SwInsDBColumn( rColName ));
241 Any aCol = xCols->getByName(rColName);
242 Reference <XPropertySet> xCol;
243 aCol >>= xCol;
244 Any aType = xCol->getPropertyValue(u"Type"_ustr);
245 sal_Int32 eDataType = 0;
246 aType >>= eDataType;
247 switch(eDataType)
249 case DataType::BIT:
250 case DataType::BOOLEAN:
251 case DataType::TINYINT:
252 case DataType::SMALLINT:
253 case DataType::INTEGER:
254 case DataType::BIGINT:
255 case DataType::FLOAT:
256 case DataType::REAL:
257 case DataType::DOUBLE:
258 case DataType::NUMERIC:
259 case DataType::DECIMAL:
260 case DataType::DATE:
261 case DataType::TIME:
262 case DataType::TIMESTAMP:
264 pNew->bHasFormat = true;
265 Any aFormat = xCol->getPropertyValue(u"FormatKey"_ustr);
266 if(aFormat.hasValue())
268 sal_Int32 nFormat = 0;
269 aFormat >>= nFormat;
270 if(xNumberFormats.is())
274 Reference<XPropertySet> xNumProps = xNumberFormats->getByKey( nFormat );
275 Any aFormatVal = xNumProps->getPropertyValue(u"FormatString"_ustr);
276 Any aLocale = xNumProps->getPropertyValue(u"Locale"_ustr);
277 OUString sFormat;
278 aFormatVal >>= sFormat;
279 lang::Locale aLoc;
280 aLocale >>= aLoc;
281 sal_Int32 nKey = xDocNumberFormats->queryKey( sFormat, aLoc, true);
282 if(nKey < 0)
284 nKey = xDocNumberFormats->addNew( sFormat, aLoc );
286 pNew->nDBNumFormat = nKey;
288 catch (const Exception&)
290 OSL_FAIL("illegal number format key");
294 else
296 pNew->nDBNumFormat = getDefaultNumberFormat(xCol,
297 xDocNumberFormatTypes, LanguageTag( rSh.GetCurLang() ).getLocale());
301 break;
303 if( !m_aDBColumns.insert( std::move(pNew) ).second )
305 OSL_ENSURE( false, "Spaltenname mehrfach vergeben?" );
310 // fill paragraph templates-ListBox
312 SfxStyleSheetBasePool* pPool = m_pView->GetDocShell()->GetStyleSheetPool();
313 m_xLbDbParaColl->append_text( m_sNoTmpl );
315 const SfxStyleSheetBase* pBase = pPool->First(SfxStyleFamily::Para);
316 while( pBase )
318 m_xLbDbParaColl->append_text( pBase->GetName() );
319 pBase = pPool->Next();
321 m_xLbDbParaColl->set_active( 0 );
324 // when the cursor is inside of a table, table must NEVER be selectable
325 if( m_pView->GetWrtShell().GetTableFormat() )
327 m_xRbAsField->set_active(true);
328 m_xRbAsTable->set_sensitive(false);
329 m_xRbDbFormatFromDb->set_active(true);
331 else
333 m_xRbAsTable->set_active(true);
334 m_xRbDbFormatFromDb->set_active(true);
335 m_xIbDbcolOneFrom->set_sensitive( false );
336 m_xIbDbcolAllFrom->set_sensitive( false );
339 // by default, select header button
340 m_xRbHeadlColnms->set_active(true);
341 m_xRbHeadlEmpty->set_active(false);
343 m_xRbAsTable->connect_toggled( LINK(this, SwInsertDBColAutoPilot, PageHdl ));
344 m_xRbAsField->connect_toggled( LINK(this, SwInsertDBColAutoPilot, PageHdl ));
345 m_xRbAsText->connect_toggled( LINK(this, SwInsertDBColAutoPilot, PageHdl ));
347 m_xRbDbFormatFromDb->connect_toggled( LINK(this, SwInsertDBColAutoPilot, DBFormatHdl ));
348 m_xRbDbFormatFromUsr->connect_toggled( LINK(this, SwInsertDBColAutoPilot, DBFormatHdl ));
350 m_xPbTableFormat->connect_clicked(LINK(this, SwInsertDBColAutoPilot, TableFormatHdl ));
351 m_xPbTableAutofmt->connect_clicked(LINK(this, SwInsertDBColAutoPilot, AutoFormatHdl ));
353 m_xIbDbcolAllTo->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl ));
354 m_xIbDbcolOneTo->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl ));
355 m_xIbDbcolOneFrom->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl ));
356 m_xIbDbcolAllFrom->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl ));
357 m_xIbDbcolToEdit->connect_clicked( LINK(this, SwInsertDBColAutoPilot, TableToFromHdl ));
359 m_xCbTableHeadon->connect_toggled( LINK(this, SwInsertDBColAutoPilot, HeaderHdl ));
361 m_xLbTextDbColumn->connect_selection_changed(LINK(this, SwInsertDBColAutoPilot, TVSelectHdl));
362 m_xLbTableDbColumn->connect_selection_changed(LINK(this, SwInsertDBColAutoPilot, TVSelectHdl));
363 m_xLbDbFormatFromUsr->connect_changed( LINK( this, SwInsertDBColAutoPilot, CBSelectHdl ));
364 m_xLbTableCol->connect_selection_changed(LINK(this, SwInsertDBColAutoPilot, TVSelectHdl));
366 m_xLbTextDbColumn->connect_row_activated( LINK( this, SwInsertDBColAutoPilot, DblClickHdl ));
367 m_xLbTableDbColumn->connect_row_activated( LINK( this, SwInsertDBColAutoPilot, DblClickHdl ));
368 m_xLbTableCol->connect_row_activated( LINK( this, SwInsertDBColAutoPilot, DblClickHdl ));
370 for( size_t n = 0; n < m_aDBColumns.size(); ++n )
372 const OUString& rS = m_aDBColumns[ n ]->sColumn;
373 m_xLbTableDbColumn->append_text(rS);
374 m_xLbTextDbColumn->append_text(rS);
376 m_xLbTextDbColumn->select(0);
377 m_xLbTableDbColumn->select(0);
379 // read configuration
380 Load();
382 // lock size to widest config
383 m_xHeadFrame->set_size_request(m_xHeadFrame->get_preferred_size().Width(), -1);
384 // initialise Controls:
385 PageHdl(m_xRbAsTable->get_active() ? *m_xRbAsTable : *m_xRbAsField);
388 SwInsertDBColAutoPilot::~SwInsertDBColAutoPilot()
392 IMPL_LINK( SwInsertDBColAutoPilot, PageHdl, weld::Toggleable&, rButton, void )
394 if (!rButton.get_active())
395 return;
397 bool bShowTable = m_xRbAsTable->get_active();
399 weld::RadioButton& rRadio = dynamic_cast<weld::RadioButton&>(rButton);
400 m_xHeadFrame->set_label(MnemonicGenerator::EraseAllMnemonicChars(rRadio.get_label().replace('_', '~')));
402 m_xLbTextDbColumn->set_visible( !bShowTable );
403 m_xIbDbcolToEdit->set_visible( !bShowTable );
404 m_xEdDbText->set_visible( !bShowTable );
405 m_xFtDbParaColl->set_visible( !bShowTable );
406 m_xLbDbParaColl->set_visible( !bShowTable );
408 m_xLbTableDbColumn->set_visible( bShowTable );
409 m_xIbDbcolAllTo->set_visible( bShowTable );
410 m_xIbDbcolOneTo->set_visible( bShowTable );
411 m_xIbDbcolOneFrom->set_visible( bShowTable );
412 m_xIbDbcolAllFrom->set_visible( bShowTable );
413 m_xFtTableCol->set_visible( bShowTable );
414 m_xLbTableCol->set_visible( bShowTable );
415 m_xCbTableHeadon->set_visible( bShowTable );
416 m_xRbHeadlColnms->set_visible( bShowTable );
417 m_xRbHeadlEmpty->set_visible( bShowTable );
418 m_xPbTableFormat->set_visible( bShowTable );
419 m_xPbTableAutofmt->set_visible( bShowTable );
421 if( bShowTable )
422 m_xPbTableFormat->set_sensitive( 0 != m_xLbTableCol->n_children() );
424 TVSelectHdl( bShowTable ? *m_xLbTableDbColumn : *m_xLbTextDbColumn );
427 IMPL_LINK( SwInsertDBColAutoPilot, DBFormatHdl, weld::Toggleable&, rButton, void )
429 if (!rButton.get_active())
430 return;
432 weld::TreeView& rBox = m_xRbAsTable->get_active()
433 ? ( m_xLbTableCol->get_id(0).isEmpty()
434 ? *m_xLbTableDbColumn
435 : *m_xLbTableCol )
436 : *m_xLbTextDbColumn;
438 SwInsDBColumn aSrch(rBox.get_selected_text());
439 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
441 bool bFromDB = m_xRbDbFormatFromDb->get_active();
442 (*it)->bIsDBFormat = bFromDB;
443 m_xLbDbFormatFromUsr->set_sensitive( !bFromDB );
446 IMPL_LINK( SwInsertDBColAutoPilot, TableToFromHdl, weld::Button&, rButton, void )
448 bool bChgEnable = true, bEnableTo = true, bEnableFrom = true;
450 if( &rButton == m_xIbDbcolAllTo.get() )
452 bEnableTo = false;
454 sal_Int32 n, nInsPos = m_xLbTableCol->get_selected_index(),
455 nCnt = m_xLbTableDbColumn->n_children();
457 m_xLbTableDbColumn->unselect_all();
459 m_xLbTableDbColumn->freeze();
460 m_xLbTableCol->freeze();
462 if (nInsPos == -1)
463 for( n = 0; n < nCnt; ++n )
464 m_xLbTableCol->append_text(m_xLbTableDbColumn->get_text(n));
465 else
466 for( n = 0; n < nCnt; ++n, ++nInsPos )
467 m_xLbTableCol->insert_text(nInsPos, m_xLbTableDbColumn->get_text(n));
468 m_xLbTableDbColumn->clear();
470 m_xLbTableDbColumn->thaw();
471 m_xLbTableCol->thaw();
473 m_xLbTableCol->select(nInsPos);
475 else if( &rButton == m_xIbDbcolOneTo.get() &&
476 m_xLbTableDbColumn->get_selected_index() != -1 )
478 sal_Int32 nInsPos = m_xLbTableCol->get_selected_index(),
479 nDelPos = m_xLbTableDbColumn->get_selected_index();
480 m_xLbTableCol->insert_text(nInsPos, m_xLbTableDbColumn->get_text(nDelPos));
481 m_xLbTableDbColumn->remove(nDelPos);
483 m_xLbTableCol->select(nInsPos);
484 if (nDelPos >= m_xLbTableDbColumn->n_children())
485 nDelPos = m_xLbTableDbColumn->n_children() - 1;
486 m_xLbTableDbColumn->select(nDelPos);
488 bEnableTo = 0 != m_xLbTableDbColumn->n_children();
490 else if( &rButton == m_xIbDbcolOneFrom.get() )
492 if (m_xLbTableCol->get_selected_index() != -1)
494 sal_Int32 nInsPos,
495 nDelPos = m_xLbTableCol->get_selected_index();
497 // look for the right InsertPos!!
498 SwInsDBColumn aSrch(m_xLbTableCol->get_text(nDelPos));
499 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
500 if( it == m_aDBColumns.begin() || (it+1) == m_aDBColumns.end() )
501 nInsPos = it - m_aDBColumns.begin();
502 else
504 nInsPos = -1;
505 while( ++it != m_aDBColumns.end() &&
506 -1 == (nInsPos = m_xLbTableDbColumn->
507 find_text( (*it)->sColumn )) )
511 m_xLbTableDbColumn->insert_text(nInsPos, aSrch.sColumn);
512 m_xLbTableCol->remove( nDelPos );
514 if (nInsPos >= m_xLbTableDbColumn->n_children())
515 nInsPos = m_xLbTableDbColumn->n_children() - 1;
516 m_xLbTableDbColumn->select(nInsPos);
518 if (nDelPos >= m_xLbTableCol->n_children())
519 nDelPos = m_xLbTableCol->n_children() - 1;
520 m_xLbTableCol->select(nDelPos);
522 else
523 bEnableTo = 0 != m_xLbTableDbColumn->n_children();
525 bEnableFrom = 0 != m_xLbTableCol->n_children();
527 else if( &rButton == m_xIbDbcolAllFrom.get() )
529 bEnableFrom = false;
531 m_xLbTableDbColumn->freeze();
532 m_xLbTableCol->freeze();
534 m_xLbTableDbColumn->clear();
535 m_xLbTableCol->clear();
536 for (size_t n = 0; n < m_aDBColumns.size(); ++n)
537 m_xLbTableDbColumn->append_text(m_aDBColumns[n]->sColumn);
539 m_xLbTableDbColumn->thaw();
540 m_xLbTableCol->thaw();
542 m_xLbTableDbColumn->select(0);
544 else if( &rButton == m_xIbDbcolToEdit.get() )
546 bChgEnable = false;
547 // move data to Edit:
548 OUString aField(m_xLbTextDbColumn->get_selected_text());
549 if( !aField.isEmpty() )
551 OUString aStr( m_xEdDbText->get_text() );
552 int nStartPos, nEndPos;
553 m_xEdDbText->get_selection_bounds(nStartPos, nEndPos);
554 sal_Int32 nPos = std::min(nStartPos, nEndPos);
555 sal_Int32 nMax = std::max(nStartPos, nEndPos);
556 const sal_Int32 nSel = nMax - nPos;
557 if( nSel )
558 // first delete the existing selection
559 aStr = aStr.replaceAt( nPos, nSel, u"" );
561 aField = OUStringChar(cDBFieldStart) + aField + OUStringChar(cDBFieldEnd);
562 if( !aStr.isEmpty() )
564 if( nPos ) // one blank in front
566 sal_Unicode c = aStr[ nPos-1 ];
567 if( '\n' != c && '\r' != c )
568 aField = " " + aField;
570 if( nPos < aStr.getLength() ) // one blank behind
572 sal_Unicode c = aStr[ nPos ];
573 if( '\n' != c && '\r' != c )
574 aField += " ";
578 m_xEdDbText->set_text( aStr.replaceAt( nPos, 0, aField ) );
579 nPos += aField.getLength();
580 m_xEdDbText->select_region(nPos, nPos);
584 if( !bChgEnable )
585 return;
587 m_xIbDbcolOneTo->set_sensitive( bEnableTo );
588 m_xIbDbcolAllTo->set_sensitive( bEnableTo );
589 m_xIbDbcolOneFrom->set_sensitive( bEnableFrom );
590 m_xIbDbcolAllFrom->set_sensitive( bEnableFrom );
592 m_xRbDbFormatFromDb->set_sensitive( false );
593 m_xRbDbFormatFromUsr->set_sensitive( false );
594 m_xLbDbFormatFromUsr->set_sensitive( false );
596 m_xPbTableFormat->set_sensitive( bEnableFrom );
599 IMPL_LINK(SwInsertDBColAutoPilot, DblClickHdl, weld::TreeView&, rBox, bool)
601 weld::Button* pButton = nullptr;
602 if( &rBox == m_xLbTextDbColumn.get() )
603 pButton = m_xIbDbcolToEdit.get();
604 else if( &rBox == m_xLbTableDbColumn.get() && m_xIbDbcolOneTo->get_sensitive() )
605 pButton = m_xIbDbcolOneTo.get();
606 else if( &rBox == m_xLbTableCol.get() && m_xIbDbcolOneFrom->get_sensitive() )
607 pButton = m_xIbDbcolOneFrom.get();
609 if (pButton)
610 TableToFromHdl(*pButton);
612 return true;
615 IMPL_LINK_NOARG(SwInsertDBColAutoPilot, TableFormatHdl, weld::Button&, void)
617 SwWrtShell& rSh = m_pView->GetWrtShell();
618 bool bNewSet = false;
619 if( !m_pTableSet )
621 bNewSet = true;
622 m_pTableSet.reset(new SfxItemSet( rSh.GetAttrPool(), SwuiGetUITableAttrRange() ));
624 // At first acquire the simple attributes
625 m_pTableSet->Put( SfxStringItem( FN_PARAM_TABLE_NAME, rSh.GetUniqueTableName() ));
626 m_pTableSet->Put( SfxUInt16Item( FN_PARAM_TABLE_HEADLINE, 1 ) );
628 m_pTableSet->Put( SfxUInt16Item( SID_BACKGRND_DESTINATION,
629 rSh.GetViewOptions()->GetTableDest() ));
631 SvxBrushItem aBrush( RES_BACKGROUND );
632 m_pTableSet->Put( aBrush );
633 aBrush.SetWhich(SID_ATTR_BRUSH_ROW);
634 m_pTableSet->Put( aBrush );
635 aBrush.SetWhich(SID_ATTR_BRUSH_TABLE);
636 m_pTableSet->Put( aBrush );
638 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
639 // table variant, when multiple table cells are selected
640 aBoxInfo.SetTable( true );
641 // always show gap field
642 aBoxInfo.SetDist( true);
643 // set minimum size in tables and paragraphs
644 aBoxInfo.SetMinDist( false );
645 // always set default-gap
646 aBoxInfo.SetDefDist( MIN_BORDER_DIST );
647 // Single lines can have DontCare-status only in tables
648 aBoxInfo.SetValid( SvxBoxInfoItemValidFlags::DISABLE );
649 m_pTableSet->Put( aBoxInfo );
651 SwGetCurColNumPara aPara;
652 const sal_uInt16 nNum = rSh.GetCurColNum( &aPara );
653 tools::Long nWidth;
655 if( nNum )
657 nWidth = aPara.pPrtRect->Width();
658 const SwFormatCol& rCol = aPara.pFrameFormat->GetCol();
659 const SwColumns& rCols = rCol.GetColumns();
661 // initialise nStart and nEnd for nNum == 0
662 tools::Long nWidth1 = 0,
663 nStart1 = 0,
664 nEnd1 = nWidth;
665 for( sal_uInt16 i = 0; i < nNum; ++i )
667 const SwColumn* pCol = &rCols[i];
668 nStart1 = pCol->GetLeft() + nWidth1;
669 nWidth1 += static_cast<tools::Long>(rCol.CalcColWidth( i, o3tl::narrowing<sal_uInt16>(nWidth) ));
670 nEnd1 = nWidth1 - pCol->GetRight();
672 if(nStart1 || nEnd1 != nWidth)
673 nWidth = nEnd1 - nStart1;
675 else
676 nWidth = rSh.GetAnyCurRect(
677 (FrameTypeFlags::FLY_ANY & rSh.GetFrameType( nullptr, true ))
678 ? CurRectType::FlyEmbeddedPrt
679 : CurRectType::PagePrt ).Width();
681 SwTabCols aTabCols;
682 aTabCols.SetRight( nWidth );
683 aTabCols.SetRightMax( nWidth );
684 m_pRep.reset(new SwTableRep( aTabCols ));
685 m_pRep->SetAlign( text::HoriOrientation::NONE );
686 m_pRep->SetSpace( nWidth );
687 m_pRep->SetWidth( nWidth );
688 m_pRep->SetWidthPercent( 100 );
689 m_pTableSet->Put( SwPtrItem( FN_TABLE_REP, m_pRep.get() ));
691 m_pTableSet->Put( SfxUInt16Item( SID_HTML_MODE,
692 ::GetHtmlMode( m_pView->GetDocShell() )));
695 sal_Int32 nCols = m_xLbTableCol->n_children();
696 if (nCols != m_pRep->GetAllColCount() && nCols > 0)
698 // Number of columns has changed: then the TabCols have to be adjusted
699 tools::Long nWidth = m_pRep->GetWidth();
700 --nCols;
701 SwTabCols aTabCols( nCols );
702 aTabCols.SetRight( nWidth );
703 aTabCols.SetRightMax( nWidth );
704 if( nCols )
706 const sal_Int32 nStep = nWidth / (nCols+1);
707 for( sal_Int32 n = 0; n < nCols; ++n )
709 aTabCols.Insert( nStep*(n+1), false, n );
712 m_pRep.reset(new SwTableRep( aTabCols ));
713 m_pRep->SetAlign( text::HoriOrientation::NONE );
714 m_pRep->SetSpace( nWidth );
715 m_pRep->SetWidth( nWidth );
716 m_pRep->SetWidthPercent( 100 );
717 m_pTableSet->Put( SwPtrItem( FN_TABLE_REP, m_pRep.get() ));
720 SwAbstractDialogFactory& rFact = swui::GetFactory();
722 VclPtr<SfxAbstractTabDialog> pDlg(rFact.CreateSwTableTabDlg(m_xDialog.get(), m_pTableSet.get(), &rSh));
723 pDlg->StartExecuteAsync(
724 [this, pDlg, bNewSet] (sal_Int32 nResult)->void
726 if( nResult == RET_OK )
727 m_pTableSet->Put( *pDlg->GetOutputItemSet() );
728 else if( bNewSet )
730 m_pTableSet.reset();
731 m_pRep.reset();
733 pDlg->disposeOnce();
738 IMPL_LINK_NOARG(SwInsertDBColAutoPilot, AutoFormatHdl, weld::Button&, void)
740 SwAbstractDialogFactory& rFact = swui::GetFactory();
742 VclPtr<AbstractSwAutoFormatDlg> pDlg(rFact.CreateSwAutoFormatDlg(m_xDialog.get(), m_pView->GetWrtShellPtr(), false, m_xTAutoFormat.get()));
743 pDlg->StartExecuteAsync(
744 [this, pDlg] (sal_Int32 nResult)->void
746 if (nResult == RET_OK)
748 pDlg->Apply();
749 m_xTAutoFormat = pDlg->FillAutoFormatOfIndex();
751 pDlg->disposeOnce();
756 IMPL_LINK(SwInsertDBColAutoPilot, TVSelectHdl, weld::TreeView&, rBox, void)
758 weld::TreeView* pGetBox = &rBox;
760 SwInsDBColumn aSrch(pGetBox->get_selected_text());
761 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
763 // set the selected FieldName at the FormatGroupBox, so that
764 // it's clear what field is configured by the format!
765 OUString sText( m_xFormatFrame->get_label().copy( 0, m_nGBFormatLen ));
766 if( aSrch.sColumn.isEmpty() )
768 m_xRbDbFormatFromDb->set_sensitive( false );
769 m_xRbDbFormatFromUsr->set_sensitive( false );
770 m_xLbDbFormatFromUsr->set_sensitive( false );
772 else
774 bool bEnableFormat = (*it)->bHasFormat;
775 m_xRbDbFormatFromDb->set_sensitive( bEnableFormat );
776 m_xRbDbFormatFromUsr->set_sensitive( bEnableFormat );
778 if( bEnableFormat )
780 sText += " (" + aSrch.sColumn + ")";
783 bool bIsDBFormat = (*it)->bIsDBFormat;
784 m_xRbDbFormatFromDb->set_active( bIsDBFormat );
785 m_xRbDbFormatFromUsr->set_active( !bIsDBFormat );
786 m_xLbDbFormatFromUsr->set_sensitive( !bIsDBFormat );
787 if( !bIsDBFormat )
788 m_xLbDbFormatFromUsr->SetDefFormat( (*it)->nUsrNumFormat );
791 m_xFormatFrame->set_label(sText);
793 if (m_xLbTableCol->n_children())
795 // to know later on, what ListBox was the "active", a Flag
796 // is remembered in the 1st entry
797 if (&rBox == m_xLbTableCol.get())
798 m_xLbTableCol->set_id(0, u"tablecols"_ustr);
799 else
800 m_xLbTableCol->set_id(0, OUString());
804 IMPL_LINK_NOARG(SwInsertDBColAutoPilot, CBSelectHdl, weld::ComboBox&, void)
806 weld::TreeView* pGetBox = m_xRbAsTable->get_active()
807 ? ( m_xLbTableCol->get_id(0).isEmpty()
808 ? m_xLbTableDbColumn.get()
809 : m_xLbTableCol.get() )
810 : m_xLbTextDbColumn.get();
812 SwInsDBColumn aSrch(pGetBox->get_selected_text());
813 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
815 if( !aSrch.sColumn.isEmpty() )
817 m_xLbDbFormatFromUsr->CallSelectHdl();
818 (*it)->nUsrNumFormat = m_xLbDbFormatFromUsr->GetFormat();
822 IMPL_LINK_NOARG(SwInsertDBColAutoPilot, HeaderHdl, weld::Toggleable&, void)
824 bool bEnable = m_xCbTableHeadon->get_active();
825 m_xRbHeadlColnms->set_sensitive( bEnable );
826 m_xRbHeadlEmpty->set_sensitive( bEnable );
829 static void lcl_InsTextInArr( std::u16string_view aText, DB_Columns& rColArr )
831 size_t nSttPos = 0;
832 size_t nFndPos;
833 while( std::u16string_view::npos != ( nFndPos = aText.find( '\x0A', nSttPos )) )
835 if( 1 < nFndPos )
837 rColArr.push_back(std::make_unique<DB_Column>(OUString(aText.substr(nSttPos, nFndPos -1))));
839 rColArr.push_back(std::make_unique<DB_Column>());
840 nSttPos = nFndPos + 1;
842 if( nSttPos < aText.size() )
844 rColArr.push_back(std::make_unique<DB_Column>(OUString(aText.substr(nSttPos))));
848 bool SwInsertDBColAutoPilot::SplitTextToColArr( const OUString& rText,
849 DB_Columns& rColArr,
850 bool bInsField )
852 // create each of the database columns from the text again
853 // and then save in an array
854 // database columns are in <> and must be present in the columns' array:
855 OUString sText( rText );
856 sal_Int32 nFndPos, nEndPos, nSttPos = 0;
858 while( -1 != ( nFndPos = sText.indexOf( cDBFieldStart, nSttPos )))
860 nSttPos = nFndPos + 1;
861 nEndPos = sText.indexOf( cDBFieldEnd, nSttPos+1 );
862 if( -1 != nEndPos )
864 // Text in <> brackets found: what is it:
865 SwInsDBColumn aSrch( sText.copy( nSttPos, nEndPos - nSttPos ));
866 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
867 if( it != m_aDBColumns.end() )
869 // that is a valid field
870 // so surely the text "before":
871 const SwInsDBColumn& rFndCol = **it;
873 DB_Column* pNew;
875 if( 1 < nSttPos )
877 ::lcl_InsTextInArr( sText.subView( 0, nSttPos-1 ), rColArr );
878 sText = sText.copy( nSttPos-1 );
881 sText = sText.copy( rFndCol.sColumn.getLength() + 2 );
882 nSttPos = 0;
884 sal_uInt16 nSubType = 0;
885 sal_uInt32 nFormat;
886 if( rFndCol.bHasFormat )
888 if( rFndCol.bIsDBFormat )
889 nFormat = static_cast<sal_uInt32>(rFndCol.nDBNumFormat);
890 else
892 nFormat = rFndCol.nUsrNumFormat;
893 nSubType = nsSwExtendedSubType::SUB_OWN_FMT;
896 else
897 nFormat = 0;
899 if( bInsField )
901 SwWrtShell& rSh = m_pView->GetWrtShell();
902 SwDBFieldType aFieldType( rSh.GetDoc(), aSrch.sColumn,
903 m_aDBData );
904 pNew = new DB_Column( rFndCol, *new SwDBField(
905 static_cast<SwDBFieldType*>(rSh.InsertFieldType( aFieldType )),
906 nFormat ) );
907 if( nSubType )
908 pNew->pField->SetSubType( nSubType );
910 else
911 pNew = new DB_Column( rFndCol, nFormat );
913 rColArr.push_back( std::unique_ptr<DB_Column>(pNew) );
918 // don't forget the last text
919 if( !sText.isEmpty() )
920 ::lcl_InsTextInArr( sText, rColArr );
922 return !rColArr.empty();
925 void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection,
926 Reference< XDataSource> const & xSource,
927 Reference< XConnection> const & xConnection,
928 Reference< sdbc::XResultSet > const & xResultSet_in )
930 auto xResultSet = xResultSet_in;
932 const Any* pSelection = rSelection.hasElements() ? rSelection.getConstArray() : nullptr;
933 SwWrtShell& rSh = m_pView->GetWrtShell();
935 //with the drag and drop interface no result set is initially available
936 bool bDisposeResultSet = false;
937 // we don't have a cursor, so we have to create our own RowSet
938 if ( !xResultSet.is() )
940 xResultSet = SwDBManager::createCursor(m_aDBData.sDataSource,m_aDBData.sCommand,m_aDBData.nCommandType,xConnection,m_pView);
941 bDisposeResultSet = xResultSet.is();
944 Reference< sdbc::XRow > xRow(xResultSet, UNO_QUERY);
945 if ( !xRow.is() )
946 return;
948 rSh.StartAllAction();
949 bool bUndo = rSh.DoesUndo();
950 if( bUndo )
951 rSh.StartUndo();
953 bool bAsTable = m_xRbAsTable->get_active();
954 SvNumberFormatter& rNumFormatr = *rSh.GetNumberFormatter();
956 if( rSh.HasSelection() )
957 rSh.DelRight();
959 std::optional<SwWait> oWait;
961 Reference< XColumnsSupplier > xColsSupp( xResultSet, UNO_QUERY );
962 Reference <XNameAccess> xCols = xColsSupp->getColumns();
964 uno::Reference<sdbcx::XRowLocate> xRowLocate(xResultSet, uno::UNO_QUERY_THROW);
966 do{ // middle checked loop!!
967 if( bAsTable ) // fill in data as table
969 rSh.DoUndo( false );
971 sal_Int32 nCols = m_xLbTableCol->n_children();
972 sal_Int32 nRows = 0;
973 if( m_xCbTableHeadon->get_active() )
974 nRows++;
976 if( pSelection )
977 nRows += rSelection.getLength();
978 else
979 ++nRows;
981 // prepare the array for the selected columns
982 std::vector<SwInsDBColumn*> aColFields;
983 for( sal_Int32 n = 0; n < nCols; ++n )
985 SwInsDBColumn aSrch(m_xLbTableCol->get_text(n));
986 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
987 if (it != m_aDBColumns.end())
988 aColFields.push_back(it->get());
989 else {
990 OSL_ENSURE( false, "database column not found" );
994 if( static_cast<size_t>(nCols) != aColFields.size() )
996 OSL_ENSURE( false, "not all database columns found" );
997 nCols = static_cast<sal_Int32>(aColFields.size());
1000 if(!nRows || !nCols)
1002 OSL_ENSURE( false, "wrong parameters" );
1003 break;
1006 const SwModuleOptions* pModOpt = SwModule::get()->GetModuleConfig();
1008 bool bHTML = 0 != (::GetHtmlMode( m_pView->GetDocShell() ) & HTMLMODE_ON);
1009 rSh.InsertTable(
1010 pModOpt->GetInsTableFlags(bHTML),
1011 nRows, nCols, (pSelection ? m_xTAutoFormat.get(): nullptr) );
1012 rSh.MoveTable( GotoPrevTable, fnTableStart );
1014 if( pSelection && m_pTableSet )
1015 SetTabSet();
1017 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aTableSet( rSh.GetAttrPool() );
1018 bool bIsAutoUpdateCells = rSh.IsAutoUpdateCells();
1019 rSh.SetAutoUpdateCells( false );
1021 if( m_xCbTableHeadon->get_active() )
1023 for( sal_Int32 n = 0; n < nCols; ++n )
1025 if( m_xRbHeadlColnms->get_active() )
1027 rSh.SwEditShell::Insert2( aColFields[ n ]->sColumn );
1029 rSh.GoNextCell();
1032 else
1033 rSh.SetRowsToRepeat( 0 );
1035 for( sal_Int32 i = 0 ; ; ++i )
1037 bool bBreak = false;
1040 if(pSelection)
1042 bBreak = !xRowLocate->moveToBookmark(pSelection[i]);
1044 else if(!i)
1045 bBreak = !xResultSet->first();
1047 catch (const Exception&)
1049 bBreak = true;
1051 if(bBreak)
1052 break;
1054 for( sal_Int32 n = 0; n < nCols; ++n )
1056 // at the very first time, NO GoNextCell, because we're
1057 // already in it. Also no GoNextCell after the Insert,
1058 // because an empty line is added at the end.
1059 if( i || n )
1060 rSh.GoNextCell();
1062 const SwInsDBColumn* pEntry = aColFields[ n ];
1064 Reference< XColumn > xColumn;
1065 xCols->getByName(pEntry->sColumn) >>= xColumn;
1066 Reference< XPropertySet > xColumnProps( xColumn, UNO_QUERY );
1067 sal_Int32 eDataType = 0;
1068 if( xColumnProps.is() )
1070 Any aType = xColumnProps->getPropertyValue(u"Type"_ustr);
1071 aType >>= eDataType;
1075 if( pEntry->bHasFormat )
1077 SwTableBoxNumFormat aNumFormat(
1078 pEntry->bIsDBFormat ? static_cast<sal_uInt32>(pEntry->nDBNumFormat)
1079 : pEntry->nUsrNumFormat );
1080 aTableSet.Put(aNumFormat);
1081 if( xColumn.is() )
1083 double fVal = xColumn->getDouble();
1084 if( xColumn->wasNull() )
1085 aTableSet.ClearItem( RES_BOXATR_VALUE );
1086 else
1088 if(rNumFormatr.GetType(aNumFormat.GetValue()) & SvNumFormatType::DATE)
1090 ::Date aStandard(1,1,1900);
1091 if (rNumFormatr.GetNullDate() != aStandard)
1092 fVal += (aStandard - rNumFormatr.GetNullDate());
1094 aTableSet.Put( SwTableBoxValue( fVal ));
1097 else
1098 aTableSet.ClearItem( RES_BOXATR_VALUE );
1099 rSh.SetTableBoxFormulaAttrs( aTableSet );
1101 //#i60207# don't insert binary data as string - creates a loop
1102 else if( DataType::BINARY == eDataType ||
1103 DataType::VARBINARY == eDataType ||
1104 DataType::LONGVARBINARY== eDataType ||
1105 DataType::SQLNULL == eDataType ||
1106 DataType::OTHER == eDataType ||
1107 DataType::OBJECT == eDataType ||
1108 DataType::DISTINCT == eDataType ||
1109 DataType::STRUCT == eDataType ||
1110 DataType::ARRAY == eDataType ||
1111 DataType::BLOB == eDataType ||
1112 DataType::CLOB == eDataType ||
1113 DataType::REF == eDataType
1116 // do nothing
1118 else
1120 const OUString sVal = xColumn->getString();
1121 if(!xColumn->wasNull())
1123 rSh.SwEditShell::Insert2( sVal );
1127 catch (const Exception&)
1129 TOOLS_WARN_EXCEPTION("sw", "");
1133 if( !pSelection )
1135 if ( !xResultSet->next() )
1136 break;
1138 else if( i+1 >= rSelection.getLength() )
1139 break;
1141 if( 10 == i )
1142 oWait.emplace( *m_pView->GetDocShell(), true );
1145 rSh.MoveTable( GotoCurrTable, fnTableStart );
1146 if( !pSelection && ( m_pTableSet || m_xTAutoFormat ))
1148 if( m_pTableSet )
1149 SetTabSet();
1151 if (m_xTAutoFormat)
1152 rSh.SetTableStyle(*m_xTAutoFormat);
1154 rSh.SetAutoUpdateCells( bIsAutoUpdateCells );
1156 else // add data as fields/text
1158 DB_Columns aColArr;
1159 if( SplitTextToColArr( m_xEdDbText->get_text(), aColArr, m_xRbAsField->get_active() ) )
1161 // now for each data set, we can iterate over the array
1162 // and add the data
1164 if( !rSh.IsSttPara() )
1165 rSh.SwEditShell::SplitNode();
1166 if( !rSh.IsEndPara() )
1168 rSh.SwEditShell::SplitNode();
1169 rSh.SwCursorShell::Left(1,SwCursorSkipMode::Chars);
1172 rSh.DoUndo( false );
1174 SwTextFormatColl* pColl = nullptr;
1176 const OUString sTmplNm(m_xLbDbParaColl->get_active_text());
1177 if( m_sNoTmpl != sTmplNm )
1179 pColl = rSh.FindTextFormatCollByName( sTmplNm );
1180 if( !pColl )
1182 const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName(
1183 sTmplNm, SwGetPoolIdFromName::TxtColl );
1184 if( USHRT_MAX != nId )
1185 pColl = rSh.GetTextCollFromPool( nId );
1186 else
1187 pColl = rSh.MakeTextFormatColl( sTmplNm );
1189 rSh.SetTextFormatColl( pColl );
1193 // for adding as fields -> insert a "NextField" after
1194 // every data set
1195 SwDBFormatData aDBFormatData;
1196 const Reference< XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
1197 aDBFormatData.xFormatter.set(util::NumberFormatter::create(xContext), UNO_QUERY_THROW) ;
1199 Reference<XPropertySet> xSourceProps(xSource, UNO_QUERY);
1200 if(xSourceProps.is())
1202 Any aFormats = xSourceProps->getPropertyValue(u"NumberFormatsSupplier"_ustr);
1203 if(aFormats.hasValue())
1205 Reference< util::XNumberFormatsSupplier> xSuppl;
1206 aFormats >>= xSuppl;
1207 if(xSuppl.is())
1209 Reference< XPropertySet > xSettings = xSuppl->getNumberFormatSettings();
1210 Any aNull = xSettings->getPropertyValue(u"NullDate"_ustr);
1211 aNull >>= aDBFormatData.aNullDate;
1212 if(aDBFormatData.xFormatter.is())
1213 aDBFormatData.xFormatter->attachNumberFormatsSupplier(xSuppl);
1217 aDBFormatData.aLocale = LanguageTag( rSh.GetCurLang() ).getLocale();
1218 SwDBNextSetField aNxtDBField( static_cast<SwDBNextSetFieldType*>(rSh.
1219 GetFieldType( 0, SwFieldIds::DbNextSet )),
1220 u"1"_ustr, m_aDBData );
1222 bool bSetCursor = true;
1223 const size_t nCols = aColArr.size();
1224 ::sw::mark::MarkBase* pMark = nullptr;
1225 for( sal_Int32 i = 0 ; ; ++i )
1227 bool bBreak = false;
1230 if(pSelection)
1232 bBreak = !xRowLocate->moveToBookmark(pSelection[i]);
1234 else if(!i)
1235 bBreak = !xResultSet->first();
1237 catch (const Exception&)
1239 bBreak = true;
1242 if(bBreak)
1243 break;
1245 for( size_t n = 0; n < nCols; ++n )
1247 DB_Column* pDBCol = aColArr[ n ].get();
1248 OUString sIns;
1249 switch( pDBCol->eColType )
1251 case DB_Column::Type::FILLTEXT:
1252 sIns = *pDBCol->pText;
1253 break;
1255 case DB_Column::Type::SPLITPARA:
1256 rSh.SplitNode();
1257 // when the template is not the same as the follow template,
1258 // the selected has to be set newly
1259 if( pColl && &pColl->GetNextTextFormatColl() != pColl )
1260 rSh.SetTextFormatColl( pColl );
1261 break;
1263 case DB_Column::Type::COL_FIELD:
1265 std::unique_ptr<SwDBField> pField(static_cast<SwDBField *>(
1266 pDBCol->pField->CopyField().release()));
1267 double nValue = DBL_MAX;
1269 Reference< XPropertySet > xColumnProps;
1270 xCols->getByName(pDBCol->pColInfo->sColumn) >>= xColumnProps;
1272 pField->SetExpansion( SwDBManager::GetDBField(
1273 xColumnProps,
1274 aDBFormatData,
1275 &nValue ) );
1276 if( DBL_MAX != nValue )
1278 Any aType = xColumnProps->getPropertyValue(u"Type"_ustr);
1279 sal_Int32 eDataType = 0;
1280 aType >>= eDataType;
1281 if( DataType::DATE == eDataType || DataType::TIME == eDataType ||
1282 DataType::TIMESTAMP == eDataType)
1285 ::Date aStandard(1,1,1900);
1286 ::Date aCompare(aDBFormatData.aNullDate.Day ,
1287 aDBFormatData.aNullDate.Month,
1288 aDBFormatData.aNullDate.Year);
1289 if(aStandard != aCompare)
1290 nValue += (aStandard - aCompare);
1292 pField->ChgValue( nValue, true );
1294 pField->SetInitialized();
1296 rSh.InsertField2( *pField );
1298 break;
1300 case DB_Column::Type::COL_TEXT:
1302 double nValue = DBL_MAX;
1303 Reference< XPropertySet > xColumnProps;
1304 xCols->getByName(pDBCol->pColInfo->sColumn) >>= xColumnProps;
1305 sIns = SwDBManager::GetDBField(
1306 xColumnProps,
1307 aDBFormatData,
1308 &nValue );
1309 if( pDBCol->nFormat &&
1310 DBL_MAX != nValue )
1312 const Color* pCol;
1313 if(rNumFormatr.GetType(pDBCol->nFormat) & SvNumFormatType::DATE)
1315 ::Date aStandard(1,1,1900);
1316 if (rNumFormatr.GetNullDate() != aStandard)
1317 nValue += (aStandard - rNumFormatr.GetNullDate());
1319 rNumFormatr.GetOutputString( nValue,
1320 pDBCol->nFormat,
1321 sIns, &pCol );
1324 break;
1327 if( !sIns.isEmpty() )
1329 rSh.Insert( sIns );
1331 if( bSetCursor)
1333 // to the beginning and set a mark, so that
1334 // the cursor can be set to the initial position
1335 // at the end.
1337 rSh.SwCursorShell::MovePara(
1338 GoCurrPara, fnParaStart );
1339 pMark = rSh.SetBookmark(
1340 vcl::KeyCode(),
1341 OUString(),
1342 IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
1343 rSh.SwCursorShell::MovePara(
1344 GoCurrPara, fnParaEnd );
1345 bSetCursor = false;
1350 if( !pSelection )
1352 bool bNext = xResultSet->next();
1353 if(!bNext)
1354 break;
1356 else if( i+1 >= rSelection.getLength() )
1357 break;
1359 if( m_xRbAsField->get_active() )
1360 rSh.InsertField2( aNxtDBField );
1362 if( !rSh.IsSttPara() )
1363 rSh.SwEditShell::SplitNode();
1365 if( 10 == i )
1366 oWait.emplace( *m_pView->GetDocShell(), true );
1369 if( !bSetCursor && pMark != nullptr)
1371 rSh.SetMark();
1372 rSh.GotoMark( pMark );
1373 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
1374 break;
1378 // write configuration
1379 Commit();
1380 }while( false ); // middle checked loop
1382 if( bUndo )
1384 rSh.DoUndo();
1385 rSh.AppendUndoForInsertFromDB( bAsTable );
1386 rSh.EndUndo();
1388 rSh.ClearMark();
1389 rSh.EndAllAction();
1391 if ( bDisposeResultSet )
1392 ::comphelper::disposeComponent(xResultSet);
1395 void SwInsertDBColAutoPilot::SetTabSet()
1397 SwWrtShell& rSh = m_pView->GetWrtShell();
1398 const SfxPoolItem* pItem;
1400 if (m_xTAutoFormat)
1402 if (m_xTAutoFormat->IsFrame())
1404 // border is from AutoFormat
1405 m_pTableSet->ClearItem( RES_BOX );
1406 m_pTableSet->ClearItem( SID_ATTR_BORDER_INNER );
1408 if (m_xTAutoFormat->IsBackground())
1410 m_pTableSet->ClearItem( RES_BACKGROUND );
1411 m_pTableSet->ClearItem( SID_ATTR_BRUSH_ROW );
1412 m_pTableSet->ClearItem( SID_ATTR_BRUSH_TABLE );
1415 else
1417 // remove the defaults again, it makes no sense to set them
1418 SvxBrushItem aBrush( RES_BACKGROUND );
1419 static const sal_uInt16 aIds[3] =
1420 { RES_BACKGROUND, SID_ATTR_BRUSH_ROW, SID_ATTR_BRUSH_TABLE };
1421 for(sal_uInt16 i : aIds)
1422 if( SfxItemState::SET == m_pTableSet->GetItemState( i,
1423 false, &pItem ) && *pItem == aBrush )
1424 m_pTableSet->ClearItem( i );
1427 const SfxStringItem* pTableNameItem = m_pTableSet->GetItemIfSet( FN_PARAM_TABLE_NAME, false);
1428 if( pTableNameItem && pTableNameItem->GetValue() == rSh.GetTableFormat()->GetName() )
1429 m_pTableSet->ClearItem( FN_PARAM_TABLE_NAME );
1431 rSh.MoveTable( GotoCurrTable, fnTableStart );
1432 rSh.SetMark();
1433 rSh.MoveTable( GotoCurrTable, fnTableEnd );
1435 ItemSetToTableParam( *m_pTableSet, rSh );
1437 rSh.ClearMark();
1438 rSh.MoveTable( GotoCurrTable, fnTableStart );
1441 static Sequence<OUString> lcl_createSourceNames(std::u16string_view rNodeName)
1443 Sequence<OUString> aSourceNames(11);
1444 OUString* pNames = aSourceNames.getArray();
1445 pNames[0] = OUString::Concat(rNodeName) + "/DataSource";
1446 pNames[1] = OUString::Concat(rNodeName) + "/Command";
1447 pNames[2] = OUString::Concat(rNodeName) + "/CommandType";
1448 pNames[3] = OUString::Concat(rNodeName) + "/ColumnsToText";
1449 pNames[4] = OUString::Concat(rNodeName) + "/ColumnsToTable";
1450 pNames[5] = OUString::Concat(rNodeName) + "/ParaStyle";
1451 pNames[6] = OUString::Concat(rNodeName) + "/TableAutoFormat";
1452 pNames[7] = OUString::Concat(rNodeName) + "/IsTable";
1453 pNames[8] = OUString::Concat(rNodeName) + "/IsField";
1454 pNames[9] = OUString::Concat(rNodeName) + "/IsHeadlineOn";
1455 pNames[10] = OUString::Concat(rNodeName) + "/IsEmptyHeadline";
1456 return aSourceNames;
1459 static Sequence<OUString> lcl_CreateSubNames(std::u16string_view rSubNodeName)
1461 return
1463 OUString::Concat(rSubNodeName) + "/ColumnName",
1464 OUString::Concat(rSubNodeName) + "/ColumnIndex",
1465 OUString::Concat(rSubNodeName) + "/IsNumberFormat",
1466 OUString::Concat(rSubNodeName) + "/IsNumberFormatFromDataBase",
1467 OUString::Concat(rSubNodeName) + "/NumberFormat",
1468 OUString::Concat(rSubNodeName) + "/NumberFormatLocale"
1472 static OUString lcl_CreateUniqueName(const Sequence<OUString>& aNames)
1474 sal_Int32 nIdx = aNames.getLength();
1475 while(true)
1477 const OUString sRet = "_" + OUString::number(nIdx++);
1478 if ( comphelper::findValue(aNames, sRet) == -1 )
1479 return sRet; // No match found, return unique name
1483 void SwInsertDBColAutoPilot::Notify( const css::uno::Sequence< OUString >& ) {}
1485 void SwInsertDBColAutoPilot::ImplCommit()
1487 Sequence <OUString> aNames = GetNodeNames(OUString());
1488 //remove entries that contain this data source + table at first
1489 for (OUString const& nodeName : aNames)
1491 Sequence<Any> aSourceProperties = GetProperties({ nodeName + "/DataSource", nodeName + "/Command" });
1492 const Any* pSourceProps = aSourceProperties.getArray();
1493 OUString sSource, sCommand;
1494 pSourceProps[0] >>= sSource;
1495 pSourceProps[1] >>= sCommand;
1496 if(sSource==m_aDBData.sDataSource && sCommand==m_aDBData.sCommand)
1498 ClearNodeElements(OUString(), { nodeName });
1502 aNames = GetNodeNames(OUString());
1503 OUString sNewNode = lcl_CreateUniqueName(aNames);
1504 Sequence<OUString> aNodeNames = lcl_createSourceNames(sNewNode);
1505 Sequence<PropertyValue> aValues(aNodeNames.getLength());
1506 PropertyValue* pValues = aValues.getArray();
1507 const OUString* pNodeNames = aNodeNames.getConstArray();
1508 for(sal_Int32 i = 0; i < aNodeNames.getLength(); i++)
1510 pValues[i].Name = "/" + pNodeNames[i];
1513 pValues[0].Value <<= m_aDBData.sDataSource;
1514 pValues[1].Value <<= m_aDBData.sCommand;
1515 pValues[2].Value <<= m_aDBData.nCommandType;
1516 pValues[3].Value <<= m_xEdDbText->get_text();
1518 OUString sTmp;
1519 const sal_Int32 nCnt = m_xLbTableCol->n_children();
1520 for( sal_Int32 n = 0; n < nCnt; ++n )
1521 sTmp += m_xLbTableCol->get_text(n) + "\x0a";
1523 if (!sTmp.isEmpty())
1524 pValues[4].Value <<= sTmp;
1526 if( m_sNoTmpl != (sTmp = m_xLbDbParaColl->get_active_text()) )
1527 pValues[5].Value <<= sTmp;
1529 if (m_xTAutoFormat)
1530 pValues[6].Value <<= m_xTAutoFormat->GetName();
1532 pValues[7].Value <<= m_xRbAsTable->get_active();
1533 pValues[8].Value <<= m_xRbAsField->get_active();
1534 pValues[9].Value <<= m_xCbTableHeadon->get_active();
1535 pValues[10].Value <<= m_xRbHeadlEmpty->get_active();
1537 SetSetProperties(OUString(), aValues);
1539 sNewNode += "/ColumnSet";
1541 LanguageType ePrevLang(0xffff);
1543 SvNumberFormatter& rNFormatr = *m_pView->GetWrtShell().GetNumberFormatter();
1544 for(size_t nCol = 0; nCol < m_aDBColumns.size(); nCol++)
1546 SwInsDBColumn* pColumn = m_aDBColumns[nCol].get();
1547 OUString sColumnInsertNode(sNewNode + "/__");
1548 if( nCol < 10 )
1549 sColumnInsertNode += "00";
1550 else if( nCol < 100 )
1551 sColumnInsertNode += "0";
1552 sColumnInsertNode += OUString::number( nCol );
1554 const Sequence <OUString> aSubNodeNames = lcl_CreateSubNames(sColumnInsertNode);
1555 Sequence<PropertyValue> aSubValues(aSubNodeNames.getLength());
1556 PropertyValue* pSubValues = aSubValues.getArray();
1557 sal_Int32 i = 0;
1559 for( const OUString& rSubNodeName : aSubNodeNames)
1560 pSubValues[i++].Name = rSubNodeName;
1561 pSubValues[0].Value <<= pColumn->sColumn;
1562 pSubValues[1].Value <<= i;
1563 pSubValues[2].Value <<= pColumn->bHasFormat;
1564 pSubValues[3].Value <<= pColumn->bIsDBFormat;
1566 SwStyleNameMapper::FillUIName( RES_POOLCOLL_STANDARD, sTmp );
1567 const SvNumberformat* pNF = rNFormatr.GetEntry( pColumn->nUsrNumFormat );
1568 LanguageType eLang;
1569 if( pNF )
1571 pSubValues[4].Value <<= pNF->GetFormatstring();
1572 eLang = pNF->GetLanguage();
1574 else
1576 pSubValues[4].Value <<= sTmp;
1577 eLang = GetAppLanguage();
1580 OUString sPrevLang;
1581 if( eLang != ePrevLang )
1583 sPrevLang = LanguageTag::convertToBcp47( eLang );
1584 ePrevLang = eLang;
1587 pSubValues[5].Value <<= sPrevLang;
1588 SetSetProperties(sNewNode, aSubValues);
1592 void SwInsertDBColAutoPilot::Load()
1594 const Sequence<OUString> aNames = GetNodeNames(OUString());
1595 SvNumberFormatter& rNFormatr = *m_pView->GetWrtShell().GetNumberFormatter();
1596 for(OUString const & nodeName : aNames)
1598 //search for entries with the appropriate data source and table
1599 Sequence<OUString> aSourceNames = lcl_createSourceNames(nodeName);
1601 Sequence< Any> aDataSourceProps = GetProperties(aSourceNames);
1602 const Any* pDataSourceProps = aDataSourceProps.getConstArray();
1603 OUString sSource, sCommand;
1604 sal_Int16 nCommandType;
1605 pDataSourceProps[0] >>= sSource;
1606 pDataSourceProps[1] >>= sCommand;
1607 pDataSourceProps[2] >>= nCommandType;
1608 if(sSource == m_aDBData.sDataSource && sCommand == m_aDBData.sCommand)
1610 DB_ColumnConfigData aNewData;
1612 pDataSourceProps[3] >>= aNewData.sEdit;
1613 pDataSourceProps[4] >>= aNewData.sTableList;
1614 pDataSourceProps[5] >>= aNewData.sTmplNm;
1615 pDataSourceProps[6] >>= aNewData.sTAutoFormatNm;
1616 if(pDataSourceProps[7].hasValue())
1617 aNewData.bIsTable = *o3tl::doAccess<bool>(pDataSourceProps[7]);
1618 if(pDataSourceProps[8].hasValue())
1619 aNewData.bIsField = *o3tl::doAccess<bool>(pDataSourceProps[8]);
1620 if(pDataSourceProps[9].hasValue())
1621 aNewData.bIsHeadlineOn = *o3tl::doAccess<bool>(pDataSourceProps[9]);
1622 if(pDataSourceProps[10].hasValue())
1623 aNewData.bIsEmptyHeadln = *o3tl::doAccess<bool>(pDataSourceProps[10]);
1625 const OUString sSubNodeName(nodeName + "/ColumnSet/");
1626 const Sequence <OUString> aSubNames = GetNodeNames(sSubNodeName);
1627 for(const OUString& rSubName : aSubNames)
1629 Sequence <OUString> aSubNodeNames =
1630 lcl_CreateSubNames(Concat2View(sSubNodeName + rSubName));
1631 Sequence< Any> aSubProps = GetProperties(aSubNodeNames);
1632 const Any* pSubProps = aSubProps.getConstArray();
1634 OUString sColumn;
1635 pSubProps[0] >>= sColumn;
1636 // check for existence of the loaded column name
1637 bool bFound = false;
1638 for(size_t nRealColumn = 0; nRealColumn < m_aDBColumns.size(); ++nRealColumn)
1640 if(m_aDBColumns[nRealColumn]->sColumn == sColumn)
1642 bFound = true;
1643 break;
1646 if(!bFound)
1647 continue;
1648 sal_Int16 nIndex = 0;
1649 pSubProps[1] >>= nIndex;
1650 std::unique_ptr<SwInsDBColumn> pInsDBColumn(new SwInsDBColumn(sColumn));
1651 if(pSubProps[2].hasValue())
1652 pInsDBColumn->bHasFormat = *o3tl::doAccess<bool>(pSubProps[2]);
1653 if(pSubProps[3].hasValue())
1654 pInsDBColumn->bIsDBFormat = *o3tl::doAccess<bool>(pSubProps[3]);
1656 pSubProps[4] >>= pInsDBColumn->sUsrNumFormat;
1657 OUString sNumberFormatLocale;
1658 pSubProps[5] >>= sNumberFormatLocale;
1660 /* XXX Earlier versions wrote a Country-Language string in
1661 * SwInsertDBColAutoPilot::Commit() that here was read as
1662 * Language-Country with 2 characters copied to language,
1663 * 1 character separator and unconditionally 2 characters read
1664 * as country. So for 'DE-de' and locales that have similar
1665 * case-insensitive equal language/country combos that may have
1666 * worked, for all others not. FIXME if you need to read old
1667 * data that you were never able to read before. */
1668 pInsDBColumn->eUsrNumFormatLng = LanguageTag::convertToLanguageType( sNumberFormatLocale );
1670 pInsDBColumn->nUsrNumFormat = rNFormatr.GetEntryKey( pInsDBColumn->sUsrNumFormat,
1671 pInsDBColumn->eUsrNumFormatLng );
1673 aNewData.aDBColumns.insert(std::move(pInsDBColumn));
1675 OUString sTmp( aNewData.sTableList );
1676 if( !sTmp.isEmpty() )
1678 sal_Int32 n = 0;
1679 do {
1680 const OUString sEntry( sTmp.getToken( 0, '\x0a', n ) );
1681 //preselect column - if they still exist!
1682 if (m_xLbTableDbColumn->find_text(sEntry) != -1)
1684 m_xLbTableCol->append_text(sEntry);
1685 m_xLbTableDbColumn->remove_text(sEntry);
1687 } while( n>=0 );
1689 if (!m_xLbTableDbColumn->n_children())
1691 m_xIbDbcolAllTo->set_sensitive( false );
1692 m_xIbDbcolOneTo->set_sensitive( false );
1694 m_xIbDbcolOneFrom->set_sensitive(true);
1695 m_xIbDbcolAllFrom->set_sensitive(true);
1697 m_xEdDbText->set_text( aNewData.sEdit );
1699 sTmp = aNewData.sTmplNm;
1700 if( !sTmp.isEmpty() )
1701 m_xLbDbParaColl->set_active_text(sTmp);
1702 else
1703 m_xLbDbParaColl->set_active(0);
1705 m_xTAutoFormat.reset();
1706 sTmp = aNewData.sTAutoFormatNm;
1707 if( !sTmp.isEmpty() )
1709 // then load the AutoFormat file and look for Autoformat first
1710 SwTableAutoFormatTable aAutoFormatTable;
1711 aAutoFormatTable.Load();
1712 for( size_t nAutoFormat = aAutoFormatTable.size(); nAutoFormat; )
1713 if( sTmp == aAutoFormatTable[ --nAutoFormat ].GetName() )
1715 m_xTAutoFormat.reset(new SwTableAutoFormat(aAutoFormatTable[nAutoFormat]));
1716 break;
1720 m_xRbAsTable->set_active( aNewData.bIsTable );
1721 m_xRbAsField->set_active( aNewData.bIsField );
1722 m_xRbAsText->set_active( !aNewData.bIsTable && !aNewData.bIsField );
1724 m_xCbTableHeadon->set_active( aNewData.bIsHeadlineOn );
1725 m_xRbHeadlColnms->set_active( !aNewData.bIsEmptyHeadln );
1726 m_xRbHeadlEmpty->set_active( aNewData.bIsEmptyHeadln );
1727 HeaderHdl(*m_xCbTableHeadon);
1729 // now copy the user defined Numberformat strings to the
1730 // Shell. Then only these are available as ID
1731 for( size_t n = 0; n < m_aDBColumns.size() ; ++n )
1733 SwInsDBColumn& rSet = *m_aDBColumns[ n ];
1734 for( size_t m = 0; m < aNewData.aDBColumns.size() ; ++m )
1736 SwInsDBColumn& rGet = *aNewData.aDBColumns[ m ];
1737 if(rGet.sColumn == rSet.sColumn)
1739 if( rGet.bHasFormat && !rGet.bIsDBFormat )
1741 rSet.bIsDBFormat = false;
1742 rSet.nUsrNumFormat = rNFormatr.GetEntryKey( rGet.sUsrNumFormat,
1743 rGet.eUsrNumFormatLng );
1744 if( NUMBERFORMAT_ENTRY_NOT_FOUND == rSet.nUsrNumFormat )
1746 sal_Int32 nCheckPos;
1747 SvNumFormatType nType;
1748 rNFormatr.PutEntry( rGet.sUsrNumFormat, nCheckPos, nType,
1749 rSet.nUsrNumFormat, rGet.eUsrNumFormatLng );
1752 break;
1757 // when the cursor is inside of a table, table must NEVER be selectable
1758 if( !m_xRbAsTable->get_sensitive() && m_xRbAsTable->get_active() )
1759 m_xRbAsField->set_active(true);
1760 break;
1765 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */