LibreOffice Module dbaccess (master) 1
WColumnSelect.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <WColumnSelect.hxx>
21#include <strings.hrc>
22#include <osl/diagnose.h>
23#include <WCopyTable.hxx>
24#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
25#include <core_resource.hxx>
26#include <com/sun/star/sdb/application/CopyTableOperation.hpp>
27
28using namespace ::com::sun::star::uno;
29using namespace ::com::sun::star::beans;
30using namespace ::com::sun::star::container;
31using namespace ::com::sun::star::sdbc;
32using namespace ::com::sun::star::sdbcx;
33using namespace dbaui;
34
35namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation;
36
37OUString OWizColumnSelect::GetTitle() const { return DBA_RES(STR_WIZ_COLUMN_SELECT_TITLE); }
38
39OWizardPage::OWizardPage(weld::Container* pPage, OCopyTableWizard* pWizard, const OUString& rUIXMLDescription, const OUString& rID)
40 : ::vcl::OWizardPage(pPage, pWizard, rUIXMLDescription, rID)
41 , m_pParent(pWizard)
42 , m_bFirstTime(true)
43{
44}
45
47{
48}
49
50// OWizColumnSelect
51OWizColumnSelect::OWizColumnSelect(weld::Container* pPage, OCopyTableWizard* pWizard)
52 : OWizardPage(pPage, pWizard, "dbaccess/ui/applycolpage.ui", "ApplyColPage")
53 , m_xOrgColumnNames(m_xBuilder->weld_tree_view("from"))
54 , m_xColumn_RH(m_xBuilder->weld_button("colrh"))
55 , m_xColumns_RH(m_xBuilder->weld_button("colsrh"))
56 , m_xColumn_LH(m_xBuilder->weld_button("collh"))
57 , m_xColumns_LH(m_xBuilder->weld_button("colslh"))
58 , m_xNewColumnNames(m_xBuilder->weld_tree_view("to"))
59{
60 m_xColumn_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
61 m_xColumn_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
62 m_xColumns_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
63 m_xColumns_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl));
64
65 m_xOrgColumnNames->set_selection_mode(SelectionMode::Multiple);
66 m_xNewColumnNames->set_selection_mode(SelectionMode::Multiple);
67
68 m_xOrgColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl));
69 m_xNewColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl));
70}
71
73{
74 while (m_xNewColumnNames->n_children())
75 {
76 delete weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(0));
77 m_xNewColumnNames->remove(0);
78 }
79}
80
82{
83 // restore original state
86 m_pParent->m_mNameMapping.clear();
87
88 // insert the source columns in the left listbox
89 const ODatabaseExport::TColumnVector& rSrcColumns = m_pParent->getSrcVector();
90
91 for (auto const& column : rSrcColumns)
92 {
93 OUString sId(weld::toId(column->second));
94 m_xOrgColumnNames->append(sId, column->first);
95 }
96
97 if (m_xOrgColumnNames->n_children())
98 m_xOrgColumnNames->select(0);
99
100 m_bFirstTime = false;
101}
102
104{
105 // if there are no dest columns reset the left side with the original columns
106 if(m_pParent->getDestColumns().empty())
107 Reset();
108
110
111 const ODatabaseExport::TColumnVector& rDestColumns = m_pParent->getDestVector();
112
113 // tdf#113923, the added columns must exist in the table
114 // in the case where:
115 // 1: we enabled the creation of a primary key
116 // 2: we come back here from the "Back" button of the next page,
117 // we want to avoid to list the new column generated in the next page
118 const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns();
119
120 for (auto const& column : rDestColumns)
121 {
122 if (rSrcColumns.find(column->first) != rSrcColumns.end())
123 {
124 OUString sId(weld::toId(new OFieldDescription(*(column->second))));
125 m_xNewColumnNames->append(sId, column->first);
126 int nRemove = m_xOrgColumnNames->find_text(column->first);
127 if (nRemove != -1)
128 m_xOrgColumnNames->remove(nRemove);
129 }
130 }
131 m_pParent->GetOKButton().set_sensitive(m_xNewColumnNames->n_children() != 0);
132 m_pParent->EnableNextButton(m_xNewColumnNames->n_children() && m_pParent->getOperation() != CopyTableOperation::AppendData);
133 m_xColumns_RH->grab_focus();
134}
135
137{
138
139 m_pParent->clearDestColumns();
140
141 for(sal_Int32 i=0 ; i< m_xNewColumnNames->n_children();++i)
142 {
143 OFieldDescription* pField = weld::fromId<OFieldDescription*>(m_xNewColumnNames->get_id(i));
144 OSL_ENSURE(pField,"The field information can not be null!");
145 m_pParent->insertColumn(i,pField);
146 }
147
149
150 if ( m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_NEXT
151 || m_pParent->GetPressedButton() == OCopyTableWizard::WIZARD_FINISH
152 )
153 return !m_pParent->getDestColumns().empty();
154 else
155 return true;
156}
157
158IMPL_LINK(OWizColumnSelect, ButtonClickHdl, weld::Button&, rButton, void)
159{
160 weld::TreeView *pLeft = nullptr;
161 weld::TreeView *pRight = nullptr;
162 bool bAll = false;
163
164 if (&rButton == m_xColumn_RH.get())
165 {
166 pLeft = m_xOrgColumnNames.get();
167 pRight = m_xNewColumnNames.get();
168 }
169 else if (&rButton == m_xColumn_LH.get())
170 {
171 pLeft = m_xNewColumnNames.get();
172 pRight = m_xOrgColumnNames.get();
173 }
174 else if (&rButton == m_xColumns_RH.get())
175 {
176 pLeft = m_xOrgColumnNames.get();
177 pRight = m_xNewColumnNames.get();
178 bAll = true;
179 }
180 else if (&rButton == m_xColumns_LH.get())
181 {
182 pLeft = m_xNewColumnNames.get();
183 pRight = m_xOrgColumnNames.get();
184 bAll = true;
185 }
186
187 if (!pLeft || !pRight)
188 return;
189
190 Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() );
191 OUString sExtraChars = xMetaData->getExtraNameCharacters();
192 sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength();
193
194 ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers());
195 std::vector< OUString> aRightColumns;
196 fillColumns(pRight,aRightColumns);
197
198 if(!bAll)
199 {
200 auto aRows = pLeft->get_selected_rows();
201 std::sort(aRows.begin(), aRows.end());
202
203 for (auto it = aRows.begin(); it != aRows.end(); ++it)
204 moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase);
205
206 for (auto it = aRows.rbegin(); it != aRows.rend(); ++it)
207 pLeft->remove(*it);
208 }
209 else
210 {
211 const sal_Int32 nEntries = pLeft->n_children();
212 for(sal_Int32 i=0; i < nEntries; ++i)
213 moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(i),sExtraChars,nMaxNameLen,aCase);
214 for(sal_Int32 j=pLeft->n_children(); j ; )
215 pLeft->remove(--j);
216 }
217
218 enableButtons();
219
220 if (m_xOrgColumnNames->n_children())
221 m_xOrgColumnNames->select(0);
222}
223
224IMPL_LINK( OWizColumnSelect, ListDoubleClickHdl, weld::TreeView&, rListBox, bool )
225{
226 weld::TreeView *pLeft,*pRight;
227 if (&rListBox == m_xOrgColumnNames.get())
228 {
229 pLeft = m_xOrgColumnNames.get();
230 pRight = m_xNewColumnNames.get();
231 }
232 else
233 {
234 pRight = m_xOrgColumnNames.get();
235 pLeft = m_xNewColumnNames.get();
236 }
237
238 // If database is able to process PrimaryKeys, set PrimaryKey
239 Reference< XDatabaseMetaData > xMetaData( m_pParent->m_xDestConnection->getMetaData() );
240 OUString sExtraChars = xMetaData->getExtraNameCharacters();
241 sal_Int32 nMaxNameLen = m_pParent->getMaxColumnNameLength();
242
243 ::comphelper::UStringMixEqual aCase(xMetaData->supportsMixedCaseQuotedIdentifiers());
244 std::vector< OUString> aRightColumns;
245 fillColumns(pRight,aRightColumns);
246
247 auto aRows = pLeft->get_selected_rows();
248 std::sort(aRows.begin(), aRows.end());
249
250 for (auto it = aRows.begin(); it != aRows.end(); ++it)
251 moveColumn(pRight,pLeft,aRightColumns,pLeft->get_text(*it),sExtraChars,nMaxNameLen,aCase);
252
253 for (auto it = aRows.rbegin(); it != aRows.rend(); ++it)
254 pLeft->remove(*it);
255
256 enableButtons();
257
258 return true;
259}
260
262{
263 rListBox.clear();
264}
265
266void OWizColumnSelect::fillColumns(weld::TreeView const * pRight,std::vector< OUString> &_rRightColumns)
267{
268 const sal_Int32 nCount = pRight->n_children();
269 _rRightColumns.reserve(nCount);
270 for (sal_Int32 i=0; i < nCount; ++i)
271 _rRightColumns.push_back(pRight->get_text(i));
272}
273
275 OFieldDescription const * _pSrcField,
276 std::vector< OUString>& _rRightColumns,
277 const OUString& _sColumnName,
278 std::u16string_view _sExtraChars,
279 sal_Int32 _nMaxNameLen,
280 const ::comphelper::UStringMixEqual& _aCase)
281{
282 OUString sConvertedName = m_pParent->convertColumnName(TMultiListBoxEntryFindFunctor(&_rRightColumns,_aCase),
283 _sColumnName,
284 _sExtraChars,
285 _nMaxNameLen);
286 OFieldDescription* pNewField = new OFieldDescription(*_pSrcField);
287 pNewField->SetName(sConvertedName);
288 bool bNotConvert = true;
289 pNewField->SetType(m_pParent->convertType(_pSrcField->getSpecialTypeInfo(),bNotConvert));
290 if ( !m_pParent->supportsPrimaryKey() )
291 pNewField->SetPrimaryKey(false);
292
293 _pListbox->append(weld::toId(pNewField), sConvertedName);
294 _rRightColumns.push_back(sConvertedName);
295
296 if ( !bNotConvert )
297 m_pParent->showColumnTypeNotSupported(sConvertedName);
298}
299
301 weld::TreeView const * _pLeft,
302 std::vector< OUString>& _rRightColumns,
303 const OUString& _sColumnName,
304 std::u16string_view _sExtraChars,
305 sal_Int32 _nMaxNameLen,
306 const ::comphelper::UStringMixEqual& _aCase)
307{
308 if(_pRight == m_xNewColumnNames.get())
309 {
310 // we copy the column into the new format for the dest
311 OFieldDescription* pSrcField = weld::fromId<OFieldDescription*>(_pLeft->get_id(_pLeft->find_text(_sColumnName)));
312 createNewColumn(_pRight,pSrcField,_rRightColumns,_sColumnName,_sExtraChars,_nMaxNameLen,_aCase);
313 }
314 else
315 {
316 // find the new column in the dest name mapping to obtain the old column
317 OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(),
318 [&_aCase, &_sColumnName] (const OCopyTableWizard::TNameMapping::value_type& nameMap) {
319 return _aCase(nameMap.second, _sColumnName);
320 });
321
322 OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined");
323 if ( aIter == m_pParent->m_mNameMapping.end() )
324 return; // do nothing
325 const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns();
326 ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first);
327 if ( aSrcIter != rSrcColumns.end() )
328 {
329 // we need also the old position of this column to insert it back on that position again
330 const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector();
331 ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter);
332 OSL_ENSURE( aPos != rSrcVector.end(),"Invalid position for the iterator here!");
333 ODatabaseExport::TColumnVector::size_type nPos = (aPos - rSrcVector.begin()) - adjustColumnPosition(_pLeft, _sColumnName, (aPos - rSrcVector.begin()), _aCase);
334
335 OUString sId(weld::toId(aSrcIter->second));
336 const OUString& rStr = (*aIter).first;
337 _pRight->insert(nullptr, nPos, &rStr, &sId, nullptr, nullptr, false, nullptr);
338 _rRightColumns.push_back(rStr);
339 m_pParent->removeColumnNameFromNameMap(_sColumnName);
340 }
341 }
342}
343
344// Simply returning fields back to their original position is
345// not enough. We need to take into account what fields have
346// been removed earlier and adjust accordingly. Based on the
347// algorithm employed in moveColumn().
349 std::u16string_view _sColumnName,
350 ODatabaseExport::TColumnVector::size_type nCurrentPos,
351 const ::comphelper::UStringMixEqual& _aCase)
352{
353 sal_Int32 nAdjustedPos = 0;
354
355 // if returning all entries to their original position,
356 // then there is no need to adjust the positions.
357 if (m_xColumns_LH->has_focus())
358 return nAdjustedPos;
359
360 const sal_Int32 nCount = _pLeft->n_children();
361 OUString sColumnString;
362 for(sal_Int32 i=0; i < nCount; ++i)
363 {
364 sColumnString = _pLeft->get_text(i);
365 if(_sColumnName != sColumnString)
366 {
367 // find the new column in the dest name mapping to obtain the old column
368 OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(),
369 [&_aCase, &sColumnString] (const OCopyTableWizard::TNameMapping::value_type& nameMap) {
370 return _aCase(nameMap.second, sColumnString);
371 });
372
373 OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined");
374 const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns();
375 ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first);
376 if ( aSrcIter != rSrcColumns.end() )
377 {
378 // we need also the old position of this column to insert it back on that position again
379 const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector();
380 ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter);
381 ODatabaseExport::TColumnVector::size_type nPos = aPos - rSrcVector.begin();
382 if( nPos < nCurrentPos)
383 {
384 nAdjustedPos++;
385 }
386 }
387 }
388 }
389
390 return nAdjustedPos;
391}
392
394{
395 bool bEntries = m_xNewColumnNames->n_children() != 0;
396 if (!bEntries)
397 m_pParent->m_mNameMapping.clear();
398
399 m_pParent->GetOKButton().set_sensitive(bEntries);
400 m_pParent->EnableNextButton(bEntries && m_pParent->getOperation() != CopyTableOperation::AppendData);
401}
402
403/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::map< OUString, OFieldDescription *, ::comphelper::UStringMixLess > TColumns
Definition: DExport.hxx:57
std::vector< TColumns::const_iterator > TColumnVector
Definition: DExport.hxx:58
void SetPrimaryKey(bool _bPKey)
void SetType(const TOTypeInfoSP &_pType)
void SetName(const OUString &_rName)
TOTypeInfoSP getSpecialTypeInfo() const
std::unique_ptr< weld::TreeView > m_xOrgColumnNames
virtual void Activate() override
std::unique_ptr< weld::Button > m_xColumn_RH
std::unique_ptr< weld::Button > m_xColumns_RH
void createNewColumn(weld::TreeView *_pListbox, OFieldDescription const *_pSrcField, std::vector< OUString > &_rRightColumns, const OUString &_sColumnName, std::u16string_view _sExtraChars, sal_Int32 _nMaxNameLen, const ::comphelper::UStringMixEqual &_aCase)
virtual void Reset() override
virtual ~OWizColumnSelect() override
void moveColumn(weld::TreeView *_pRight, weld::TreeView const *_pLeft, std::vector< OUString > &_rRightColumns, const OUString &_sColumnName, std::u16string_view _sExtraChars, sal_Int32 _nMaxNameLen, const ::comphelper::UStringMixEqual &_aCase)
virtual bool LeavePage() override
sal_Int32 adjustColumnPosition(weld::TreeView const *_pLeft, std::u16string_view _sColumnName, ODatabaseExport::TColumnVector::size_type nCurrentPos, const ::comphelper::UStringMixEqual &_aCase)
std::unique_ptr< weld::Button > m_xColumns_LH
static void clearListBox(weld::TreeView &_rListBox)
std::unique_ptr< weld::Button > m_xColumn_LH
std::unique_ptr< weld::TreeView > m_xNewColumnNames
static void fillColumns(weld::TreeView const *pRight, std::vector< OUString > &_rRightColumns)
virtual ~OWizardPage() override
OWizardPage(weld::Container *pPage, weld::DialogController *pController, const OUString &rUIXMLDescription, const OUString &rID)
virtual int find_text(const OUString &rText) const=0
virtual OUString get_text(int row, int col=-1) const=0
virtual int n_children() const=0
virtual void insert(const TreeIter *pParent, int pos, const OUString *pStr, const OUString *pId, const OUString *pIconName, VirtualDevice *pImageSurface, bool bChildrenOnDemand, TreeIter *pRet)=0
virtual void clear()=0
void append(TreeIter *pRet=nullptr)
virtual void remove(int pos)=0
virtual std::vector< int > get_selected_rows() const=0
virtual OUString get_id(int pos) const=0
#define DBA_RES(id)
int nCount
sal_uInt16 nPos
IMPL_LINK(OApplicationController, OnSelectContainer, void *, _pType, void)
int i
OUString toId(const void *pValue)
OUString sId
Definition: unodatbr.cxx:1040