merge the formfield patch from ooo-build
[ooovba.git] / sc / source / core / tool / chartpos.cxx
blobde1a053b3855678e44a8c020c0e736f0ba33ea91
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: chartpos.cxx,v $
10 * $Revision: 1.4.32.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <tools/table.hxx>
38 #include "chartpos.hxx"
39 #include "document.hxx"
40 #include "rechead.hxx"
43 ScChartPositioner::ScChartPositioner( ScDocument* pDoc, SCTAB nTab,
44 SCCOL nStartColP, SCROW nStartRowP, SCCOL nEndColP, SCROW nEndRowP) :
45 pDocument( pDoc ),
46 pPositionMap( NULL ),
47 eGlue( SC_CHARTGLUE_NA ),
48 nStartCol(0),
49 nStartRow(0),
50 bColHeaders( FALSE ),
51 bRowHeaders( FALSE ),
52 bDummyUpperLeft( FALSE )
54 SetRangeList( ScRange( nStartColP, nStartRowP, nTab, nEndColP, nEndRowP, nTab ) );
55 CheckColRowHeaders();
58 ScChartPositioner::ScChartPositioner( ScDocument* pDoc, const ScRangeListRef& rRangeList ) :
59 aRangeListRef( rRangeList ),
60 pDocument( pDoc ),
61 pPositionMap( NULL ),
62 eGlue( SC_CHARTGLUE_NA ),
63 nStartCol(0),
64 nStartRow(0),
65 bColHeaders( FALSE ),
66 bRowHeaders( FALSE ),
67 bDummyUpperLeft( FALSE )
69 if ( aRangeListRef.Is() )
70 CheckColRowHeaders();
73 ScChartPositioner::ScChartPositioner( const ScChartPositioner& rPositioner ) :
74 aRangeListRef( rPositioner.aRangeListRef ),
75 pDocument(rPositioner.pDocument),
76 pPositionMap( NULL ),
77 eGlue(rPositioner.eGlue),
78 nStartCol(rPositioner.nStartCol),
79 nStartRow(rPositioner.nStartRow),
80 bColHeaders(rPositioner.bColHeaders),
81 bRowHeaders(rPositioner.bRowHeaders),
82 bDummyUpperLeft( rPositioner.bDummyUpperLeft )
86 ScChartPositioner::~ScChartPositioner()
88 delete pPositionMap;
91 BOOL ScChartPositioner::operator==(const ScChartPositioner& rCmp) const
93 return bColHeaders == rCmp.bColHeaders
94 && bRowHeaders == rCmp.bRowHeaders
95 && *aRangeListRef == *rCmp.aRangeListRef;
98 void ScChartPositioner::SetRangeList( const ScRange& rRange )
100 aRangeListRef = new ScRangeList;
101 aRangeListRef->Append( rRange );
102 InvalidateGlue();
105 void ScChartPositioner::GlueState()
107 if ( eGlue != SC_CHARTGLUE_NA )
108 return;
109 bDummyUpperLeft = FALSE;
110 ScRangePtr pR;
111 if ( aRangeListRef->Count() <= 1 )
113 if ( (pR = aRangeListRef->First())!=NULL )
115 if ( pR->aStart.Tab() == pR->aEnd.Tab() )
116 eGlue = SC_CHARTGLUE_NONE;
117 else
118 eGlue = SC_CHARTGLUE_COLS; // mehrere Tabellen spaltenweise
119 nStartCol = pR->aStart.Col();
120 nStartRow = pR->aStart.Row();
122 else
124 InvalidateGlue();
125 nStartCol = 0;
126 nStartRow = 0;
128 return;
130 // ULONG nOldPos = aRangeListRef->GetCurPos();
132 pR = aRangeListRef->First();
133 nStartCol = pR->aStart.Col();
134 nStartRow = pR->aStart.Row();
135 SCCOL nMaxCols, nEndCol;
136 SCROW nMaxRows, nEndRow;
137 nMaxCols = nEndCol = 0;
138 nMaxRows = nEndRow = 0;
140 { // umspannenden Bereich etc. feststellen
141 SCCOLROW nTmp, n1, n2;
142 if ( (n1 = pR->aStart.Col()) < nStartCol )
143 nStartCol = static_cast<SCCOL>(n1);
144 if ( (n2 = pR->aEnd.Col()) > nEndCol )
145 nEndCol = static_cast<SCCOL>(n2);
146 if ( (nTmp = n2 - n1 + 1) > nMaxCols )
147 nMaxCols = static_cast<SCCOL>(nTmp);
148 if ( (n1 = pR->aStart.Row()) < nStartRow )
149 nStartRow = static_cast<SCROW>(n1);
150 if ( (n2 = pR->aEnd.Row()) > nEndRow )
151 nEndRow = static_cast<SCROW>(n2);
152 if ( (nTmp = n2 - n1 + 1) > nMaxRows )
153 nMaxRows = static_cast<SCROW>(nTmp);
154 } while ( (pR = aRangeListRef->Next())!=NULL );
155 SCCOL nC = nEndCol - nStartCol + 1;
156 if ( nC == 1 )
158 eGlue = SC_CHARTGLUE_ROWS;
159 return;
161 SCROW nR = nEndRow - nStartRow + 1;
162 if ( nR == 1 )
164 eGlue = SC_CHARTGLUE_COLS;
165 return;
167 ULONG nCR = (ULONG)nC * nR;
168 //2do:
170 Erstmal simpel ohne Bitmaskiererei, maximal koennten so 8MB alloziert
171 werden (256 Cols mal 32000 Rows), das liesse sich mit 2 Bit je Eintrag
172 auf 2MB reduzieren, andererseits ist es so schneller.
173 Weitere Platz-Optimierung waere, in dem Array nur die wirklich benutzten
174 Zeilen/Spalten abzulegen, wuerde aber ein weiteres durchlaufen der
175 RangeList und indirekten Zugriff auf das Array bedeuten.
177 const BYTE nHole = 0;
178 const BYTE nOccu = 1;
179 const BYTE nFree = 2;
180 const BYTE nGlue = 3;
181 #ifdef WIN
182 // we hate 16bit, don't we?
183 BYTE huge* p;
184 BYTE huge* pA = (BYTE huge*) SvMemAlloc( nCR );
185 if ( nCR > (ULONG)((USHORT)~0) )
186 { // in 32k Bloecken initialisieren
187 ULONG j;
188 for ( j=0; j<nCR; j+=0x8000 )
190 memset( pA+j, nHole, Min( (ULONG)0x8000, nCR-j ) );
193 else
194 memset( pA, nHole, nCR * sizeof(BYTE) );
195 #else
196 BYTE* p;
197 BYTE* pA = new BYTE[ nCR ];
198 memset( pA, 0, nCR * sizeof(BYTE) );
199 #endif
201 SCCOL nCol, nCol1, nCol2;
202 SCROW nRow, nRow1, nRow2;
203 for ( pR = aRangeListRef->First(); pR; pR = aRangeListRef->Next() )
204 { // Selektionen 2D als belegt markieren
205 nCol1 = pR->aStart.Col() - nStartCol;
206 nCol2 = pR->aEnd.Col() - nStartCol;
207 nRow1 = pR->aStart.Row() - nStartRow;
208 nRow2 = pR->aEnd.Row() - nStartRow;
209 for ( nCol = nCol1; nCol <= nCol2; nCol++ )
211 p = pA + (ULONG)nCol * nR + nRow1;
212 for ( nRow = nRow1; nRow <= nRow2; nRow++, p++ )
213 *p = nOccu;
216 BOOL bGlue = TRUE;
218 BOOL bGlueCols = FALSE;
219 for ( nCol = 0; bGlue && nCol < nC; nCol++ )
220 { // Spalten probieren durchzugehen und als frei markieren
221 p = pA + (ULONG)nCol * nR;
222 for ( nRow = 0; bGlue && nRow < nR; nRow++, p++ )
224 if ( *p == nOccu )
225 { // Wenn einer mittendrin liegt ist keine Zusammenfassung
226 // moeglich. Am Rand koennte ok sein, wenn in dieser Spalte
227 // in jeder belegten Zeile einer belegt ist.
228 if ( nRow > 0 && nCol > 0 )
229 bGlue = FALSE; // nCol==0 kann DummyUpperLeft sein
230 else
231 nRow = nR;
233 else
234 *p = nFree;
236 if ( bGlue && *(p = (pA + ((((ULONG)nCol+1) * nR) - 1))) == nFree )
237 { // Spalte als komplett frei markieren
238 *p = nGlue;
239 bGlueCols = TRUE; // mindestens eine freie Spalte
243 BOOL bGlueRows = FALSE;
244 for ( nRow = 0; bGlue && nRow < nR; nRow++ )
245 { // Zeilen probieren durchzugehen und als frei markieren
246 p = pA + nRow;
247 for ( nCol = 0; bGlue && nCol < nC; nCol++, p+=nR )
249 if ( *p == nOccu )
251 if ( nCol > 0 && nRow > 0 )
252 bGlue = FALSE; // nRow==0 kann DummyUpperLeft sein
253 else
254 nCol = nC;
256 else
257 *p = nFree;
259 if ( bGlue && *(p = (pA + ((((ULONG)nC-1) * nR) + nRow))) == nFree )
260 { // Zeile als komplett frei markieren
261 *p = nGlue;
262 bGlueRows = TRUE; // mindestens eine freie Zeile
266 // n=1: die linke obere Ecke koennte bei Beschriftung automagisch
267 // hinzugezogen werden
268 p = pA + 1;
269 for ( ULONG n = 1; bGlue && n < nCR; n++, p++ )
270 { // ein unberuehrtes Feld heisst, dass es weder spaltenweise noch
271 // zeilenweise zu erreichen war, also nichts zusamenzufassen
272 if ( *p == nHole )
273 bGlue = FALSE;
275 if ( bGlue )
277 if ( bGlueCols && bGlueRows )
278 eGlue = SC_CHARTGLUE_BOTH;
279 else if ( bGlueRows )
280 eGlue = SC_CHARTGLUE_ROWS;
281 else
282 eGlue = SC_CHARTGLUE_COLS;
283 if ( *pA != nOccu )
284 bDummyUpperLeft = TRUE;
286 else
288 eGlue = SC_CHARTGLUE_NONE;
291 #ifdef WIN
292 SvMemFree( pA );
293 #else
294 delete [] pA;
295 #endif
298 void ScChartPositioner::CheckColRowHeaders()
300 SCCOL nCol1, nCol2, iCol;
301 SCROW nRow1, nRow2, iRow;
302 SCTAB nTab1, nTab2;
304 BOOL bColStrings = TRUE;
305 BOOL bRowStrings = TRUE;
306 GlueState();
307 if ( aRangeListRef->Count() == 1 )
309 aRangeListRef->First()->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
310 if ( nCol1 > nCol2 || nRow1 > nRow2 )
311 bColStrings = bRowStrings = FALSE;
312 else
314 for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
316 if (pDocument->HasValueData( iCol, nRow1, nTab1 ))
317 bColStrings = FALSE;
319 for (iRow=nRow1; iRow<=nRow2 && bRowStrings; iRow++)
321 if (pDocument->HasValueData( nCol1, iRow, nTab1 ))
322 bRowStrings = FALSE;
326 else
328 BOOL bVert = (eGlue == SC_CHARTGLUE_NONE || eGlue == SC_CHARTGLUE_ROWS);
329 for ( ScRangePtr pR = aRangeListRef->First();
330 pR && (bColStrings || bRowStrings);
331 pR = aRangeListRef->Next() )
333 pR->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
334 BOOL bTopRow = (nRow1 == nStartRow);
335 if ( bRowStrings && (bVert || nCol1 == nStartCol) )
336 { // NONE oder ROWS: RowStrings in jeder Selektion moeglich
337 // COLS oder BOTH: nur aus der ersten Spalte
338 if ( nCol1 <= nCol2 )
339 for (iRow=nRow1; iRow<=nRow2 && bRowStrings; iRow++)
341 if (pDocument->HasValueData( nCol1, iRow, nTab1 ))
342 bRowStrings = FALSE;
345 if ( bColStrings && bTopRow )
346 { // ColStrings nur aus der ersten Zeile
347 if ( nRow1 <= nRow2 )
348 for (iCol=nCol1; iCol<=nCol2 && bColStrings; iCol++)
350 if (pDocument->HasValueData( iCol, nRow1, nTab1 ))
351 bColStrings = FALSE;
356 bColHeaders = bColStrings;
357 bRowHeaders = bRowStrings;
360 const ScChartPositionMap* ScChartPositioner::GetPositionMap()
362 CreatePositionMap();
363 return pPositionMap;
367 void ScChartPositioner::CreatePositionMap()
369 if ( eGlue == SC_CHARTGLUE_NA && pPositionMap )
371 delete pPositionMap;
372 pPositionMap = NULL;
375 if ( pPositionMap )
376 return ;
378 SCSIZE nColAdd = bRowHeaders ? 1 : 0;
379 SCSIZE nRowAdd = bColHeaders ? 1 : 0;
381 SCCOL nCol, nCol1, nCol2;
382 SCROW nRow, nRow1, nRow2;
383 SCTAB nTab, nTab1, nTab2;
386 // wirkliche Groesse (ohne versteckte Zeilen/Spalten)
389 SCSIZE nColCount = 0;
390 SCSIZE nRowCount = 0;
392 GlueState();
394 BOOL bNoGlue = (eGlue == SC_CHARTGLUE_NONE);
395 Table* pCols = new Table;
396 Table* pNewRowTable = new Table;
397 ScAddress* pNewAddress = new ScAddress;
398 ScRangePtr pR;
399 Table* pCol;
400 ScAddress* pPos;
401 SCROW nNoGlueRow = 0;
402 for ( pR = aRangeListRef->First(); pR; pR = aRangeListRef->Next() )
404 pR->GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
405 for ( nTab = nTab1; nTab <= nTab2; nTab++ )
407 // nTab im ColKey, um gleiche Col/Row in anderer Table haben zu koennen
408 ULONG nInsCol = (static_cast<ULONG>(nTab) << 16) | (bNoGlue ? 0 :
409 static_cast<ULONG>(nCol1));
410 for ( nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol )
412 if ( bNoGlue || eGlue == SC_CHARTGLUE_ROWS )
413 { // meistens gleiche Cols
414 if ( (pCol = (Table*) pCols->Get( nInsCol ))==NULL )
416 pCols->Insert( nInsCol, pNewRowTable );
417 pCol = pNewRowTable;
418 pNewRowTable = new Table;
421 else
422 { // meistens neue Cols
423 if ( pCols->Insert( nInsCol, pNewRowTable ) )
425 pCol = pNewRowTable;
426 pNewRowTable = new Table;
428 else
429 pCol = (Table*) pCols->Get( nInsCol );
431 // bei anderer Tabelle wurde bereits neuer ColKey erzeugt,
432 // die Zeilen muessen fuer's Dummy fuellen gleich sein!
433 ULONG nInsRow = (bNoGlue ? nNoGlueRow : nRow1);
434 for ( nRow = nRow1; nRow <= nRow2; nRow++, nInsRow++ )
436 if ( pCol->Insert( nInsRow, pNewAddress ) )
438 pNewAddress->Set( nCol, nRow, nTab );
439 pNewAddress = new ScAddress;
444 // bei NoGlue werden zusammengehoerige Tabellen als ColGlue dargestellt
445 nNoGlueRow += nRow2 - nRow1 + 1;
447 delete pNewAddress;
448 delete pNewRowTable;
450 // Anzahl der Daten
451 nColCount = static_cast< SCSIZE >( pCols->Count());
452 if ( (pCol = (Table*) pCols->First())!=NULL )
454 if ( bDummyUpperLeft )
455 pCol->Insert( 0, (void*)0 ); // Dummy fuer Beschriftung
456 nRowCount = static_cast< SCSIZE >( pCol->Count());
458 else
459 nRowCount = 0;
460 if ( nColCount > 0 )
461 nColCount -= nColAdd;
462 if ( nRowCount > 0 )
463 nRowCount -= nRowAdd;
465 if ( nColCount==0 || nRowCount==0 )
466 { // einen Eintrag ohne Daten erzeugen
467 pR = aRangeListRef->First();
468 if ( pCols->Count() > 0 )
469 pCol = (Table*) pCols->First();
470 else
472 pCol = new Table;
473 pCols->Insert( 0, pCol );
475 nColCount = 1;
476 if ( pCol->Count() > 0 )
477 { // kann ja eigentlich nicht sein, wenn nColCount==0 || nRowCount==0
478 pPos = (ScAddress*) pCol->First();
479 if ( pPos )
481 delete pPos;
482 pCol->Replace( pCol->GetCurKey(), (void*)0 );
485 else
486 pCol->Insert( 0, (void*)0 );
487 nRowCount = 1;
488 nColAdd = 0;
489 nRowAdd = 0;
491 else
493 if ( bNoGlue )
494 { // Luecken mit Dummies fuellen, erste Spalte ist Master
495 Table* pFirstCol = (Table*) pCols->First();
496 ULONG nCount = pFirstCol->Count();
497 pFirstCol->First();
498 for ( ULONG n = 0; n < nCount; n++, pFirstCol->Next() )
500 ULONG nKey = pFirstCol->GetCurKey();
501 pCols->First();
502 while ( (pCol = (Table*) pCols->Next())!=NULL )
503 pCol->Insert( nKey, (void*)0 ); // keine Daten
508 pPositionMap = new ScChartPositionMap( static_cast<SCCOL>(nColCount), static_cast<SCROW>(nRowCount),
509 static_cast<SCCOL>(nColAdd), static_cast<SCROW>(nRowAdd), *pCols );
511 // Aufraeumen
512 for ( pCol = (Table*) pCols->First(); pCol; pCol = (Table*) pCols->Next() )
513 { //! nur Tables loeschen, nicht die ScAddress*
514 delete pCol;
516 delete pCols;
520 ScChartPositionMap::ScChartPositionMap( SCCOL nChartCols, SCROW nChartRows,
521 SCCOL nColAdd, SCROW nRowAdd, Table& rCols ) :
522 ppData( new ScAddress* [ nChartCols * nChartRows ] ),
523 ppColHeader( new ScAddress* [ nChartCols ] ),
524 ppRowHeader( new ScAddress* [ nChartRows ] ),
525 nCount( (ULONG) nChartCols * nChartRows ),
526 nColCount( nChartCols ),
527 nRowCount( nChartRows )
529 DBG_ASSERT( nColCount && nRowCount, "ScChartPositionMap without dimension" );
530 #ifdef WIN
531 #error ScChartPositionMap not implemented for 16-bit dumdums
532 #endif
534 ScAddress* pPos;
535 SCCOL nCol;
536 SCROW nRow;
538 Table* pCol = (Table*) rCols.First();
540 // Zeilen-Header
541 pPos = (ScAddress*) pCol->First();
542 if ( nRowAdd )
543 pPos = (ScAddress*) pCol->Next();
544 if ( nColAdd )
545 { // eigenstaendig
546 for ( nRow = 0; nRow < nRowCount; nRow++ )
548 ppRowHeader[ nRow ] = pPos;
549 pPos = (ScAddress*) pCol->Next();
552 else
553 { // Kopie
554 for ( nRow = 0; nRow < nRowCount; nRow++ )
556 ppRowHeader[ nRow ] = ( pPos ? new ScAddress( *pPos ) : NULL );
557 pPos = (ScAddress*) pCol->Next();
560 if ( nColAdd )
561 pCol = (Table*) rCols.Next();
563 // Daten spaltenweise und Spalten-Header
564 ULONG nIndex = 0;
565 for ( nCol = 0; nCol < nColCount; nCol++ )
567 if ( pCol )
569 pPos = (ScAddress*) pCol->First();
570 if ( nRowAdd )
572 ppColHeader[ nCol ] = pPos; // eigenstaendig
573 pPos = (ScAddress*) pCol->Next();
575 else
576 ppColHeader[ nCol ] = ( pPos ? new ScAddress( *pPos ) : NULL );
577 for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
579 ppData[ nIndex ] = pPos;
580 pPos = (ScAddress*) pCol->Next();
583 else
585 ppColHeader[ nCol ] = NULL;
586 for ( nRow = 0; nRow < nRowCount; nRow++, nIndex++ )
588 ppData[ nIndex ] = NULL;
591 pCol = (Table*) rCols.Next();
596 ScChartPositionMap::~ScChartPositionMap()
598 for ( ULONG nIndex=0; nIndex < nCount; nIndex++ )
600 delete ppData[nIndex];
602 delete [] ppData;
604 SCCOL j;
605 for ( j=0; j < nColCount; j++ )
607 delete ppColHeader[j];
609 delete [] ppColHeader;
610 SCROW i;
611 for ( i=0; i < nRowCount; i++ )
613 delete ppRowHeader[i];
615 delete [] ppRowHeader;
619 //UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetColRanges( SCCOL nChartCol ) const
620 //UNUSED2009-05 {
621 //UNUSED2009-05 ScRangeListRef xRangeList = new ScRangeList;
622 //UNUSED2009-05 if ( nChartCol < nColCount )
623 //UNUSED2009-05 {
624 //UNUSED2009-05 ULONG nStop = GetIndex( nChartCol, nRowCount );
625 //UNUSED2009-05 for ( ULONG nIndex = GetIndex( nChartCol, 0 ); nIndex < nStop; nIndex++ )
626 //UNUSED2009-05 {
627 //UNUSED2009-05 if ( ppData[ nIndex ] )
628 //UNUSED2009-05 xRangeList->Join( *ppData[ nIndex ] );
629 //UNUSED2009-05 }
630 //UNUSED2009-05 }
631 //UNUSED2009-05 return xRangeList;
632 //UNUSED2009-05 }
635 //UNUSED2009-05 ScRangeListRef ScChartPositionMap::GetRowRanges( SCROW nChartRow ) const
636 //UNUSED2009-05 {
637 //UNUSED2009-05 ScRangeListRef xRangeList = new ScRangeList;
638 //UNUSED2009-05 if ( nChartRow < nRowCount )
639 //UNUSED2009-05 {
640 //UNUSED2009-05 ULONG nStop = GetIndex( nColCount, nChartRow );
641 //UNUSED2009-05 for ( ULONG nIndex = GetIndex( 0, nChartRow ); nIndex < nStop;
642 //UNUSED2009-05 nIndex += nRowCount )
643 //UNUSED2009-05 {
644 //UNUSED2009-05 if ( ppData[ nIndex ] )
645 //UNUSED2009-05 xRangeList->Join( *ppData[ nIndex ] );
646 //UNUSED2009-05 }
647 //UNUSED2009-05 }
648 //UNUSED2009-05 return xRangeList;
649 //UNUSED2009-05 }