LibreOffice Module sc (master)  1
scuiasciiopt.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 #undef SC_DLLIMPLEMENTATION
21 
22 #include <svx/txencbox.hxx>
23 
24 #include <global.hxx>
25 #include <scresid.hxx>
26 #include <impex.hxx>
27 #include <scuiasciiopt.hxx>
28 #include <strings.hrc>
29 #include <strings.hxx>
30 #include <csvtablebox.hxx>
31 #include <osl/thread.h>
33 
34 #include <optutil.hxx>
35 #include <com/sun/star/uno/Any.hxx>
36 #include <com/sun/star/uno/Sequence.hxx>
37 #include <miscuno.hxx>
38 #include <osl/diagnose.h>
39 
42 
43 using namespace com::sun::star::uno;
44 
45 namespace {
46 
47 // Defines - CSV Import Preserve Options
49 {
50  CSVIO_MergeDelimiters = 0,
51  CSVIO_Separators,
52  CSVIO_TextSeparators,
53  CSVIO_FixedWidth,
54  CSVIO_RemoveSpace,
55  CSVIO_FromRow,
56  CSVIO_Text2ColSkipEmptyCells = CSVIO_FromRow,
57  CSVIO_CharSet,
58  CSVIO_QuotedAsText,
59  CSVIO_DetectSpecialNum,
60  CSVIO_Language,
61  CSVIO_PasteSkipEmptyCells
62 };
63 
64 }
65 
66 const ::std::vector<OUString> CSVImportOptionNames =
67 {
68  "MergeDelimiters",
69  "Separators",
70  "TextSeparators",
71  "FixedWidth",
72  "RemoveSpace",
73  "FromRow",
74  "CharSet",
75  "QuotedFieldAsText",
76  "DetectSpecialNumbers",
77  "Language",
78  "SkipEmptyCells"
79 };
80 const OUString aSep_Path = "Office.Calc/Dialogs/CSVImport";
81 const OUString aSep_Path_Clpbrd = "Office.Calc/Dialogs/ClipboardTextImport";
82 const OUString aSep_Path_Text2Col = "Office.Calc/Dialogs/TextToColumnsImport";
83 
84 namespace {
85 CSVImportOptionsIndex getSkipEmptyCellsIndex( ScImportAsciiCall eCall )
86 {
87  return eCall == SC_TEXTTOCOLUMNS ? CSVIO_Text2ColSkipEmptyCells : CSVIO_PasteSkipEmptyCells;
88 }
89 }
90 
91 static void lcl_FillCombo(weld::ComboBox& rCombo, const OUString& rList, sal_Unicode cSelect)
92 {
93  OUString aStr;
94  if (!rList.isEmpty())
95  {
96  sal_Int32 nIdx {0};
97  do
98  {
99  const OUString sEntry {rList.getToken(0, '\t', nIdx)};
100  rCombo.append_text(sEntry);
101  if (nIdx>0 && static_cast<sal_Unicode>(rList.getToken(0, '\t', nIdx).toInt32()) == cSelect)
102  aStr = sEntry;
103  }
104  while (nIdx>0);
105  }
106 
107  if ( cSelect )
108  {
109  if (aStr.isEmpty())
110  aStr = OUString(cSelect); // Ascii
111 
112  rCombo.set_entry_text(aStr);
113  }
114 }
115 
116 static sal_Unicode lcl_CharFromCombo(const weld::ComboBox& rCombo, const OUString& rList)
117 {
118  sal_Unicode c = 0;
119  OUString aStr = rCombo.get_active_text();
120  if ( !aStr.isEmpty() && !rList.isEmpty() )
121  {
122  sal_Int32 nIdx {0};
123  OUString sToken {rList.getToken(0, '\t', nIdx)};
124  while (nIdx>0)
125  {
126  if ( ScGlobal::GetpTransliteration()->isEqual( aStr, sToken ) )
127  {
128  sal_Int32 nTmpIdx {nIdx};
129  c = static_cast<sal_Unicode>(rList.getToken(0, '\t', nTmpIdx).toInt32());
130  }
131  // Skip to next token at even position
132  sToken = rList.getToken(1, '\t', nIdx);
133  }
134  if (!c)
135  {
136  sal_Unicode cFirst = aStr[0];
137  // #i24235# first try the first character of the string directly
138  if( (aStr.getLength() == 1) || (cFirst < '0') || (cFirst > '9') )
139  c = cFirst;
140  else // keep old behaviour for compatibility (i.e. "39" -> "'")
141  c = static_cast<sal_Unicode>(aStr.toInt32()); // Ascii
142  }
143  }
144  return c;
145 }
146 
147 static void lcl_CreatePropertiesNames ( OUString& rSepPath, Sequence<OUString>& rNames, ScImportAsciiCall eCall )
148 {
149  sal_Int32 nProperties = 0;
150 
151  switch(eCall)
152  {
153  case SC_IMPORTFILE:
154  rSepPath = aSep_Path;
155  nProperties = 10;
156  break;
157  case SC_PASTETEXT:
158  rSepPath = aSep_Path_Clpbrd;
159  nProperties = 11;
160  break;
161  case SC_TEXTTOCOLUMNS:
162  default:
163  rSepPath = aSep_Path_Text2Col;
164  nProperties = 6;
165  break;
166  }
167  rNames.realloc( nProperties );
168  OUString* pNames = rNames.getArray();
169  pNames[ CSVIO_MergeDelimiters ] = CSVImportOptionNames[ CSVIO_MergeDelimiters ];
170  pNames[ CSVIO_Separators ] = CSVImportOptionNames[ CSVIO_Separators ];
171  pNames[ CSVIO_TextSeparators ] = CSVImportOptionNames[ CSVIO_TextSeparators ];
172  pNames[ CSVIO_FixedWidth ] = CSVImportOptionNames[ CSVIO_FixedWidth ];
173  pNames[ CSVIO_RemoveSpace ] = CSVImportOptionNames[ CSVIO_RemoveSpace ];
174  if (eCall != SC_TEXTTOCOLUMNS)
175  {
176  pNames[ CSVIO_FromRow ] = CSVImportOptionNames[ CSVIO_FromRow ];
177  pNames[ CSVIO_CharSet ] = CSVImportOptionNames[ CSVIO_CharSet ];
178  pNames[ CSVIO_QuotedAsText ] = CSVImportOptionNames[ CSVIO_QuotedAsText ];
179  pNames[ CSVIO_DetectSpecialNum ] = CSVImportOptionNames[ CSVIO_DetectSpecialNum ];
180  pNames[ CSVIO_Language ] = CSVImportOptionNames[ CSVIO_Language ];
181  }
182  if (eCall != SC_IMPORTFILE)
183  {
184  const sal_Int32 nSkipEmptyCells = getSkipEmptyCellsIndex(eCall);
185  assert( nSkipEmptyCells < rNames.getLength());
186  pNames[ nSkipEmptyCells ] = CSVImportOptionNames[ CSVIO_PasteSkipEmptyCells ];
187  }
188 }
189 
190 static void lcl_LoadSeparators( OUString& rFieldSeparators, OUString& rTextSeparators,
191  bool& rMergeDelimiters, bool& rQuotedAsText, bool& rDetectSpecialNum,
192  bool& rFixedWidth, sal_Int32& rFromRow, sal_Int32& rCharSet,
193  sal_Int32& rLanguage, bool& rSkipEmptyCells, bool& rRemoveSpace, ScImportAsciiCall eCall )
194 {
195  Sequence<Any>aValues;
196  const Any *pProperties;
197  Sequence<OUString> aNames;
198  OUString aSepPath;
199  lcl_CreatePropertiesNames ( aSepPath, aNames, eCall);
200  ScLinkConfigItem aItem( aSepPath );
201  aValues = aItem.GetProperties( aNames );
202  pProperties = aValues.getConstArray();
203 
204  if( pProperties[ CSVIO_MergeDelimiters ].hasValue() )
205  rMergeDelimiters = ScUnoHelpFunctions::GetBoolFromAny( pProperties[ CSVIO_MergeDelimiters ] );
206 
207  if( pProperties[ CSVIO_RemoveSpace ].hasValue() )
208  rRemoveSpace = ScUnoHelpFunctions::GetBoolFromAny( pProperties[ CSVIO_RemoveSpace ] );
209 
210  if( pProperties[ CSVIO_Separators ].hasValue() )
211  pProperties[ CSVIO_Separators ] >>= rFieldSeparators;
212 
213  if( pProperties[ CSVIO_TextSeparators ].hasValue() )
214  pProperties[ CSVIO_TextSeparators ] >>= rTextSeparators;
215 
216  if( pProperties[ CSVIO_FixedWidth ].hasValue() )
217  rFixedWidth = ScUnoHelpFunctions::GetBoolFromAny( pProperties[ CSVIO_FixedWidth ] );
218 
219  if (eCall != SC_TEXTTOCOLUMNS)
220  {
221  if( pProperties[ CSVIO_FromRow ].hasValue() )
222  pProperties[ CSVIO_FromRow ] >>= rFromRow;
223 
224  if( pProperties[ CSVIO_CharSet ].hasValue() )
225  pProperties[ CSVIO_CharSet ] >>= rCharSet;
226 
227  if ( pProperties[ CSVIO_QuotedAsText ].hasValue() )
228  pProperties[ CSVIO_QuotedAsText ] >>= rQuotedAsText;
229 
230  if ( pProperties[ CSVIO_DetectSpecialNum ].hasValue() )
231  pProperties[ CSVIO_DetectSpecialNum ] >>= rDetectSpecialNum;
232 
233  if ( pProperties[ CSVIO_Language ].hasValue() )
234  pProperties[ CSVIO_Language ] >>= rLanguage;
235  }
236  if (eCall != SC_IMPORTFILE)
237  {
238  const sal_Int32 nSkipEmptyCells = getSkipEmptyCellsIndex(eCall);
239  assert( nSkipEmptyCells < aValues.getLength());
240  if ( pProperties[nSkipEmptyCells].hasValue() )
241  rSkipEmptyCells = ScUnoHelpFunctions::GetBoolFromAny( pProperties[nSkipEmptyCells] );
242  }
243 }
244 
245 static void lcl_SaveSeparators(
246  const OUString& sFieldSeparators, const OUString& sTextSeparators, bool bMergeDelimiters, bool bQuotedAsText,
247  bool bDetectSpecialNum, bool bFixedWidth, sal_Int32 nFromRow,
248  sal_Int32 nCharSet, sal_Int32 nLanguage, bool bSkipEmptyCells, bool bRemoveSpace, ScImportAsciiCall eCall )
249 {
250  Sequence<Any> aValues;
251  Any *pProperties;
252  Sequence<OUString> aNames;
253  OUString aSepPath;
254  lcl_CreatePropertiesNames ( aSepPath, aNames, eCall );
255  ScLinkConfigItem aItem( aSepPath );
256  aValues = aItem.GetProperties( aNames );
257  pProperties = aValues.getArray();
258 
259  pProperties[ CSVIO_MergeDelimiters ] <<= bMergeDelimiters;
260  pProperties[ CSVIO_RemoveSpace ] <<= bRemoveSpace;
261  pProperties[ CSVIO_Separators ] <<= sFieldSeparators;
262  pProperties[ CSVIO_TextSeparators ] <<= sTextSeparators;
263  pProperties[ CSVIO_FixedWidth ] <<= bFixedWidth;
264  if (eCall != SC_TEXTTOCOLUMNS)
265  {
266  pProperties[ CSVIO_FromRow ] <<= nFromRow;
267  pProperties[ CSVIO_CharSet ] <<= nCharSet;
268  pProperties[ CSVIO_QuotedAsText ] <<= bQuotedAsText;
269  pProperties[ CSVIO_DetectSpecialNum ] <<= bDetectSpecialNum;
270  pProperties[ CSVIO_Language ] <<= nLanguage;
271  }
272  if (eCall != SC_IMPORTFILE)
273  {
274  const sal_Int32 nSkipEmptyCells = getSkipEmptyCellsIndex(eCall);
275  assert( nSkipEmptyCells < aValues.getLength());
276  pProperties[ nSkipEmptyCells ] <<= bSkipEmptyCells;
277  }
278 
279  aItem.PutProperties(aNames, aValues);
280 }
281 
282 constexpr OUStringLiteral gaTextSepList(SCSTR_TEXTSEP);
283 
284 ScImportAsciiDlg::ScImportAsciiDlg(weld::Window* pParent, const OUString& aDatName,
285  SvStream* pInStream, ScImportAsciiCall eCall)
286  : GenericDialogController(pParent, "modules/scalc/ui/textimportcsv.ui", "TextImportCsvDialog")
287  , mpDatStream(pInStream)
288  , mnStreamPos(pInStream ? pInStream->Tell() : 0)
289  , mnRowPosCount(0)
290  , mcTextSep(ScAsciiOptions::cDefaultTextSep)
291  , meCall(eCall)
292  , mbDetectSpaceSep(eCall != SC_TEXTTOCOLUMNS)
293  , mxFtCharSet(m_xBuilder->weld_label("textcharset"))
294  , mxLbCharSet(new SvxTextEncodingBox(m_xBuilder->weld_combo_box("charset")))
295  , mxFtCustomLang(m_xBuilder->weld_label("textlanguage"))
296  , mxLbCustomLang(new SvxLanguageBox(m_xBuilder->weld_combo_box("language")))
297  , mxFtRow(m_xBuilder->weld_label("textfromrow"))
298  , mxNfRow(m_xBuilder->weld_spin_button("fromrow"))
299  , mxRbFixed(m_xBuilder->weld_radio_button("tofixedwidth"))
300  , mxRbSeparated(m_xBuilder->weld_radio_button("toseparatedby"))
301  , mxCkbTab(m_xBuilder->weld_check_button("tab"))
302  , mxCkbSemicolon(m_xBuilder->weld_check_button("semicolon"))
303  , mxCkbComma(m_xBuilder->weld_check_button("comma"))
304  , mxCkbRemoveSpace(m_xBuilder->weld_check_button("removespace"))
305  , mxCkbSpace(m_xBuilder->weld_check_button("space"))
306  , mxCkbOther(m_xBuilder->weld_check_button("other"))
307  , mxEdOther(m_xBuilder->weld_entry("inputother"))
308  , mxCkbAsOnce(m_xBuilder->weld_check_button("mergedelimiters"))
309  , mxFtTextSep(m_xBuilder->weld_label("texttextdelimiter"))
310  , mxCbTextSep(m_xBuilder->weld_combo_box("textdelimiter"))
311  , mxCkbQuotedAsText(m_xBuilder->weld_check_button("quotedfieldastext"))
312  , mxCkbDetectNumber(m_xBuilder->weld_check_button("detectspecialnumbers"))
313  , mxCkbSkipEmptyCells(m_xBuilder->weld_check_button("skipemptycells"))
314  , mxFtType(m_xBuilder->weld_label("textcolumntype"))
315  , mxLbType(m_xBuilder->weld_combo_box("columntype"))
316  , mxAltTitle(m_xBuilder->weld_label("textalttitle"))
317  , mxTableBox(new ScCsvTableBox(*m_xBuilder))
318 {
319  OUString aName = m_xDialog->get_title();
320  switch (meCall)
321  {
322  case SC_TEXTTOCOLUMNS:
323  m_xDialog->set_title(mxAltTitle->get_label());
324  break;
325  case SC_IMPORTFILE:
326  aName += " - [" + aDatName + "]";
327  m_xDialog->set_title(aName);
328  break;
329  default:
330  break;
331  }
332 
333  // To be able to prefill the correct values based on the file extension
334  bool bIsTSV = (aDatName.endsWithIgnoreAsciiCase(".tsv") || aDatName.endsWithIgnoreAsciiCase(".tab"));
335 
336  // Default options are set in officecfg/registry/schema/org/openoffice/Office/Calc.xcs
337  OUString sFieldSeparators(",;\t");
338  OUString sTextSeparators(mcTextSep);
339  bool bMergeDelimiters = false;
340  bool bFixedWidth = false;
341  bool bQuotedFieldAsText = false;
342  bool bDetectSpecialNum = true;
343  bool bSkipEmptyCells = true;
344  bool bRemoveSpace = false;
345  sal_Int32 nFromRow = 1;
346  sal_Int32 nCharSet = -1;
347  sal_Int32 nLanguage = 0;
348  lcl_LoadSeparators (sFieldSeparators, sTextSeparators, bMergeDelimiters,
349  bQuotedFieldAsText, bDetectSpecialNum, bFixedWidth, nFromRow,
350  nCharSet, nLanguage, bSkipEmptyCells, bRemoveSpace, meCall);
351  // load from saved settings
352  maFieldSeparators = sFieldSeparators;
353 
354  if( bMergeDelimiters && !bIsTSV )
355  mxCkbAsOnce->set_active(true);
356  if (bQuotedFieldAsText)
357  mxCkbQuotedAsText->set_active(true);
358  if (bRemoveSpace)
359  mxCkbRemoveSpace->set_active(true);
360  if (bDetectSpecialNum)
361  mxCkbDetectNumber->set_active(true);
362  if (bSkipEmptyCells)
363  mxCkbSkipEmptyCells->set_active(true);
364  if (bFixedWidth && !bIsTSV)
365  mxRbFixed->set_active(true);
366  if (nFromRow != 1)
367  mxNfRow->set_value(nFromRow);
368 
369  if ( bIsTSV )
370  mxCkbTab->set_active(true);
371  else
372  SetSeparators(); // Set Separators in the dialog from maFieldSeparators (empty are not set)
373 
374  // Get Separators from the dialog (empty are set from default)
376 
377  // Clipboard is always Unicode, else detect.
378  rtl_TextEncoding ePreselectUnicode = (meCall == SC_IMPORTFILE ?
379  RTL_TEXTENCODING_DONTKNOW : RTL_TEXTENCODING_UNICODE);
380  // Sniff for Unicode / not
381  if( ePreselectUnicode == RTL_TEXTENCODING_DONTKNOW && mpDatStream )
382  {
383  Seek( 0 );
384  mpDatStream->StartReadingUnicodeText( RTL_TEXTENCODING_DONTKNOW );
385  sal_uLong nUniPos = mpDatStream->Tell();
386  switch (nUniPos)
387  {
388  case 2:
389  ePreselectUnicode = RTL_TEXTENCODING_UNICODE; // UTF-16
390  break;
391  case 3:
392  ePreselectUnicode = RTL_TEXTENCODING_UTF8; // UTF-8
393  break;
394  case 0:
395  {
396  sal_uInt16 n;
397  mpDatStream->ReadUInt16( n );
398  // Assume that normal ASCII/ANSI/ISO/etc. text doesn't start with
399  // control characters except CR,LF,TAB
400  if ( (n & 0xff00) < 0x2000 )
401  {
402  switch ( n & 0xff00 )
403  {
404  case 0x0900 :
405  case 0x0a00 :
406  case 0x0d00 :
407  break;
408  default:
409  ePreselectUnicode = RTL_TEXTENCODING_UNICODE; // UTF-16
410  }
411  }
412  mpDatStream->Seek(0);
413  }
414  break;
415  default:
416  ; // nothing
417  }
419  }
420 
421  mxNfRow->connect_value_changed( LINK( this, ScImportAsciiDlg, FirstRowHdl ) );
422 
423  // *** Separator characters ***
425  mxCbTextSep->set_entry_text(sTextSeparators);
426 
427  Link<weld::Button&,void> aSeparatorClickHdl =LINK( this, ScImportAsciiDlg, SeparatorClickHdl );
428  mxCbTextSep->connect_changed( LINK( this, ScImportAsciiDlg, SeparatorComboBoxHdl ) );
429  mxCkbTab->connect_clicked( aSeparatorClickHdl );
430  mxCkbSemicolon->connect_clicked( aSeparatorClickHdl );
431  mxCkbComma->connect_clicked( aSeparatorClickHdl );
432  mxCkbAsOnce->connect_clicked( aSeparatorClickHdl );
433  mxCkbQuotedAsText->connect_clicked( aSeparatorClickHdl );
434  mxCkbDetectNumber->connect_clicked( aSeparatorClickHdl );
435  mxCkbSkipEmptyCells->connect_clicked( aSeparatorClickHdl );
436  mxCkbSpace->connect_clicked( aSeparatorClickHdl );
437  mxCkbRemoveSpace->connect_clicked( aSeparatorClickHdl );
438  mxCkbOther->connect_clicked( aSeparatorClickHdl );
439  mxEdOther->connect_changed(LINK(this, ScImportAsciiDlg, SeparatorEditHdl));
440 
441  // *** text encoding ListBox ***
442  // all encodings allowed, including Unicode, but subsets are excluded
443  mxLbCharSet->FillFromTextEncodingTable( true );
444  // Insert one "SYSTEM" entry for compatibility in AsciiOptions and system
445  // independent document linkage.
446  mxLbCharSet->InsertTextEncoding( RTL_TEXTENCODING_DONTKNOW, ScResId( SCSTR_CHARSET_USER ) );
447  if ( ePreselectUnicode == RTL_TEXTENCODING_DONTKNOW )
448  {
449  rtl_TextEncoding eSystemEncoding = osl_getThreadTextEncoding();
450  // Prefer UTF-8, as UTF-16 would have already been detected from the stream.
451  // This gives a better chance that the file is going to be opened correctly.
452  if ( ( eSystemEncoding == RTL_TEXTENCODING_UNICODE ) && mpDatStream )
453  eSystemEncoding = RTL_TEXTENCODING_UTF8;
454  mxLbCharSet->SelectTextEncoding( eSystemEncoding );
455  }
456  else
457  {
458  mxLbCharSet->SelectTextEncoding( ePreselectUnicode );
459  }
460 
461  if (nCharSet >= 0 && ePreselectUnicode == RTL_TEXTENCODING_DONTKNOW)
462  mxLbCharSet->set_active(nCharSet);
463 
465  mxLbCharSet->connect_changed( LINK( this, ScImportAsciiDlg, CharSetHdl ) );
466 
467  mxLbCustomLang->SetLanguageList(
468  SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, false, false);
469  mxLbCustomLang->InsertLanguage(LANGUAGE_SYSTEM);
470  mxLbCustomLang->set_active_id(static_cast<LanguageType>(nLanguage));
471 
472  // *** column type ListBox ***
473  OUString aColumnUser( ScResId( SCSTR_COLUMN_USER ) );
474  for (sal_Int32 nIdx {0}; nIdx>=0; )
475  {
476  mxLbType->append_text(aColumnUser.getToken(0, ';', nIdx));
477  }
478 
479  mxLbType->connect_changed( LINK( this, ScImportAsciiDlg, LbColTypeHdl ) );
480  mxFtType->set_sensitive(false);
481  mxLbType->set_sensitive(false);
482 
483  // *** table box preview ***
484  mxTableBox->Init();
485  mxTableBox->SetUpdateTextHdl( LINK( this, ScImportAsciiDlg, UpdateTextHdl ) );
486  mxTableBox->InitTypes( *mxLbType );
487  mxTableBox->SetColTypeHdl( LINK( this, ScImportAsciiDlg, ColTypeHdl ) );
488 
489  mxRbSeparated->connect_clicked( LINK( this, ScImportAsciiDlg, RbSepFixHdl ) );
490  mxRbFixed->connect_clicked( LINK( this, ScImportAsciiDlg, RbSepFixHdl ) );
491 
493  RbSepFixHdl(*mxRbFixed);
494 
495  UpdateVertical();
496 
497  mxTableBox->GetGrid().Execute( CSVCMD_NEWCELLTEXTS );
498 
499  if (meCall == SC_TEXTTOCOLUMNS)
500  {
501  mxFtCharSet->set_sensitive(false);
502  mxLbCharSet->set_sensitive(false);
503  mxFtCustomLang->set_sensitive(false);
504  mxLbCustomLang->set_active_id(LANGUAGE_SYSTEM);
505  mxLbCustomLang->set_sensitive(false);
506  mxFtRow->set_sensitive(false);
507  mxNfRow->set_sensitive(false);
508 
509  // Quoted field as text option is not used for text-to-columns mode.
510  mxCkbQuotedAsText->set_active(false);
511  mxCkbQuotedAsText->set_sensitive(false);
512 
513  // Always detect special numbers for text-to-columns mode.
514  mxCkbDetectNumber->set_active(true);
515  mxCkbDetectNumber->set_sensitive(false);
516  }
517  if (meCall == SC_IMPORTFILE)
518  {
519  //Empty cells in imported file are empty
520  mxCkbSkipEmptyCells->set_active(false);
521  mxCkbSkipEmptyCells->hide();
522  }
523 }
524 
526 {
527 }
528 
529 bool ScImportAsciiDlg::GetLine( sal_uLong nLine, OUString &rText, sal_Unicode& rcDetectSep )
530 {
531  if (nLine >= ASCIIDLG_MAXROWS || !mpDatStream)
532  return false;
533 
534  bool bRet = true;
535  bool bFixed = mxRbFixed->get_active();
536 
537  if (!mpRowPosArray)
538  mpRowPosArray.reset( new sal_uLong[ASCIIDLG_MAXROWS + 2] );
539 
540  if (!mnRowPosCount) // complete re-fresh
541  {
542  memset( mpRowPosArray.get(), 0, sizeof(mpRowPosArray[0]) * (ASCIIDLG_MAXROWS+2));
543 
544  Seek(0);
546 
549  }
550 
551  if (nLine >= mnRowPosCount)
552  {
553  // need to work out some more line information
554  do
555  {
557  {
558  bRet = false;
559  break;
560  }
561  rText = ReadCsvLine(*mpDatStream, !bFixed, maFieldSeparators,
562  mcTextSep, rcDetectSep);
565  } while (nLine >= mnRowPosCount && mpDatStream->good());
566  if (mpDatStream->eof() &&
568  {
569  // the very end, not even an empty line read
570  bRet = false;
571  --mnRowPosCount;
572  }
573  }
574  else
575  {
576  Seek( mpRowPosArray[nLine]);
577  rText = ReadCsvLine(*mpDatStream, !bFixed, maFieldSeparators, mcTextSep, rcDetectSep);
579  }
580 
581  // If the file content isn't unicode, ReadUniStringLine
582  // may try to seek beyond the file's end and cause a CANTSEEK error
583  // (depending on the stream type). The error code has to be cleared,
584  // or further read operations (including non-unicode) will fail.
587 
589 
590  return bRet;
591 }
592 
594 {
595  rOpt.SetCharSet( meCharSet );
597  rOpt.SetLanguage(mxLbCustomLang->get_active_id());
598  rOpt.SetFixedLen( mxRbFixed->get_active() );
599  rOpt.SetStartRow( mxNfRow->get_value() );
600  mxTableBox->FillColumnData( rOpt );
601  if( mxRbSeparated->get_active() )
602  {
603  rOpt.SetFieldSeps( GetSeparators() );
604  rOpt.SetMergeSeps( mxCkbAsOnce->get_active() );
605  rOpt.SetRemoveSpace( mxCkbRemoveSpace->get_active() );
607  }
608 
609  rOpt.SetQuotedAsText(mxCkbQuotedAsText->get_active());
610  rOpt.SetDetectSpecialNumber(mxCkbDetectNumber->get_active());
611  rOpt.SetSkipEmptyCells(mxCkbSkipEmptyCells->get_active());
612 }
613 
615 {
616  lcl_SaveSeparators( maFieldSeparators, mxCbTextSep->get_active_text(), mxCkbAsOnce->get_active(),
617  mxCkbQuotedAsText->get_active(), mxCkbDetectNumber->get_active(),
618  mxRbFixed->get_active(),
619  mxNfRow->get_value(),
620  mxLbCharSet->get_active(),
621  static_cast<sal_uInt16>(mxLbCustomLang->get_active_id()),
622  mxCkbSkipEmptyCells->get_active(), mxCkbRemoveSpace->get_active(), meCall );
623 }
624 
626 {
627  OString sString(OUStringToOString(maFieldSeparators,
628  RTL_TEXTENCODING_MS_1252));
629  const char *aSep = sString.getStr();
630  sal_Int32 len = maFieldSeparators.getLength();
631  for (int i = 0; i < len; ++i)
632  {
633  switch( aSep[i] )
634  {
635  case '\t': mxCkbTab->set_active(true); break;
636  case ';': mxCkbSemicolon->set_active(true); break;
637  case ',': mxCkbComma->set_active(true); break;
638  case ' ': mxCkbSpace->set_active(true); break;
639  default:
640  mxCkbOther->set_active(true);
641  mxEdOther->set_text(mxEdOther->get_text() + OUStringChar(aSep[i]));
642  }
643  }
644 }
645 
647 {
648  meCharSet = mxLbCharSet->GetSelectTextEncoding();
649  mbCharSetSystem = (meCharSet == RTL_TEXTENCODING_DONTKNOW);
650  if( mbCharSetSystem )
651  meCharSet = osl_getThreadTextEncoding();
652 }
653 
655 {
656  OUString aSepChars;
657  if( mxCkbTab->get_active() )
658  aSepChars += "\t";
659  if( mxCkbSemicolon->get_active() )
660  aSepChars += ";";
661  if( mxCkbComma->get_active() )
662  aSepChars += ",";
663  if( mxCkbSpace->get_active() )
664  aSepChars += " ";
665  if( mxCkbOther->get_active() )
666  aSepChars += mxEdOther->get_text();
667  return aSepChars;
668 }
669 
671 {
672  bool bEnable = mxRbSeparated->get_active();
673  mxCkbTab->set_sensitive( bEnable );
674  mxCkbSemicolon->set_sensitive( bEnable );
675  mxCkbComma->set_sensitive( bEnable );
676  mxCkbSpace->set_sensitive( bEnable );
677  mxCkbRemoveSpace->set_sensitive( bEnable );
678  mxCkbOther->set_sensitive( bEnable );
679  mxEdOther->set_sensitive( bEnable );
680  mxCkbAsOnce->set_sensitive( bEnable );
681  mxFtTextSep->set_sensitive( bEnable );
682  mxCbTextSep->set_sensitive( bEnable );
683 }
684 
686 {
687  mnRowPosCount = 0;
688  if (mpDatStream)
690 }
691 
692 IMPL_LINK(ScImportAsciiDlg, RbSepFixHdl, weld::Button&, rButton, void)
693 {
694  if (&rButton == mxRbFixed.get() || &rButton == mxRbSeparated.get())
695  {
696  weld::WaitObject aWaitObj(m_xDialog.get());
697  if( mxRbFixed->get_active() )
698  mxTableBox->SetFixedWidthMode();
699  else
700  mxTableBox->SetSeparatorsMode();
701  SetupSeparatorCtrls();
702  }
703 }
704 
705 IMPL_LINK(ScImportAsciiDlg, SeparatorClickHdl, weld::Button&, rCtrl, void)
706 {
707  SeparatorHdl(&rCtrl);
708 }
709 
710 IMPL_LINK( ScImportAsciiDlg, SeparatorComboBoxHdl, weld::ComboBox&, rCtrl, void )
711 {
712  SeparatorHdl(&rCtrl);
713 }
714 
715 IMPL_LINK( ScImportAsciiDlg, SeparatorEditHdl, weld::Entry&, rEdit, void )
716 {
717  SeparatorHdl(&rEdit);
718 }
719 
721 {
722  OSL_ENSURE( pCtrl, "ScImportAsciiDlg::SeparatorHdl - missing sender" );
723  OSL_ENSURE( !mxRbFixed->get_active(), "ScImportAsciiDlg::SeparatorHdl - not allowed in fixed width" );
724 
725  /* #i41550# First update state of the controls. The GetSeparators()
726  function needs final state of the check boxes. */
727  if (pCtrl == mxCkbOther.get() && mxCkbOther->get_active())
728  mxEdOther->grab_focus();
729  else if (pCtrl == mxEdOther.get())
730  mxCkbOther->set_active(!mxEdOther->get_text().isEmpty());
731 
732  OUString aOldFldSeps( maFieldSeparators);
734  sal_Unicode cOldSep = mcTextSep;
736  // Any separator changed may result in completely different lines due to
737  // embedded line breaks.
738  if (cOldSep != mcTextSep || aOldFldSeps != maFieldSeparators)
739  UpdateVertical();
740 
741  mxTableBox->GetGrid().Execute( CSVCMD_NEWCELLTEXTS );
742 }
743 
745 {
746  if (mxLbCharSet->get_active() != -1)
747  {
748  weld::WaitObject aWaitObj(m_xDialog.get());
749  rtl_TextEncoding eOldCharSet = meCharSet;
750  SetSelectedCharSet();
751  // switching char-set invalidates 8bit -> String conversions
752  if (eOldCharSet != meCharSet)
753  UpdateVertical();
754 
755  mxTableBox->GetGrid().Execute( CSVCMD_NEWCELLTEXTS );
756  }
757 }
758 
759 IMPL_LINK(ScImportAsciiDlg, FirstRowHdl, weld::SpinButton&, rNumField, void)
760 {
761  mxTableBox->GetGrid().Execute( CSVCMD_SETFIRSTIMPORTLINE, rNumField.get_value() - 1);
762 }
763 
764 IMPL_LINK(ScImportAsciiDlg, LbColTypeHdl, weld::ComboBox&, rListBox, void)
765 {
766  if (&rListBox == mxLbType.get())
767  mxTableBox->GetGrid().Execute(CSVCMD_SETCOLUMNTYPE, rListBox.get_active());
768 }
769 
771 {
772  // Checking the separator can only be done once for the very first time
773  // when the dialog wasn't already presented to the user.
774  // As a side effect this has the benefit that the check is only done on the
775  // first set of visible lines.
776  sal_Unicode cDetectSep = (mbDetectSpaceSep && !mxRbFixed->get_active() && !mxCkbSpace->get_active() ? 0 : 0xffff);
777 
778  sal_Int32 nBaseLine = mxTableBox->GetGrid().GetFirstVisLine();
779  sal_Int32 nRead = mxTableBox->GetGrid().GetVisLineCount();
780  // If mnRowPosCount==0, this is an initializing call, read ahead for row
781  // count and resulting scroll bar size and position to be able to scroll at
782  // all. When adding lines, read only the amount of next lines to be
783  // displayed.
784  if (!mnRowPosCount || nRead > CSV_PREVIEW_LINES)
785  nRead = CSV_PREVIEW_LINES;
786 
787  sal_Int32 i;
788  for (i = 0; i < nRead; i++)
789  {
790  if (!GetLine( nBaseLine + i, maPreviewLine[i], cDetectSep))
791  break;
792  }
793  for (; i < CSV_PREVIEW_LINES; i++)
794  maPreviewLine[i].clear();
795 
796  if (mbDetectSpaceSep)
797  {
798  mbDetectSpaceSep = false;
799  if (cDetectSep == ' ')
800  {
801  // Expect space to be appended by now so all subsequent
802  // GetLine()/ReadCsvLine() actually used it.
803  assert(maFieldSeparators.endsWith(" "));
804  // Preselect Space in UI.
805  mxCkbSpace->set_active(true);
806  }
807  }
808 
809  mxTableBox->GetGrid().Execute( CSVCMD_SETLINECOUNT, mnRowPosCount);
810  bool bMergeSep = mxCkbAsOnce->get_active();
811  bool bRemoveSpace = mxCkbRemoveSpace->get_active();
812  mxTableBox->SetUniStrings( maPreviewLine, maFieldSeparators, mcTextSep, bMergeSep, bRemoveSpace );
813 }
814 
815 IMPL_LINK( ScImportAsciiDlg, ColTypeHdl, ScCsvTableBox&, rTableBox, void )
816 {
817  sal_Int32 nType = rTableBox.GetSelColumnType();
818  sal_Int32 nTypeCount = mxLbType->get_count();
819  bool bEmpty = (nType == CSV_TYPE_MULTI);
820  bool bEnable = ((0 <= nType) && (nType < nTypeCount)) || bEmpty;
821 
822  mxFtType->set_sensitive( bEnable );
823  mxLbType->set_sensitive( bEnable );
824 
825  if (bEmpty)
826  mxLbType->set_active(-1);
827  else if (bEnable)
828  mxLbType->set_active(nType);
829 }
830 
831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< weld::Dialog > m_xDialog
std::unique_ptr< weld::ComboBox > mxLbType
OUString maFieldSeparators
virtual ~ScImportAsciiDlg() override
std::unique_ptr< weld::RadioButton > mxRbFixed
std::unique_ptr< weld::CheckButton > mxCkbOther
static SC_DLLPUBLIC::utl::TransliterationWrapper * GetpTransliteration()
Definition: global.cxx:982
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
void SeparatorHdl(const weld::Widget *)
sal_Int32 nProperties
const ::std::vector< OUString > CSVImportOptionNames
std::unique_ptr< weld::ComboBox > mxCbTextSep
void SetSeparators()
Set separators in ui from maFieldSeparators.
sal_Unicode mcTextSep
IMPL_LINK_NOARG(ScImportAsciiDlg, CharSetHdl, weld::ComboBox &, void)
bool Seek(sal_uLong nPos)
sal_uIntPtr sal_uLong
static void lcl_FillCombo(weld::ComboBox &rCombo, const OUString &rList, sal_Unicode cSelect)
const OUString aSep_Path_Clpbrd
Update cell texts with current split settings. [-].
Definition: csvcontrol.hxx:186
sal_Int64 n
void SetCharSetSystem(bool bSet)
Definition: asciiopt.hxx:72
sal_uInt64 Seek(sal_uInt64 nPos)
const OUString aSep_Path
std::unique_ptr< weld::SpinButton > mxNfRow
static void lcl_CreatePropertiesNames(OUString &rSepPath, Sequence< OUString > &rNames, ScImportAsciiCall eCall)
void SetupSeparatorCtrls()
Enables or disables all separator checkboxes and edit fields.
bool GetLine(sal_uLong nLine, OUString &rText, sal_Unicode &rcDetectSep)
void SetSkipEmptyCells(bool bSet)
Definition: asciiopt.hxx:79
std::unique_ptr< weld::CheckButton > mxCkbQuotedAsText
const OUString aSep_Path_Text2Col
std::unique_ptr< weld::RadioButton > mxRbSeparated
sal_uLong mnStreamPos
SvStream * mpDatStream
#define ERRCODE_IO_CANTSEEK
std::unique_ptr< weld::CheckButton > mxCkbSpace
void SetCharSet(rtl_TextEncoding eNew)
Definition: asciiopt.hxx:71
sal_uInt16 sal_Unicode
static void lcl_LoadSeparators(OUString &rFieldSeparators, OUString &rTextSeparators, bool &rMergeDelimiters, bool &rQuotedAsText, bool &rDetectSpecialNum, bool &rFixedWidth, sal_Int32 &rFromRow, sal_Int32 &rCharSet, sal_Int32 &rLanguage, bool &rSkipEmptyCells, bool &rRemoveSpace, ScImportAsciiCall eCall)
void SetDetectSpecialNumber(bool bSet)
Definition: asciiopt.hxx:78
ErrCode GetError() const
bool eof() const
void StartReadingUnicodeText(rtl_TextEncoding eReadBomCharSet)
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:45
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
const SCSIZE ASCIIDLG_MAXROWS
TODO make dynamic.
std::unique_ptr< weld::CheckButton > mxCkbSkipEmptyCells
const SCROW MAXROWCOUNT
Definition: address.hxx:63
std::unique_ptr< weld::CheckButton > mxCkbSemicolon
std::unique_ptr< weld::CheckButton > mxCkbComma
OUString GetSeparators() const
Returns all separator characters in a string.
Send selected column type to external controls. [-].
Definition: csvcontrol.hxx:188
std::unique_ptr< weld::Label > mxFtCharSet
Whether to detect a possible space separator.
std::unique_ptr< weld::Label > mxFtRow
void SetQuotedAsText(bool bSet)
Definition: asciiopt.hxx:77
rtl_TextEncoding meCharSet
int i
std::unique_ptr< ScCsvTableBox > mxTableBox
void SetLanguage(LanguageType e)
Definition: asciiopt.hxx:82
#define LANGUAGE_SYSTEM
void SetRemoveSpace(bool bSet)
Definition: asciiopt.hxx:76
void SetSelectedCharSet()
Sets the selected char set data to meCharSet and mbCharSetSystem.
std::unique_ptr< weld::CheckButton > mxCkbTab
bool mbCharSetSystem
Selected char set.
OUString ScResId(const char *pId)
Definition: scdll.cxx:95
std::unique_ptr< weld::CheckButton > mxCkbDetectNumber
static void lcl_SaveSeparators(const OUString &sFieldSeparators, const OUString &sTextSeparators, bool bMergeDelimiters, bool bQuotedAsText, bool bDetectSpecialNum, bool bFixedWidth, sal_Int32 nFromRow, sal_Int32 nCharSet, sal_Int32 nLanguage, bool bSkipEmptyCells, bool bRemoveSpace, ScImportAsciiCall eCall)
std::unique_ptr< SvxTextEncodingBox > mxLbCharSet
void SetFixedLen(bool bSet)
Definition: asciiopt.hxx:73
void SetFieldSeps(const OUString &rStr)
Definition: asciiopt.hxx:74
void GetOptions(ScAsciiOptions &rOpt)
void SetStartRow(long nRow)
Definition: asciiopt.hxx:81
void PutProperties(const css::uno::Sequence< OUString > &rNames, const css::uno::Sequence< css::uno::Any > &rValues)
Definition: optutil.hxx:54
IMPL_LINK(ScImportAsciiDlg, RbSepFixHdl, weld::Button &, rButton, void)
The control in the CSV import dialog that contains a ruler and a data grid to visualize and modify th...
Definition: csvtablebox.hxx:44
static void EmbeddedNullTreatment(OUString &rStr)
Definition: impex.cxx:1533
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
Move to make passed position visible (for mouse tracking). [position].
Definition: csvcontrol.hxx:184
std::unique_ptr< weld::Label > mxFtTextSep
#define SCSTR_TEXTSEP
Definition: strings.hxx:13
std::unique_ptr< sal_uLong[]> mpRowPosArray
weld::Entry & rEdit
std::unique_ptr< weld::Entry > mxEdOther
const sal_Int32 CSV_TYPE_MULTI
Multi selection with different types.
Definition: csvcontrol.hxx:51
static sal_Unicode lcl_CharFromCombo(const weld::ComboBox &rCombo, const OUString &rList)
constexpr OUStringLiteral gaTextSepList(SCSTR_TEXTSEP)
OUString aName
std::unique_ptr< weld::Label > mxAltTitle
ScImportAsciiCall
How ScImportAsciiDlg is called.
Definition: asciiopt.hxx:101
void SetStreamCharSet(rtl_TextEncoding eCharSet)
rtl_TextEncoding GetStreamCharSet() const
Reference< XExecutableDialog > m_xDialog
std::unique_ptr< weld::CheckButton > mxCkbAsOnce
sal_uLong mnRowPosCount
sal_uInt64 Tell() const
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:401
Change character pixel width. [width in pixel].
Definition: csvcontrol.hxx:173
bool good() const
ScImportAsciiCall meCall
Is System char set selected?
OUString ReadCsvLine(SvStream &rStream, bool bEmbeddedLineBreak, OUString &rFieldSeparators, sal_Unicode cFieldQuote, sal_Unicode &rcDetectSep)
Read a CSV (comma separated values) data line using ReadUniOrByteStringLine().
Definition: impex.cxx:2401
void append_text(const OUString &rStr)
virtual void ResetError()
std::unique_ptr< weld::CheckButton > mxCkbRemoveSpace
void SetMergeSeps(bool bSet)
Definition: asciiopt.hxx:75
static bool GetBoolFromAny(const css::uno::Any &aAny)
Definition: miscuno.cxx:138
std::unique_ptr< SvxLanguageBox > mxLbCustomLang
css::uno::Sequence< css::uno::Any > GetProperties(const css::uno::Sequence< OUString > &rNames)
Definition: optutil.hxx:52
ScImportAsciiDlg(weld::Window *pParent, const OUString &aDatName, SvStream *pInStream, ScImportAsciiCall eCall)
aStr
virtual void set_entry_text(const OUString &rStr)=0
void SetTextSep(sal_Unicode c)
Definition: asciiopt.hxx:80
std::unique_ptr< weld::Label > mxFtCustomLang
const sal_Int32 CSV_PREVIEW_LINES
TODO make string array dynamic.
Definition: csvcontrol.hxx:44
virtual OUString get_active_text() const =0
CSVImportOptionsIndex
std::unique_ptr< weld::Label > mxFtType