Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / dif / difimp.cxx
blob48feb1bfae5404da7f57c834b31ab7e8410f22df
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 <math.h>
22 #include <svl/zforlist.hxx>
23 #include <osl/diagnose.h>
24 #include "attrib.hxx"
25 #include "dif.hxx"
26 #include "docpool.hxx"
27 #include "document.hxx"
28 #include "filter.hxx"
29 #include "fprogressbar.hxx"
30 #include "ftools.hxx"
31 #include "patattr.hxx"
32 #include "scerrors.hxx"
33 #include "scitems.hxx"
34 #include "stringutil.hxx"
35 #include <memory>
37 const sal_Unicode pKeyTABLE[] = { 'T', 'A', 'B', 'L', 'E', 0 };
38 const sal_Unicode pKeyVECTORS[] = { 'V', 'E', 'C', 'T', 'O', 'R', 'S', 0 };
39 const sal_Unicode pKeyTUPLES[] = { 'T', 'U', 'P', 'L', 'E', 'S', 0 };
40 const sal_Unicode pKeyDATA[] = { 'D', 'A', 'T', 'A', 0 };
41 const sal_Unicode pKeyBOT[] = { 'B', 'O', 'T', 0 };
42 const sal_Unicode pKeyEOD[] = { 'E', 'O', 'D', 0 };
43 const sal_Unicode pKeyERROR[] = { 'E', 'R', 'R', 'O', 'R', 0 };
44 const sal_Unicode pKeyTRUE[] = { 'T', 'R', 'U', 'E', 0 };
45 const sal_Unicode pKeyFALSE[] = { 'F', 'A', 'L', 'S', 'E', 0 };
46 const sal_Unicode pKeyNA[] = { 'N', 'A', 0 };
47 const sal_Unicode pKeyV[] = { 'V', 0 };
48 const sal_Unicode pKey1_0[] = { '1', ',', '0', 0 };
50 FltError ScFormatFilterPluginImpl::ScImportDif( SvStream& rIn, ScDocument* pDoc, const ScAddress& rInsPos,
51 const rtl_TextEncoding eVon, sal_uInt32 nDifOption )
53 DifParser aDifParser( rIn, nDifOption, *pDoc, eVon );
55 const bool bPlain = aDifParser.IsPlain();
57 SCTAB nBaseTab = rInsPos.Tab();
59 TOPIC eTopic = T_UNKNOWN;
60 bool bSyntErrWarn = false;
61 bool bOverflowWarn = false;
63 OUString& aData = aDifParser.aData;
65 rIn.Seek( 0 );
67 ScfStreamProgressBar aPrgrsBar( rIn, pDoc->GetDocumentShell() );
69 while( eTopic != T_DATA && eTopic != T_END )
71 eTopic = aDifParser.GetNextTopic();
73 aPrgrsBar.Progress();
75 const bool bData = !aData.isEmpty();
77 switch( eTopic )
79 case T_TABLE:
81 if( aDifParser.nVector != 0 || aDifParser.nVal != 1 )
82 bSyntErrWarn = true;
83 if( bData )
84 pDoc->RenameTab( nBaseTab, aData );
86 break;
87 case T_VECTORS:
89 if( aDifParser.nVector != 0 )
90 bSyntErrWarn = true;
92 break;
93 case T_TUPLES:
95 if( aDifParser.nVector != 0 )
96 bSyntErrWarn = true;
98 break;
99 case T_DATA:
101 if( aDifParser.nVector != 0 || aDifParser.nVal != 0 )
102 bSyntErrWarn = true;
104 break;
105 case T_LABEL:
106 case T_COMMENT:
107 case T_SIZE:
108 case T_PERIODICITY:
109 case T_MAJORSTART:
110 case T_MINORSTART:
111 case T_TRUELENGTH:
112 case T_UINITS:
113 case T_DISPLAYUNITS:
114 case T_END:
115 case T_UNKNOWN:
116 break;
117 default:
118 OSL_FAIL( "ScImportDif - missing enum" );
123 if( eTopic == T_DATA )
124 { // data starts here
125 SCCOL nBaseCol = rInsPos.Col();
127 SCCOL nColCnt = SCCOL_MAX;
128 SCROW nRowCnt = rInsPos.Row();
129 DifAttrCache aAttrCache( bPlain );
131 DATASET eAkt = D_UNKNOWN;
133 ScSetStringParam aStrParam; // used to set string value without number detection.
134 aStrParam.setTextInput();
136 while( eAkt != D_EOD )
138 eAkt = aDifParser.GetNextDataset();
140 aPrgrsBar.Progress();
141 ScAddress aPos(nColCnt, nRowCnt, nBaseTab);
143 switch( eAkt )
145 case D_BOT:
146 if( nColCnt < SCCOL_MAX )
147 nRowCnt++;
148 nColCnt = nBaseCol;
149 break;
150 case D_EOD:
151 break;
152 case D_NUMERIC: // Number cell
153 if( nColCnt == SCCOL_MAX )
154 nColCnt = nBaseCol;
156 if( ValidCol(nColCnt) && ValidRow(nRowCnt) )
158 pDoc->EnsureTable(nBaseTab);
160 if( DifParser::IsV( aData.getStr() ) )
162 pDoc->SetValue(aPos, aDifParser.fVal);
163 if( !bPlain )
164 aAttrCache.SetNumFormat( nColCnt, nRowCnt,
165 aDifParser.nNumFormat );
167 else if( aData == pKeyTRUE || aData == pKeyFALSE )
169 pDoc->SetValue(aPos, aDifParser.fVal);
170 if( bPlain )
171 aAttrCache.SetLogical( nColCnt, nRowCnt );
172 else
173 aAttrCache.SetNumFormat( nColCnt, nRowCnt,
174 aDifParser.nNumFormat );
176 else if( aData == pKeyNA || aData == pKeyERROR )
178 pDoc->SetString(aPos, aData, &aStrParam);
180 else
182 OUString aTmp = "#IND:" + aData + "?";
183 pDoc->SetString(aPos, aTmp, &aStrParam);
186 else
187 bOverflowWarn = true;
189 nColCnt++;
190 break;
191 case D_STRING: // Text cell
192 if( nColCnt == SCCOL_MAX )
193 nColCnt = nBaseCol;
195 if( ValidCol(nColCnt) && ValidRow(nRowCnt) )
197 if (!aData.isEmpty())
199 pDoc->EnsureTable(nBaseTab);
200 pDoc->SetTextCell(aPos, aData);
203 else
204 bOverflowWarn = true;
206 nColCnt++;
207 break;
208 case D_UNKNOWN:
209 break;
210 case D_SYNT_ERROR:
211 break;
212 default:
213 OSL_FAIL( "ScImportDif - missing enum" );
217 aAttrCache.Apply( *pDoc, nBaseTab );
219 else
220 return eERR_FORMAT;
222 if( bSyntErrWarn )
224 // FIXME: Add proper Warnung!
225 return eERR_RNGOVRFLW;
227 else if( bOverflowWarn )
228 return eERR_RNGOVRFLW;
229 else
230 return eERR_OK;
233 DifParser::DifParser( SvStream& rNewIn, const sal_uInt32 nOption, ScDocument& rDoc, rtl_TextEncoding e )
234 : fVal(0.0)
235 , nVector(0)
236 , nVal(0)
237 , nNumFormat(0)
238 , eCharSet(e)
239 , rIn(rNewIn)
241 if ( rIn.GetStreamCharSet() != eCharSet )
243 OSL_FAIL( "CharSet passed overrides and modifies StreamCharSet" );
244 rIn.SetStreamCharSet( eCharSet );
246 rIn.StartReadingUnicodeText( eCharSet );
248 bPlain = ( nOption == SC_DIFOPT_PLAIN );
250 if( bPlain )
251 pNumFormatter = nullptr;
252 else
253 pNumFormatter = rDoc.GetFormatTable();
256 TOPIC DifParser::GetNextTopic()
258 enum STATE { S_VectorVal, S_Data, S_END, S_START, S_UNKNOWN, S_ERROR_L2 };
260 static const sal_Unicode pKeyLABEL[] = { 'L', 'A', 'B', 'E', 'L', 0 };
261 static const sal_Unicode pKeyCOMMENT[] = { 'C', 'O', 'M', 'M', 'E', 'N', 'T', 0 };
262 static const sal_Unicode pKeySIZE[] = { 'S', 'I', 'Z', 'E', 0 };
263 static const sal_Unicode pKeyPERIODICITY[] = { 'P', 'E', 'R', 'I', 'O', 'D', 'I', 'C', 'I', 'T', 'Y', 0 };
264 static const sal_Unicode pKeyMAJORSTART[] = { 'M', 'A', 'J', 'O', 'R', 'S', 'T', 'A', 'R', 'T', 0 };
265 static const sal_Unicode pKeyMINORSTART[] = { 'M', 'I', 'N', 'O', 'R', 'S', 'T', 'A', 'R', 'T', 0 };
266 static const sal_Unicode pKeyTRUELENGTH[] = { 'T', 'R', 'U', 'E', 'L', 'E', 'N', 'G', 'T', 'H', 0 };
267 static const sal_Unicode pKeyUINITS[] = { 'U', 'I', 'N', 'I', 'T', 'S', 0 };
268 static const sal_Unicode pKeyDISPLAYUNITS[] = { 'D', 'I', 'S', 'P', 'L', 'A', 'Y', 'U', 'N', 'I', 'T', 'S', 0 };
269 static const sal_Unicode pKeyUNKNOWN[] = { 0 };
271 static const sal_Unicode* ppKeys[] =
273 pKeyTABLE, // 0
274 pKeyVECTORS,
275 pKeyTUPLES,
276 pKeyDATA,
277 pKeyLABEL,
278 pKeyCOMMENT, // 5
279 pKeySIZE,
280 pKeyPERIODICITY,
281 pKeyMAJORSTART,
282 pKeyMINORSTART,
283 pKeyTRUELENGTH, // 10
284 pKeyUINITS,
285 pKeyDISPLAYUNITS,
286 pKeyUNKNOWN // 13
289 static const TOPIC pTopics[] =
291 T_TABLE, // 0
292 T_VECTORS,
293 T_TUPLES,
294 T_DATA,
295 T_LABEL,
296 T_COMMENT, // 5
297 T_SIZE,
298 T_PERIODICITY,
299 T_MAJORSTART,
300 T_MINORSTART,
301 T_TRUELENGTH, // 10
302 T_UINITS,
303 T_DISPLAYUNITS,
304 T_UNKNOWN // 13
307 STATE eS = S_START;
308 OUString aLine;
310 nVector = 0;
311 nVal = 0;
312 TOPIC eRet = T_UNKNOWN;
314 while( eS != S_END )
316 if( !ReadNextLine( aLine ) )
318 eS = S_END;
319 eRet = T_END;
322 switch( eS )
324 case S_START:
326 const sal_Unicode* pRef;
327 sal_uInt16 nCnt = 0;
328 bool bSearch = true;
330 pRef = ppKeys[ nCnt ];
332 while( bSearch )
334 if( aLine == pRef )
336 eRet = pTopics[ nCnt ];
337 bSearch = false;
339 else
341 nCnt++;
342 pRef = ppKeys[ nCnt ];
343 if( !*pRef )
344 bSearch = false;
348 if( *pRef )
349 eS = S_VectorVal;
350 else
351 eS = S_UNKNOWN;
353 break;
354 case S_VectorVal:
356 const sal_Unicode* pCur = aLine.getStr();
358 pCur = ScanIntVal( pCur, nVector );
360 if( pCur && *pCur == ',' )
362 pCur++;
363 ScanIntVal( pCur, nVal );
364 eS = S_Data;
366 else
367 eS = S_ERROR_L2;
369 break;
370 case S_Data:
371 OSL_ENSURE( aLine.getLength() >= 2,
372 "+GetNextTopic(): <String> is too short!" );
373 if( aLine.getLength() > 2 )
374 aData = aLine.copy( 1, aLine.getLength() - 2 );
375 else
376 aData.clear();
377 eS = S_END;
378 break;
379 case S_END:
380 OSL_FAIL( "DifParser::GetNextTopic - unexpected state" );
381 break;
382 case S_UNKNOWN:
383 // skip 2 lines
384 ReadNextLine( aLine );
385 SAL_FALLTHROUGH;
386 case S_ERROR_L2: // error happened in line 2
387 // skip 1 line
388 ReadNextLine( aLine );
389 eS = S_END;
390 break;
391 default:
392 OSL_FAIL( "DifParser::GetNextTopic - missing enum" );
396 return eRet;
399 static void lcl_DeEscapeQuotesDif( OUString& rString )
401 // Special handling for DIF import: Escaped (duplicated) quotes are resolved.
402 // Single quote characters are left in place because older versions didn't
403 // escape quotes in strings (and Excel doesn't when using the clipboard).
404 // The quotes around the string are removed before this function is called.
406 rString = rString.replaceAll("\"\"", "\"");
409 // Determine if passed in string is numeric data and set fVal/nNumFormat if so
410 DATASET DifParser::GetNumberDataset( const sal_Unicode* pPossibleNumericData )
412 DATASET eRet = D_SYNT_ERROR;
413 if( bPlain )
415 if( ScanFloatVal( pPossibleNumericData ) )
416 eRet = D_NUMERIC;
417 else
418 eRet = D_SYNT_ERROR;
420 else
421 { // ...and for punishment, with number formatting...
422 OSL_ENSURE( pNumFormatter, "-DifParser::GetNextDataset(): No Formatter, more fun!" );
423 OUString aTestVal( pPossibleNumericData );
424 sal_uInt32 nFormat = 0;
425 double fTmpVal;
426 if( pNumFormatter->IsNumberFormat( aTestVal, nFormat, fTmpVal ) )
428 fVal = fTmpVal;
429 nNumFormat = nFormat;
430 eRet = D_NUMERIC;
432 else
433 eRet = D_SYNT_ERROR;
435 return eRet;
438 bool DifParser::ReadNextLine( OUString& rStr )
440 if( aLookAheadLine.isEmpty() )
442 return rIn.ReadUniOrByteStringLine( rStr, rIn.GetStreamCharSet() );
444 else
446 rStr = aLookAheadLine;
447 aLookAheadLine.clear();
448 return true;
452 // Look ahead in the stream to determine if the next line is the first line of
453 // a valid data record structure
454 bool DifParser::LookAhead()
456 const sal_Unicode* pAktBuffer;
457 bool bValidStructure = false;
459 OSL_ENSURE( aLookAheadLine.isEmpty(), "*DifParser::LookAhead(): LookAhead called twice in a row" );
460 rIn.ReadUniOrByteStringLine( aLookAheadLine, rIn.GetStreamCharSet() );
462 pAktBuffer = aLookAheadLine.getStr();
464 switch( *pAktBuffer )
466 case '-': // Special Datatype
467 pAktBuffer++;
469 if( Is1_0( pAktBuffer ) )
471 bValidStructure = true;
473 break;
474 case '0': // Numeric Data
475 pAktBuffer++;
476 if( *pAktBuffer == ',' )
478 pAktBuffer++;
479 bValidStructure = ( GetNumberDataset(pAktBuffer) != D_SYNT_ERROR );
481 break;
482 case '1': // String Data
483 if( Is1_0( aLookAheadLine.getStr() ) )
485 bValidStructure = true;
487 break;
489 return bValidStructure;
492 DATASET DifParser::GetNextDataset()
494 DATASET eRet = D_UNKNOWN;
495 OUString aLine;
496 const sal_Unicode* pAktBuffer;
498 ReadNextLine( aLine );
500 pAktBuffer = aLine.getStr();
502 switch( *pAktBuffer )
504 case '-': // Special Datatype
505 pAktBuffer++;
507 if( Is1_0( pAktBuffer ) )
509 ReadNextLine( aLine );
510 if( IsBOT( aLine.getStr() ) )
511 eRet = D_BOT;
512 else if( IsEOD( aLine.getStr() ) )
513 eRet = D_EOD;
515 break;
516 case '0': // Numeric Data
517 pAktBuffer++; // value in fVal, 2. line in aData
518 if( *pAktBuffer == ',' )
520 pAktBuffer++;
521 eRet = GetNumberDataset(pAktBuffer);
522 OUString aTmpLine;
523 ReadNextLine( aTmpLine );
524 if ( eRet == D_SYNT_ERROR )
525 { // for broken records write "#ERR: data" to cell
526 OUStringBuffer aTmp("#ERR: ");
527 aTmp.append(pAktBuffer).append(" (");
528 aTmp.append(aTmpLine).append(')');
529 aData = aTmp.makeStringAndClear();
530 eRet = D_STRING;
532 else
534 aData = aTmpLine;
537 break;
538 case '1': // String Data
539 if( Is1_0( aLine.getStr() ) )
541 ReadNextLine( aLine );
542 sal_Int32 nLineLength = aLine.getLength();
543 const sal_Unicode* pLine = aLine.getStr();
545 if( nLineLength >= 1 && *pLine == '"' )
547 // Quotes are not always escaped (duplicated), see lcl_DeEscapeQuotesDif
548 // A look ahead into the next line is needed in order to deal with
549 // multiline strings containing quotes
550 if( LookAhead() )
552 // Single line string
553 if( nLineLength >= 2 && pLine[nLineLength - 1] == '"' )
555 aData = aLine.copy( 1, nLineLength - 2 );
556 lcl_DeEscapeQuotesDif( aData );
557 eRet = D_STRING;
560 else
562 // Multiline string
563 aData = aLine.copy( 1 );
564 bool bContinue = true;
565 while ( bContinue )
567 aData = aData + "\n";
568 bContinue = !rIn.IsEof() && ReadNextLine( aLine );
569 if( bContinue )
571 nLineLength = aLine.getLength();
572 if( nLineLength >= 1 )
574 pLine = aLine.getStr();
575 bContinue = !LookAhead();
576 if( bContinue )
578 aData = aData + aLine;
580 else if( pLine[nLineLength - 1] == '"' )
582 aData = aData + aLine.copy(0, nLineLength -1 );
583 lcl_DeEscapeQuotesDif( aData );
584 eRet = D_STRING;
592 break;
595 if( eRet == D_UNKNOWN )
596 ReadNextLine( aLine );
598 if( rIn.IsEof() )
599 eRet = D_EOD;
601 return eRet;
604 const sal_Unicode* DifParser::ScanIntVal( const sal_Unicode* pStart, sal_uInt32& rRet )
606 // eat leading whitespace, not specified, but seen in the wild
607 while (*pStart == ' ' || *pStart == '\t')
608 ++pStart;
610 sal_Unicode cAkt = *pStart;
612 if( IsNumber( cAkt ) )
613 rRet = ( sal_uInt32 ) ( cAkt - '0' );
614 else
615 return nullptr;
617 pStart++;
618 cAkt = *pStart;
620 while( IsNumber( cAkt ) && rRet < ( 0xFFFFFFFF / 10 ) )
622 rRet *= 10;
623 rRet += ( sal_uInt32 ) ( cAkt - '0' );
625 pStart++;
626 cAkt = *pStart;
629 return pStart;
632 bool DifParser::ScanFloatVal( const sal_Unicode* pStart )
634 bool bNeg = false;
635 double fFracPos = 1.0;
636 sal_Int32 nExp = 0;
637 bool bExpNeg = false;
638 bool bExpOverflow = false;
639 static const sal_uInt16 nExpLimit = 4096; // FIXME: has to be set more accurately!
641 sal_Unicode cAkt;
642 bool bRet = false;
644 enum STATE { S_FIRST, S_PRE, S_POST, S_EXP_FIRST, S_EXP, S_END, S_FINDEND };
646 STATE eS = S_FIRST;
648 double fNewVal = 0.0;
650 while( eS != S_END )
652 cAkt = *pStart;
653 switch( eS )
655 case S_FIRST:
656 if( IsNumber( cAkt ) )
658 fNewVal *= 10;
659 fNewVal += cAkt - '0';
660 eS = S_PRE;
662 else
664 switch( cAkt )
666 case ' ':
667 case '\t':
668 case '+':
669 break;
670 case '-':
671 bNeg = !bNeg;
672 break;
673 case '.':
674 case ',':
675 eS = S_POST;
676 fFracPos = 0.1;
677 break;
678 default:
679 eS = S_END;
682 break;
683 case S_PRE:
684 if( IsNumber( cAkt ) )
686 fNewVal *= 10;
687 fNewVal += cAkt - '0';
689 else
691 switch( cAkt )
693 case '.':
694 case ',':
695 eS = S_POST;
696 fFracPos = 0.1;
697 break;
698 case 'e':
699 case 'E':
700 eS = S_EXP;
701 break;
702 case 0x00: // IsNumberEnding( cAkt )
703 bRet = true;
704 SAL_FALLTHROUGH;
705 default:
706 eS = S_END;
709 break;
710 case S_POST:
711 if( IsNumber( cAkt ) )
713 fNewVal += fFracPos * ( cAkt - '0' );
714 fFracPos /= 10.0;
716 else
718 switch( cAkt )
720 case 'e':
721 case 'E':
722 eS = S_EXP_FIRST;
723 break;
724 case 0x00: // IsNumberEnding( cAkt )
725 bRet = true;
726 SAL_FALLTHROUGH;
727 default:
728 eS = S_END;
731 break;
732 case S_EXP_FIRST:
733 if( IsNumber( cAkt ) )
735 if( nExp < nExpLimit )
737 nExp *= 10;
738 nExp += ( sal_uInt16 ) ( cAkt - '0' );
740 eS = S_EXP;
742 else
744 switch( cAkt )
746 case '+':
747 break;
748 case '-':
749 bExpNeg = !bExpNeg;
750 break;
751 default:
752 eS = S_END;
755 break;
756 case S_EXP:
757 if( IsNumber( cAkt ) )
759 if( nExp < ( 0xFFFF / 10 ) )
761 nExp *= 10;
762 nExp += ( sal_uInt16 ) ( cAkt - '0' );
764 else
766 bExpOverflow = true;
767 eS = S_FINDEND;
770 else
772 bRet = IsNumberEnding( cAkt );
773 eS = S_END;
775 break;
776 case S_FINDEND:
777 if( IsNumberEnding( cAkt ) )
779 bRet = true; // to continue parsing
780 eS = S_END;
782 break;
783 // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
784 case S_END:
785 OSL_FAIL( "DifParser::ScanFloatVal - unexpected state" );
786 break;
787 default:
788 OSL_FAIL( "DifParser::ScanFloatVal - missing enum" );
790 pStart++;
793 if( bRet )
795 if( bExpOverflow )
796 return false; // FIXME: add special cases here
798 if( bNeg )
799 fNewVal *= 1.0;
801 if( bExpNeg )
802 nExp *= -1;
804 if( nExp != 0 )
805 fNewVal *= pow( 10.0, ( double ) nExp );
806 fVal = fNewVal;
809 return bRet;
812 DifColumn::DifColumn ()
813 : mpAkt(nullptr)
817 void DifColumn::SetLogical( SCROW nRow )
819 OSL_ENSURE( ValidRow(nRow), "*DifColumn::SetLogical(): Row too big!" );
821 if( mpAkt )
823 OSL_ENSURE( nRow > 0, "*DifColumn::SetLogical(): more cannot be zero!" );
825 nRow--;
827 if( mpAkt->nEnd == nRow )
828 mpAkt->nEnd++;
829 else
830 mpAkt = nullptr;
832 else
834 maEntries.push_back(ENTRY());
835 mpAkt = &maEntries.back();
836 mpAkt->nStart = mpAkt->nEnd = nRow;
840 void DifColumn::SetNumFormat( SCROW nRow, const sal_uInt32 nNumFormat )
842 OSL_ENSURE( ValidRow(nRow), "*DifColumn::SetNumFormat(): Row too big!" );
844 if( nNumFormat > 0 )
846 if(mpAkt)
848 OSL_ENSURE( nRow > 0,
849 "*DifColumn::SetNumFormat(): more cannot be zero!" );
850 OSL_ENSURE( nRow > mpAkt->nEnd,
851 "*DifColumn::SetNumFormat(): start from scratch?" );
853 if( mpAkt->nNumFormat == nNumFormat && mpAkt->nEnd == nRow - 1 )
854 mpAkt->nEnd = nRow;
855 else
856 NewEntry( nRow, nNumFormat );
858 else
859 NewEntry(nRow,nNumFormat );
861 else
862 mpAkt = nullptr;
865 void DifColumn::NewEntry( const SCROW nPos, const sal_uInt32 nNumFormat )
867 maEntries.push_back(ENTRY());
868 mpAkt = &maEntries.back();
869 mpAkt->nStart = mpAkt->nEnd = nPos;
870 mpAkt->nNumFormat = nNumFormat;
874 void DifColumn::Apply( ScDocument& rDoc, const SCCOL nCol, const SCTAB nTab, const ScPatternAttr& rPattAttr )
876 for (std::vector<ENTRY>::const_iterator it = maEntries.begin(); it != maEntries.end(); ++it)
877 rDoc.ApplyPatternAreaTab( nCol, it->nStart, nCol, it->nEnd, nTab, rPattAttr );
880 void DifColumn::Apply( ScDocument& rDoc, const SCCOL nCol, const SCTAB nTab )
882 ScPatternAttr aAttr( rDoc.GetPool() );
883 SfxItemSet &rItemSet = aAttr.GetItemSet();
885 for (std::vector<ENTRY>::const_iterator it = maEntries.begin(); it != maEntries.end(); ++it)
887 OSL_ENSURE( it->nNumFormat > 0,
888 "+DifColumn::Apply(): Number format must not be 0!" );
890 rItemSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, it->nNumFormat ) );
892 rDoc.ApplyPatternAreaTab( nCol, it->nStart, nCol, it->nEnd, nTab, aAttr );
894 rItemSet.ClearItem();
898 DifAttrCache::DifAttrCache( const bool bNewPlain )
900 bPlain = bNewPlain;
901 ppCols = new DifColumn *[ MAXCOL + 1 ];
902 for( SCCOL nCnt = 0 ; nCnt <= MAXCOL ; nCnt++ )
903 ppCols[ nCnt ] = nullptr;
906 DifAttrCache::~DifAttrCache()
908 for( SCCOL nCnt = 0 ; nCnt <= MAXCOL ; nCnt++ )
910 if( ppCols[ nCnt ] )
911 delete ppCols[ nCnt ];
914 delete[] ppCols;
917 void DifAttrCache::SetLogical( const SCCOL nCol, const SCROW nRow )
919 OSL_ENSURE( ValidCol(nCol), "-DifAttrCache::SetLogical(): Col too big!" );
920 OSL_ENSURE( bPlain, "*DifAttrCache::SetLogical(): has to be Plain!" );
922 if( !ppCols[ nCol ] )
923 ppCols[ nCol ] = new DifColumn;
925 ppCols[ nCol ]->SetLogical( nRow );
928 void DifAttrCache::SetNumFormat( const SCCOL nCol, const SCROW nRow, const sal_uInt32 nNumFormat )
930 OSL_ENSURE( ValidCol(nCol), "-DifAttrCache::SetNumFormat(): Col too big!" );
931 OSL_ENSURE( !bPlain, "*DifAttrCache::SetNumFormat(): should not be Plain!" );
933 if( !ppCols[ nCol ] )
934 ppCols[ nCol ] = new DifColumn;
936 ppCols[ nCol ]->SetNumFormat( nRow, nNumFormat );
939 void DifAttrCache::Apply( ScDocument& rDoc, SCTAB nTab )
941 if( bPlain )
943 std::unique_ptr<ScPatternAttr> pPatt;
945 for( SCCOL nCol = 0 ; nCol <= MAXCOL ; nCol++ )
947 if( ppCols[ nCol ] )
949 if( !pPatt )
951 pPatt.reset(new ScPatternAttr( rDoc.GetPool() ));
952 pPatt->GetItemSet().Put( SfxUInt32Item( ATTR_VALUE_FORMAT,
953 rDoc.GetFormatTable()->GetStandardFormat( css::util::NumberFormat::LOGICAL ) ) );
956 ppCols[ nCol ]->Apply( rDoc, nCol, nTab, *pPatt );
960 else
962 for( SCCOL nCol = 0 ; nCol <= MAXCOL ; nCol++ )
964 if( ppCols[ nCol ] )
965 ppCols[ nCol ]->Apply( rDoc, nCol, nTab );
970 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */