LibreOffice Module dbaccess (master) 1
TextConnectionHelper.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 <core_resource.hxx>
22#include <strings.hrc>
23#include <strings.hxx>
24#include <svl/itemset.hxx>
25#include <svl/stritem.hxx>
26#include <svl/eitem.hxx>
27#include <dsitems.hxx>
28#include <vcl/svapp.hxx>
29#include <vcl/weld.hxx>
30#include <vcl/mnemonic.hxx>
31#include <o3tl/string_view.hxx>
32
33namespace
34{
35
36OUString lcl_getListEntry(std::u16string_view rStr, sal_Int32& rIdx)
37{
38 const OUString sTkn {o3tl::getToken(rStr, 0, '\t', rIdx )};
39 if (rIdx>=0)
40 {
41 size_t nFnd = rStr.find('\t', rIdx);
42 if (nFnd == std::u16string_view::npos)
43 rIdx = -1;
44 else
45 {
46 rIdx = nFnd + 1;
47 if (rIdx >= static_cast<sal_Int32>(rStr.size()))
48 rIdx = -1;
49 }
50 }
51 return sTkn;
52}
53
54}
55
56namespace dbaui
57{
58
59 OTextConnectionHelper::OTextConnectionHelper(weld::Widget* pParent, const short _nAvailableSections)
60 : m_aFieldSeparatorList (DBA_RES(STR_AUTOFIELDSEPARATORLIST))
61 , m_aTextSeparatorList (STR_AUTOTEXTSEPARATORLIST)
62 , m_aTextNone (DBA_RES(STR_AUTOTEXT_FIELD_SEP_NONE))
63 , m_nAvailableSections( _nAvailableSections )
64 , m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/textpage.ui"))
65 , m_xContainer(m_xBuilder->weld_widget("TextPage"))
66 , m_xExtensionHeader(m_xBuilder->weld_widget("extensionframe"))
67 , m_xAccessTextFiles(m_xBuilder->weld_radio_button("textfile"))
68 , m_xAccessCSVFiles(m_xBuilder->weld_radio_button("csvfile"))
69 , m_xAccessOtherFiles(m_xBuilder->weld_radio_button("custom"))
70 , m_xOwnExtension(m_xBuilder->weld_entry("extension"))
71 , m_xExtensionExample(m_xBuilder->weld_label("example"))
72 , m_xFormatHeader(m_xBuilder->weld_widget("formatframe"))
73 , m_xFieldSeparatorLabel(m_xBuilder->weld_label("fieldlabel"))
74 , m_xFieldSeparator(m_xBuilder->weld_combo_box("fieldseparator"))
75 , m_xTextSeparatorLabel(m_xBuilder->weld_label("textlabel"))
76 , m_xTextSeparator(m_xBuilder->weld_combo_box("textseparator"))
77 , m_xDecimalSeparatorLabel(m_xBuilder->weld_label("decimallabel"))
78 , m_xDecimalSeparator(m_xBuilder->weld_combo_box("decimalseparator"))
79 , m_xThousandsSeparatorLabel(m_xBuilder->weld_label("thousandslabel"))
80 , m_xThousandsSeparator(m_xBuilder->weld_combo_box("thousandsseparator"))
81 , m_xRowHeader(m_xBuilder->weld_check_button("containsheaders"))
82 , m_xCharSetHeader(m_xBuilder->weld_widget("charsetframe"))
83 , m_xCharSetLabel(m_xBuilder->weld_label("charsetlabel"))
84 , m_xCharSet(new CharSetListBox(m_xBuilder->weld_combo_box("charset")))
85 {
86 for(sal_Int32 nIdx {0}; nIdx>=0;)
87 m_xFieldSeparator->append_text( lcl_getListEntry(m_aFieldSeparatorList, nIdx) );
88
89 for(sal_Int32 nIdx {0}; nIdx>=0;)
90 m_xTextSeparator->append_text( lcl_getListEntry(m_aTextSeparatorList, nIdx) );
91 m_xTextSeparator->append_text(m_aTextNone);
92
93 m_xOwnExtension->connect_changed(LINK(this, OTextConnectionHelper, OnEditModified));
94 m_xAccessTextFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl));
95 m_xAccessCSVFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl));
96 m_xAccessOtherFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl));
97 m_xAccessCSVFiles->set_active(true);
98
99 struct SectionDescriptor
100 {
101 short nFlag;
102 weld::Widget* pFrame;
103 } const aSections[] = {
106 { TC_HEADER, m_xRowHeader.get() },
108 };
109
110 for (auto const & section: aSections)
111 {
112 if ( ( m_nAvailableSections & section.nFlag ) != 0 )
113 {
114 // the section is visible, no need to do anything here
115 continue;
116 }
117
118 // hide all elements from this section
119 section.pFrame->hide();
120 }
121
122 m_xContainer->show();
123 }
124
126 {
127 m_aGetExtensionHandler.Call(this);
128 }
129
131 {
132 bool bDoEnable = m_xAccessOtherFiles->get_active();
133 m_xOwnExtension->set_sensitive(bDoEnable);
134 m_xExtensionExample->set_sensitive(bDoEnable);
135 m_aGetExtensionHandler.Call(this);
136 }
137
138 void OTextConnectionHelper::fillControls(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
139 {
140 _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xFieldSeparator.get()));
141 _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xTextSeparator.get()));
142 _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xDecimalSeparator.get()));
143 _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xThousandsSeparator.get()));
144 _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::Toggleable>(m_xRowHeader.get()));
145 _rControlList.emplace_back(new OSaveValueWidgetWrapper<weld::ComboBox>(m_xCharSet->get_widget()));
146 }
147
148 void OTextConnectionHelper::fillWindows(std::vector< std::unique_ptr<ISaveValueWrapper> >& _rControlList)
149 {
150 _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xFieldSeparatorLabel.get()));
151 _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xTextSeparatorLabel.get()));
152 _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xDecimalSeparatorLabel.get()));
153 _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xThousandsSeparatorLabel.get()));
154 _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Widget>(m_xCharSetHeader.get()));
155 _rControlList.emplace_back(new ODisableWidgetWrapper<weld::Label>(m_xCharSetLabel.get()));
156 _rControlList.emplace_back(new ODisableWidgetWrapper<weld::ComboBox>(m_xCharSet->get_widget()));
157 }
158
160 {
161 if ( !_bValid )
162 return;
163
164 const SfxStringItem* pDelItem = _rSet.GetItem<SfxStringItem>(DSID_FIELDDELIMITER);
165 const SfxStringItem* pStrItem = _rSet.GetItem<SfxStringItem>(DSID_TEXTDELIMITER);
166 const SfxStringItem* pDecdelItem = _rSet.GetItem<SfxStringItem>(DSID_DECIMALDELIMITER);
167 const SfxStringItem* pThodelItem = _rSet.GetItem<SfxStringItem>(DSID_THOUSANDSDELIMITER);
168 const SfxStringItem* pExtensionItem = _rSet.GetItem<SfxStringItem>(DSID_TEXTFILEEXTENSION);
169 const SfxStringItem* pCharsetItem = _rSet.GetItem<SfxStringItem>(DSID_CHARSET);
170
171 if ( ( m_nAvailableSections & TC_EXTENSION ) != 0 )
172 {
173 m_aOldExtension = pExtensionItem->GetValue();
175 }
176
177 if ( ( m_nAvailableSections & TC_HEADER ) != 0 )
178 {
179 const SfxBoolItem* pHdrItem = _rSet.GetItem<SfxBoolItem>(DSID_TEXTFILEHEADER);
180 m_xRowHeader->set_active(pHdrItem->GetValue());
181 }
182
183 if ( ( m_nAvailableSections & TC_SEPARATORS ) != 0 )
184 {
186 SetSeparator(*m_xTextSeparator, m_aTextSeparatorList, pStrItem->GetValue());
187 m_xDecimalSeparator->set_entry_text( pDecdelItem->GetValue() );
188 m_xThousandsSeparator->set_entry_text( pThodelItem->GetValue() );
189 }
190
191 if ( ( m_nAvailableSections & TC_CHARSET ) != 0 )
192 {
193 m_xCharSet->SelectEntryByIanaName( pCharsetItem->GetValue() );
194 }
195 }
196
198 {
199 OUString sExtension = GetExtension();
200 OUString aErrorText;
201 weld::Widget* pErrorWin = nullptr;
202 OUString aDelText(m_xFieldSeparator->get_active_text());
203 if(aDelText.isEmpty())
204 { // No FieldSeparator
205 aErrorText = DBA_RES(STR_AUTODELIMITER_MISSING);
206 aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label());
207 pErrorWin = m_xFieldSeparator.get();
208 }
209 else if (m_xDecimalSeparator->get_active_text().isEmpty())
210 { // No DecimalSeparator
211 aErrorText = DBA_RES(STR_AUTODELIMITER_MISSING);
212 aErrorText = aErrorText.replaceFirst("#1",m_xDecimalSeparatorLabel->get_label());
213 pErrorWin = m_xDecimalSeparator.get();
214 }
215 else if (m_xTextSeparator->get_active_text() == m_xFieldSeparator->get_active_text())
216 { // Field and TextSeparator must not be the same
217 aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
218 aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label());
219 aErrorText = aErrorText.replaceFirst("#2",m_xFieldSeparatorLabel->get_label());
220 pErrorWin = m_xTextSeparator.get();
221 }
222 else if (m_xDecimalSeparator->get_active_text() == m_xThousandsSeparator->get_active_text())
223 { // Thousands and DecimalSeparator must not be the same
224 aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
225 aErrorText = aErrorText.replaceFirst("#1",m_xDecimalSeparatorLabel->get_label());
226 aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label());
227 pErrorWin = m_xDecimalSeparator.get();
228 }
229 else if (m_xFieldSeparator->get_active_text() == m_xThousandsSeparator->get_active_text())
230 { // Thousands and FieldSeparator must not be the same
231 aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
232 aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label());
233 aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label());
234 pErrorWin = m_xFieldSeparator.get();
235 }
236 else if (m_xFieldSeparator->get_active_text() == m_xDecimalSeparator->get_active_text())
237 { // Tenner and FieldSeparator must not be the same
238 aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
239 aErrorText = aErrorText.replaceFirst("#1",m_xFieldSeparatorLabel->get_label());
240 aErrorText = aErrorText.replaceFirst("#2",m_xDecimalSeparatorLabel->get_label());
241 pErrorWin = m_xFieldSeparator.get();
242 }
243 else if (m_xTextSeparator->get_active_text() == m_xThousandsSeparator->get_active_text())
244 { // Thousands and TextSeparator must not be the same
245 aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
246 aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label());
247 aErrorText = aErrorText.replaceFirst("#2",m_xThousandsSeparatorLabel->get_label());
248 pErrorWin = m_xTextSeparator.get();
249 }
250 else if (m_xTextSeparator->get_active_text() == m_xDecimalSeparator->get_active_text())
251 { // Tenner and TextSeparator must not be the same
252 aErrorText = DBA_RES(STR_AUTODELIMITER_MUST_DIFFER);
253 aErrorText = aErrorText.replaceFirst("#1",m_xTextSeparatorLabel->get_label());
254 aErrorText = aErrorText.replaceFirst("#2",m_xDecimalSeparatorLabel->get_label());
255 pErrorWin = m_xTextSeparator.get();
256 }
257 else if ((sExtension.indexOf('*') != -1) || (sExtension.indexOf('?') != -1))
258 {
259 aErrorText = DBA_RES(STR_AUTONO_WILDCARDS);
260 aErrorText = aErrorText.replaceFirst("#1",sExtension);
261 pErrorWin = m_xOwnExtension.get();
262 }
263 else
264 return true;
265 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(),
266 VclMessageType::Warning, VclButtonsType::Ok,
268 xBox->run();
269 pErrorWin->grab_focus();
270 return false;
271 }
272
273 bool OTextConnectionHelper::FillItemSet( SfxItemSet& rSet, const bool _bChangedSomething )
274 {
275 bool bChangedSomething = _bChangedSomething;
276
277 if ( ( m_nAvailableSections & TC_EXTENSION ) != 0 )
278 {
279 OUString sExtension = GetExtension();
280 if( m_aOldExtension != sExtension )
281 {
283 bChangedSomething = true;
284 }
285 }
286
287 if ( ( m_nAvailableSections & TC_HEADER ) != 0 )
288 {
289 if (m_xRowHeader->get_state_changed_from_saved())
290 {
292 bChangedSomething = true;
293 }
294 }
295
296 if ( ( m_nAvailableSections & TC_SEPARATORS ) != 0 )
297 {
298 if (m_xFieldSeparator->get_value_changed_from_saved())
299 {
301 bChangedSomething = true;
302 }
303 if (m_xTextSeparator->get_value_changed_from_saved())
304 {
306 bChangedSomething = true;
307 }
308
309 if (m_xDecimalSeparator->get_value_changed_from_saved())
310 {
311 rSet.Put( SfxStringItem(DSID_DECIMALDELIMITER, m_xDecimalSeparator->get_active_text().copy(0, 1) ) );
312 bChangedSomething = true;
313 }
314 if (m_xThousandsSeparator->get_value_changed_from_saved())
315 {
316 rSet.Put( SfxStringItem(DSID_THOUSANDSDELIMITER, m_xThousandsSeparator->get_active_text().copy(0,1) ) );
317 bChangedSomething = true;
318 }
319 }
320
321 if ( ( m_nAvailableSections & TC_CHARSET ) != 0 )
322 {
323 if ( m_xCharSet->StoreSelectedCharSet( rSet, DSID_CHARSET ) )
324 bChangedSomething = true;
325 }
326
327 return bChangedSomething;
328 }
329
330 void OTextConnectionHelper::SetExtension(const OUString& _rVal)
331 {
332 if (_rVal == "txt")
333 m_xAccessTextFiles->set_active(true);
334 else if (_rVal == "csv")
335 m_xAccessCSVFiles->set_active(true);
336 else
337 {
338 m_xAccessOtherFiles->set_active(true);
339 m_xExtensionExample->set_label(_rVal);
340 }
341 }
342
344 {
345 OUString sExtension;
346 if (m_xAccessTextFiles->get_active())
347 sExtension = "txt";
348 else if (m_xAccessCSVFiles->get_active())
349 sExtension = "csv";
350 else
351 {
352 sExtension = m_xOwnExtension->get_text();
353 if ( sExtension.startsWith("*.") )
354 sExtension = sExtension.copy(2);
355 }
356 return sExtension;
357 }
358
359 OUString OTextConnectionHelper::GetSeparator(const weld::ComboBox& rBox, std::u16string_view rList)
360 {
361 sal_Unicode const nTok = '\t';
362 int nPos(rBox.find_text(rBox.get_active_text()));
363
364 if (nPos == -1)
365 return rBox.get_active_text();
366
367 if ( m_xTextSeparator.get() != &rBox || nPos != (rBox.get_count()-1) )
368 return OUString(
369 static_cast< sal_Unicode >( o3tl::toInt32(o3tl::getToken(rList, (nPos*2)+1, nTok )) ));
370 // somewhat strange ... translates for instance an "32" into " "
371 return OUString();
372 }
373
374 void OTextConnectionHelper::SetSeparator( weld::ComboBox& rBox, std::u16string_view rList, const OUString& rVal )
375 {
376 if (rVal.getLength()==1)
377 {
378 const sal_Unicode nVal {rVal[0]};
379 for(sal_Int32 nIdx {0}; nIdx>=0;)
380 {
381 sal_Int32 nPrevIdx {nIdx};
382 if (static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(rList, 1, '\t', nIdx))) == nVal)
383 {
384 rBox.set_entry_text(OUString(o3tl::getToken(rList,0, '\t', nPrevIdx)));
385 return;
386 }
387 }
388 rBox.set_entry_text( rVal );
389 }
390 else if ( m_xTextSeparator.get() == &rBox && rVal.isEmpty() )
392 else
393 rBox.set_entry_text(rVal.copy(0, 1));
394 }
395}
396
397/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define TC_HEADER
#define TC_CHARSET
#define TC_SEPARATORS
#define TC_EXTENSION
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
const OUString & GetValue() const
static OUString EraseAllMnemonicChars(const OUString &rStr)
bool GetValue() const
const SfxPoolItem * GetItem(sal_uInt16 nWhich, bool bSearchInParent=true) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
bool FillItemSet(SfxItemSet &rSet, const bool bChangedSomething)
OTextConnectionHelper(weld::Widget *pParent, const short _nAvailableSections)
std::unique_ptr< weld::Widget > m_xFormatHeader
std::unique_ptr< weld::Entry > m_xOwnExtension
void fillControls(std::vector< std::unique_ptr< ISaveValueWrapper > > &_rControlList)
std::unique_ptr< weld::Widget > m_xCharSetHeader
void SetExtension(const OUString &_rVal)
std::unique_ptr< weld::ComboBox > m_xDecimalSeparator
std::unique_ptr< weld::Label > m_xExtensionExample
short m_nAvailableSections
to be called if a new type is selected
void implInitControls(const SfxItemSet &_rSet, bool _bValid)
std::unique_ptr< weld::RadioButton > m_xAccessCSVFiles
std::unique_ptr< weld::ComboBox > m_xFieldSeparator
std::unique_ptr< weld::RadioButton > m_xAccessTextFiles
std::unique_ptr< CharSetListBox > m_xCharSet
void SetSeparator(weld::ComboBox &rBox, std::u16string_view rList, const OUString &rVal)
std::unique_ptr< weld::Widget > m_xExtensionHeader
std::unique_ptr< weld::Label > m_xDecimalSeparatorLabel
std::unique_ptr< weld::Label > m_xThousandsSeparatorLabel
std::unique_ptr< weld::Label > m_xCharSetLabel
std::unique_ptr< weld::ComboBox > m_xTextSeparator
OUString GetSeparator(const weld::ComboBox &rBox, std::u16string_view rList)
std::unique_ptr< weld::ComboBox > m_xThousandsSeparator
std::unique_ptr< weld::RadioButton > m_xAccessOtherFiles
std::unique_ptr< weld::Widget > m_xContainer
std::unique_ptr< weld::Label > m_xFieldSeparatorLabel
std::unique_ptr< weld::Label > m_xTextSeparatorLabel
std::unique_ptr< weld::CheckButton > m_xRowHeader
void fillWindows(std::vector< std::unique_ptr< ISaveValueWrapper > > &_rControlList)
virtual int find_text(const OUString &rStr) const=0
virtual OUString get_active_text() const=0
virtual void set_entry_text(const OUString &rStr)=0
virtual int get_count() const=0
virtual void grab_focus()=0
#define DBA_RES(id)
#define DSID_CHARSET
Definition: dsitems.hxx:44
#define DSID_DECIMALDELIMITER
Definition: dsitems.hxx:51
#define DSID_THOUSANDSDELIMITER
Definition: dsitems.hxx:52
#define DSID_TEXTFILEEXTENSION
Definition: dsitems.hxx:53
#define DSID_FIELDDELIMITER
Definition: dsitems.hxx:49
#define DSID_TEXTFILEHEADER
Definition: dsitems.hxx:54
#define DSID_TEXTDELIMITER
Definition: dsitems.hxx:50
sal_uInt16 nPos
@ section
IMPL_LINK_NOARG(OApplicationController, OnClipboardChanged, TransferableDataHelper *, void)
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
Reference< XNameAccess > m_xContainer
Definition: objectnames.cxx:80
static SfxItemSet & rSet
constexpr OUStringLiteral STR_AUTOTEXTSEPARATORLIST
Definition: strings.hxx:272
sal_uInt16 sal_Unicode