fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / docshell / docsh8.cxx
blobc78021f26bf5d7cb1023fb3cf655dba1a0fe4c09
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <stdio.h>
23 #include <tools/urlobj.hxx>
24 #include <svl/converter.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <comphelper/string.hxx>
27 #include <comphelper/types.hxx>
28 #include <ucbhelper/content.hxx>
29 #include <svx/txenctab.hxx>
30 #include <unotools/sharedunocomponent.hxx>
32 #if HAVE_FEATURE_DBCONNECTIVITY
33 #include <svx/dbcharsethelper.hxx>
34 #endif
36 #include <com/sun/star/sdb/CommandType.hpp>
37 #include <com/sun/star/sdbc/DataType.hpp>
38 #include <com/sun/star/sdbc/XConnection.hpp>
39 #include <com/sun/star/sdbc/XDriver.hpp>
40 #include <com/sun/star/sdbc/XDriverAccess.hpp>
41 #include <com/sun/star/sdbc/DriverManager.hpp>
42 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
43 #include <com/sun/star/sdbc/XRow.hpp>
44 #include <com/sun/star/sdbc/XRowSet.hpp>
45 #include <com/sun/star/sdbc/XRowUpdate.hpp>
46 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
47 #include <com/sun/star/sdbcx/XAppend.hpp>
48 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
49 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
50 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
51 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
52 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #include <com/sun/star/container/XEnumerationAccess.hpp>
55 #include <com/sun/star/lang/XComponent.hpp>
56 #include <com/sun/star/ucb/NameClash.hpp>
57 #include <com/sun/star/ucb/TransferInfo.hpp>
58 #include <com/sun/star/ucb/XCommandInfo.hpp>
60 #include "scerrors.hxx"
61 #include "docsh.hxx"
62 #include "filter.hxx"
63 #include "progress.hxx"
64 #include "formulacell.hxx"
65 #include "editutil.hxx"
66 #include "cellform.hxx"
67 #include "dbdocutl.hxx"
68 #include "dociter.hxx"
69 #include "globstr.hrc"
70 #include <svl/zformat.hxx>
71 #include <svl/intitem.hxx>
72 #include "patattr.hxx"
73 #include "scitems.hxx"
74 #include "docpool.hxx"
75 #include "segmenttree.hxx"
76 #include "docparam.hxx"
77 #include "cellvalue.hxx"
79 #include <unordered_set>
80 #include <vector>
82 using namespace com::sun::star;
83 using ::std::vector;
85 #if HAVE_FEATURE_DBCONNECTIVITY
87 #define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
89 //! move to a header file?
90 #define SC_DBPROP_ACTIVECONNECTION "ActiveConnection"
91 #define SC_DBPROP_COMMAND "Command"
92 #define SC_DBPROP_COMMANDTYPE "CommandType"
93 #define SC_DBPROP_PROPCHANGE_NOTIFY "PropertyChangeNotificationEnabled"
95 #define SC_DBPROP_NAME "Name"
96 #define SC_DBPROP_TYPE "Type"
97 #define SC_DBPROP_PRECISION "Precision"
98 #define SC_DBPROP_SCALE "Scale"
100 #define SC_DBPROP_EXTENSION "Extension"
101 #define SC_DBPROP_CHARSET "CharSet"
103 namespace
105 sal_uLong lcl_getDBaseConnection(uno::Reference<sdbc::XDriverManager2>& _rDrvMgr, uno::Reference<sdbc::XConnection>& _rConnection, OUString& _rTabName, const OUString& rFullFileName, rtl_TextEncoding eCharSet)
107 INetURLObject aURL;
108 aURL.SetSmartProtocol( INetProtocol::File );
109 aURL.SetSmartURL( rFullFileName );
110 _rTabName = aURL.getBase( INetURLObject::LAST_SEGMENT, true,
111 INetURLObject::DECODE_UNAMBIGUOUS );
112 OUString aExtension = aURL.getExtension();
113 aURL.removeSegment();
114 aURL.removeFinalSlash();
115 OUString aPath = aURL.GetMainURL(INetURLObject::NO_DECODE);
116 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
118 _rDrvMgr.set( sdbc::DriverManager::create( xContext ) );
120 // get connection
122 OUString aConnUrl("sdbc:dbase:");
123 aConnUrl += aPath;
125 ::std::vector< rtl_TextEncoding > aEncodings;
126 svxform::charset_helper::getSupportedTextEncodings( aEncodings );
127 ::std::vector< rtl_TextEncoding >::iterator aIter = ::std::find(aEncodings.begin(),aEncodings.end(),(rtl_TextEncoding) eCharSet);
128 if ( aIter == aEncodings.end() )
130 OSL_FAIL( "DBaseImport: dbtools::OCharsetMap doesn't know text encoding" );
131 return SCERR_IMPORT_CONNECT;
132 } // if ( aIter == aMap.end() )
133 OUString aCharSetStr;
134 if ( RTL_TEXTENCODING_DONTKNOW != *aIter )
135 { // it's not the virtual "system charset"
136 const char* pIanaName = rtl_getMimeCharsetFromTextEncoding( *aIter );
137 OSL_ENSURE( pIanaName, "invalid mime name!" );
138 if ( pIanaName )
139 aCharSetStr = OUString::createFromAscii( pIanaName );
142 uno::Sequence<beans::PropertyValue> aProps(2);
143 aProps[0].Name = SC_DBPROP_EXTENSION;
144 aProps[0].Value <<= OUString( aExtension );
145 aProps[1].Name = SC_DBPROP_CHARSET;
146 aProps[1].Value <<= aCharSetStr;
148 _rConnection = _rDrvMgr->getConnectionWithInfo( aConnUrl, aProps );
149 return 0L;
153 #endif // HAVE_FEATURE_DBCONNECTIVITY
155 // MoveFile/KillFile/IsDocument: similar to SfxContentHelper
157 bool ScDocShell::MoveFile( const INetURLObject& rSourceObj, const INetURLObject& rDestObj )
159 bool bMoveData = true;
160 bool bRet = true, bKillSource = false;
161 if ( rSourceObj.GetProtocol() != rDestObj.GetProtocol() )
163 bMoveData = false;
164 bKillSource = true;
166 OUString aName = rDestObj.getName();
167 INetURLObject aDestPathObj = rDestObj;
168 aDestPathObj.removeSegment();
169 aDestPathObj.setFinalSlash();
173 ::ucbhelper::Content aDestPath( aDestPathObj.GetMainURL(INetURLObject::NO_DECODE),
174 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
175 comphelper::getProcessComponentContext() );
176 uno::Reference< ::com::sun::star::ucb::XCommandInfo > xInfo = aDestPath.getCommands();
177 OUString aTransferName = "transfer";
178 if ( xInfo->hasCommandByName( aTransferName ) )
180 aDestPath.executeCommand( aTransferName, uno::makeAny(
181 ::com::sun::star::ucb::TransferInfo( bMoveData, rSourceObj.GetMainURL(INetURLObject::NO_DECODE), aName,
182 ::com::sun::star::ucb::NameClash::ERROR ) ) );
184 else
186 OSL_FAIL( "transfer command not available" );
189 catch( uno::Exception& )
191 // ucb may throw different exceptions on failure now
192 bRet = false;
195 if ( bKillSource )
196 KillFile( rSourceObj );
198 return bRet;
201 bool ScDocShell::KillFile( const INetURLObject& rURL )
203 bool bRet = true;
206 ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::NO_DECODE),
207 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
208 comphelper::getProcessComponentContext() );
209 aCnt.executeCommand( OUString( "delete" ),
210 comphelper::makeBoolAny( true ) );
212 catch( uno::Exception& )
214 // ucb may throw different exceptions on failure now
215 bRet = false;
218 return bRet;
221 bool ScDocShell::IsDocument( const INetURLObject& rURL )
223 bool bRet = false;
226 ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::NO_DECODE),
227 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
228 comphelper::getProcessComponentContext() );
229 bRet = aCnt.isDocument();
231 catch( uno::Exception& )
233 // ucb may throw different exceptions on failure now - warning only
234 OSL_FAIL( "Any other exception" );
237 return bRet;
240 #if HAVE_FEATURE_DBCONNECTIVITY
242 static void lcl_setScalesToColumns(ScDocument& rDoc, const vector<long>& rScales)
244 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
245 if (!pFormatter)
246 return;
248 SCCOL nColCount = static_cast<SCCOL>(rScales.size());
249 for (SCCOL i = 0; i < nColCount; ++i)
251 if (rScales[i] < 0)
252 continue;
254 sal_uInt32 nOldFormat;
255 rDoc.GetNumberFormat(static_cast<SCCOL>(i), 0, 0, nOldFormat);
256 const SvNumberformat* pOldEntry = pFormatter->GetEntry(nOldFormat);
257 if (!pOldEntry)
258 continue;
260 LanguageType eLang = pOldEntry->GetLanguage();
261 bool bThousand, bNegRed;
262 sal_uInt16 nPrecision, nLeading;
263 pOldEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrecision, nLeading);
265 nPrecision = static_cast<sal_uInt16>(rScales[i]);
266 OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLang,
267 bThousand, bNegRed, nPrecision, nLeading);
269 sal_uInt32 nNewFormat = pFormatter->GetEntryKey(aNewPicture, eLang);
270 if (nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
272 sal_Int32 nErrPos = 0;
273 short nNewType = 0;
274 bool bOk = pFormatter->PutEntry(
275 aNewPicture, nErrPos, nNewType, nNewFormat, eLang);
277 if (!bOk)
278 continue;
281 ScPatternAttr aNewAttrs( rDoc.GetPool() );
282 SfxItemSet& rSet = aNewAttrs.GetItemSet();
283 rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nNewFormat) );
284 rDoc.ApplyPatternAreaTab(static_cast<SCCOL>(i), 0, static_cast<SCCOL>(i), MAXROW, 0, aNewAttrs);
288 #endif // HAVE_FEATURE_DBCONNECTIVITY
290 sal_uLong ScDocShell::DBaseImport( const OUString& rFullFileName, rtl_TextEncoding eCharSet,
291 ScColWidthParam aColWidthParam[MAXCOLCOUNT], ScFlatBoolRowSegments& rRowHeightsRecalc )
293 #if !HAVE_FEATURE_DBCONNECTIVITY
294 (void) rFullFileName;
295 (void) eCharSet;
296 (void) aColWidthParam;
297 (void) rRowHeightsRecalc;
299 return ERRCODE_IO_GENERAL;
300 #else
302 sal_uLong nErr = eERR_OK;
304 // Try to get the Text Encoding from the driver
305 if( eCharSet == RTL_TEXTENCODING_IBM_850 )
306 eCharSet = RTL_TEXTENCODING_DONTKNOW;
310 long i;
311 long nColCount = 0;
312 OUString aTabName;
313 uno::Reference<sdbc::XDriverManager2> xDrvMan;
314 uno::Reference<sdbc::XConnection> xConnection;
315 sal_uLong nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
316 if ( !xConnection.is() || !xDrvMan.is() )
317 return nRet;
318 ::utl::DisposableComponent aConnectionHelper(xConnection);
320 ScProgress aProgress( this, ScGlobal::GetRscString( STR_LOAD_DOC ), 0 );
321 uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
322 uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(
323 OUString( SC_SERVICE_ROWSET ) ),
324 uno::UNO_QUERY);
325 ::utl::DisposableComponent aRowSetHelper(xRowSet);
326 uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
327 OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
328 if (!xRowProp.is()) return SCERR_IMPORT_CONNECT;
330 sal_Int32 nType = sdb::CommandType::TABLE;
331 uno::Any aAny;
333 aAny <<= xConnection;
334 xRowProp->setPropertyValue( OUString(SC_DBPROP_ACTIVECONNECTION), aAny );
336 aAny <<= nType;
337 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMANDTYPE), aAny );
339 aAny <<= OUString( aTabName );
340 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMAND), aAny );
342 aAny <<= false;
343 xRowProp->setPropertyValue( OUString(SC_DBPROP_PROPCHANGE_NOTIFY), aAny );
345 xRowSet->execute();
347 uno::Reference<sdbc::XResultSetMetaData> xMeta;
348 uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( xRowSet, uno::UNO_QUERY );
349 if ( xMetaSupp.is() )
350 xMeta = xMetaSupp->getMetaData();
351 if ( xMeta.is() )
352 nColCount = xMeta->getColumnCount(); // this is the number of real columns
354 if ( nColCount > MAXCOL+1 )
356 nColCount = MAXCOL+1;
357 nErr = SCWARN_IMPORT_COLUMN_OVERFLOW; // warning
360 uno::Reference<sdbc::XRow> xRow( xRowSet, uno::UNO_QUERY );
361 OSL_ENSURE( xRow.is(), "can't get Row" );
362 if (!xRow.is()) return SCERR_IMPORT_CONNECT;
364 // currency flag is not needed for dBase
365 uno::Sequence<sal_Int32> aColTypes( nColCount ); // column types
366 sal_Int32* pTypeArr = aColTypes.getArray();
367 for (i=0; i<nColCount; i++)
368 pTypeArr[i] = xMeta->getColumnType( i+1 );
370 // read column names
371 //! add type descriptions
373 aProgress.SetState( 0 );
375 vector<long> aScales(nColCount, -1);
376 for (i=0; i<nColCount; i++)
378 OUString aHeader = xMeta->getColumnLabel( i+1 );
380 switch ( pTypeArr[i] )
382 case sdbc::DataType::BIT:
383 aHeader += ",L";
384 break;
385 case sdbc::DataType::DATE:
386 aHeader += ",D";
387 break;
388 case sdbc::DataType::LONGVARCHAR:
389 aHeader += ",M";
390 break;
391 case sdbc::DataType::VARCHAR:
392 aHeader += ",C," + OUString::number( xMeta->getColumnDisplaySize( i+1 ) );
393 break;
394 case sdbc::DataType::DECIMAL:
396 long nPrec = xMeta->getPrecision( i+1 );
397 long nScale = xMeta->getScale( i+1 );
398 aHeader += ",N," +
399 OUString::number(
400 SvDbaseConverter::ConvertPrecisionToDbase(
401 nPrec, nScale ) ) +
402 "," +
403 OUString::number( nScale );
404 aScales[i] = nScale;
406 break;
409 aDocument.SetString( static_cast<SCCOL>(i), 0, 0, aHeader );
412 lcl_setScalesToColumns(aDocument, aScales);
414 SCROW nRow = 1; // 0 is column titles
415 bool bEnd = false;
416 while ( !bEnd && xRowSet->next() )
418 if ( nRow <= MAXROW )
420 bool bSimpleRow = true;
421 SCCOL nCol = 0;
422 for (i=0; i<nColCount; i++)
424 ScDatabaseDocUtil::StrData aStrData;
425 ScDatabaseDocUtil::PutData( &aDocument, nCol, nRow, 0,
426 xRow, i+1, pTypeArr[i], false,
427 &aStrData );
429 if (aStrData.mnStrLength > aColWidthParam[nCol].mnMaxTextLen)
431 aColWidthParam[nCol].mnMaxTextLen = aStrData.mnStrLength;
432 aColWidthParam[nCol].mnMaxTextRow = nRow;
435 if (!aStrData.mbSimpleText)
437 bSimpleRow = false;
438 aColWidthParam[nCol].mbSimpleText = false;
441 ++nCol;
443 if (!bSimpleRow)
444 rRowHeightsRecalc.setTrue(nRow, nRow);
445 ++nRow;
447 else // past the end of the spreadsheet
449 bEnd = true; // don't continue
450 nErr = SCWARN_IMPORT_RANGE_OVERFLOW; // warning message
454 catch ( sdbc::SQLException& )
456 nErr = SCERR_IMPORT_CONNECT;
458 catch ( uno::Exception& )
460 OSL_FAIL("Unexpected exception in database");
461 nErr = ERRCODE_IO_GENERAL;
464 return nErr;
465 #endif // HAVE_FEATURE_DBCONNECTIVITY
468 #if HAVE_FEATURE_DBCONNECTIVITY
470 namespace {
472 inline bool IsAsciiDigit( sal_Unicode c )
474 return 0x30 <= c && c <= 0x39;
477 inline bool IsAsciiAlpha( sal_Unicode c )
479 return (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a);
482 void lcl_GetColumnTypes(
483 ScDocShell& rDocShell, const ScRange& rDataRange, bool bHasFieldNames,
484 OUString* pColNames, sal_Int32* pColTypes, sal_Int32* pColLengths,
485 sal_Int32* pColScales, bool& bHasMemo, rtl_TextEncoding eCharSet )
487 ScDocument& rDoc = rDocShell.GetDocument();
488 SvNumberFormatter* pNumFmt = rDoc.GetFormatTable();
490 SCTAB nTab = rDataRange.aStart.Tab();
491 SCCOL nFirstCol = rDataRange.aStart.Col();
492 SCROW nFirstRow = rDataRange.aStart.Row();
493 SCCOL nLastCol = rDataRange.aEnd.Col();
494 SCROW nLastRow = rDataRange.aEnd.Row();
496 typedef std::unordered_set<OUString, OUStringHash> StrSetType;
497 StrSetType aFieldNames;
499 long nField = 0;
500 SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
501 for ( SCCOL nCol = nFirstCol; nCol <= nLastCol; nCol++ )
503 bool bTypeDefined = false;
504 bool bPrecDefined = false;
505 sal_Int32 nFieldLen = 0;
506 sal_Int32 nPrecision = 0;
507 sal_Int32 nDbType = sdbc::DataType::SQLNULL;
508 OUString aFieldName;
509 OUString aString;
511 // Fieldname[,Type[,Width[,Prec]]]
512 // Type etc.: L; D; C[,W]; N[,W[,P]]
513 if ( bHasFieldNames )
515 aString = rDoc.GetString(nCol, nFirstRow, nTab);
516 aString = aString.toAsciiUpperCase();
517 sal_Int32 nToken = comphelper::string::getTokenCount(aString, ',');
518 if ( nToken > 1 )
520 aFieldName = aString.getToken( 0, ',' );
521 aString = comphelper::string::remove(aString, ' ');
522 switch ( aString.getToken( 1, ',' )[0] )
524 case 'L' :
525 nDbType = sdbc::DataType::BIT;
526 nFieldLen = 1;
527 bTypeDefined = true;
528 bPrecDefined = true;
529 break;
530 case 'D' :
531 nDbType = sdbc::DataType::DATE;
532 nFieldLen = 8;
533 bTypeDefined = true;
534 bPrecDefined = true;
535 break;
536 case 'M' :
537 nDbType = sdbc::DataType::LONGVARCHAR;
538 nFieldLen = 10;
539 bTypeDefined = true;
540 bPrecDefined = true;
541 bHasMemo = true;
542 break;
543 case 'C' :
544 nDbType = sdbc::DataType::VARCHAR;
545 bTypeDefined = true;
546 bPrecDefined = true;
547 break;
548 case 'N' :
549 nDbType = sdbc::DataType::DECIMAL;
550 bTypeDefined = true;
551 break;
553 if ( bTypeDefined && !nFieldLen && nToken > 2 )
555 nFieldLen = aString.getToken( 2, ',' ).toInt32();
556 if ( !bPrecDefined && nToken > 3 )
558 OUString aTmp( aString.getToken( 3, ',' ) );
559 if ( CharClass::isAsciiNumeric(aTmp) )
561 nPrecision = aTmp.toInt32();
562 if (nPrecision && nFieldLen < nPrecision+1)
563 nFieldLen = nPrecision + 1; // include decimal separator
564 bPrecDefined = true;
569 else
570 aFieldName = aString;
572 // Check field name and generate valid field name if necessary.
573 // First character has to be alphabetical, subsequent characters
574 // have to be alphanumerical or underscore.
575 // "_DBASELOCK" is reserved (obsolete because first character is
576 // not alphabetical).
577 // No duplicated names.
578 if ( !IsAsciiAlpha( aFieldName[0] ) )
579 aFieldName = "N" + aFieldName;
580 OUString aTmpStr;
581 sal_Unicode c;
582 for ( const sal_Unicode* p = aFieldName.getStr(); ( c = *p ) != 0; p++ )
584 if ( IsAsciiAlpha( c ) || IsAsciiDigit( c ) || c == '_' )
585 aTmpStr += OUString(c);
586 else
587 aTmpStr += "_";
589 aFieldName = aTmpStr;
590 if ( aFieldName.getLength() > 10 )
591 aFieldName = aFieldName.copy(0, 10);
593 if (!aFieldNames.insert(aFieldName).second)
594 { // Duplicated field name, append numeric suffix.
595 sal_uInt16 nSub = 1;
596 OUString aFixPart( aFieldName );
599 ++nSub;
600 OUString aVarPart = OUString::number( nSub );
601 if ( aFixPart.getLength() + aVarPart.getLength() > 10 )
602 aFixPart = aFixPart.copy( 0, 10 - aVarPart.getLength() );
603 aFieldName = aFixPart;
604 aFieldName += aVarPart;
605 } while (!aFieldNames.insert(aFieldName).second);
608 else
610 aFieldName = "N" + OUString::number(nCol+1);
613 if ( !bTypeDefined )
614 { // Field type.
615 ScRefCellValue aCell;
616 aCell.assign(rDoc, ScAddress(nCol, nFirstDataRow, nTab));
617 if (aCell.isEmpty() || aCell.hasString())
618 nDbType = sdbc::DataType::VARCHAR;
619 else
621 sal_uInt32 nFormat;
622 rDoc.GetNumberFormat( nCol, nFirstDataRow, nTab, nFormat );
623 switch ( pNumFmt->GetType( nFormat ) )
625 case css::util::NumberFormat::LOGICAL :
626 nDbType = sdbc::DataType::BIT;
627 nFieldLen = 1;
628 break;
629 case css::util::NumberFormat::DATE :
630 nDbType = sdbc::DataType::DATE;
631 nFieldLen = 8;
632 break;
633 case css::util::NumberFormat::TIME :
634 case css::util::NumberFormat::DATETIME :
635 nDbType = sdbc::DataType::VARCHAR;
636 break;
637 default:
638 nDbType = sdbc::DataType::DECIMAL;
642 bool bSdbLenAdjusted = false;
643 bool bSdbLenBad = false;
644 // Field length.
645 if ( nDbType == sdbc::DataType::VARCHAR && !nFieldLen )
646 { // Determine maximum field width.
647 nFieldLen = rDoc.GetMaxStringLen( nTab, nCol, nFirstDataRow,
648 nLastRow, eCharSet );
649 if ( nFieldLen == 0 )
650 nFieldLen = 1;
652 else if ( nDbType == sdbc::DataType::DECIMAL )
653 { // Determine maximum field width and precision.
654 sal_Int32 nLen;
655 sal_uInt16 nPrec;
656 nLen = rDoc.GetMaxNumberStringLen( nPrec, nTab, nCol,
657 nFirstDataRow, nLastRow );
658 // dBaseIII precision limit: 15
659 if ( nPrecision > 15 )
660 nPrecision = 15;
661 if ( nPrec > 15 )
662 nPrec = 15;
663 if ( bPrecDefined && nPrecision != nPrec )
665 if (nPrecision < nPrec)
667 // This is a hairy case. User defined nPrecision but a
668 // number format has more precision. Modifying a dBase
669 // field may as well render the resulting file useless for
670 // an application that relies on its defined structure,
671 // especially if we are resaving an already existing file.
672 // So who's right, the user who (or the loaded file that)
673 // defined the field, or the user who applied the format?
674 // Commit f59e350d1733125055f1144f8b3b1b0a46f6d1ca gave the
675 // format a higher priority, which is debatable.
676 SAL_WARN( "sc", "lcl_GetColumnTypes: conflicting dBase field precision for "
677 << aFieldName << " (" << nPrecision << "<" << nPrec << ")");
679 // Adjust length to larger predefined integer part. There
680 // may be a reason that the field was prepared for larger
681 // numbers.
682 if (nFieldLen - nPrecision > nLen - nPrec)
683 nLen = nFieldLen - (nPrecision ? nPrecision+1 : 0) + 1 + nPrec;
684 // And override precision.
685 nPrecision = nPrec;
687 else
689 #if 1
690 // Adjust length to predefined precision.
691 nLen = nLen + ( nPrecision - nPrec );
692 #else
693 /* If the above override for (nPrecision < nPrec) was not in place then
694 * nPrecision could be 0 and this would be the code path to correctly
695 * calculate nLen. But as is, nPrecision is never 0 here, see CID#982304 */
697 // Adjust length to predefined precision.
698 if ( nPrecision )
699 nLen = nLen + ( nPrecision - nPrec );
700 else
701 nLen -= nPrec+1; // also remove the decimal separator
702 #endif
705 if (nFieldLen < nLen)
707 if (!bTypeDefined)
708 nFieldLen = nLen;
709 else
711 // Again a hairy case and conflict. Furthermore, the
712 // larger overall length may be a result of only a higher
713 // precision obtained from formats.
714 SAL_WARN( "sc", "lcl_GetColumnTypes: conflicting dBase field length for "
715 << aFieldName << " (" << nFieldLen << "<" << nLen << ")");
716 nFieldLen = nLen;
719 if ( !bPrecDefined )
720 nPrecision = nPrec;
721 if ( nFieldLen == 0 )
722 nFieldLen = 1;
723 else if ( nFieldLen > 19 )
724 nFieldLen = 19; // dBaseIII numeric field length limit: 19
725 if ( nPrecision && nFieldLen < nPrecision + 2 )
726 nFieldLen = nPrecision + 2; // 0. must fit into
727 // 538 MUST: Sdb internal representation adds 2 to the field length!
728 // To give the user what he wants we must subtract it here.
729 //! CAVEAT! There is no way to define a numeric field with a length
730 //! of 1 and no decimals!
731 if ( nFieldLen == 1 && nPrecision == 0 )
732 bSdbLenBad = true;
733 nFieldLen = SvDbaseConverter::ConvertPrecisionToOdbc( nFieldLen, nPrecision );
734 bSdbLenAdjusted = true;
736 if ( nFieldLen > 254 )
738 if ( nDbType == sdbc::DataType::VARCHAR )
739 { // Too long for a normal text field => memo field.
740 nDbType = sdbc::DataType::LONGVARCHAR;
741 nFieldLen = 10;
742 bHasMemo = true;
744 else
745 nFieldLen = 254; // bad luck..
748 pColNames[nField] = aFieldName;
749 pColTypes[nField] = nDbType;
750 pColLengths[nField] = nFieldLen;
751 pColScales[nField] = nPrecision;
753 // undo change to field length, reflect reality
754 if ( bSdbLenAdjusted )
756 nFieldLen = SvDbaseConverter::ConvertPrecisionToDbase( nFieldLen, nPrecision );
757 if ( bSdbLenBad && nFieldLen == 1 )
758 nFieldLen = 2; // THIS is reality
760 ++nField;
764 inline void lcl_getLongVarCharEditString( OUString& rString,
765 const ScRefCellValue& rCell, ScFieldEditEngine& rEditEngine )
767 if (!rCell.mpEditText)
768 return;
770 rEditEngine.SetText(*rCell.mpEditText);
771 rString = rEditEngine.GetText( LINEEND_CRLF );
774 inline void lcl_getLongVarCharString(
775 OUString& rString, ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, SvNumberFormatter& rNumFmt )
777 Color* pColor;
778 ScAddress aPos(nCol, nRow, nTab);
779 sal_uInt32 nFormat = rDoc.GetNumberFormat(aPos);
780 rString = ScCellFormat::GetString(rDoc, aPos, nFormat, &pColor, rNumFmt);
785 #endif // HAVE_FEATURE_DBCONNECTIVITY
787 sal_uLong ScDocShell::DBaseExport( const OUString& rFullFileName, rtl_TextEncoding eCharSet, bool& bHasMemo )
789 #if !HAVE_FEATURE_DBCONNECTIVITY
790 (void) rFullFileName;
791 (void) eCharSet;
792 (void) bHasMemo;
794 return ERRCODE_IO_GENERAL;
795 #else
796 // remove the file so the dBase driver doesn't find an invalid file
797 INetURLObject aDeleteObj( rFullFileName, INetProtocol::File );
798 KillFile( aDeleteObj );
800 sal_uLong nErr = eERR_OK;
801 uno::Any aAny;
803 SCCOL nFirstCol, nLastCol;
804 SCROW nFirstRow, nLastRow;
805 SCTAB nTab = GetSaveTab();
806 aDocument.GetDataStart( nTab, nFirstCol, nFirstRow );
807 aDocument.GetCellArea( nTab, nLastCol, nLastRow );
808 if ( nFirstCol > nLastCol )
809 nFirstCol = nLastCol;
810 if ( nFirstRow > nLastRow )
811 nFirstRow = nLastRow;
812 ScProgress aProgress( this, ScGlobal::GetRscString( STR_SAVE_DOC ),
813 nLastRow - nFirstRow );
814 SvNumberFormatter* pNumFmt = aDocument.GetFormatTable();
816 bool bHasFieldNames = true;
817 for ( SCCOL nDocCol = nFirstCol; nDocCol <= nLastCol && bHasFieldNames; nDocCol++ )
818 { // nur Strings in erster Zeile => sind Feldnamen
819 if ( !aDocument.HasStringData( nDocCol, nFirstRow, nTab ) )
820 bHasFieldNames = false;
823 long nColCount = nLastCol - nFirstCol + 1;
824 uno::Sequence<OUString> aColNames( nColCount );
825 uno::Sequence<sal_Int32> aColTypes( nColCount );
826 uno::Sequence<sal_Int32> aColLengths( nColCount );
827 uno::Sequence<sal_Int32> aColScales( nColCount );
829 ScRange aDataRange( nFirstCol, nFirstRow, nTab, nLastCol, nLastRow, nTab );
830 lcl_GetColumnTypes( *this, aDataRange, bHasFieldNames,
831 aColNames.getArray(), aColTypes.getArray(),
832 aColLengths.getArray(), aColScales.getArray(),
833 bHasMemo, eCharSet );
834 // also needed for exception catch
835 SCROW nDocRow = 0;
836 ScFieldEditEngine aEditEngine(&aDocument, aDocument.GetEditPool());
837 OUString aString;
838 OUString aTabName;
842 uno::Reference<sdbc::XDriverManager2> xDrvMan;
843 uno::Reference<sdbc::XConnection> xConnection;
844 sal_uLong nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
845 if ( !xConnection.is() || !xDrvMan.is() )
846 return nRet;
847 ::utl::DisposableComponent aConnectionHelper(xConnection);
849 // get dBase driver
850 uno::Reference< sdbc::XDriverAccess> xAccess(xDrvMan,uno::UNO_QUERY);
851 uno::Reference< sdbcx::XDataDefinitionSupplier > xDDSup( xAccess->getDriverByURL( xConnection->getMetaData()->getURL() ), uno::UNO_QUERY );
852 if ( !xDDSup.is() )
853 return SCERR_EXPORT_CONNECT;
855 // create table
856 uno::Reference<sdbcx::XTablesSupplier> xTablesSupp =xDDSup->getDataDefinitionByConnection( xConnection );
857 OSL_ENSURE( xTablesSupp.is(), "can't get Data Definition" );
858 if (!xTablesSupp.is()) return SCERR_EXPORT_CONNECT;
860 uno::Reference<container::XNameAccess> xTables = xTablesSupp->getTables();
861 OSL_ENSURE( xTables.is(), "can't get Tables" );
862 if (!xTables.is()) return SCERR_EXPORT_CONNECT;
864 uno::Reference<sdbcx::XDataDescriptorFactory> xTablesFact( xTables, uno::UNO_QUERY );
865 OSL_ENSURE( xTablesFact.is(), "can't get tables factory" );
866 if (!xTablesFact.is()) return SCERR_EXPORT_CONNECT;
868 uno::Reference<sdbcx::XAppend> xTablesAppend( xTables, uno::UNO_QUERY );
869 OSL_ENSURE( xTablesAppend.is(), "can't get tables XAppend" );
870 if (!xTablesAppend.is()) return SCERR_EXPORT_CONNECT;
872 uno::Reference<beans::XPropertySet> xTableDesc = xTablesFact->createDataDescriptor();
873 OSL_ENSURE( xTableDesc.is(), "can't get table descriptor" );
874 if (!xTableDesc.is()) return SCERR_EXPORT_CONNECT;
876 aAny <<= OUString( aTabName );
877 xTableDesc->setPropertyValue( OUString(SC_DBPROP_NAME), aAny );
879 // create columns
881 uno::Reference<sdbcx::XColumnsSupplier> xColumnsSupp( xTableDesc, uno::UNO_QUERY );
882 OSL_ENSURE( xColumnsSupp.is(), "can't get columns supplier" );
883 if (!xColumnsSupp.is()) return SCERR_EXPORT_CONNECT;
885 uno::Reference<container::XNameAccess> xColumns = xColumnsSupp->getColumns();
886 OSL_ENSURE( xColumns.is(), "can't get columns" );
887 if (!xColumns.is()) return SCERR_EXPORT_CONNECT;
889 uno::Reference<sdbcx::XDataDescriptorFactory> xColumnsFact( xColumns, uno::UNO_QUERY );
890 OSL_ENSURE( xColumnsFact.is(), "can't get columns factory" );
891 if (!xColumnsFact.is()) return SCERR_EXPORT_CONNECT;
893 uno::Reference<sdbcx::XAppend> xColumnsAppend( xColumns, uno::UNO_QUERY );
894 OSL_ENSURE( xColumnsAppend.is(), "can't get columns XAppend" );
895 if (!xColumnsAppend.is()) return SCERR_EXPORT_CONNECT;
897 const OUString* pColNames = aColNames.getConstArray();
898 const sal_Int32* pColTypes = aColTypes.getConstArray();
899 const sal_Int32* pColLengths = aColLengths.getConstArray();
900 const sal_Int32* pColScales = aColScales.getConstArray();
901 long nCol;
903 for (nCol=0; nCol<nColCount; nCol++)
905 uno::Reference<beans::XPropertySet> xColumnDesc = xColumnsFact->createDataDescriptor();
906 OSL_ENSURE( xColumnDesc.is(), "can't get column descriptor" );
907 if (!xColumnDesc.is()) return SCERR_EXPORT_CONNECT;
909 aAny <<= pColNames[nCol];
910 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_NAME), aAny );
912 aAny <<= pColTypes[nCol];
913 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_TYPE), aAny );
915 aAny <<= pColLengths[nCol];
916 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_PRECISION), aAny );
918 aAny <<= pColScales[nCol];
919 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_SCALE), aAny );
921 xColumnsAppend->appendByDescriptor( xColumnDesc );
924 xTablesAppend->appendByDescriptor( xTableDesc );
926 // get row set for writing
927 uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
928 uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(
929 OUString( SC_SERVICE_ROWSET ) ),
930 uno::UNO_QUERY);
931 ::utl::DisposableComponent aRowSetHelper(xRowSet);
932 uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
933 OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
934 if (!xRowProp.is()) return SCERR_EXPORT_CONNECT;
936 aAny <<= xConnection;
937 xRowProp->setPropertyValue( OUString(SC_DBPROP_ACTIVECONNECTION), aAny );
939 aAny <<= (sal_Int32) sdb::CommandType::TABLE;
940 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMANDTYPE), aAny );
942 aAny <<= OUString( aTabName );
943 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMAND), aAny );
945 xRowSet->execute();
947 // write data rows
949 uno::Reference<sdbc::XResultSetUpdate> xResultUpdate( xRowSet, uno::UNO_QUERY );
950 OSL_ENSURE( xResultUpdate.is(), "can't get XResultSetUpdate" );
951 if (!xResultUpdate.is()) return SCERR_EXPORT_CONNECT;
953 uno::Reference<sdbc::XRowUpdate> xRowUpdate( xRowSet, uno::UNO_QUERY );
954 OSL_ENSURE( xRowUpdate.is(), "can't get XRowUpdate" );
955 if (!xRowUpdate.is()) return SCERR_EXPORT_CONNECT;
957 SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
958 double fVal;
960 for ( nDocRow = nFirstDataRow; nDocRow <= nLastRow; nDocRow++ )
962 xResultUpdate->moveToInsertRow();
964 for (nCol=0; nCol<nColCount; nCol++)
966 SCCOL nDocCol = sal::static_int_cast<SCCOL>( nFirstCol + nCol );
968 switch (pColTypes[nCol])
970 case sdbc::DataType::LONGVARCHAR:
972 ScRefCellValue aCell;
973 aCell.assign(aDocument, ScAddress(nDocCol, nDocRow, nTab));
974 if (!aCell.isEmpty())
976 if (aCell.meType == CELLTYPE_EDIT)
977 { // Paragraphs erhalten
978 lcl_getLongVarCharEditString(aString, aCell, aEditEngine);
980 else
982 lcl_getLongVarCharString(
983 aString, aDocument, nDocCol, nDocRow, nTab, *pNumFmt);
985 xRowUpdate->updateString( nCol+1, aString );
987 else
988 xRowUpdate->updateNull( nCol+1 );
990 break;
992 case sdbc::DataType::VARCHAR:
993 aString = aDocument.GetString(nDocCol, nDocRow, nTab);
994 xRowUpdate->updateString( nCol+1, aString );
995 if ( nErr == eERR_OK && pColLengths[nCol] < aString.getLength() )
996 nErr = SCWARN_EXPORT_DATALOST;
997 break;
999 case sdbc::DataType::DATE:
1001 aDocument.GetValue( nDocCol, nDocRow, nTab, fVal );
1002 // zwischen 0 Wert und 0 kein Wert unterscheiden
1003 bool bIsNull = (fVal == 0.0);
1004 if ( bIsNull )
1005 bIsNull = !aDocument.HasValueData( nDocCol, nDocRow, nTab );
1006 if ( bIsNull )
1008 xRowUpdate->updateNull( nCol+1 );
1009 if ( nErr == eERR_OK &&
1010 aDocument.HasStringData( nDocCol, nDocRow, nTab ) )
1011 nErr = SCWARN_EXPORT_DATALOST;
1013 else
1015 Date aDate = *(pNumFmt->GetNullDate()); // tools date
1016 aDate += (long)fVal; //! approxfloor?
1017 xRowUpdate->updateDate( nCol+1, aDate.GetUNODate() );
1020 break;
1022 case sdbc::DataType::DECIMAL:
1023 case sdbc::DataType::BIT:
1024 aDocument.GetValue( nDocCol, nDocRow, nTab, fVal );
1025 if ( fVal == 0.0 && nErr == eERR_OK &&
1026 aDocument.HasStringData( nDocCol, nDocRow, nTab ) )
1027 nErr = SCWARN_EXPORT_DATALOST;
1028 if ( pColTypes[nCol] == sdbc::DataType::BIT )
1029 xRowUpdate->updateBoolean( nCol+1, ( fVal != 0.0 ) );
1030 else
1031 xRowUpdate->updateDouble( nCol+1, fVal );
1032 break;
1034 default:
1035 OSL_FAIL( "ScDocShell::DBaseExport: unknown FieldType" );
1036 if ( nErr == eERR_OK )
1037 nErr = SCWARN_EXPORT_DATALOST;
1038 aDocument.GetValue( nDocCol, nDocRow, nTab, fVal );
1039 xRowUpdate->updateDouble( nCol+1, fVal );
1043 xResultUpdate->insertRow();
1045 //! error handling and recovery of old
1046 //! ScDocShell::SbaSdbExport is still missing!
1048 if ( !aProgress.SetStateOnPercent( nDocRow - nFirstRow ) )
1049 { // UserBreak
1050 nErr = SCERR_EXPORT_DATA;
1051 break;
1055 comphelper::disposeComponent( xRowSet );
1056 comphelper::disposeComponent( xConnection );
1058 catch ( const sdbc::SQLException& aException )
1060 sal_Int32 nError = aException.ErrorCode;
1061 #if OSL_DEBUG_LEVEL > 1
1062 fprintf( stderr, "ScDocShell::DBaseExport: SQLException ErrorCode: %d, SQLState: %s, Message: %s\n",
1063 (int)nError, OUStringToOString( aException.SQLState,
1064 RTL_TEXTENCODING_UTF8).getStr(), OUStringToOString(
1065 aException.Message, RTL_TEXTENCODING_UTF8).getStr());
1066 #endif
1067 if (nError == 22018 || nError == 22001)
1069 // SQL error 22018: Character not in target encoding.
1070 // SQL error 22001: String length exceeds field width (after encoding).
1071 bool bEncErr = (nError == 22018);
1072 bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
1073 OSL_ENSURE( !bEncErr || bIsOctetTextEncoding, "ScDocShell::DBaseExport: encoding error and not an octect textencoding");
1074 SCCOL nDocCol = nFirstCol;
1075 const sal_Int32* pColTypes = aColTypes.getConstArray();
1076 const sal_Int32* pColLengths = aColLengths.getConstArray();
1077 ScHorizontalCellIterator aIter( &aDocument, nTab, nFirstCol,
1078 nDocRow, nLastCol, nDocRow);
1079 ScRefCellValue* pCell = NULL;
1080 bool bTest = true;
1081 while (bTest && ((pCell = aIter.GetNext( nDocCol, nDocRow)) != NULL))
1083 SCCOL nCol = nDocCol - nFirstCol;
1084 switch (pColTypes[nCol])
1086 case sdbc::DataType::LONGVARCHAR:
1088 if (pCell->meType == CELLTYPE_EDIT)
1089 lcl_getLongVarCharEditString(aString, *pCell, aEditEngine);
1090 else
1091 lcl_getLongVarCharString(
1092 aString, aDocument, nDocCol, nDocRow, nTab, *pNumFmt);
1094 break;
1096 case sdbc::DataType::VARCHAR:
1097 aString = aDocument.GetString(nDocCol, nDocRow, nTab);
1098 break;
1100 // NOTE: length of DECIMAL fields doesn't need to be
1101 // checked here, the database driver adjusts the field
1102 // width accordingly.
1104 default:
1105 bTest = false;
1107 if (bTest)
1109 sal_Int32 nLen;
1110 if (bIsOctetTextEncoding)
1112 OUString aOUString( aString);
1113 OString aOString;
1114 if (!aOUString.convertToString( &aOString, eCharSet,
1115 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1116 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
1118 bTest = false;
1119 bEncErr = true;
1121 nLen = aOString.getLength();
1122 #if OSL_DEBUG_LEVEL > 1
1123 if (!bTest)
1124 fprintf( stderr, "ScDocShell::DBaseExport encoding error, string with default replacements: ``%s''\n",
1125 OUStringToOString( aOUString, eCharSet).getStr());
1126 #endif
1128 else
1129 nLen = aString.getLength() * sizeof(sal_Unicode);
1130 if (!bEncErr &&
1131 pColTypes[nCol] != sdbc::DataType::LONGVARCHAR &&
1132 pColLengths[nCol] < nLen)
1134 bTest = false;
1135 #if OSL_DEBUG_LEVEL > 1
1136 fprintf( stderr, "ScDocShell::DBaseExport: field width: %d, encoded length: %d\n",
1137 (int)pColLengths[nCol], (int)nLen);
1138 #endif
1141 else
1142 bTest = true;
1144 OUString sPosition( ScAddress( nDocCol, nDocRow, nTab).GetColRowString());
1145 OUString sEncoding( SvxTextEncodingTable().GetTextString( eCharSet));
1146 nErr = *new TwoStringErrorInfo( (bEncErr ? SCERR_EXPORT_ENCODING :
1147 SCERR_EXPORT_FIELDWIDTH), sPosition, sEncoding,
1148 ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR);
1150 else if ( !aException.Message.isEmpty() )
1151 nErr = *new StringErrorInfo( (SCERR_EXPORT_SQLEXCEPTION), aException.Message, ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR);
1152 else
1153 nErr = SCERR_EXPORT_DATA;
1155 catch ( uno::Exception& )
1157 OSL_FAIL("Unexpected exception in database");
1158 nErr = ERRCODE_IO_GENERAL;
1161 return nErr;
1162 #endif // HAVE_FEATURE_DBCONNECTIVITY
1165 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */