1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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>
28 using namespace ::com::sun::star::uno
;
29 using namespace ::com::sun::star::beans
;
30 using namespace ::com::sun::star::container
;
31 using namespace ::com::sun::star::sdbc
;
32 using namespace ::com::sun::star::sdbcx
;
33 using namespace dbaui
;
35 namespace CopyTableOperation
= ::com::sun::star::sdb::application::CopyTableOperation
;
37 OUString
OWizColumnSelect::GetTitle() const { return DBA_RES(STR_WIZ_COLUMN_SELECT_TITLE
); }
39 OWizardPage::OWizardPage(weld::Container
* pPage
, OCopyTableWizard
* pWizard
, const OUString
& rUIXMLDescription
, const OString
& rID
)
40 : ::vcl::OWizardPage(pPage
, pWizard
, rUIXMLDescription
, rID
)
46 OWizardPage::~OWizardPage()
51 OWizColumnSelect::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"))
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
));
65 m_xOrgColumnNames
->set_selection_mode(SelectionMode::Multiple
);
66 m_xNewColumnNames
->set_selection_mode(SelectionMode::Multiple
);
68 m_xOrgColumnNames
->connect_row_activated(LINK(this,OWizColumnSelect
,ListDoubleClickHdl
));
69 m_xNewColumnNames
->connect_row_activated(LINK(this,OWizColumnSelect
,ListDoubleClickHdl
));
72 OWizColumnSelect::~OWizColumnSelect()
74 while (m_xNewColumnNames
->n_children())
76 delete reinterpret_cast<OFieldDescription
*>(m_xNewColumnNames
->get_id(0).toInt64());
77 m_xNewColumnNames
->remove(0);
81 void OWizColumnSelect::Reset()
83 // restore original state
84 clearListBox(*m_xOrgColumnNames
);
85 clearListBox(*m_xNewColumnNames
);
86 m_pParent
->m_mNameMapping
.clear();
88 // insert the source columns in the left listbox
89 const ODatabaseExport::TColumnVector
& rSrcColumns
= m_pParent
->getSrcVector();
91 for (auto const& column
: rSrcColumns
)
93 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(column
->second
)));
94 m_xOrgColumnNames
->append(sId
, column
->first
);
97 if (m_xOrgColumnNames
->n_children())
98 m_xOrgColumnNames
->select(0);
100 m_bFirstTime
= false;
103 void OWizColumnSelect::Activate( )
105 // if there are no dest columns reset the left side with the original columns
106 if(m_pParent
->getDestColumns().empty())
109 clearListBox(*m_xNewColumnNames
);
111 const ODatabaseExport::TColumnVector
& rDestColumns
= m_pParent
->getDestVector();
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();
120 for (auto const& column
: rDestColumns
)
122 if (rSrcColumns
.find(column
->first
) != rSrcColumns
.end())
124 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(new OFieldDescription(*(column
->second
)))));
125 m_xNewColumnNames
->append(sId
, column
->first
);
126 int nRemove
= m_xOrgColumnNames
->find_text(column
->first
);
128 m_xOrgColumnNames
->remove(nRemove
);
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();
136 bool OWizColumnSelect::LeavePage()
139 m_pParent
->clearDestColumns();
141 for(sal_Int32 i
=0 ; i
< m_xNewColumnNames
->n_children();++i
)
143 OFieldDescription
* pField
= reinterpret_cast<OFieldDescription
*>(m_xNewColumnNames
->get_id(i
).toInt64());
144 OSL_ENSURE(pField
,"The field information can not be null!");
145 m_pParent
->insertColumn(i
,pField
);
148 clearListBox(*m_xNewColumnNames
);
150 if ( m_pParent
->GetPressedButton() == OCopyTableWizard::WIZARD_NEXT
151 || m_pParent
->GetPressedButton() == OCopyTableWizard::WIZARD_FINISH
153 return !m_pParent
->getDestColumns().empty();
158 IMPL_LINK(OWizColumnSelect
, ButtonClickHdl
, weld::Button
&, rButton
, void)
160 weld::TreeView
*pLeft
= nullptr;
161 weld::TreeView
*pRight
= nullptr;
164 if (&rButton
== m_xColumn_RH
.get())
166 pLeft
= m_xOrgColumnNames
.get();
167 pRight
= m_xNewColumnNames
.get();
169 else if (&rButton
== m_xColumn_LH
.get())
171 pLeft
= m_xNewColumnNames
.get();
172 pRight
= m_xOrgColumnNames
.get();
174 else if (&rButton
== m_xColumns_RH
.get())
176 pLeft
= m_xOrgColumnNames
.get();
177 pRight
= m_xNewColumnNames
.get();
180 else if (&rButton
== m_xColumns_LH
.get())
182 pLeft
= m_xNewColumnNames
.get();
183 pRight
= m_xOrgColumnNames
.get();
187 if (!pLeft
|| !pRight
)
190 Reference
< XDatabaseMetaData
> xMetaData( m_pParent
->m_xDestConnection
->getMetaData() );
191 OUString sExtraChars
= xMetaData
->getExtraNameCharacters();
192 sal_Int32 nMaxNameLen
= m_pParent
->getMaxColumnNameLength();
194 ::comphelper::UStringMixEqual
aCase(xMetaData
->supportsMixedCaseQuotedIdentifiers());
195 std::vector
< OUString
> aRightColumns
;
196 fillColumns(pRight
,aRightColumns
);
200 auto aRows
= pLeft
->get_selected_rows();
201 std::sort(aRows
.begin(), aRows
.end());
203 for (auto it
= aRows
.begin(); it
!= aRows
.end(); ++it
)
204 moveColumn(pRight
,pLeft
,aRightColumns
,pLeft
->get_text(*it
),sExtraChars
,nMaxNameLen
,aCase
);
206 for (auto it
= aRows
.rbegin(); it
!= aRows
.rend(); ++it
)
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
; )
220 if (m_xOrgColumnNames
->n_children())
221 m_xOrgColumnNames
->select(0);
224 IMPL_LINK( OWizColumnSelect
, ListDoubleClickHdl
, weld::TreeView
&, rListBox
, bool )
226 weld::TreeView
*pLeft
,*pRight
;
227 if (&rListBox
== m_xOrgColumnNames
.get())
229 pLeft
= m_xOrgColumnNames
.get();
230 pRight
= m_xNewColumnNames
.get();
234 pRight
= m_xOrgColumnNames
.get();
235 pLeft
= m_xNewColumnNames
.get();
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();
243 ::comphelper::UStringMixEqual
aCase(xMetaData
->supportsMixedCaseQuotedIdentifiers());
244 std::vector
< OUString
> aRightColumns
;
245 fillColumns(pRight
,aRightColumns
);
247 auto aRows
= pLeft
->get_selected_rows();
248 std::sort(aRows
.begin(), aRows
.end());
250 for (auto it
= aRows
.begin(); it
!= aRows
.end(); ++it
)
251 moveColumn(pRight
,pLeft
,aRightColumns
,pLeft
->get_text(*it
),sExtraChars
,nMaxNameLen
,aCase
);
253 for (auto it
= aRows
.rbegin(); it
!= aRows
.rend(); ++it
)
261 void OWizColumnSelect::clearListBox(weld::TreeView
& rListBox
)
266 void OWizColumnSelect::fillColumns(weld::TreeView
const * pRight
,std::vector
< OUString
> &_rRightColumns
)
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
));
274 void OWizColumnSelect::createNewColumn( weld::TreeView
* _pListbox
,
275 OFieldDescription
const * _pSrcField
,
276 std::vector
< OUString
>& _rRightColumns
,
277 const OUString
& _sColumnName
,
278 const OUString
& _sExtraChars
,
279 sal_Int32 _nMaxNameLen
,
280 const ::comphelper::UStringMixEqual
& _aCase
)
282 OUString sConvertedName
= m_pParent
->convertColumnName(TMultiListBoxEntryFindFunctor(&_rRightColumns
,_aCase
),
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);
293 _pListbox
->append(OUString::number(reinterpret_cast<sal_Int64
>(pNewField
)), sConvertedName
);
294 _rRightColumns
.push_back(sConvertedName
);
297 m_pParent
->showColumnTypeNotSupported(sConvertedName
);
300 void OWizColumnSelect::moveColumn( weld::TreeView
* _pRight
,
301 weld::TreeView
const * _pLeft
,
302 std::vector
< OUString
>& _rRightColumns
,
303 const OUString
& _sColumnName
,
304 const OUString
& _sExtraChars
,
305 sal_Int32 _nMaxNameLen
,
306 const ::comphelper::UStringMixEqual
& _aCase
)
308 if(_pRight
== m_xNewColumnNames
.get())
310 // we copy the column into the new format for the dest
311 OFieldDescription
* pSrcField
= reinterpret_cast<OFieldDescription
*>(_pLeft
->get_id(_pLeft
->find_text(_sColumnName
)).toInt64());
312 createNewColumn(_pRight
,pSrcField
,_rRightColumns
,_sColumnName
,_sExtraChars
,_nMaxNameLen
,_aCase
);
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
);
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() )
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
);
335 OUString
sId(OUString::number(reinterpret_cast<sal_Int64
>(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
);
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().
348 sal_Int32
OWizColumnSelect::adjustColumnPosition(weld::TreeView
const * _pLeft
,
349 const OUString
& _sColumnName
,
350 ODatabaseExport::TColumnVector::size_type nCurrentPos
,
351 const ::comphelper::UStringMixEqual
& _aCase
)
353 sal_Int32 nAdjustedPos
= 0;
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())
360 const sal_Int32 nCount
= _pLeft
->n_children();
361 OUString sColumnString
;
362 for(sal_Int32 i
=0; i
< nCount
; ++i
)
364 sColumnString
= _pLeft
->get_text(i
);
365 if(_sColumnName
!= sColumnString
)
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
);
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() )
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
)
393 void OWizColumnSelect::enableButtons()
395 bool bEntries
= m_xNewColumnNames
->n_children() != 0;
397 m_pParent
->m_mNameMapping
.clear();
399 m_pParent
->GetOKButton().set_sensitive(bEntries
);
400 m_pParent
->EnableNextButton(bEntries
&& m_pParent
->getOperation() != CopyTableOperation::AppendData
);
403 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */