android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / ui / dbui / dbinsdlg.cxx
blobe6dac3049caa10d5bd87dba419ff306d93551679
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(), "modules/swriter/ui/insertdbcolumnsdialog.ui", "InsertDbColumnsDialog")
178 , ConfigItem("Office.Writer/InsertData/DataSet", 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("astable"))
183 , m_xRbAsField(m_xBuilder->weld_radio_button("asfields"))
184 , m_xRbAsText(m_xBuilder->weld_radio_button("astext"))
185 , m_xHeadFrame(m_xBuilder->weld_frame("dbframe"))
186 , m_xLbTableDbColumn(m_xBuilder->weld_tree_view("tabledbcols"))
187 , m_xLbTextDbColumn(m_xBuilder->weld_tree_view("tabletxtcols"))
188 , m_xFormatFrame(m_xBuilder->weld_frame("formatframe"))
189 , m_xRbDbFormatFromDb(m_xBuilder->weld_radio_button("fromdatabase"))
190 , m_xRbDbFormatFromUsr(m_xBuilder->weld_radio_button("userdefined"))
191 , m_xLbDbFormatFromUsr(new NumFormatListBox(m_xBuilder->weld_combo_box("numformat")))
192 , m_xIbDbcolToEdit(m_xBuilder->weld_button("toedit"))
193 , m_xEdDbText(m_xBuilder->weld_text_view("textview"))
194 , m_xFtDbParaColl(m_xBuilder->weld_label("parastylelabel"))
195 , m_xLbDbParaColl(m_xBuilder->weld_combo_box("parastyle"))
196 , m_xIbDbcolAllTo(m_xBuilder->weld_button("oneright"))
197 , m_xIbDbcolOneTo(m_xBuilder->weld_button("allright"))
198 , m_xIbDbcolOneFrom(m_xBuilder->weld_button("oneleft"))
199 , m_xIbDbcolAllFrom(m_xBuilder->weld_button("allleft"))
200 , m_xFtTableCol(m_xBuilder->weld_label("tablecolft"))
201 , m_xLbTableCol(m_xBuilder->weld_tree_view("tablecols"))
202 , m_xCbTableHeadon(m_xBuilder->weld_check_button("tableheading"))
203 , m_xRbHeadlColnms(m_xBuilder->weld_radio_button("columnname"))
204 , m_xRbHeadlEmpty(m_xBuilder->weld_radio_button("rowonly"))
205 , m_xPbTableFormat(m_xBuilder->weld_button("tableformat"))
206 , m_xPbTableAutofmt(m_xBuilder->weld_button("autoformat"))
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("NumberFormatsSupplier");
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("Type");
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("FormatKey");
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("FormatString");
276 Any aLocale = xNumProps->getPropertyValue("Locale");
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_changed( LINK( this, SwInsertDBColAutoPilot, TVSelectHdl ));
362 m_xLbTableDbColumn->connect_changed( LINK( this, SwInsertDBColAutoPilot, TVSelectHdl ));
363 m_xLbDbFormatFromUsr->connect_changed( LINK( this, SwInsertDBColAutoPilot, CBSelectHdl ));
364 m_xLbTableCol->connect_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 ScopedVclPtr<SfxAbstractTabDialog> pDlg(rFact.CreateSwTableTabDlg(m_xDialog.get(), m_pTableSet.get(), &rSh));
723 if( RET_OK == pDlg->Execute() )
724 m_pTableSet->Put( *pDlg->GetOutputItemSet() );
725 else if( bNewSet )
727 m_pTableSet.reset();
728 m_pRep.reset();
732 IMPL_LINK_NOARG(SwInsertDBColAutoPilot, AutoFormatHdl, weld::Button&, void)
734 SwAbstractDialogFactory& rFact = swui::GetFactory();
736 ScopedVclPtr<AbstractSwAutoFormatDlg> pDlg(rFact.CreateSwAutoFormatDlg(m_xDialog.get(), m_pView->GetWrtShellPtr(), false, m_xTAutoFormat.get()));
737 if( RET_OK == pDlg->Execute())
738 m_xTAutoFormat = pDlg->FillAutoFormatOfIndex();
741 IMPL_LINK(SwInsertDBColAutoPilot, TVSelectHdl, weld::TreeView&, rBox, void)
743 weld::TreeView* pGetBox = &rBox;
745 SwInsDBColumn aSrch(pGetBox->get_selected_text());
746 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
748 // set the selected FieldName at the FormatGroupBox, so that
749 // it's clear what field is configured by the format!
750 OUString sText( m_xFormatFrame->get_label().copy( 0, m_nGBFormatLen ));
751 if( aSrch.sColumn.isEmpty() )
753 m_xRbDbFormatFromDb->set_sensitive( false );
754 m_xRbDbFormatFromUsr->set_sensitive( false );
755 m_xLbDbFormatFromUsr->set_sensitive( false );
757 else
759 bool bEnableFormat = (*it)->bHasFormat;
760 m_xRbDbFormatFromDb->set_sensitive( bEnableFormat );
761 m_xRbDbFormatFromUsr->set_sensitive( bEnableFormat );
763 if( bEnableFormat )
765 sText += " (" + aSrch.sColumn + ")";
768 bool bIsDBFormat = (*it)->bIsDBFormat;
769 m_xRbDbFormatFromDb->set_active( bIsDBFormat );
770 m_xRbDbFormatFromUsr->set_active( !bIsDBFormat );
771 m_xLbDbFormatFromUsr->set_sensitive( !bIsDBFormat );
772 if( !bIsDBFormat )
773 m_xLbDbFormatFromUsr->SetDefFormat( (*it)->nUsrNumFormat );
776 m_xFormatFrame->set_label(sText);
778 if (m_xLbTableCol->n_children())
780 // to know later on, what ListBox was the "active", a Flag
781 // is remembered in the 1st entry
782 if (&rBox == m_xLbTableCol.get())
783 m_xLbTableCol->set_id(0, "tablecols");
784 else
785 m_xLbTableCol->set_id(0, OUString());
789 IMPL_LINK_NOARG(SwInsertDBColAutoPilot, CBSelectHdl, weld::ComboBox&, void)
791 weld::TreeView* pGetBox = m_xRbAsTable->get_active()
792 ? ( m_xLbTableCol->get_id(0).isEmpty()
793 ? m_xLbTableDbColumn.get()
794 : m_xLbTableCol.get() )
795 : m_xLbTextDbColumn.get();
797 SwInsDBColumn aSrch(pGetBox->get_selected_text());
798 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
800 if( !aSrch.sColumn.isEmpty() )
802 m_xLbDbFormatFromUsr->CallSelectHdl();
803 (*it)->nUsrNumFormat = m_xLbDbFormatFromUsr->GetFormat();
807 IMPL_LINK_NOARG(SwInsertDBColAutoPilot, HeaderHdl, weld::Toggleable&, void)
809 bool bEnable = m_xCbTableHeadon->get_active();
810 m_xRbHeadlColnms->set_sensitive( bEnable );
811 m_xRbHeadlEmpty->set_sensitive( bEnable );
814 static void lcl_InsTextInArr( std::u16string_view aText, DB_Columns& rColArr )
816 size_t nSttPos = 0;
817 size_t nFndPos;
818 while( std::u16string_view::npos != ( nFndPos = aText.find( '\x0A', nSttPos )) )
820 if( 1 < nFndPos )
822 rColArr.push_back(std::make_unique<DB_Column>(OUString(aText.substr(nSttPos, nFndPos -1))));
824 rColArr.push_back(std::make_unique<DB_Column>());
825 nSttPos = nFndPos + 1;
827 if( nSttPos < aText.size() )
829 rColArr.push_back(std::make_unique<DB_Column>(OUString(aText.substr(nSttPos))));
833 bool SwInsertDBColAutoPilot::SplitTextToColArr( const OUString& rText,
834 DB_Columns& rColArr,
835 bool bInsField )
837 // create each of the database columns from the text again
838 // and then save in an array
839 // database columns are in <> and must be present in the columns' array:
840 OUString sText( rText );
841 sal_Int32 nFndPos, nEndPos, nSttPos = 0;
843 while( -1 != ( nFndPos = sText.indexOf( cDBFieldStart, nSttPos )))
845 nSttPos = nFndPos + 1;
846 nEndPos = sText.indexOf( cDBFieldEnd, nSttPos+1 );
847 if( -1 != nEndPos )
849 // Text in <> brackets found: what is it:
850 SwInsDBColumn aSrch( sText.copy( nSttPos, nEndPos - nSttPos ));
851 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
852 if( it != m_aDBColumns.end() )
854 // that is a valid field
855 // so surely the text "before":
856 const SwInsDBColumn& rFndCol = **it;
858 DB_Column* pNew;
860 if( 1 < nSttPos )
862 ::lcl_InsTextInArr( sText.subView( 0, nSttPos-1 ), rColArr );
863 sText = sText.copy( nSttPos-1 );
866 sText = sText.copy( rFndCol.sColumn.getLength() + 2 );
867 nSttPos = 0;
869 sal_uInt16 nSubType = 0;
870 sal_uInt32 nFormat;
871 if( rFndCol.bHasFormat )
873 if( rFndCol.bIsDBFormat )
874 nFormat = static_cast<sal_uInt32>(rFndCol.nDBNumFormat);
875 else
877 nFormat = rFndCol.nUsrNumFormat;
878 nSubType = nsSwExtendedSubType::SUB_OWN_FMT;
881 else
882 nFormat = 0;
884 if( bInsField )
886 SwWrtShell& rSh = m_pView->GetWrtShell();
887 SwDBFieldType aFieldType( rSh.GetDoc(), aSrch.sColumn,
888 m_aDBData );
889 pNew = new DB_Column( rFndCol, *new SwDBField(
890 static_cast<SwDBFieldType*>(rSh.InsertFieldType( aFieldType )),
891 nFormat ) );
892 if( nSubType )
893 pNew->pField->SetSubType( nSubType );
895 else
896 pNew = new DB_Column( rFndCol, nFormat );
898 rColArr.push_back( std::unique_ptr<DB_Column>(pNew) );
903 // don't forget the last text
904 if( !sText.isEmpty() )
905 ::lcl_InsTextInArr( sText, rColArr );
907 return !rColArr.empty();
910 void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection,
911 Reference< XDataSource> const & xSource,
912 Reference< XConnection> const & xConnection,
913 Reference< sdbc::XResultSet > const & xResultSet_in )
915 auto xResultSet = xResultSet_in;
917 const Any* pSelection = rSelection.hasElements() ? rSelection.getConstArray() : nullptr;
918 SwWrtShell& rSh = m_pView->GetWrtShell();
920 //with the drag and drop interface no result set is initially available
921 bool bDisposeResultSet = false;
922 // we don't have a cursor, so we have to create our own RowSet
923 if ( !xResultSet.is() )
925 xResultSet = SwDBManager::createCursor(m_aDBData.sDataSource,m_aDBData.sCommand,m_aDBData.nCommandType,xConnection,m_pView);
926 bDisposeResultSet = xResultSet.is();
929 Reference< sdbc::XRow > xRow(xResultSet, UNO_QUERY);
930 if ( !xRow.is() )
931 return;
933 rSh.StartAllAction();
934 bool bUndo = rSh.DoesUndo();
935 if( bUndo )
936 rSh.StartUndo();
938 bool bAsTable = m_xRbAsTable->get_active();
939 SvNumberFormatter& rNumFormatr = *rSh.GetNumberFormatter();
941 if( rSh.HasSelection() )
942 rSh.DelRight();
944 std::optional<SwWait> oWait;
946 Reference< XColumnsSupplier > xColsSupp( xResultSet, UNO_QUERY );
947 Reference <XNameAccess> xCols = xColsSupp->getColumns();
949 uno::Reference<sdbcx::XRowLocate> xRowLocate(xResultSet, uno::UNO_QUERY_THROW);
951 do{ // middle checked loop!!
952 if( bAsTable ) // fill in data as table
954 rSh.DoUndo( false );
956 sal_Int32 nCols = m_xLbTableCol->n_children();
957 sal_Int32 nRows = 0;
958 if( m_xCbTableHeadon->get_active() )
959 nRows++;
961 if( pSelection )
962 nRows += rSelection.getLength();
963 else
964 ++nRows;
966 // prepare the array for the selected columns
967 std::vector<SwInsDBColumn*> aColFields;
968 for( sal_Int32 n = 0; n < nCols; ++n )
970 SwInsDBColumn aSrch(m_xLbTableCol->get_text(n));
971 SwInsDBColumns::const_iterator it = m_aDBColumns.find( &aSrch );
972 if (it != m_aDBColumns.end())
973 aColFields.push_back(it->get());
974 else {
975 OSL_ENSURE( false, "database column not found" );
979 if( static_cast<size_t>(nCols) != aColFields.size() )
981 OSL_ENSURE( false, "not all database columns found" );
982 nCols = static_cast<sal_Int32>(aColFields.size());
985 if(!nRows || !nCols)
987 OSL_ENSURE( false, "wrong parameters" );
988 break;
991 const SwModuleOptions* pModOpt = SW_MOD()->GetModuleConfig();
993 bool bHTML = 0 != (::GetHtmlMode( m_pView->GetDocShell() ) & HTMLMODE_ON);
994 rSh.InsertTable(
995 pModOpt->GetInsTableFlags(bHTML),
996 nRows, nCols, (pSelection ? m_xTAutoFormat.get(): nullptr) );
997 rSh.MoveTable( GotoPrevTable, fnTableStart );
999 if( pSelection && m_pTableSet )
1000 SetTabSet();
1002 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aTableSet( rSh.GetAttrPool() );
1003 bool bIsAutoUpdateCells = rSh.IsAutoUpdateCells();
1004 rSh.SetAutoUpdateCells( false );
1006 if( m_xCbTableHeadon->get_active() )
1008 for( sal_Int32 n = 0; n < nCols; ++n )
1010 if( m_xRbHeadlColnms->get_active() )
1012 rSh.SwEditShell::Insert2( aColFields[ n ]->sColumn );
1014 rSh.GoNextCell();
1017 else
1018 rSh.SetRowsToRepeat( 0 );
1020 for( sal_Int32 i = 0 ; ; ++i )
1022 bool bBreak = false;
1025 if(pSelection)
1027 bBreak = !xRowLocate->moveToBookmark(pSelection[i]);
1029 else if(!i)
1030 bBreak = !xResultSet->first();
1032 catch (const Exception&)
1034 bBreak = true;
1036 if(bBreak)
1037 break;
1039 for( sal_Int32 n = 0; n < nCols; ++n )
1041 // at the very first time, NO GoNextCell, because we're
1042 // already in it. Also no GoNextCell after the Insert,
1043 // because an empty line is added at the end.
1044 if( i || n )
1045 rSh.GoNextCell();
1047 const SwInsDBColumn* pEntry = aColFields[ n ];
1049 Reference< XColumn > xColumn;
1050 xCols->getByName(pEntry->sColumn) >>= xColumn;
1051 Reference< XPropertySet > xColumnProps( xColumn, UNO_QUERY );
1052 sal_Int32 eDataType = 0;
1053 if( xColumnProps.is() )
1055 Any aType = xColumnProps->getPropertyValue("Type");
1056 aType >>= eDataType;
1060 if( pEntry->bHasFormat )
1062 SwTableBoxNumFormat aNumFormat(
1063 pEntry->bIsDBFormat ? static_cast<sal_uInt32>(pEntry->nDBNumFormat)
1064 : pEntry->nUsrNumFormat );
1065 aTableSet.Put(aNumFormat);
1066 if( xColumn.is() )
1068 double fVal = xColumn->getDouble();
1069 if( xColumn->wasNull() )
1070 aTableSet.ClearItem( RES_BOXATR_VALUE );
1071 else
1073 if(rNumFormatr.GetType(aNumFormat.GetValue()) & SvNumFormatType::DATE)
1075 ::Date aStandard(1,1,1900);
1076 if (rNumFormatr.GetNullDate() != aStandard)
1077 fVal += (aStandard - rNumFormatr.GetNullDate());
1079 aTableSet.Put( SwTableBoxValue( fVal ));
1082 else
1083 aTableSet.ClearItem( RES_BOXATR_VALUE );
1084 rSh.SetTableBoxFormulaAttrs( aTableSet );
1086 //#i60207# don't insert binary data as string - creates a loop
1087 else if( DataType::BINARY == eDataType ||
1088 DataType::VARBINARY == eDataType ||
1089 DataType::LONGVARBINARY== eDataType ||
1090 DataType::SQLNULL == eDataType ||
1091 DataType::OTHER == eDataType ||
1092 DataType::OBJECT == eDataType ||
1093 DataType::DISTINCT == eDataType ||
1094 DataType::STRUCT == eDataType ||
1095 DataType::ARRAY == eDataType ||
1096 DataType::BLOB == eDataType ||
1097 DataType::CLOB == eDataType ||
1098 DataType::REF == eDataType
1101 // do nothing
1103 else
1105 const OUString sVal = xColumn->getString();
1106 if(!xColumn->wasNull())
1108 rSh.SwEditShell::Insert2( sVal );
1112 catch (const Exception&)
1114 TOOLS_WARN_EXCEPTION("sw", "");
1118 if( !pSelection )
1120 if ( !xResultSet->next() )
1121 break;
1123 else if( i+1 >= rSelection.getLength() )
1124 break;
1126 if( 10 == i )
1127 oWait.emplace( *m_pView->GetDocShell(), true );
1130 rSh.MoveTable( GotoCurrTable, fnTableStart );
1131 if( !pSelection && ( m_pTableSet || m_xTAutoFormat ))
1133 if( m_pTableSet )
1134 SetTabSet();
1136 if (m_xTAutoFormat)
1137 rSh.SetTableStyle(*m_xTAutoFormat);
1139 rSh.SetAutoUpdateCells( bIsAutoUpdateCells );
1141 else // add data as fields/text
1143 DB_Columns aColArr;
1144 if( SplitTextToColArr( m_xEdDbText->get_text(), aColArr, m_xRbAsField->get_active() ) )
1146 // now for each data set, we can iterate over the array
1147 // and add the data
1149 if( !rSh.IsSttPara() )
1150 rSh.SwEditShell::SplitNode();
1151 if( !rSh.IsEndPara() )
1153 rSh.SwEditShell::SplitNode();
1154 rSh.SwCursorShell::Left(1,SwCursorSkipMode::Chars);
1157 rSh.DoUndo( false );
1159 SwTextFormatColl* pColl = nullptr;
1161 const OUString sTmplNm(m_xLbDbParaColl->get_active_text());
1162 if( m_sNoTmpl != sTmplNm )
1164 pColl = rSh.FindTextFormatCollByName( sTmplNm );
1165 if( !pColl )
1167 const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName(
1168 sTmplNm, SwGetPoolIdFromName::TxtColl );
1169 if( USHRT_MAX != nId )
1170 pColl = rSh.GetTextCollFromPool( nId );
1171 else
1172 pColl = rSh.MakeTextFormatColl( sTmplNm );
1174 rSh.SetTextFormatColl( pColl );
1178 // for adding as fields -> insert a "NextField" after
1179 // every data set
1180 SwDBFormatData aDBFormatData;
1181 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1182 aDBFormatData.xFormatter.set(util::NumberFormatter::create(xContext), UNO_QUERY_THROW) ;
1184 Reference<XPropertySet> xSourceProps(xSource, UNO_QUERY);
1185 if(xSourceProps.is())
1187 Any aFormats = xSourceProps->getPropertyValue("NumberFormatsSupplier");
1188 if(aFormats.hasValue())
1190 Reference< util::XNumberFormatsSupplier> xSuppl;
1191 aFormats >>= xSuppl;
1192 if(xSuppl.is())
1194 Reference< XPropertySet > xSettings = xSuppl->getNumberFormatSettings();
1195 Any aNull = xSettings->getPropertyValue("NullDate");
1196 aNull >>= aDBFormatData.aNullDate;
1197 if(aDBFormatData.xFormatter.is())
1198 aDBFormatData.xFormatter->attachNumberFormatsSupplier(xSuppl);
1202 aDBFormatData.aLocale = LanguageTag( rSh.GetCurLang() ).getLocale();
1203 SwDBNextSetField aNxtDBField( static_cast<SwDBNextSetFieldType*>(rSh.
1204 GetFieldType( 0, SwFieldIds::DbNextSet )),
1205 "1", m_aDBData );
1207 bool bSetCursor = true;
1208 const size_t nCols = aColArr.size();
1209 ::sw::mark::IMark* pMark = nullptr;
1210 for( sal_Int32 i = 0 ; ; ++i )
1212 bool bBreak = false;
1215 if(pSelection)
1217 bBreak = !xRowLocate->moveToBookmark(pSelection[i]);
1219 else if(!i)
1220 bBreak = !xResultSet->first();
1222 catch (const Exception&)
1224 bBreak = true;
1227 if(bBreak)
1228 break;
1230 for( size_t n = 0; n < nCols; ++n )
1232 DB_Column* pDBCol = aColArr[ n ].get();
1233 OUString sIns;
1234 switch( pDBCol->eColType )
1236 case DB_Column::Type::FILLTEXT:
1237 sIns = *pDBCol->pText;
1238 break;
1240 case DB_Column::Type::SPLITPARA:
1241 rSh.SplitNode();
1242 // when the template is not the same as the follow template,
1243 // the selected has to be set newly
1244 if( pColl && &pColl->GetNextTextFormatColl() != pColl )
1245 rSh.SetTextFormatColl( pColl );
1246 break;
1248 case DB_Column::Type::COL_FIELD:
1250 std::unique_ptr<SwDBField> pField(static_cast<SwDBField *>(
1251 pDBCol->pField->CopyField().release()));
1252 double nValue = DBL_MAX;
1254 Reference< XPropertySet > xColumnProps;
1255 xCols->getByName(pDBCol->pColInfo->sColumn) >>= xColumnProps;
1257 pField->SetExpansion( SwDBManager::GetDBField(
1258 xColumnProps,
1259 aDBFormatData,
1260 &nValue ) );
1261 if( DBL_MAX != nValue )
1263 Any aType = xColumnProps->getPropertyValue("Type");
1264 sal_Int32 eDataType = 0;
1265 aType >>= eDataType;
1266 if( DataType::DATE == eDataType || DataType::TIME == eDataType ||
1267 DataType::TIMESTAMP == eDataType)
1270 ::Date aStandard(1,1,1900);
1271 ::Date aCompare(aDBFormatData.aNullDate.Day ,
1272 aDBFormatData.aNullDate.Month,
1273 aDBFormatData.aNullDate.Year);
1274 if(aStandard != aCompare)
1275 nValue += (aStandard - aCompare);
1277 pField->ChgValue( nValue, true );
1279 pField->SetInitialized();
1281 rSh.InsertField2( *pField );
1283 break;
1285 case DB_Column::Type::COL_TEXT:
1287 double nValue = DBL_MAX;
1288 Reference< XPropertySet > xColumnProps;
1289 xCols->getByName(pDBCol->pColInfo->sColumn) >>= xColumnProps;
1290 sIns = SwDBManager::GetDBField(
1291 xColumnProps,
1292 aDBFormatData,
1293 &nValue );
1294 if( pDBCol->nFormat &&
1295 DBL_MAX != nValue )
1297 const Color* pCol;
1298 if(rNumFormatr.GetType(pDBCol->nFormat) & SvNumFormatType::DATE)
1300 ::Date aStandard(1,1,1900);
1301 if (rNumFormatr.GetNullDate() != aStandard)
1302 nValue += (aStandard - rNumFormatr.GetNullDate());
1304 rNumFormatr.GetOutputString( nValue,
1305 pDBCol->nFormat,
1306 sIns, &pCol );
1309 break;
1312 if( !sIns.isEmpty() )
1314 rSh.Insert( sIns );
1316 if( bSetCursor)
1318 // to the beginning and set a mark, so that
1319 // the cursor can be set to the initial position
1320 // at the end.
1322 rSh.SwCursorShell::MovePara(
1323 GoCurrPara, fnParaStart );
1324 pMark = rSh.SetBookmark(
1325 vcl::KeyCode(),
1326 OUString(),
1327 IDocumentMarkAccess::MarkType::UNO_BOOKMARK );
1328 rSh.SwCursorShell::MovePara(
1329 GoCurrPara, fnParaEnd );
1330 bSetCursor = false;
1335 if( !pSelection )
1337 bool bNext = xResultSet->next();
1338 if(!bNext)
1339 break;
1341 else if( i+1 >= rSelection.getLength() )
1342 break;
1344 if( m_xRbAsField->get_active() )
1345 rSh.InsertField2( aNxtDBField );
1347 if( !rSh.IsSttPara() )
1348 rSh.SwEditShell::SplitNode();
1350 if( 10 == i )
1351 oWait.emplace( *m_pView->GetDocShell(), true );
1354 if( !bSetCursor && pMark != nullptr)
1356 rSh.SetMark();
1357 rSh.GotoMark( pMark );
1358 rSh.getIDocumentMarkAccess()->deleteMark( pMark );
1359 break;
1363 // write configuration
1364 Commit();
1365 }while( false ); // middle checked loop
1367 if( bUndo )
1369 rSh.DoUndo();
1370 rSh.AppendUndoForInsertFromDB( bAsTable );
1371 rSh.EndUndo();
1373 rSh.ClearMark();
1374 rSh.EndAllAction();
1376 if ( bDisposeResultSet )
1377 ::comphelper::disposeComponent(xResultSet);
1380 void SwInsertDBColAutoPilot::SetTabSet()
1382 SwWrtShell& rSh = m_pView->GetWrtShell();
1383 const SfxPoolItem* pItem;
1385 if (m_xTAutoFormat)
1387 if (m_xTAutoFormat->IsFrame())
1389 // border is from AutoFormat
1390 m_pTableSet->ClearItem( RES_BOX );
1391 m_pTableSet->ClearItem( SID_ATTR_BORDER_INNER );
1393 if (m_xTAutoFormat->IsBackground())
1395 m_pTableSet->ClearItem( RES_BACKGROUND );
1396 m_pTableSet->ClearItem( SID_ATTR_BRUSH_ROW );
1397 m_pTableSet->ClearItem( SID_ATTR_BRUSH_TABLE );
1400 else
1402 // remove the defaults again, it makes no sense to set them
1403 SvxBrushItem aBrush( RES_BACKGROUND );
1404 static const sal_uInt16 aIds[3] =
1405 { RES_BACKGROUND, SID_ATTR_BRUSH_ROW, SID_ATTR_BRUSH_TABLE };
1406 for(sal_uInt16 i : aIds)
1407 if( SfxItemState::SET == m_pTableSet->GetItemState( i,
1408 false, &pItem ) && *pItem == aBrush )
1409 m_pTableSet->ClearItem( i );
1412 const SfxStringItem* pTableNameItem = m_pTableSet->GetItemIfSet( FN_PARAM_TABLE_NAME, false);
1413 if( pTableNameItem && pTableNameItem->GetValue() == rSh.GetTableFormat()->GetName() )
1414 m_pTableSet->ClearItem( FN_PARAM_TABLE_NAME );
1416 rSh.MoveTable( GotoCurrTable, fnTableStart );
1417 rSh.SetMark();
1418 rSh.MoveTable( GotoCurrTable, fnTableEnd );
1420 ItemSetToTableParam( *m_pTableSet, rSh );
1422 rSh.ClearMark();
1423 rSh.MoveTable( GotoCurrTable, fnTableStart );
1426 static Sequence<OUString> lcl_createSourceNames(std::u16string_view rNodeName)
1428 Sequence<OUString> aSourceNames(11);
1429 OUString* pNames = aSourceNames.getArray();
1430 pNames[0] = OUString::Concat(rNodeName) + "/DataSource";
1431 pNames[1] = OUString::Concat(rNodeName) + "/Command";
1432 pNames[2] = OUString::Concat(rNodeName) + "/CommandType";
1433 pNames[3] = OUString::Concat(rNodeName) + "/ColumnsToText";
1434 pNames[4] = OUString::Concat(rNodeName) + "/ColumnsToTable";
1435 pNames[5] = OUString::Concat(rNodeName) + "/ParaStyle";
1436 pNames[6] = OUString::Concat(rNodeName) + "/TableAutoFormat";
1437 pNames[7] = OUString::Concat(rNodeName) + "/IsTable";
1438 pNames[8] = OUString::Concat(rNodeName) + "/IsField";
1439 pNames[9] = OUString::Concat(rNodeName) + "/IsHeadlineOn";
1440 pNames[10] = OUString::Concat(rNodeName) + "/IsEmptyHeadline";
1441 return aSourceNames;
1444 static Sequence<OUString> lcl_CreateSubNames(std::u16string_view rSubNodeName)
1446 return
1448 OUString::Concat(rSubNodeName) + "/ColumnName",
1449 OUString::Concat(rSubNodeName) + "/ColumnIndex",
1450 OUString::Concat(rSubNodeName) + "/IsNumberFormat",
1451 OUString::Concat(rSubNodeName) + "/IsNumberFormatFromDataBase",
1452 OUString::Concat(rSubNodeName) + "/NumberFormat",
1453 OUString::Concat(rSubNodeName) + "/NumberFormatLocale"
1457 static OUString lcl_CreateUniqueName(const Sequence<OUString>& aNames)
1459 sal_Int32 nIdx = aNames.getLength();
1460 while(true)
1462 const OUString sRet = "_" + OUString::number(nIdx++);
1463 if ( comphelper::findValue(aNames, sRet) == -1 )
1464 return sRet; // No match found, return unique name
1468 void SwInsertDBColAutoPilot::Notify( const css::uno::Sequence< OUString >& ) {}
1470 void SwInsertDBColAutoPilot::ImplCommit()
1472 Sequence <OUString> aNames = GetNodeNames(OUString());
1473 //remove entries that contain this data source + table at first
1474 for(OUString const & nodeName : std::as_const(aNames))
1476 Sequence<Any> aSourceProperties = GetProperties({ nodeName + "/DataSource", nodeName + "/Command" });
1477 const Any* pSourceProps = aSourceProperties.getArray();
1478 OUString sSource, sCommand;
1479 pSourceProps[0] >>= sSource;
1480 pSourceProps[1] >>= sCommand;
1481 if(sSource==m_aDBData.sDataSource && sCommand==m_aDBData.sCommand)
1483 ClearNodeElements(OUString(), { nodeName });
1487 aNames = GetNodeNames(OUString());
1488 OUString sNewNode = lcl_CreateUniqueName(aNames);
1489 Sequence<OUString> aNodeNames = lcl_createSourceNames(sNewNode);
1490 Sequence<PropertyValue> aValues(aNodeNames.getLength());
1491 PropertyValue* pValues = aValues.getArray();
1492 const OUString* pNodeNames = aNodeNames.getConstArray();
1493 for(sal_Int32 i = 0; i < aNodeNames.getLength(); i++)
1495 pValues[i].Name = "/" + pNodeNames[i];
1498 pValues[0].Value <<= m_aDBData.sDataSource;
1499 pValues[1].Value <<= m_aDBData.sCommand;
1500 pValues[2].Value <<= m_aDBData.nCommandType;
1501 pValues[3].Value <<= m_xEdDbText->get_text();
1503 OUString sTmp;
1504 const sal_Int32 nCnt = m_xLbTableCol->n_children();
1505 for( sal_Int32 n = 0; n < nCnt; ++n )
1506 sTmp += m_xLbTableCol->get_text(n) + "\x0a";
1508 if (!sTmp.isEmpty())
1509 pValues[4].Value <<= sTmp;
1511 if( m_sNoTmpl != (sTmp = m_xLbDbParaColl->get_active_text()) )
1512 pValues[5].Value <<= sTmp;
1514 if (m_xTAutoFormat)
1515 pValues[6].Value <<= m_xTAutoFormat->GetName();
1517 pValues[7].Value <<= m_xRbAsTable->get_active();
1518 pValues[8].Value <<= m_xRbAsField->get_active();
1519 pValues[9].Value <<= m_xCbTableHeadon->get_active();
1520 pValues[10].Value <<= m_xRbHeadlEmpty->get_active();
1522 SetSetProperties(OUString(), aValues);
1524 sNewNode += "/ColumnSet";
1526 LanguageType ePrevLang(0xffff);
1528 SvNumberFormatter& rNFormatr = *m_pView->GetWrtShell().GetNumberFormatter();
1529 for(size_t nCol = 0; nCol < m_aDBColumns.size(); nCol++)
1531 SwInsDBColumn* pColumn = m_aDBColumns[nCol].get();
1532 OUString sColumnInsertNode(sNewNode + "/__");
1533 if( nCol < 10 )
1534 sColumnInsertNode += "00";
1535 else if( nCol < 100 )
1536 sColumnInsertNode += "0";
1537 sColumnInsertNode += OUString::number( nCol );
1539 const Sequence <OUString> aSubNodeNames = lcl_CreateSubNames(sColumnInsertNode);
1540 Sequence<PropertyValue> aSubValues(aSubNodeNames.getLength());
1541 PropertyValue* pSubValues = aSubValues.getArray();
1542 sal_Int32 i = 0;
1544 for( const OUString& rSubNodeName : aSubNodeNames)
1545 pSubValues[i++].Name = rSubNodeName;
1546 pSubValues[0].Value <<= pColumn->sColumn;
1547 pSubValues[1].Value <<= i;
1548 pSubValues[2].Value <<= pColumn->bHasFormat;
1549 pSubValues[3].Value <<= pColumn->bIsDBFormat;
1551 SwStyleNameMapper::FillUIName( RES_POOLCOLL_STANDARD, sTmp );
1552 const SvNumberformat* pNF = rNFormatr.GetEntry( pColumn->nUsrNumFormat );
1553 LanguageType eLang;
1554 if( pNF )
1556 pSubValues[4].Value <<= pNF->GetFormatstring();
1557 eLang = pNF->GetLanguage();
1559 else
1561 pSubValues[4].Value <<= sTmp;
1562 eLang = GetAppLanguage();
1565 OUString sPrevLang;
1566 if( eLang != ePrevLang )
1568 sPrevLang = LanguageTag::convertToBcp47( eLang );
1569 ePrevLang = eLang;
1572 pSubValues[5].Value <<= sPrevLang;
1573 SetSetProperties(sNewNode, aSubValues);
1577 void SwInsertDBColAutoPilot::Load()
1579 const Sequence<OUString> aNames = GetNodeNames(OUString());
1580 SvNumberFormatter& rNFormatr = *m_pView->GetWrtShell().GetNumberFormatter();
1581 for(OUString const & nodeName : aNames)
1583 //search for entries with the appropriate data source and table
1584 Sequence<OUString> aSourceNames = lcl_createSourceNames(nodeName);
1586 Sequence< Any> aDataSourceProps = GetProperties(aSourceNames);
1587 const Any* pDataSourceProps = aDataSourceProps.getConstArray();
1588 OUString sSource, sCommand;
1589 sal_Int16 nCommandType;
1590 pDataSourceProps[0] >>= sSource;
1591 pDataSourceProps[1] >>= sCommand;
1592 pDataSourceProps[2] >>= nCommandType;
1593 if(sSource == m_aDBData.sDataSource && sCommand == m_aDBData.sCommand)
1595 DB_ColumnConfigData aNewData;
1597 pDataSourceProps[3] >>= aNewData.sEdit;
1598 pDataSourceProps[4] >>= aNewData.sTableList;
1599 pDataSourceProps[5] >>= aNewData.sTmplNm;
1600 pDataSourceProps[6] >>= aNewData.sTAutoFormatNm;
1601 if(pDataSourceProps[7].hasValue())
1602 aNewData.bIsTable = *o3tl::doAccess<bool>(pDataSourceProps[7]);
1603 if(pDataSourceProps[8].hasValue())
1604 aNewData.bIsField = *o3tl::doAccess<bool>(pDataSourceProps[8]);
1605 if(pDataSourceProps[9].hasValue())
1606 aNewData.bIsHeadlineOn = *o3tl::doAccess<bool>(pDataSourceProps[9]);
1607 if(pDataSourceProps[10].hasValue())
1608 aNewData.bIsEmptyHeadln = *o3tl::doAccess<bool>(pDataSourceProps[10]);
1610 const OUString sSubNodeName(nodeName + "/ColumnSet/");
1611 const Sequence <OUString> aSubNames = GetNodeNames(sSubNodeName);
1612 for(const OUString& rSubName : aSubNames)
1614 Sequence <OUString> aSubNodeNames =
1615 lcl_CreateSubNames(Concat2View(sSubNodeName + rSubName));
1616 Sequence< Any> aSubProps = GetProperties(aSubNodeNames);
1617 const Any* pSubProps = aSubProps.getConstArray();
1619 OUString sColumn;
1620 pSubProps[0] >>= sColumn;
1621 // check for existence of the loaded column name
1622 bool bFound = false;
1623 for(size_t nRealColumn = 0; nRealColumn < m_aDBColumns.size(); ++nRealColumn)
1625 if(m_aDBColumns[nRealColumn]->sColumn == sColumn)
1627 bFound = true;
1628 break;
1631 if(!bFound)
1632 continue;
1633 sal_Int16 nIndex = 0;
1634 pSubProps[1] >>= nIndex;
1635 std::unique_ptr<SwInsDBColumn> pInsDBColumn(new SwInsDBColumn(sColumn));
1636 if(pSubProps[2].hasValue())
1637 pInsDBColumn->bHasFormat = *o3tl::doAccess<bool>(pSubProps[2]);
1638 if(pSubProps[3].hasValue())
1639 pInsDBColumn->bIsDBFormat = *o3tl::doAccess<bool>(pSubProps[3]);
1641 pSubProps[4] >>= pInsDBColumn->sUsrNumFormat;
1642 OUString sNumberFormatLocale;
1643 pSubProps[5] >>= sNumberFormatLocale;
1645 /* XXX Earlier versions wrote a Country-Language string in
1646 * SwInsertDBColAutoPilot::Commit() that here was read as
1647 * Language-Country with 2 characters copied to language,
1648 * 1 character separator and unconditionally 2 characters read
1649 * as country. So for 'DE-de' and locales that have similar
1650 * case-insensitive equal language/country combos that may have
1651 * worked, for all others not. FIXME if you need to read old
1652 * data that you were never able to read before. */
1653 pInsDBColumn->eUsrNumFormatLng = LanguageTag::convertToLanguageType( sNumberFormatLocale );
1655 pInsDBColumn->nUsrNumFormat = rNFormatr.GetEntryKey( pInsDBColumn->sUsrNumFormat,
1656 pInsDBColumn->eUsrNumFormatLng );
1658 aNewData.aDBColumns.insert(std::move(pInsDBColumn));
1660 OUString sTmp( aNewData.sTableList );
1661 if( !sTmp.isEmpty() )
1663 sal_Int32 n = 0;
1664 do {
1665 const OUString sEntry( sTmp.getToken( 0, '\x0a', n ) );
1666 //preselect column - if they still exist!
1667 if (m_xLbTableDbColumn->find_text(sEntry) != -1)
1669 m_xLbTableCol->append_text(sEntry);
1670 m_xLbTableDbColumn->remove_text(sEntry);
1672 } while( n>=0 );
1674 if (!m_xLbTableDbColumn->n_children())
1676 m_xIbDbcolAllTo->set_sensitive( false );
1677 m_xIbDbcolOneTo->set_sensitive( false );
1679 m_xIbDbcolOneFrom->set_sensitive(true);
1680 m_xIbDbcolAllFrom->set_sensitive(true);
1682 m_xEdDbText->set_text( aNewData.sEdit );
1684 sTmp = aNewData.sTmplNm;
1685 if( !sTmp.isEmpty() )
1686 m_xLbDbParaColl->set_active_text(sTmp);
1687 else
1688 m_xLbDbParaColl->set_active(0);
1690 m_xTAutoFormat.reset();
1691 sTmp = aNewData.sTAutoFormatNm;
1692 if( !sTmp.isEmpty() )
1694 // then load the AutoFormat file and look for Autoformat first
1695 SwTableAutoFormatTable aAutoFormatTable;
1696 aAutoFormatTable.Load();
1697 for( size_t nAutoFormat = aAutoFormatTable.size(); nAutoFormat; )
1698 if( sTmp == aAutoFormatTable[ --nAutoFormat ].GetName() )
1700 m_xTAutoFormat.reset(new SwTableAutoFormat(aAutoFormatTable[nAutoFormat]));
1701 break;
1705 m_xRbAsTable->set_active( aNewData.bIsTable );
1706 m_xRbAsField->set_active( aNewData.bIsField );
1707 m_xRbAsText->set_active( !aNewData.bIsTable && !aNewData.bIsField );
1709 m_xCbTableHeadon->set_active( aNewData.bIsHeadlineOn );
1710 m_xRbHeadlColnms->set_active( !aNewData.bIsEmptyHeadln );
1711 m_xRbHeadlEmpty->set_active( aNewData.bIsEmptyHeadln );
1712 HeaderHdl(*m_xCbTableHeadon);
1714 // now copy the user defined Numberformat strings to the
1715 // Shell. Then only these are available as ID
1716 for( size_t n = 0; n < m_aDBColumns.size() ; ++n )
1718 SwInsDBColumn& rSet = *m_aDBColumns[ n ];
1719 for( size_t m = 0; m < aNewData.aDBColumns.size() ; ++m )
1721 SwInsDBColumn& rGet = *aNewData.aDBColumns[ m ];
1722 if(rGet.sColumn == rSet.sColumn)
1724 if( rGet.bHasFormat && !rGet.bIsDBFormat )
1726 rSet.bIsDBFormat = false;
1727 rSet.nUsrNumFormat = rNFormatr.GetEntryKey( rGet.sUsrNumFormat,
1728 rGet.eUsrNumFormatLng );
1729 if( NUMBERFORMAT_ENTRY_NOT_FOUND == rSet.nUsrNumFormat )
1731 sal_Int32 nCheckPos;
1732 SvNumFormatType nType;
1733 rNFormatr.PutEntry( rGet.sUsrNumFormat, nCheckPos, nType,
1734 rSet.nUsrNumFormat, rGet.eUsrNumFormatLng );
1737 break;
1742 // when the cursor is inside of a table, table must NEVER be selectable
1743 if( !m_xRbAsTable->get_sensitive() && m_xRbAsTable->get_active() )
1744 m_xRbAsField->set_active(true);
1745 break;
1750 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */