Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / ui / docshell / docsh8.cxx
blobc0d66c7fade28a7b34273ab52fde3b5665e9bf19
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 <stdio.h>
21 #include <tools/urlobj.hxx>
22 #include <svl/converter.hxx>
23 #include <comphelper/processfactory.hxx>
24 #include <comphelper/string.hxx>
25 #include <comphelper/types.hxx>
26 #include <ucbhelper/content.hxx>
27 #include <svx/txenctab.hxx>
29 #ifndef DISABLE_DBCONNECTIVITY
30 #include <svx/dbcharsethelper.hxx>
31 #endif
33 #include <com/sun/star/sdb/CommandType.hpp>
34 #include <com/sun/star/sdbc/DataType.hpp>
35 #include <com/sun/star/sdbc/XConnection.hpp>
36 #include <com/sun/star/sdbc/XDriver.hpp>
37 #include <com/sun/star/sdbc/XDriverAccess.hpp>
38 #include <com/sun/star/sdbc/DriverManager.hpp>
39 #include <com/sun/star/sdbc/XResultSetUpdate.hpp>
40 #include <com/sun/star/sdbc/XRow.hpp>
41 #include <com/sun/star/sdbc/XRowSet.hpp>
42 #include <com/sun/star/sdbc/XRowUpdate.hpp>
43 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
44 #include <com/sun/star/sdbcx/XAppend.hpp>
45 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
46 #include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
47 #include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
48 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <com/sun/star/beans/XPropertySet.hpp>
51 #include <com/sun/star/container/XEnumerationAccess.hpp>
52 #include <com/sun/star/lang/XComponent.hpp>
53 #include <com/sun/star/ucb/NameClash.hpp>
54 #include <com/sun/star/ucb/TransferInfo.hpp>
55 #include <com/sun/star/ucb/XCommandInfo.hpp>
57 #include "scerrors.hxx"
58 #include "docsh.hxx"
59 #include "filter.hxx"
60 #include "progress.hxx"
61 #include "formulacell.hxx"
62 #include "editutil.hxx"
63 #include "cellform.hxx"
64 #include "dbdocutl.hxx"
65 #include "dociter.hxx"
66 #include "globstr.hrc"
67 #include "svl/zformat.hxx"
68 #include "svl/intitem.hxx"
69 #include "patattr.hxx"
70 #include "scitems.hxx"
71 #include "docpool.hxx"
72 #include "segmenttree.hxx"
73 #include "docparam.hxx"
74 #include "cellvalue.hxx"
76 #include <vector>
77 #include <boost/unordered_set.hpp>
79 using namespace com::sun::star;
80 using ::std::vector;
82 // -----------------------------------------------------------------------
84 #define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
86 //! move to a header file?
87 #define SC_DBPROP_ACTIVECONNECTION "ActiveConnection"
88 #define SC_DBPROP_COMMAND "Command"
89 #define SC_DBPROP_COMMANDTYPE "CommandType"
90 #define SC_DBPROP_PROPCHANGE_NOTIFY "PropertyChangeNotificationEnabled"
92 #define SC_DBPROP_NAME "Name"
93 #define SC_DBPROP_TYPE "Type"
94 #define SC_DBPROP_PRECISION "Precision"
95 #define SC_DBPROP_SCALE "Scale"
97 #define SC_DBPROP_EXTENSION "Extension"
98 #define SC_DBPROP_CHARSET "CharSet"
100 #ifndef DISABLE_DBCONNECTIVITY
102 namespace
104 sal_uLong lcl_getDBaseConnection(uno::Reference<sdbc::XDriverManager2>& _rDrvMgr, uno::Reference<sdbc::XConnection>& _rConnection, OUString& _rTabName, const OUString& rFullFileName, rtl_TextEncoding eCharSet)
106 INetURLObject aURL;
107 aURL.SetSmartProtocol( INET_PROT_FILE );
108 aURL.SetSmartURL( rFullFileName );
109 _rTabName = aURL.getBase( INetURLObject::LAST_SEGMENT, true,
110 INetURLObject::DECODE_UNAMBIGUOUS );
111 OUString aExtension = aURL.getExtension();
112 aURL.removeSegment();
113 aURL.removeFinalSlash();
114 OUString aPath = aURL.GetMainURL(INetURLObject::NO_DECODE);
115 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
117 _rDrvMgr.set( sdbc::DriverManager::create( xContext ) );
119 // get connection
121 OUString aConnUrl("sdbc:dbase:");
122 aConnUrl += aPath;
124 svxform::ODataAccessCharsetHelper aHelper;
125 ::std::vector< rtl_TextEncoding > aEncodings;
126 aHelper.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 // !DISABLE_DBCONNECTIVITY
155 // -----------------------------------------------------------------------
156 // MoveFile/KillFile/IsDocument: similar to SfxContentHelper
158 bool ScDocShell::MoveFile( const INetURLObject& rSourceObj, const INetURLObject& rDestObj )
160 bool bMoveData = true;
161 bool bRet = true, bKillSource = false;
162 if ( rSourceObj.GetProtocol() != rDestObj.GetProtocol() )
164 bMoveData = false;
165 bKillSource = true;
167 OUString aName = rDestObj.getName();
168 INetURLObject aDestPathObj = rDestObj;
169 aDestPathObj.removeSegment();
170 aDestPathObj.setFinalSlash();
174 ::ucbhelper::Content aDestPath( aDestPathObj.GetMainURL(INetURLObject::NO_DECODE),
175 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
176 comphelper::getProcessComponentContext() );
177 uno::Reference< ::com::sun::star::ucb::XCommandInfo > xInfo = aDestPath.getCommands();
178 OUString aTransferName = "transfer";
179 if ( xInfo->hasCommandByName( aTransferName ) )
181 aDestPath.executeCommand( aTransferName, uno::makeAny(
182 ::com::sun::star::ucb::TransferInfo( bMoveData, rSourceObj.GetMainURL(INetURLObject::NO_DECODE), aName,
183 ::com::sun::star::ucb::NameClash::ERROR ) ) );
185 else
187 OSL_FAIL( "transfer command not available" );
190 catch( uno::Exception& )
192 // ucb may throw different exceptions on failure now
193 bRet = false;
196 if ( bKillSource )
197 KillFile( rSourceObj );
199 return bRet;
203 bool ScDocShell::KillFile( const INetURLObject& rURL )
205 bool bRet = true;
208 ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::NO_DECODE),
209 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
210 comphelper::getProcessComponentContext() );
211 aCnt.executeCommand( OUString( "delete" ),
212 comphelper::makeBoolAny( sal_True ) );
214 catch( uno::Exception& )
216 // ucb may throw different exceptions on failure now
217 bRet = false;
220 return bRet;
223 bool ScDocShell::IsDocument( const INetURLObject& rURL )
225 bool bRet = false;
228 ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::NO_DECODE),
229 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
230 comphelper::getProcessComponentContext() );
231 bRet = aCnt.isDocument();
233 catch( uno::Exception& )
235 // ucb may throw different exceptions on failure now - warning only
236 OSL_FAIL( "Any other exception" );
239 return bRet;
242 // -----------------------------------------------------------------------
244 #ifndef DISABLE_DBCONNECTIVITY
246 static void lcl_setScalesToColumns(ScDocument& rDoc, const vector<long>& rScales)
248 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
249 if (!pFormatter)
250 return;
252 SCCOL nColCount = static_cast<SCCOL>(rScales.size());
253 for (SCCOL i = 0; i < nColCount; ++i)
255 if (rScales[i] < 0)
256 continue;
258 sal_uInt32 nOldFormat;
259 rDoc.GetNumberFormat(static_cast<SCCOL>(i), 0, 0, nOldFormat);
260 const SvNumberformat* pOldEntry = pFormatter->GetEntry(nOldFormat);
261 if (!pOldEntry)
262 continue;
264 LanguageType eLang = pOldEntry->GetLanguage();
265 bool bThousand, bNegRed;
266 sal_uInt16 nPrecision, nLeading;
267 pOldEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrecision, nLeading);
269 nPrecision = static_cast<sal_uInt16>(rScales[i]);
270 OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLang,
271 bThousand, bNegRed, nPrecision, nLeading);
273 sal_uInt32 nNewFormat = pFormatter->GetEntryKey(aNewPicture, eLang);
274 if (nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
276 sal_Int32 nErrPos = 0;
277 short nNewType = 0;
278 bool bOk = pFormatter->PutEntry(
279 aNewPicture, nErrPos, nNewType, nNewFormat, eLang);
281 if (!bOk)
282 continue;
285 ScPatternAttr aNewAttrs( rDoc.GetPool() );
286 SfxItemSet& rSet = aNewAttrs.GetItemSet();
287 rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nNewFormat) );
288 rDoc.ApplyPatternAreaTab(static_cast<SCCOL>(i), 0, static_cast<SCCOL>(i), MAXROW, 0, aNewAttrs);
292 #endif // !DISABLE_DBCONNECTIVITY
294 sal_uLong ScDocShell::DBaseImport( const OUString& rFullFileName, rtl_TextEncoding eCharSet,
295 ScColWidthParam aColWidthParam[MAXCOLCOUNT], ScFlatBoolRowSegments& rRowHeightsRecalc )
297 #ifdef DISABLE_DBCONNECTIVITY
298 (void) rFullFileName;
299 (void) eCharSet;
300 (void) aColWidthParam;
301 (void) rRowHeightsRecalc;
303 return ERRCODE_IO_GENERAL;
304 #else
306 sal_uLong nErr = eERR_OK;
307 long i;
308 long nColCount = 0;
310 // Try to get the Text Encoding from the driver
311 if( eCharSet == RTL_TEXTENCODING_IBM_850 )
312 eCharSet = RTL_TEXTENCODING_DONTKNOW;
316 OUString aTabName;
317 uno::Reference<sdbc::XDriverManager2> xDrvMan;
318 uno::Reference<sdbc::XConnection> xConnection;
319 sal_uLong nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
320 if ( !xConnection.is() || !xDrvMan.is() )
321 return nRet;
322 ::utl::DisposableComponent aConnectionHelper(xConnection);
324 ScProgress aProgress( this, ScGlobal::GetRscString( STR_LOAD_DOC ), 0 );
325 uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
326 uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(
327 OUString( SC_SERVICE_ROWSET ) ),
328 uno::UNO_QUERY);
329 ::utl::DisposableComponent aRowSetHelper(xRowSet);
330 uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
331 OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
332 if (!xRowProp.is()) return SCERR_IMPORT_CONNECT;
334 sal_Int32 nType = sdb::CommandType::TABLE;
335 uno::Any aAny;
337 aAny <<= xConnection;
338 xRowProp->setPropertyValue( OUString(SC_DBPROP_ACTIVECONNECTION), aAny );
340 aAny <<= nType;
341 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMANDTYPE), aAny );
343 aAny <<= OUString( aTabName );
344 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMAND), aAny );
346 aAny <<= false;
347 xRowProp->setPropertyValue( OUString(SC_DBPROP_PROPCHANGE_NOTIFY), aAny );
349 xRowSet->execute();
351 uno::Reference<sdbc::XResultSetMetaData> xMeta;
352 uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( xRowSet, uno::UNO_QUERY );
353 if ( xMetaSupp.is() )
354 xMeta = xMetaSupp->getMetaData();
355 if ( xMeta.is() )
356 nColCount = xMeta->getColumnCount(); // this is the number of real columns
358 if ( nColCount > MAXCOL+1 )
360 nColCount = MAXCOL+1;
361 nErr = SCWARN_IMPORT_COLUMN_OVERFLOW; // warning
364 uno::Reference<sdbc::XRow> xRow( xRowSet, uno::UNO_QUERY );
365 OSL_ENSURE( xRow.is(), "can't get Row" );
366 if (!xRow.is()) return SCERR_IMPORT_CONNECT;
368 // currency flag is not needed for dBase
369 uno::Sequence<sal_Int32> aColTypes( nColCount ); // column types
370 sal_Int32* pTypeArr = aColTypes.getArray();
371 for (i=0; i<nColCount; i++)
372 pTypeArr[i] = xMeta->getColumnType( i+1 );
374 // read column names
375 //! add type descriptions
377 aProgress.SetState( 0 );
379 vector<long> aScales(nColCount, -1);
380 for (i=0; i<nColCount; i++)
382 OUString aHeader = xMeta->getColumnLabel( i+1 );
384 switch ( pTypeArr[i] )
386 case sdbc::DataType::BIT:
387 aHeader += ",L";
388 break;
389 case sdbc::DataType::DATE:
390 aHeader += ",D";
391 break;
392 case sdbc::DataType::LONGVARCHAR:
393 aHeader += ",M";
394 break;
395 case sdbc::DataType::VARCHAR:
396 aHeader += ",C," + OUString::number( xMeta->getColumnDisplaySize( i+1 ) );
397 break;
398 case sdbc::DataType::DECIMAL:
400 long nPrec = xMeta->getPrecision( i+1 );
401 long nScale = xMeta->getScale( i+1 );
402 aHeader += ",N," +
403 OUString::number(
404 SvDbaseConverter::ConvertPrecisionToDbase(
405 nPrec, nScale ) ) +
406 "," +
407 OUString::number( nScale );
408 aScales[i] = nScale;
410 break;
413 aDocument.SetString( static_cast<SCCOL>(i), 0, 0, aHeader );
416 lcl_setScalesToColumns(aDocument, aScales);
418 SCROW nRow = 1; // 0 is column titles
419 sal_Bool bEnd = false;
420 while ( !bEnd && xRowSet->next() )
422 if ( nRow <= MAXROW )
424 bool bSimpleRow = true;
425 SCCOL nCol = 0;
426 for (i=0; i<nColCount; i++)
428 ScDatabaseDocUtil::StrData aStrData;
429 ScDatabaseDocUtil::PutData( &aDocument, nCol, nRow, 0,
430 xRow, i+1, pTypeArr[i], false,
431 &aStrData );
433 if (aStrData.mnStrLength > aColWidthParam[nCol].mnMaxTextLen)
435 aColWidthParam[nCol].mnMaxTextLen = aStrData.mnStrLength;
436 aColWidthParam[nCol].mnMaxTextRow = nRow;
439 if (!aStrData.mbSimpleText)
441 bSimpleRow = false;
442 aColWidthParam[nCol].mbSimpleText = false;
445 ++nCol;
447 if (!bSimpleRow)
448 rRowHeightsRecalc.setTrue(nRow, nRow);
449 ++nRow;
451 else // past the end of the spreadsheet
453 bEnd = sal_True; // don't continue
454 nErr = SCWARN_IMPORT_RANGE_OVERFLOW; // warning message
458 catch ( sdbc::SQLException& )
460 nErr = SCERR_IMPORT_CONNECT;
462 catch ( uno::Exception& )
464 OSL_FAIL("Unexpected exception in database");
465 nErr = ERRCODE_IO_GENERAL;
468 return nErr;
469 #endif // !DISABLE_DBCONNECTIVITY
472 #ifndef DISABLE_DBCONNECTIVITY
474 namespace {
476 inline bool IsAsciiDigit( sal_Unicode c )
478 return 0x30 <= c && c <= 0x39;
481 inline bool IsAsciiAlpha( sal_Unicode c )
483 return (0x41 <= c && c <= 0x5a) || (0x61 <= c && c <= 0x7a);
486 void lcl_GetColumnTypes(
487 ScDocShell& rDocShell, const ScRange& rDataRange, bool bHasFieldNames,
488 OUString* pColNames, sal_Int32* pColTypes, sal_Int32* pColLengths,
489 sal_Int32* pColScales, bool& bHasMemo, rtl_TextEncoding eCharSet )
491 // updating of column titles didn't work in 5.2 and isn't always wanted
492 // (saving normally shouldn't modify the document)
493 //! read flag from configuration
494 bool bUpdateTitles = false;
496 ScDocument* pDoc = rDocShell.GetDocument();
497 SvNumberFormatter* pNumFmt = pDoc->GetFormatTable();
499 SCTAB nTab = rDataRange.aStart.Tab();
500 SCCOL nFirstCol = rDataRange.aStart.Col();
501 SCROW nFirstRow = rDataRange.aStart.Row();
502 SCCOL nLastCol = rDataRange.aEnd.Col();
503 SCROW nLastRow = rDataRange.aEnd.Row();
505 typedef boost::unordered_set<OUString, OUStringHash> StrSetType;
506 StrSetType aFieldNames;
508 long nField = 0;
509 SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
510 for ( SCCOL nCol = nFirstCol; nCol <= nLastCol; nCol++ )
512 bool bTypeDefined = false;
513 bool bPrecDefined = false;
514 sal_Int32 nFieldLen = 0;
515 sal_Int32 nPrecision = 0;
516 sal_Int32 nDbType = sdbc::DataType::SQLNULL;
517 OUString aFieldName;
518 OUString aString;
520 // Feldname[,Type[,Width[,Prec]]]
521 // Typ etc.: L; D; C[,W]; N[,W[,P]]
522 if ( bHasFieldNames )
524 aString = pDoc->GetString(nCol, nFirstRow, nTab);
525 aString = aString.toAsciiUpperCase();
526 sal_Int32 nToken = comphelper::string::getTokenCount(aString, ',');
527 if ( nToken > 1 )
529 aFieldName = aString.getToken( 0, ',' );
530 aString = comphelper::string::remove(aString, ' ');
531 switch ( aString.getToken( 1, ',' )[0] )
533 case 'L' :
534 nDbType = sdbc::DataType::BIT;
535 nFieldLen = 1;
536 bTypeDefined = sal_True;
537 bPrecDefined = sal_True;
538 break;
539 case 'D' :
540 nDbType = sdbc::DataType::DATE;
541 nFieldLen = 8;
542 bTypeDefined = sal_True;
543 bPrecDefined = sal_True;
544 break;
545 case 'M' :
546 nDbType = sdbc::DataType::LONGVARCHAR;
547 nFieldLen = 10;
548 bTypeDefined = sal_True;
549 bPrecDefined = sal_True;
550 bHasMemo = sal_True;
551 break;
552 case 'C' :
553 nDbType = sdbc::DataType::VARCHAR;
554 bTypeDefined = sal_True;
555 bPrecDefined = sal_True;
556 break;
557 case 'N' :
558 nDbType = sdbc::DataType::DECIMAL;
559 break;
561 if ( bTypeDefined && !nFieldLen && nToken > 2 )
563 nFieldLen = aString.getToken( 2, ',' ).toInt32();
564 if ( !bPrecDefined && nToken > 3 )
566 OUString aTmp( aString.getToken( 3, ',' ) );
567 if ( CharClass::isAsciiNumeric(aTmp) )
569 nPrecision = aTmp.toInt32();
570 bPrecDefined = sal_True;
575 else
576 aFieldName = aString;
578 // Feldnamen pruefen und ggbf. gueltigen Feldnamen erzeugen.
579 // Erstes Zeichen muss Buchstabe sein,
580 // weitere nur alphanumerisch und Unterstrich erlaubt,
581 // "_DBASELOCK" ist reserviert (obsolet weil erstes Zeichen kein Buchstabe),
582 // keine doppelten Namen.
583 if ( !IsAsciiAlpha( aFieldName[0] ) )
584 aFieldName = "N" + aFieldName;
585 OUString aTmpStr;
586 sal_Unicode c;
587 for ( const sal_Unicode* p = aFieldName.getStr(); ( c = *p ) != 0; p++ )
589 if ( IsAsciiAlpha( c ) || IsAsciiDigit( c ) || c == '_' )
590 aTmpStr += OUString(c);
591 else
592 aTmpStr += "_";
594 aFieldName = aTmpStr;
595 if ( aFieldName.getLength() > 10 )
596 aFieldName = aFieldName.copy(0, 10);
598 if (!aFieldNames.insert(aFieldName).second)
599 { // doppelter Feldname, numerisch erweitern
600 sal_uInt16 nSub = 1;
601 OUString aFixPart( aFieldName );
604 ++nSub;
605 OUString aVarPart = OUString::number( nSub );
606 if ( aFixPart.getLength() + aVarPart.getLength() > 10 )
607 aFixPart = aFixPart.copy( 0, 10 - aVarPart.getLength() );
608 aFieldName = aFixPart;
609 aFieldName += aVarPart;
610 } while (!aFieldNames.insert(aFieldName).second);
613 else
615 aFieldName = "N" + OUString::number(nCol+1);
618 if ( !bTypeDefined )
619 { // Feldtyp
620 ScRefCellValue aCell;
621 aCell.assign(*pDoc, ScAddress(nCol, nFirstDataRow, nTab));
622 if (aCell.isEmpty() || aCell.hasString())
623 nDbType = sdbc::DataType::VARCHAR;
624 else
626 sal_uInt32 nFormat;
627 pDoc->GetNumberFormat( nCol, nFirstDataRow, nTab, nFormat );
628 switch ( pNumFmt->GetType( nFormat ) )
630 case NUMBERFORMAT_LOGICAL :
631 nDbType = sdbc::DataType::BIT;
632 nFieldLen = 1;
633 break;
634 case NUMBERFORMAT_DATE :
635 nDbType = sdbc::DataType::DATE;
636 nFieldLen = 8;
637 break;
638 case NUMBERFORMAT_TIME :
639 case NUMBERFORMAT_DATETIME :
640 nDbType = sdbc::DataType::VARCHAR;
641 break;
642 default:
643 nDbType = sdbc::DataType::DECIMAL;
647 bool bSdbLenAdjusted = false;
648 bool bSdbLenBad = false;
649 // Feldlaenge
650 if ( nDbType == sdbc::DataType::VARCHAR && !nFieldLen )
651 { // maximale Feldbreite bestimmen
652 nFieldLen = pDoc->GetMaxStringLen( nTab, nCol, nFirstDataRow,
653 nLastRow, eCharSet );
654 if ( nFieldLen == 0 )
655 nFieldLen = 1;
657 else if ( nDbType == sdbc::DataType::DECIMAL )
658 { // maximale Feldbreite und Nachkommastellen bestimmen
659 xub_StrLen nLen;
660 sal_uInt16 nPrec;
661 nLen = pDoc->GetMaxNumberStringLen( nPrec, nTab, nCol,
662 nFirstDataRow, nLastRow );
663 // dBaseIII Limit Nachkommastellen: 15
664 if ( nPrecision > 15 )
665 nPrecision = 15;
666 if ( nPrec > 15 )
667 nPrec = 15;
668 if ( bPrecDefined && nPrecision != nPrec )
669 { // Laenge auf vorgegebene Nachkommastellen anpassen
670 if ( nPrecision )
671 nLen = sal::static_int_cast<xub_StrLen>( nLen + ( nPrecision - nPrec ) );
672 else
673 nLen -= nPrec+1; // auch den . mit raus
675 if ( nLen > nFieldLen && !bTypeDefined )
676 nFieldLen = nLen;
677 if ( !bPrecDefined )
678 nPrecision = nPrec;
679 if ( nFieldLen == 0 )
680 nFieldLen = 1;
681 else if ( nFieldLen > 19 )
682 nFieldLen = 19; // dBaseIII Limit Feldlaenge numerisch: 19
683 if ( nPrecision && nFieldLen < nPrecision + 2 )
684 nFieldLen = nPrecision + 2; // 0. muss mit reinpassen
685 // 538 MUST: Sdb internal representation adds 2 to the field length!
686 // To give the user what he wants we must substract it here.
687 //! CAVEAT! There is no way to define a numeric field with a length
688 //! of 1 and no decimals!
689 if ( nFieldLen == 1 && nPrecision == 0 )
690 bSdbLenBad = sal_True;
691 nFieldLen = SvDbaseConverter::ConvertPrecisionToOdbc( nFieldLen, nPrecision );
692 bSdbLenAdjusted = sal_True;
694 if ( nFieldLen > 254 )
696 if ( nDbType == sdbc::DataType::VARCHAR )
697 { // zu lang fuer normales Textfeld => Memofeld
698 nDbType = sdbc::DataType::LONGVARCHAR;
699 nFieldLen = 10;
700 bHasMemo = sal_True;
702 else
703 nFieldLen = 254; // dumm gelaufen..
706 pColNames[nField] = aFieldName;
707 pColTypes[nField] = nDbType;
708 pColLengths[nField] = nFieldLen;
709 pColScales[nField] = nPrecision;
711 // undo change to field length, reflect reality
712 if ( bSdbLenAdjusted )
714 nFieldLen = SvDbaseConverter::ConvertPrecisionToDbase( nFieldLen, nPrecision );
715 if ( bSdbLenBad && nFieldLen == 1 )
716 nFieldLen = 2; // THIS is reality
718 if ( bUpdateTitles )
719 { // Angabe anpassen und ausgeben
720 OUString aOutString = aFieldName;
721 switch ( nDbType )
723 case sdbc::DataType::BIT :
724 aOutString += ",L";
725 break;
726 case sdbc::DataType::DATE :
727 aOutString += ",D";
728 break;
729 case sdbc::DataType::LONGVARCHAR :
730 aOutString += ",M";
731 break;
732 case sdbc::DataType::VARCHAR :
733 aOutString += ",C," + OUString::number( nFieldLen );
734 break;
735 case sdbc::DataType::DECIMAL :
736 aOutString += ",N," + OUString::number( nFieldLen ) +
737 "," + OUString::number( nPrecision );
738 break;
740 if ( !aOutString.equalsIgnoreAsciiCase( aString ) )
742 pDoc->SetString( nCol, nFirstRow, nTab, aOutString );
743 rDocShell.PostPaint( nCol, nFirstRow, nTab, nCol, nFirstRow, nTab, PAINT_GRID );
746 ++nField;
750 inline void lcl_getLongVarCharEditString( OUString& rString,
751 const ScRefCellValue& rCell, ScFieldEditEngine& rEditEngine )
753 if (!rCell.mpEditText)
754 return;
756 rEditEngine.SetText(*rCell.mpEditText);
757 rString = rEditEngine.GetText( LINEEND_CRLF );
760 inline void lcl_getLongVarCharString(
761 OUString& rString, ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, SvNumberFormatter& rNumFmt )
763 Color* pColor;
764 ScAddress aPos(nCol, nRow, nTab);
765 sal_uInt32 nFormat = rDoc.GetNumberFormat(aPos);
766 rString = ScCellFormat::GetString(rDoc, aPos, nFormat, &pColor, rNumFmt);
771 #endif // !DISABLE_DBCONNECTIVITY
773 sal_uLong ScDocShell::DBaseExport( const OUString& rFullFileName, rtl_TextEncoding eCharSet, bool& bHasMemo )
775 #ifdef DISABLE_DBCONNECTIVITY
776 (void) rFullFileName;
777 (void) eCharSet;
778 (void) bHasMemo;
780 return ERRCODE_IO_GENERAL;
781 #else
782 // remove the file so the dBase driver doesn't find an invalid file
783 INetURLObject aDeleteObj( rFullFileName, INET_PROT_FILE );
784 KillFile( aDeleteObj );
786 sal_uLong nErr = eERR_OK;
787 uno::Any aAny;
789 SCCOL nFirstCol, nLastCol;
790 SCROW nFirstRow, nLastRow;
791 SCTAB nTab = GetSaveTab();
792 aDocument.GetDataStart( nTab, nFirstCol, nFirstRow );
793 aDocument.GetCellArea( nTab, nLastCol, nLastRow );
794 if ( nFirstCol > nLastCol )
795 nFirstCol = nLastCol;
796 if ( nFirstRow > nLastRow )
797 nFirstRow = nLastRow;
798 ScProgress aProgress( this, ScGlobal::GetRscString( STR_SAVE_DOC ),
799 nLastRow - nFirstRow );
800 SvNumberFormatter* pNumFmt = aDocument.GetFormatTable();
802 sal_Bool bHasFieldNames = sal_True;
803 for ( SCCOL nDocCol = nFirstCol; nDocCol <= nLastCol && bHasFieldNames; nDocCol++ )
804 { // nur Strings in erster Zeile => sind Feldnamen
805 if ( !aDocument.HasStringData( nDocCol, nFirstRow, nTab ) )
806 bHasFieldNames = false;
809 long nColCount = nLastCol - nFirstCol + 1;
810 uno::Sequence<OUString> aColNames( nColCount );
811 uno::Sequence<sal_Int32> aColTypes( nColCount );
812 uno::Sequence<sal_Int32> aColLengths( nColCount );
813 uno::Sequence<sal_Int32> aColScales( nColCount );
815 ScRange aDataRange( nFirstCol, nFirstRow, nTab, nLastCol, nLastRow, nTab );
816 lcl_GetColumnTypes( *this, aDataRange, bHasFieldNames,
817 aColNames.getArray(), aColTypes.getArray(),
818 aColLengths.getArray(), aColScales.getArray(),
819 bHasMemo, eCharSet );
820 // also needed for exception catch
821 SCROW nDocRow = 0;
822 ScFieldEditEngine aEditEngine(&aDocument, aDocument.GetEditPool());
823 OUString aString;
824 OUString aTabName;
828 uno::Reference<sdbc::XDriverManager2> xDrvMan;
829 uno::Reference<sdbc::XConnection> xConnection;
830 sal_uLong nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
831 if ( !xConnection.is() || !xDrvMan.is() )
832 return nRet;
833 ::utl::DisposableComponent aConnectionHelper(xConnection);
835 // get dBase driver
836 uno::Reference< sdbc::XDriverAccess> xAccess(xDrvMan,uno::UNO_QUERY);
837 uno::Reference< sdbcx::XDataDefinitionSupplier > xDDSup( xAccess->getDriverByURL( xConnection->getMetaData()->getURL() ), uno::UNO_QUERY );
838 if ( !xDDSup.is() )
839 return SCERR_EXPORT_CONNECT;
841 // create table
842 uno::Reference<sdbcx::XTablesSupplier> xTablesSupp =xDDSup->getDataDefinitionByConnection( xConnection );
843 OSL_ENSURE( xTablesSupp.is(), "can't get Data Definition" );
844 if (!xTablesSupp.is()) return SCERR_EXPORT_CONNECT;
846 uno::Reference<container::XNameAccess> xTables = xTablesSupp->getTables();
847 OSL_ENSURE( xTables.is(), "can't get Tables" );
848 if (!xTables.is()) return SCERR_EXPORT_CONNECT;
850 uno::Reference<sdbcx::XDataDescriptorFactory> xTablesFact( xTables, uno::UNO_QUERY );
851 OSL_ENSURE( xTablesFact.is(), "can't get tables factory" );
852 if (!xTablesFact.is()) return SCERR_EXPORT_CONNECT;
854 uno::Reference<sdbcx::XAppend> xTablesAppend( xTables, uno::UNO_QUERY );
855 OSL_ENSURE( xTablesAppend.is(), "can't get tables XAppend" );
856 if (!xTablesAppend.is()) return SCERR_EXPORT_CONNECT;
858 uno::Reference<beans::XPropertySet> xTableDesc = xTablesFact->createDataDescriptor();
859 OSL_ENSURE( xTableDesc.is(), "can't get table descriptor" );
860 if (!xTableDesc.is()) return SCERR_EXPORT_CONNECT;
862 aAny <<= OUString( aTabName );
863 xTableDesc->setPropertyValue( OUString(SC_DBPROP_NAME), aAny );
865 // create columns
867 uno::Reference<sdbcx::XColumnsSupplier> xColumnsSupp( xTableDesc, uno::UNO_QUERY );
868 OSL_ENSURE( xColumnsSupp.is(), "can't get columns supplier" );
869 if (!xColumnsSupp.is()) return SCERR_EXPORT_CONNECT;
871 uno::Reference<container::XNameAccess> xColumns = xColumnsSupp->getColumns();
872 OSL_ENSURE( xColumns.is(), "can't get columns" );
873 if (!xColumns.is()) return SCERR_EXPORT_CONNECT;
875 uno::Reference<sdbcx::XDataDescriptorFactory> xColumnsFact( xColumns, uno::UNO_QUERY );
876 OSL_ENSURE( xColumnsFact.is(), "can't get columns factory" );
877 if (!xColumnsFact.is()) return SCERR_EXPORT_CONNECT;
879 uno::Reference<sdbcx::XAppend> xColumnsAppend( xColumns, uno::UNO_QUERY );
880 OSL_ENSURE( xColumnsAppend.is(), "can't get columns XAppend" );
881 if (!xColumnsAppend.is()) return SCERR_EXPORT_CONNECT;
883 const OUString* pColNames = aColNames.getConstArray();
884 const sal_Int32* pColTypes = aColTypes.getConstArray();
885 const sal_Int32* pColLengths = aColLengths.getConstArray();
886 const sal_Int32* pColScales = aColScales.getConstArray();
887 long nCol;
889 for (nCol=0; nCol<nColCount; nCol++)
891 uno::Reference<beans::XPropertySet> xColumnDesc = xColumnsFact->createDataDescriptor();
892 OSL_ENSURE( xColumnDesc.is(), "can't get column descriptor" );
893 if (!xColumnDesc.is()) return SCERR_EXPORT_CONNECT;
895 aAny <<= pColNames[nCol];
896 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_NAME), aAny );
898 aAny <<= pColTypes[nCol];
899 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_TYPE), aAny );
901 aAny <<= pColLengths[nCol];
902 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_PRECISION), aAny );
904 aAny <<= pColScales[nCol];
905 xColumnDesc->setPropertyValue( OUString(SC_DBPROP_SCALE), aAny );
907 xColumnsAppend->appendByDescriptor( xColumnDesc );
910 xTablesAppend->appendByDescriptor( xTableDesc );
912 // get row set for writing
913 uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
914 uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(
915 OUString( SC_SERVICE_ROWSET ) ),
916 uno::UNO_QUERY);
917 ::utl::DisposableComponent aRowSetHelper(xRowSet);
918 uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
919 OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
920 if (!xRowProp.is()) return SCERR_EXPORT_CONNECT;
922 aAny <<= xConnection;
923 xRowProp->setPropertyValue( OUString(SC_DBPROP_ACTIVECONNECTION), aAny );
925 aAny <<= (sal_Int32) sdb::CommandType::TABLE;
926 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMANDTYPE), aAny );
928 aAny <<= OUString( aTabName );
929 xRowProp->setPropertyValue( OUString(SC_DBPROP_COMMAND), aAny );
931 xRowSet->execute();
933 // write data rows
935 uno::Reference<sdbc::XResultSetUpdate> xResultUpdate( xRowSet, uno::UNO_QUERY );
936 OSL_ENSURE( xResultUpdate.is(), "can't get XResultSetUpdate" );
937 if (!xResultUpdate.is()) return SCERR_EXPORT_CONNECT;
939 uno::Reference<sdbc::XRowUpdate> xRowUpdate( xRowSet, uno::UNO_QUERY );
940 OSL_ENSURE( xRowUpdate.is(), "can't get XRowUpdate" );
941 if (!xRowUpdate.is()) return SCERR_EXPORT_CONNECT;
943 SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
944 double fVal;
946 for ( nDocRow = nFirstDataRow; nDocRow <= nLastRow; nDocRow++ )
948 xResultUpdate->moveToInsertRow();
950 for (nCol=0; nCol<nColCount; nCol++)
952 SCCOL nDocCol = sal::static_int_cast<SCCOL>( nFirstCol + nCol );
954 switch (pColTypes[nCol])
956 case sdbc::DataType::LONGVARCHAR:
958 ScRefCellValue aCell;
959 aCell.assign(aDocument, ScAddress(nDocCol, nDocRow, nTab));
960 if (!aCell.isEmpty())
962 if (aCell.meType == CELLTYPE_EDIT)
963 { // Paragraphs erhalten
964 lcl_getLongVarCharEditString(aString, aCell, aEditEngine);
966 else
968 lcl_getLongVarCharString(
969 aString, aDocument, nDocCol, nDocRow, nTab, *pNumFmt);
971 xRowUpdate->updateString( nCol+1, aString );
973 else
974 xRowUpdate->updateNull( nCol+1 );
976 break;
978 case sdbc::DataType::VARCHAR:
979 aString = aDocument.GetString(nDocCol, nDocRow, nTab);
980 xRowUpdate->updateString( nCol+1, aString );
981 if ( nErr == eERR_OK && pColLengths[nCol] < aString.getLength() )
982 nErr = SCWARN_EXPORT_DATALOST;
983 break;
985 case sdbc::DataType::DATE:
987 aDocument.GetValue( nDocCol, nDocRow, nTab, fVal );
988 // zwischen 0 Wert und 0 kein Wert unterscheiden
989 sal_Bool bIsNull = (fVal == 0.0);
990 if ( bIsNull )
991 bIsNull = !aDocument.HasValueData( nDocCol, nDocRow, nTab );
992 if ( bIsNull )
994 xRowUpdate->updateNull( nCol+1 );
995 if ( nErr == eERR_OK &&
996 aDocument.HasStringData( nDocCol, nDocRow, nTab ) )
997 nErr = SCWARN_EXPORT_DATALOST;
999 else
1001 Date aDate = *(pNumFmt->GetNullDate()); // tools date
1002 aDate += (long)fVal; //! approxfloor?
1003 util::Date aUnoDate( aDate.GetDay(), aDate.GetMonth(), aDate.GetYear() );
1004 xRowUpdate->updateDate( nCol+1, aUnoDate );
1007 break;
1009 case sdbc::DataType::DECIMAL:
1010 case sdbc::DataType::BIT:
1011 aDocument.GetValue( nDocCol, nDocRow, nTab, fVal );
1012 if ( fVal == 0.0 && nErr == eERR_OK &&
1013 aDocument.HasStringData( nDocCol, nDocRow, nTab ) )
1014 nErr = SCWARN_EXPORT_DATALOST;
1015 if ( pColTypes[nCol] == sdbc::DataType::BIT )
1016 xRowUpdate->updateBoolean( nCol+1, ( fVal != 0.0 ) );
1017 else
1018 xRowUpdate->updateDouble( nCol+1, fVal );
1019 break;
1021 default:
1022 OSL_FAIL( "ScDocShell::DBaseExport: unknown FieldType" );
1023 if ( nErr == eERR_OK )
1024 nErr = SCWARN_EXPORT_DATALOST;
1025 aDocument.GetValue( nDocCol, nDocRow, nTab, fVal );
1026 xRowUpdate->updateDouble( nCol+1, fVal );
1030 xResultUpdate->insertRow();
1032 //! error handling and recovery of old
1033 //! ScDocShell::SbaSdbExport is still missing!
1035 if ( !aProgress.SetStateOnPercent( nDocRow - nFirstRow ) )
1036 { // UserBreak
1037 nErr = SCERR_EXPORT_DATA;
1038 break;
1042 comphelper::disposeComponent( xRowSet );
1043 comphelper::disposeComponent( xConnection );
1045 catch ( const sdbc::SQLException& aException )
1047 sal_Int32 nError = aException.ErrorCode;
1048 #if OSL_DEBUG_LEVEL > 1
1049 fprintf( stderr, "ScDocShell::DBaseExport: SQLException ErrorCode: %d, SQLState: %s, Message: %s\n",
1050 (int)nError, OUStringToOString( aException.SQLState,
1051 RTL_TEXTENCODING_UTF8).getStr(), OUStringToOString(
1052 aException.Message, RTL_TEXTENCODING_UTF8).getStr());
1053 #endif
1054 if (nError == 22018 || nError == 22001)
1056 // SQL error 22018: Character not in target encoding.
1057 // SQL error 22001: String length exceeds field width (after encoding).
1058 bool bEncErr = (nError == 22018);
1059 bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
1060 OSL_ENSURE( !bEncErr || bIsOctetTextEncoding, "ScDocShell::DBaseExport: encoding error and not an octect textencoding");
1061 SCCOL nDocCol = nFirstCol;
1062 const sal_Int32* pColTypes = aColTypes.getConstArray();
1063 const sal_Int32* pColLengths = aColLengths.getConstArray();
1064 ScHorizontalCellIterator aIter( &aDocument, nTab, nFirstCol,
1065 nDocRow, nLastCol, nDocRow);
1066 ScRefCellValue* pCell = NULL;
1067 bool bTest = true;
1068 while (bTest && ((pCell = aIter.GetNext( nDocCol, nDocRow)) != NULL))
1070 SCCOL nCol = nDocCol - nFirstCol;
1071 switch (pColTypes[nCol])
1073 case sdbc::DataType::LONGVARCHAR:
1075 if (pCell->meType == CELLTYPE_EDIT)
1076 lcl_getLongVarCharEditString(aString, *pCell, aEditEngine);
1077 else
1078 lcl_getLongVarCharString(
1079 aString, aDocument, nDocCol, nDocRow, nTab, *pNumFmt);
1081 break;
1083 case sdbc::DataType::VARCHAR:
1084 aString = aDocument.GetString(nDocCol, nDocRow, nTab);
1085 break;
1087 // NOTE: length of DECIMAL fields doesn't need to be
1088 // checked here, the database driver adjusts the field
1089 // width accordingly.
1091 default:
1092 bTest = false;
1094 if (bTest)
1096 sal_Int32 nLen;
1097 if (bIsOctetTextEncoding)
1099 OUString aOUString( aString);
1100 OString aOString;
1101 if (!aOUString.convertToString( &aOString, eCharSet,
1102 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
1103 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
1105 bTest = false;
1106 bEncErr = true;
1108 nLen = aOString.getLength();
1109 #if OSL_DEBUG_LEVEL > 1
1110 if (!bTest)
1111 fprintf( stderr, "ScDocShell::DBaseExport encoding error, string with default replacements: ``%s''\n",
1112 OUStringToOString( aOUString, eCharSet).getStr());
1113 #endif
1115 else
1116 nLen = aString.getLength() * sizeof(sal_Unicode);
1117 if (!bEncErr &&
1118 pColTypes[nCol] != sdbc::DataType::LONGVARCHAR &&
1119 pColLengths[nCol] < nLen)
1121 bTest = false;
1122 #if OSL_DEBUG_LEVEL > 1
1123 fprintf( stderr, "ScDocShell::DBaseExport: field width: %d, encoded length: %d\n",
1124 (int)pColLengths[nCol], (int)nLen);
1125 #endif
1128 else
1129 bTest = true;
1131 OUString sPosition( ScAddress( nDocCol, nDocRow, nTab).GetColRowString());
1132 OUString sEncoding( SvxTextEncodingTable().GetTextString( eCharSet));
1133 nErr = *new TwoStringErrorInfo( (bEncErr ? SCERR_EXPORT_ENCODING :
1134 SCERR_EXPORT_FIELDWIDTH), sPosition, sEncoding,
1135 ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR);
1137 else if ( !aException.Message.isEmpty() )
1138 nErr = *new StringErrorInfo( (SCERR_EXPORT_SQLEXCEPTION), aException.Message, ERRCODE_BUTTON_OK | ERRCODE_MSG_ERROR);
1139 else
1140 nErr = SCERR_EXPORT_DATA;
1142 catch ( uno::Exception& )
1144 OSL_FAIL("Unexpected exception in database");
1145 nErr = ERRCODE_IO_GENERAL;
1148 return nErr;
1149 #endif // !DISABLE_DBCONNECTIVITY
1152 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */