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 
10 #include <dataproviderdlg.hxx>
11 
12 #include <document.hxx>
13 #include <dataprovider.hxx>
14 #include <datatransformation.hxx>
15 #include <datamapper.hxx>
16 #include <dbdata.hxx>
17 
18 #include <comphelper/string.hxx>
19 #include <sal/log.hxx>
20 #include <unotools/charclass.hxx>
21 #include <vcl/svapp.hxx>
22 
23 #include <utility>
24 
25 class ScDataProviderBaseControl
26 {
27     std::unique_ptr<weld::Builder> mxBuilder;
28     std::unique_ptr<weld::Container> mxGrid;
29     std::unique_ptr<weld::ComboBox> mxProviderList;
30     std::unique_ptr<weld::Entry> mxEditURL;
31     std::unique_ptr<weld::Entry> mxEditID;
32     std::unique_ptr<weld::Button> mxApplyBtn;
33 
34     OUString msApplyTooltip;
35 
36     Link<ScDataProviderBaseControl*, void> maImportCallback;
37 
38     DECL_LINK(ProviderSelectHdl, weld::ComboBox&, void);
39     DECL_LINK(IDEditHdl, weld::Entry&, void);
40     DECL_LINK(URLEditHdl, weld::Entry&, void);
41     DECL_LINK(ApplyBtnHdl, weld::Button&, void);
42 
43     void updateApplyBtn(bool bValidConfig);
44 
45 public:
46     ScDataProviderBaseControl(weld::Container* pParent, const Link<ScDataProviderBaseControl*, void>& rImportCallback);
47 
48     void isValid();
49 
50     sc::ExternalDataSource getDataSource(ScDocument* pDoc);
51 };
52 
ScDataProviderBaseControl(weld::Container * pParent,const Link<ScDataProviderBaseControl *,void> & rImportCallback)53 ScDataProviderBaseControl::ScDataProviderBaseControl(weld::Container* pParent,
54         const Link<ScDataProviderBaseControl*, void>& rImportCallback)
55     : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/dataproviderentry.ui"))
56     , mxGrid(mxBuilder->weld_container("grid"))
57     , mxProviderList(mxBuilder->weld_combo_box("provider_lst"))
58     , mxEditURL(mxBuilder->weld_entry("ed_url"))
59     , mxEditID(mxBuilder->weld_entry("ed_id"))
60     , mxApplyBtn(mxBuilder->weld_button("apply"))
61     , maImportCallback(rImportCallback)
62 {
63     auto aDataProvider = sc::DataProviderFactory::getDataProviders();
64     for (const auto& rDataProvider : aDataProvider)
65     {
66         mxProviderList->append_text(rDataProvider);
67     }
68 
69     mxProviderList->connect_changed(LINK(this, ScDataProviderBaseControl, ProviderSelectHdl));
70     mxEditID->connect_changed(LINK(this, ScDataProviderBaseControl, IDEditHdl));
71     mxEditURL->connect_changed(LINK(this, ScDataProviderBaseControl, URLEditHdl));
72 
73     msApplyTooltip = mxApplyBtn->get_tooltip_text();
74     mxApplyBtn->connect_clicked(LINK(this, ScDataProviderBaseControl, ApplyBtnHdl));
75     isValid();
76 }
77 
isValid()78 void ScDataProviderBaseControl::isValid()
79 {
80     bool bValid = !mxProviderList->get_active_text().isEmpty();
81     bValid &= !mxEditURL->get_text().isEmpty();
82     updateApplyBtn(bValid);
83 }
84 
getDataSource(ScDocument * pDoc)85 sc::ExternalDataSource ScDataProviderBaseControl::getDataSource(ScDocument* pDoc)
86 {
87     OUString aURL = mxEditURL->get_text();
88     OUString aProvider = mxProviderList->get_active_text();
89     sc::ExternalDataSource aSource(aURL, aProvider, pDoc);
90 
91     OUString aID = mxEditID->get_text();
92     aSource.setID(aID);
93     return aSource;
94 }
95 
updateApplyBtn(bool bValidConfig)96 void ScDataProviderBaseControl::updateApplyBtn(bool bValidConfig)
97 {
98     if (!bValidConfig)
99     {
100         mxApplyBtn->set_sensitive(false);
101         mxApplyBtn->set_tooltip_text(OUString());
102         return;
103     }
104 
105     mxApplyBtn->set_sensitive(true);
106     mxApplyBtn->set_tooltip_text(msApplyTooltip);
107 }
108 
IMPL_LINK_NOARG(ScDataProviderBaseControl,ProviderSelectHdl,weld::ComboBox &,void)109 IMPL_LINK_NOARG(ScDataProviderBaseControl, ProviderSelectHdl, weld::ComboBox&, void)
110 {
111     isValid();
112 }
113 
IMPL_LINK_NOARG(ScDataProviderBaseControl,IDEditHdl,weld::Entry &,void)114 IMPL_LINK_NOARG(ScDataProviderBaseControl, IDEditHdl, weld::Entry&, void)
115 {
116     isValid();
117 }
118 
IMPL_LINK_NOARG(ScDataProviderBaseControl,URLEditHdl,weld::Entry &,void)119 IMPL_LINK_NOARG(ScDataProviderBaseControl, URLEditHdl, weld::Entry&, void)
120 {
121     isValid();
122 }
123 
IMPL_LINK_NOARG(ScDataProviderBaseControl,ApplyBtnHdl,weld::Button &,void)124 IMPL_LINK_NOARG(ScDataProviderBaseControl, ApplyBtnHdl, weld::Button&, void)
125 {
126     updateApplyBtn(true);
127     maImportCallback.Call(this);
128 }
129 
130 class ScDataTransformationBaseControl
131 {
132 protected:
133     std::unique_ptr<weld::Builder> mxBuilder;
134     std::unique_ptr<weld::Container> mxGrid;
135     weld::Container* mpContainer;
136 
137     sal_uInt32 mnIndex;
138 
139 public:
140     ScDataTransformationBaseControl(weld::Container* pParent, const OUString& rUIFile, sal_uInt32 nIndex);
141     virtual ~ScDataTransformationBaseControl();
142 
updateIndex(sal_uInt32 nIndex)143     void updateIndex(sal_uInt32 nIndex) { mnIndex = nIndex; }
144 
145     virtual std::shared_ptr<sc::DataTransformation> getTransformation() = 0;
146 };
147 
ScDataTransformationBaseControl(weld::Container * pParent,const OUString & rUIFile,sal_uInt32 nIndex)148 ScDataTransformationBaseControl::ScDataTransformationBaseControl(weld::Container* pParent, const OUString& rUIFile, sal_uInt32 nIndex)
149     : mxBuilder(Application::CreateBuilder(pParent, rUIFile))
150     , mxGrid(mxBuilder->weld_container("grid"))
151     , mpContainer(pParent)
152     , mnIndex(nIndex)
153 {
154 }
155 
~ScDataTransformationBaseControl()156 ScDataTransformationBaseControl::~ScDataTransformationBaseControl()
157 {
158     mpContainer->move(mxGrid.get(), nullptr);
159 }
160 
161 namespace {
162 
163 struct MenuData
164 {
165     int nMenuID;
166     const char* aMenuName;
167     std::function<void(ScDataProviderDlg*)> maCallback;
168 };
169 
170 MenuData aStartData[] = {
171     { 0, "Apply & Quit", &ScDataProviderDlg::applyAndQuit },
172     { 1, "Cancel & Quit", &ScDataProviderDlg::cancelAndQuit }
173 };
174 
175 MenuData aColumnData[] = {
176     { 0, "Delete Column", &ScDataProviderDlg::deleteColumn },
177     { 1, "Split Column", &ScDataProviderDlg::splitColumn },
178     { 2, "Merge Columns", &ScDataProviderDlg::mergeColumns },
179     { 3, "Text Transformation", &ScDataProviderDlg::textTransformation },
180     { 4, "Sort Columns", &ScDataProviderDlg::sortTransformation },
181     { 5, "Aggregate Functions", &ScDataProviderDlg::aggregateFunction},
182     { 6, "Number Transformations", &ScDataProviderDlg::numberTransformation },
183     { 7, "Replace Null Transformations", &ScDataProviderDlg::replaceNullTransformation },
184     { 8, "Date & Time Transformations", &ScDataProviderDlg::dateTimeTransformation }
185 };
186 
187 class ScDeleteColumnTransformationControl : public ScDataTransformationBaseControl
188 {
189 private:
190     std::unique_ptr<weld::Entry> mxColumnNums;
191     std::unique_ptr<weld::Button> mxDelete;
192     std::function<void(sal_uInt32&)> maDeleteTransformation;
193     const ScDocument* mpDoc;
194 
195 public:
196     ScDeleteColumnTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 aIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
197 
198     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
199     DECL_LINK(DeleteHdl, weld::Button&, void);
200 };
201 
ScDeleteColumnTransformationControl(const ScDocument * pDoc,weld::Container * pParent,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)202 ScDeleteColumnTransformationControl::ScDeleteColumnTransformationControl(
203     const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
204     : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/deletecolumnentry.ui", nIndex)
205     , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
206     , mxDelete(mxBuilder->weld_button("ed_delete"))
207     , maDeleteTransformation(std::move(aDeleteTransformation))
208     , mpDoc(pDoc)
209 {
210     mxDelete->connect_clicked(LINK(this,ScDeleteColumnTransformationControl, DeleteHdl));
211 }
212 
getTransformation()213 std::shared_ptr<sc::DataTransformation> ScDeleteColumnTransformationControl::getTransformation()
214 {
215     OUString aColumnString = mxColumnNums->get_text();
216     std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
217     std::set<SCCOL> ColNums;
218     for (const auto& rColStr : aSplitColumns)
219     {
220         sal_Int32 nCol = rColStr.toInt32();
221         if (nCol <= 0)
222             continue;
223 
224         if (nCol > mpDoc->MaxCol())
225             continue;
226 
227         // translate from 1-based column notations to internal Calc one
228         ColNums.insert(nCol - 1);
229     }
230 
231     return std::make_shared<sc::ColumnRemoveTransformation>(ColNums);
232 }
233 
234 class ScSplitColumnTransformationControl : public ScDataTransformationBaseControl
235 {
236 private:
237     std::unique_ptr<weld::Entry> mxSeparator;
238     std::unique_ptr<weld::SpinButton> mxNumColumns;
239     std::unique_ptr<weld::Button> mxDelete;
240     SCCOL mnCol;
241     std::function<void(sal_uInt32&)> maDeleteTransformation;
242 
243 public:
244     ScSplitColumnTransformationControl(weld::Container* pParent, SCCOL nCol, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
245 
246     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
247     DECL_LINK(DeleteHdl, weld::Button&, void);
248 };
249 
ScSplitColumnTransformationControl(weld::Container * pParent,SCCOL nCol,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)250 ScSplitColumnTransformationControl::ScSplitColumnTransformationControl(
251     weld::Container* pParent, SCCOL nCol, sal_uInt32 nIndex,
252     std::function<void(sal_uInt32&)> aDeleteTransformation)
253     : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/splitcolumnentry.ui", nIndex)
254     , mxSeparator(mxBuilder->weld_entry("ed_separator"))
255     , mxNumColumns(mxBuilder->weld_spin_button("num_cols"))
256     , mxDelete(mxBuilder->weld_button("ed_delete"))
257     , mnCol(nCol)
258     , maDeleteTransformation(std::move(aDeleteTransformation))
259 {
260     mxDelete->connect_clicked(LINK(this,ScSplitColumnTransformationControl, DeleteHdl));
261 }
262 
getTransformation()263 std::shared_ptr<sc::DataTransformation> ScSplitColumnTransformationControl::getTransformation()
264 {
265     OUString aSeparator = mxSeparator->get_text();
266     sal_Unicode cSeparator = aSeparator.isEmpty() ? ',' : aSeparator[0];
267     return std::make_shared<sc::SplitColumnTransformation>(mnCol, cSeparator);
268 }
269 
270 class ScMergeColumnTransformationControl : public ScDataTransformationBaseControl
271 {
272 private:
273     std::unique_ptr<weld::Entry> mxSeparator;
274     std::unique_ptr<weld::Entry> mxEdColumns;
275     std::unique_ptr<weld::Button> mxDelete;
276     std::function<void(sal_uInt32&)> maDeleteTransformation;
277     const ScDocument* mpDoc;
278 
279 public:
280     ScMergeColumnTransformationControl(const ScDocument *pDoc, weld::Container* pParent, SCCOL nStartCol, SCCOL nEndCol, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
281 
282     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
283     DECL_LINK(DeleteHdl, weld::Button&, void);
284 };
285 
ScMergeColumnTransformationControl(const ScDocument * pDoc,weld::Container * pParent,SCCOL nStartCol,SCCOL nEndCol,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)286 ScMergeColumnTransformationControl::ScMergeColumnTransformationControl(
287     const ScDocument* pDoc, weld::Container* pParent, SCCOL nStartCol, SCCOL nEndCol, sal_uInt32 nIndex,
288     std::function<void(sal_uInt32&)> aDeleteTransformation)
289     : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/mergecolumnentry.ui", nIndex)
290     , mxSeparator(mxBuilder->weld_entry("ed_separator"))
291     , mxEdColumns(mxBuilder->weld_entry("ed_columns"))
292     , mxDelete(mxBuilder->weld_button("ed_delete"))
293     , maDeleteTransformation(std::move(aDeleteTransformation))
294     , mpDoc(pDoc)
295 {
296     mxDelete->connect_clicked(LINK(this,ScMergeColumnTransformationControl, DeleteHdl));
297 
298     OUStringBuffer aBuffer;
299 
300     // map from zero based to one based column numbers
301     aBuffer.append(static_cast<sal_Int32>(nStartCol + 1));
302     for ( SCCOL nCol = nStartCol + 1; nCol <= nEndCol; ++nCol)
303     {
304         aBuffer.append(";" + OUString::number(nCol + 1));
305     }
306 
307     mxEdColumns->set_text(aBuffer.makeStringAndClear());
308 }
309 
getTransformation()310 std::shared_ptr<sc::DataTransformation> ScMergeColumnTransformationControl::getTransformation()
311 {
312     OUString aColumnString = mxEdColumns->get_text();
313     std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
314     std::set<SCCOL> aMergedColumns;
315     for (const auto& rColStr : aSplitColumns)
316     {
317         sal_Int32 nCol = rColStr.toInt32();
318         if (nCol <= 0)
319             continue;
320 
321         if (nCol > mpDoc->MaxCol())
322             continue;
323 
324         // translate from 1-based column notations to internal Calc one
325         aMergedColumns.insert(nCol - 1);
326     }
327     return std::make_shared<sc::MergeColumnTransformation>(aMergedColumns, mxSeparator->get_text());
328 }
329 
330 class ScSortTransformationControl : public ScDataTransformationBaseControl
331 {
332 private:
333     std::unique_ptr<weld::CheckButton> mxAscending;
334     std::unique_ptr<weld::Entry> mxEdColumns;
335     std::unique_ptr<weld::Button> mxDelete;
336     std::function<void(sal_uInt32&)> maDeleteTransformation;
337     const ScDocument* mpDoc;
338 
339 public:
340     ScSortTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
341 
342     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
343     DECL_LINK(DeleteHdl, weld::Button&, void);
344 };
345 
ScSortTransformationControl(const ScDocument * pDoc,weld::Container * pParent,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)346 ScSortTransformationControl::ScSortTransformationControl(
347     const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
348     : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/sorttransformationentry.ui", nIndex)
349     , mxAscending(mxBuilder->weld_check_button("ed_ascending"))
350     , mxEdColumns(mxBuilder->weld_entry("ed_columns"))
351     , mxDelete(mxBuilder->weld_button("ed_delete"))
352     , maDeleteTransformation(std::move(aDeleteTransformation))
353     , mpDoc(pDoc)
354 {
355     mxDelete->connect_clicked(LINK(this,ScSortTransformationControl, DeleteHdl));
356 }
357 
getTransformation()358 std::shared_ptr<sc::DataTransformation> ScSortTransformationControl::getTransformation()
359 {
360     OUString aColStr = mxEdColumns->get_text();
361     bool aIsAscending = mxAscending->get_active();
362     SCCOL aColumn = 0;
363     sal_Int32 nCol = aColStr.toInt32();
364     if (nCol > 0 && nCol <= mpDoc->MaxCol())
365         aColumn = nCol - 1;     // translate from 1-based column notations to internal Calc one
366 
367     ScSortParam aSortParam;
368     ScSortKeyState aSortKey;
369     aSortKey.bDoSort = true;
370     aSortKey.nField = aColumn;
371     aSortKey.bAscending = aIsAscending;
372     aSortParam.maKeyState.push_back(aSortKey);
373     return std::make_shared<sc::SortTransformation>(aSortParam);
374 }
375 
376 class ScColumnTextTransformation : public ScDataTransformationBaseControl
377 {
378 private:
379     std::unique_ptr<weld::Entry> mxColumnNums;
380     std::unique_ptr<weld::ComboBox> mxType;
381     std::unique_ptr<weld::Button> mxDelete;
382     std::function<void(sal_uInt32&)> maDeleteTransformation;
383     const ScDocument* mpDoc;
384 
385 public:
386     ScColumnTextTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
387 
388     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
389     DECL_LINK(DeleteHdl, weld::Button&, void);
390 };
391 
ScColumnTextTransformation(const ScDocument * pDoc,weld::Container * pParent,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)392 ScColumnTextTransformation::ScColumnTextTransformation(
393     const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
394     : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/texttransformationentry.ui", nIndex)
395     , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
396     , mxType(mxBuilder->weld_combo_box("ed_lst"))
397     , mxDelete(mxBuilder->weld_button("ed_delete"))
398     , maDeleteTransformation(std::move(aDeleteTransformation))
399     , mpDoc(pDoc)
400 {
401     mxDelete->connect_clicked(LINK(this,ScColumnTextTransformation, DeleteHdl));
402 }
403 
getTransformation()404 std::shared_ptr<sc::DataTransformation> ScColumnTextTransformation::getTransformation()
405 {
406     OUString aColumnString = mxColumnNums->get_text();
407     std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
408     std::set<SCCOL> aColumns;
409     for (const auto& rColStr : aSplitColumns)
410     {
411         sal_Int32 nCol = rColStr.toInt32();
412         if (nCol <= 0)
413             continue;
414 
415         if (nCol > mpDoc->MaxCol())
416             continue;
417 
418         // translate from 1-based column notations to internal Calc one
419         aColumns.insert(nCol - 1);
420     }
421 
422     sal_Int32 nPos = mxType->get_active();
423     switch (nPos)
424     {
425         case 0:
426             return std::make_shared<sc::TextTransformation>(aColumns,sc::TEXT_TRANSFORM_TYPE::TO_LOWER);
427         case 1:
428             return std::make_shared<sc::TextTransformation>(aColumns,sc::TEXT_TRANSFORM_TYPE::TO_UPPER);
429         case 2:
430             return std::make_shared<sc::TextTransformation>(aColumns,sc::TEXT_TRANSFORM_TYPE::CAPITALIZE);
431         case 3:
432             return std::make_shared<sc::TextTransformation>(aColumns,sc::TEXT_TRANSFORM_TYPE::TRIM);
433         default:
434             assert(false);
435     }
436 
437     return nullptr;
438 }
439 
440 class ScAggregateFunction : public ScDataTransformationBaseControl
441 {
442 private:
443     std::unique_ptr<weld::Entry> mxColumnNums;
444     std::unique_ptr<weld::ComboBox> mxType;
445     std::unique_ptr<weld::Button> mxDelete;
446     std::function<void(sal_uInt32&)> maDeleteTransformation;
447     const ScDocument* mpDoc;
448 
449 public:
450     ScAggregateFunction(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
451 
452     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
453     DECL_LINK(DeleteHdl, weld::Button&, void);
454 };
455 
ScAggregateFunction(const ScDocument * pDoc,weld::Container * pParent,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)456 ScAggregateFunction::ScAggregateFunction(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex,
457                                          std::function<void(sal_uInt32&)> aDeleteTransformation)
458     : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/aggregatefunctionentry.ui", nIndex)
459     , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
460     , mxType(mxBuilder->weld_combo_box("ed_lst"))
461     , mxDelete(mxBuilder->weld_button("ed_delete"))
462     , maDeleteTransformation(std::move(aDeleteTransformation))
463     , mpDoc(pDoc)
464 {
465     mxDelete->connect_clicked(LINK(this,ScAggregateFunction, DeleteHdl));
466 }
467 
getTransformation()468 std::shared_ptr<sc::DataTransformation> ScAggregateFunction::getTransformation()
469 {
470     OUString aColumnString = mxColumnNums->get_text();
471     sal_Int32 nPos = mxType->get_active();
472     std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
473     std::set<SCCOL> aColumns;
474     for (const auto& rColStr : aSplitColumns)
475     {
476         sal_Int32 nCol = rColStr.toInt32();
477         if (nCol <= 0)
478             continue;
479 
480         if (nCol > mpDoc->MaxCol())
481             continue;
482 
483         // translate from 1-based column notations to internal Calc one
484         aColumns.insert(nCol - 1);
485     }
486     switch (nPos)
487     {
488         case 0:
489             return std::make_shared<sc::AggregateFunction>(aColumns,sc::AGGREGATE_FUNCTION::SUM);
490         case 1:
491             return std::make_shared<sc::AggregateFunction>(aColumns,sc::AGGREGATE_FUNCTION::AVERAGE);
492         case 2:
493             return std::make_shared<sc::AggregateFunction>(aColumns,sc::AGGREGATE_FUNCTION::MIN);
494         case 3:
495             return std::make_shared<sc::AggregateFunction>(aColumns,sc::AGGREGATE_FUNCTION::MAX);
496         default:
497             assert(false);
498     }
499 
500     return nullptr;
501 }
502 
503 class ScNumberTransformation : public ScDataTransformationBaseControl
504 {
505 private:
506     std::unique_ptr<weld::Entry> mxColumnNums;
507     std::unique_ptr<weld::ComboBox> mxType;
508     std::unique_ptr<weld::Button> mxDelete;
509     std::function<void(sal_uInt32&)> maDeleteTransformation;
510     const ScDocument* mpDoc;
511 
512 public:
513     ScNumberTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
514 
515     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
516     DECL_LINK(DeleteHdl, weld::Button&, void);
517 };
518 
ScNumberTransformation(const ScDocument * pDoc,weld::Container * pParent,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)519 ScNumberTransformation::ScNumberTransformation(
520     const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
521     : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/numbertransformationentry.ui", nIndex)
522     , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
523     , mxType(mxBuilder->weld_combo_box("ed_lst"))
524     , mxDelete(mxBuilder->weld_button("ed_delete"))
525     , maDeleteTransformation(std::move(aDeleteTransformation))
526     , mpDoc(pDoc)
527 {
528     mxDelete->connect_clicked(LINK(this,ScNumberTransformation, DeleteHdl));
529 }
530 
getTransformation()531 std::shared_ptr<sc::DataTransformation> ScNumberTransformation::getTransformation()
532 {
533     OUString aColumnString = mxColumnNums->get_text();
534     sal_Int32 nPos = mxType->get_active();
535     std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
536     std::set<SCCOL> aColumns;
537     for (const auto& rColStr : aSplitColumns)
538     {
539         sal_Int32 nCol = rColStr.toInt32();
540         if (nCol <= 0)
541             continue;
542 
543         if (nCol > mpDoc->MaxCol())
544             continue;
545 
546         // translate from 1-based column notations to internal Calc one
547         aColumns.insert(nCol - 1);
548     }
549     switch (nPos)
550     {
551         case 0:
552             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::SIGN);
553         case 1:
554             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::ROUND);
555         case 2:
556             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::ROUND_UP);
557         case 3:
558             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::ROUND_DOWN);
559         case 4:
560             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::ABSOLUTE);
561         case 5:
562             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::LOG_E);
563         case 6:
564             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::LOG_10);
565         case 7:
566             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::CUBE);
567         case 8:
568             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::SQUARE);
569         case 9:
570             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::SQUARE_ROOT);
571         case 10:
572             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::EXPONENT);
573         case 11:
574             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::IS_EVEN);
575         case 12:
576             return std::make_shared<sc::NumberTransformation>(aColumns,sc::NUMBER_TRANSFORM_TYPE::IS_ODD);
577         default:
578             assert(false);
579     }
580 
581     return nullptr;
582 }
583 
584 class ScReplaceNullTransformation : public ScDataTransformationBaseControl
585 {
586 private:
587     std::unique_ptr<weld::Entry> mxColumnNums;
588     std::unique_ptr<weld::Entry> mxReplaceString;
589     std::unique_ptr<weld::Button> mxDelete;
590     std::function<void(sal_uInt32&)> maDeleteTransformation;
591     const ScDocument *mpDoc;
592 
593 public:
594 
595     ScReplaceNullTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
596 
597     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
598     DECL_LINK(DeleteHdl, weld::Button&, void);
599 };
600 
ScReplaceNullTransformation(const ScDocument * pDoc,weld::Container * pParent,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)601 ScReplaceNullTransformation::ScReplaceNullTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
602     : ScDataTransformationBaseControl(pParent,"modules/scalc/ui/replacenulltransformationentry.ui", nIndex)
603     , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
604     , mxReplaceString(mxBuilder->weld_entry("ed_str"))
605     , mxDelete(mxBuilder->weld_button("ed_delete"))
606     , maDeleteTransformation(aDeleteTransformation)
607     , mpDoc(pDoc)
608 {
609     mxDelete->connect_clicked(LINK(this,ScReplaceNullTransformation, DeleteHdl));
610 }
611 
612 
getTransformation()613 std::shared_ptr<sc::DataTransformation> ScReplaceNullTransformation::getTransformation()
614 {
615     OUString aColumnString = mxColumnNums->get_text();
616     OUString aReplaceWithString = mxReplaceString->get_text();
617     std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
618     std::set<SCCOL> aColumns;
619     for (const auto& rColStr : aSplitColumns)
620     {
621         sal_Int32 nCol = rColStr.toInt32();
622         if (nCol <= 0)
623             continue;
624 
625         if (nCol > mpDoc->MaxCol())
626             continue;
627 
628         // translate from 1-based column notations to internal Calc one
629         aColumns.insert(nCol - 1);
630     }
631 
632     return std::make_shared<sc::ReplaceNullTransformation>(aColumns,aReplaceWithString);
633 }
634 
635 class ScDateTimeTransformation : public ScDataTransformationBaseControl
636 {
637 private:
638     std::unique_ptr<weld::Entry> mxColumnNums;
639     std::unique_ptr<weld::ComboBox> mxType;
640     std::unique_ptr<weld::Button> mxDelete;
641     std::function<void(sal_uInt32&)> maDeleteTransformation;
642     const ScDocument* mpDoc;
643 
644 public:
645 
646     ScDateTimeTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
647 
648     virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
649     DECL_LINK(DeleteHdl, weld::Button&, void);
650 };
651 
ScDateTimeTransformation(const ScDocument * pDoc,weld::Container * pParent,sal_uInt32 nIndex,std::function<void (sal_uInt32 &)> aDeleteTransformation)652 ScDateTimeTransformation::ScDateTimeTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
653     : ScDataTransformationBaseControl(pParent,"modules/scalc/ui/datetimetransformationentry.ui", nIndex)
654     , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
655     , mxType(mxBuilder->weld_combo_box("ed_lst"))
656     , mxDelete(mxBuilder->weld_button("ed_delete"))
657     , maDeleteTransformation(aDeleteTransformation)
658     , mpDoc(pDoc)
659 {
660     mxDelete->connect_clicked(LINK(this,ScDateTimeTransformation, DeleteHdl));
661 }
662 
getTransformation()663 std::shared_ptr<sc::DataTransformation> ScDateTimeTransformation::getTransformation()
664 {
665     OUString aColumnString = mxColumnNums->get_text();
666     sal_Int32 nPos = mxType->get_active();
667     std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
668     std::set<SCCOL> aColumns;
669     for (const auto& rColStr : aSplitColumns)
670     {
671         sal_Int32 nCol = rColStr.toInt32();
672         if (nCol <= 0)
673             continue;
674 
675         if (nCol > mpDoc->MaxCol())
676             continue;
677 
678         // translate from 1-based column notations to internal Calc one
679         aColumns.insert(nCol - 1);
680 }
681     switch (nPos)
682     {
683         case 0:
684             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::DATE_STRING);
685         case 1:
686             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::YEAR);
687         case 2:
688             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR);
689         case 3:
690             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR);
691         case 4:
692             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::MONTH);
693         case 5:
694             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::MONTH_NAME);
695         case 6:
696             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH);
697         case 7:
698             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH);
699         case 8:
700             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::DAY);
701         case 9:
702             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK);
703         case 10:
704             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR);
705         case 11:
706             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::QUARTER);
707         case 12:
708             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER);
709         case 13:
710             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER);
711         case 14:
712             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::HOUR);
713         case 15:
714             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::MINUTE);
715         case 16:
716             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::SECOND);
717         case 17:
718             return std::make_shared<sc::DateTimeTransformation>(aColumns,sc::DATETIME_TRANSFORMATION_TYPE::TIME);
719         default:
720             assert(false);
721     }
722 
723     return nullptr;
724 }
725 
726 }
727 
ScDataProviderDlg(weld::Window * pParent,std::shared_ptr<ScDocument> pDoc,const ScDocument * pDocument)728 ScDataProviderDlg::ScDataProviderDlg(weld::Window* pParent, std::shared_ptr<ScDocument> pDoc,
729                                      const ScDocument* pDocument)
730     : GenericDialogController(pParent, "modules/scalc/ui/dataproviderdlg.ui", "dataproviderdlg")
731     , mxDoc(std::move(pDoc))
732     , mxStartMenu(m_xBuilder->weld_menu("start"))
733     , mxColumnMenu(m_xBuilder->weld_menu("column"))
734     , mxBox(m_xBuilder->weld_container("data_table"))
735     , m_xTableParent(mxBox->CreateChildFrame())
736     , mxTable(VclPtr<ScDataTableView>::Create(m_xTableParent))
737     , mxScroll(m_xBuilder->weld_scrolled_window("scroll"))
738     , mxList(m_xBuilder->weld_container("operation_ctrl"))
739     , mxDataProviderCtrl(new ScDataProviderBaseControl(mxList.get(), LINK(this, ScDataProviderDlg, ImportHdl)))
740     , mxDBRanges(m_xBuilder->weld_combo_box("select_db_range"))
741     , mnIndex(0)
742 {
743     Size aPrefSize = mxTable->GetOptimalSize();
744     mxBox->set_size_request(aPrefSize.Width(), aPrefSize.Height());
745     mxTable->Show();
746 
747     mxTable->Init(mxDoc);
748     ScDBCollection* pDBCollection = pDocument->GetDBCollection();
749     auto& rNamedDBs = pDBCollection->getNamedDBs();
750     for (auto& rNamedDB : rNamedDBs)
751     {
752         mxDBRanges->append_text(rNamedDB->GetName());
753     }
754 
755     pDBData = new ScDBData("data", 0, 0, 0, mxDoc->MaxCol(), mxDoc->MaxRow());
756     bool bSuccess = mxDoc->GetDBCollection()->getNamedDBs().insert(std::unique_ptr<ScDBData>(pDBData));
757     SAL_WARN_IF(!bSuccess, "sc", "temporary warning");
758 
759     InitMenu();
760 
761     maIdle.SetPriority( TaskPriority::LOWEST );
762     maIdle.SetInvokeHandler( LINK( this, ScDataProviderDlg, ScrollToEnd) );
763 }
764 
~ScDataProviderDlg()765 ScDataProviderDlg::~ScDataProviderDlg()
766 {
767     mxTable.disposeAndClear();
768     m_xTableParent->dispose();
769     m_xTableParent.clear();
770 }
771 
InitMenu()772 void ScDataProviderDlg::InitMenu()
773 {
774     for (const auto& itrStartData : aStartData)
775         mxStartMenu->append(OUString::number(itrStartData.nMenuID), OUString::createFromAscii(itrStartData.aMenuName));
776     mxStartMenu->connect_activate(LINK(this, ScDataProviderDlg, StartMenuHdl));
777 
778     for (const auto& itrColumnData : aColumnData)
779         mxColumnMenu->append(OUString::number(itrColumnData.nMenuID), OUString::createFromAscii(itrColumnData.aMenuName));
780     mxColumnMenu->connect_activate(LINK(this, ScDataProviderDlg, ColumnMenuHdl));
781 }
782 
IMPL_LINK(ScDataProviderDlg,StartMenuHdl,const OString &,rIdent,void)783 IMPL_LINK(ScDataProviderDlg, StartMenuHdl, const OString&, rIdent, void)
784 {
785     auto nId = rIdent.toInt32();
786     for (auto& i: aStartData)
787     {
788         if (i.nMenuID == nId)
789         {
790             i.maCallback(this);
791             return;
792         }
793     }
794 }
795 
IMPL_LINK_NOARG(ScDataProviderDlg,ScrollToEnd,Timer *,void)796 IMPL_LINK_NOARG(ScDataProviderDlg, ScrollToEnd, Timer*, void)
797 {
798     mxScroll->vadjustment_set_value(mxScroll->vadjustment_get_upper());
799 }
800 
IMPL_LINK(ScDataProviderDlg,ColumnMenuHdl,const OString &,rIdent,void)801 IMPL_LINK(ScDataProviderDlg, ColumnMenuHdl, const OString&, rIdent, void)
802 {
803     auto nId = rIdent.toInt32();
804     for (auto& i: aColumnData)
805     {
806         if (i.nMenuID == nId)
807         {
808             i.maCallback(this);
809             // scroll to bottom when something added to the list
810             maIdle.Start();
811             return;
812         }
813     }
814 }
815 
IMPL_LINK(ScDataProviderDlg,ImportHdl,ScDataProviderBaseControl *,pCtrl,void)816 IMPL_LINK(ScDataProviderDlg, ImportHdl, ScDataProviderBaseControl*, pCtrl, void)
817 {
818     if (pCtrl == mxDataProviderCtrl.get())
819     {
820         import(*mxDoc, true);
821     }
822 }
823 
applyAndQuit()824 void ScDataProviderDlg::applyAndQuit()
825 {
826     m_xDialog->response(RET_OK);
827 }
828 
cancelAndQuit()829 void ScDataProviderDlg::cancelAndQuit()
830 {
831     m_xDialog->response(RET_CANCEL);
832 }
833 
deleteColumn()834 void ScDataProviderDlg::deleteColumn()
835 {
836     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
837     maControls.emplace_back(std::make_unique<ScDeleteColumnTransformationControl>(mxDoc.get(), mxList.get(), mnIndex++, adeleteTransformation));
838 }
839 
splitColumn()840 void ScDataProviderDlg::splitColumn()
841 {
842     SCCOL nStartCol = -1;
843     SCCOL nEndCol = -1;
844     mxTable->getColRange(nStartCol, nEndCol);
845     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
846     maControls.emplace_back(std::make_unique<ScSplitColumnTransformationControl>(mxList.get(), nStartCol, mnIndex++, adeleteTransformation));
847 }
848 
mergeColumns()849 void ScDataProviderDlg::mergeColumns()
850 {
851     SCCOL nStartCol = -1;
852     SCCOL nEndCol = -1;
853     mxTable->getColRange(nStartCol, nEndCol);
854     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
855     maControls.emplace_back(std::make_unique<ScMergeColumnTransformationControl>(mxDoc.get(), mxList.get(), nStartCol, nEndCol, mnIndex++, adeleteTransformation));
856 }
857 
textTransformation()858 void ScDataProviderDlg::textTransformation()
859 {
860     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
861     maControls.emplace_back(std::make_unique<ScColumnTextTransformation>(mxDoc.get(), mxList.get(), mnIndex++, adeleteTransformation));
862 }
863 
sortTransformation()864 void ScDataProviderDlg::sortTransformation()
865 {
866     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
867     maControls.emplace_back(std::make_unique<ScSortTransformationControl>(mxDoc.get(), mxList.get(), mnIndex++, adeleteTransformation));
868 }
869 
aggregateFunction()870 void ScDataProviderDlg::aggregateFunction()
871 {
872     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
873     maControls.emplace_back(std::make_unique<ScAggregateFunction>(mxDoc.get(), mxList.get(), mnIndex++, adeleteTransformation));
874 }
875 
numberTransformation()876 void ScDataProviderDlg::numberTransformation()
877 {
878     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
879     maControls.emplace_back(std::make_unique<ScNumberTransformation>(mxDoc.get(), mxList.get(), mnIndex++, adeleteTransformation));
880 }
881 
replaceNullTransformation()882 void ScDataProviderDlg::replaceNullTransformation()
883 {
884     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
885     maControls.emplace_back(std::make_unique<ScReplaceNullTransformation>(mxDoc.get(), mxList.get(), mnIndex++, adeleteTransformation));
886 }
887 
dateTimeTransformation()888 void ScDataProviderDlg::dateTimeTransformation()
889 {
890     std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
891     maControls.emplace_back(std::make_unique<ScDateTimeTransformation>(mxDoc.get(), mxList.get(), mnIndex++, adeleteTransformation));
892 }
893 
894 namespace {
895 
hasDBName(const OUString & rName,ScDBCollection * pDBCollection)896 bool hasDBName(const OUString& rName, ScDBCollection* pDBCollection)
897 {
898     if (pDBCollection->getNamedDBs().findByUpperName(ScGlobal::getCharClassPtr()->uppercase(rName)))
899         return true;
900 
901     return false;
902 }
903 
904 }
905 
import(ScDocument & rDoc,bool bInternal)906 void ScDataProviderDlg::import(ScDocument& rDoc, bool bInternal)
907 {
908     sc::ExternalDataSource aSource = mxDataProviderCtrl->getDataSource(&rDoc);
909 
910     for (size_t i = 0; i < maControls.size(); ++i)
911     {
912         ScDataTransformationBaseControl* pTransformationCtrl = maControls[i].get();
913         aSource.AddDataTransformation(pTransformationCtrl->getTransformation());
914     }
915     if (bInternal)
916         aSource.setDBData(pDBData->GetName());
917     else
918     {
919         aSource.setDBData(mxDBRanges->get_active_text());
920         if (!hasDBName(aSource.getDBName(), rDoc.GetDBCollection()))
921             return;
922         rDoc.GetExternalDataMapper().insertDataSource(aSource);
923     }
924     aSource.refresh(&rDoc, true);
925     mxTable->Invalidate();
926 }
927 
deletefromList(sal_uInt32 nIndex)928 void ScDataProviderDlg::deletefromList(sal_uInt32 nIndex)
929 {
930     auto itr = maControls.erase(maControls.begin() + nIndex);
931     while (itr != maControls.end())
932     {
933         (*itr)->updateIndex(nIndex++);
934         ++itr;
935     }
936     --mnIndex;
937 }
938 
IMPL_LINK_NOARG(ScDeleteColumnTransformationControl,DeleteHdl,weld::Button &,void)939 IMPL_LINK_NOARG(ScDeleteColumnTransformationControl, DeleteHdl, weld::Button&, void)
940 {
941    maDeleteTransformation(mnIndex);
942 }
943 
IMPL_LINK_NOARG(ScSplitColumnTransformationControl,DeleteHdl,weld::Button &,void)944 IMPL_LINK_NOARG(ScSplitColumnTransformationControl, DeleteHdl, weld::Button&, void)
945 {
946    maDeleteTransformation(mnIndex);
947 }
948 
IMPL_LINK_NOARG(ScMergeColumnTransformationControl,DeleteHdl,weld::Button &,void)949 IMPL_LINK_NOARG(ScMergeColumnTransformationControl, DeleteHdl, weld::Button&, void)
950 {
951    maDeleteTransformation(mnIndex);
952 }
953 
IMPL_LINK_NOARG(ScNumberTransformation,DeleteHdl,weld::Button &,void)954 IMPL_LINK_NOARG(ScNumberTransformation, DeleteHdl, weld::Button&, void)
955 {
956    maDeleteTransformation(mnIndex);
957 }
958 
IMPL_LINK_NOARG(ScAggregateFunction,DeleteHdl,weld::Button &,void)959 IMPL_LINK_NOARG(ScAggregateFunction, DeleteHdl, weld::Button&, void)
960 {
961    maDeleteTransformation(mnIndex);
962 }
963 
IMPL_LINK_NOARG(ScSortTransformationControl,DeleteHdl,weld::Button &,void)964 IMPL_LINK_NOARG(ScSortTransformationControl, DeleteHdl, weld::Button&, void)
965 {
966    maDeleteTransformation(mnIndex);
967 }
968 
IMPL_LINK_NOARG(ScColumnTextTransformation,DeleteHdl,weld::Button &,void)969 IMPL_LINK_NOARG(ScColumnTextTransformation, DeleteHdl, weld::Button&, void)
970 {
971    maDeleteTransformation(mnIndex);
972 }
973 
IMPL_LINK_NOARG(ScReplaceNullTransformation,DeleteHdl,weld::Button &,void)974 IMPL_LINK_NOARG(ScReplaceNullTransformation, DeleteHdl, weld::Button&, void)
975 {
976    maDeleteTransformation(mnIndex);
977 }
978 
IMPL_LINK_NOARG(ScDateTimeTransformation,DeleteHdl,weld::Button &,void)979 IMPL_LINK_NOARG(ScDateTimeTransformation, DeleteHdl, weld::Button&, void)
980 {
981    maDeleteTransformation(mnIndex);
982 }
983 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
984