xref: /aoo41x/main/sc/source/core/data/markdata.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 // INCLUDE ---------------------------------------------------------------
34 
35 #include <tools/debug.hxx>
36 
37 #include "markdata.hxx"
38 #include "markarr.hxx"
39 #include "rangelst.hxx"
40 
41 // STATIC DATA -----------------------------------------------------------
42 
43 //------------------------------------------------------------------------
44 
45 ScMarkData::ScMarkData() :
46 	pMultiSel( NULL )
47 {
48 	for (SCTAB i=0; i<=MAXTAB; i++)
49 		bTabMarked[i] = sal_False;
50 
51 	ResetMark();
52 }
53 
54 ScMarkData::ScMarkData(const ScMarkData& rData) :
55 	aMarkRange( rData.aMarkRange ),
56 	aMultiRange( rData.aMultiRange ),
57 	pMultiSel( NULL )
58 {
59 	bMarked		 = rData.bMarked;
60 	bMultiMarked = rData.bMultiMarked;
61 	bMarking	 = rData.bMarking;
62 	bMarkIsNeg	 = rData.bMarkIsNeg;
63 
64 	for (SCTAB i=0; i<=MAXTAB; i++)
65 		bTabMarked[i] = rData.bTabMarked[i];
66 
67 	if (rData.pMultiSel)
68 	{
69 		pMultiSel = new ScMarkArray[MAXCOLCOUNT];
70 		for (SCCOL j=0; j<MAXCOLCOUNT; j++)
71 			rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
72 	}
73 }
74 
75 ScMarkData&	ScMarkData::operator=(const ScMarkData& rData)
76 {
77 	if ( &rData == this )
78 		return *this;
79 
80 	delete[] pMultiSel;
81 	pMultiSel = NULL;
82 
83 	aMarkRange	 = rData.aMarkRange;
84 	aMultiRange  = rData.aMultiRange;
85 	bMarked		 = rData.bMarked;
86 	bMultiMarked = rData.bMultiMarked;
87 	bMarking	 = rData.bMarking;
88 	bMarkIsNeg	 = rData.bMarkIsNeg;
89 
90 	for (SCTAB i=0; i<=MAXTAB; i++)
91 		bTabMarked[i] = rData.bTabMarked[i];
92 
93 	if (rData.pMultiSel)
94 	{
95 		pMultiSel = new ScMarkArray[MAXCOLCOUNT];
96 		for (SCCOL j=0; j<MAXCOLCOUNT; j++)
97 			rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
98 	}
99 
100 	return *this;
101 }
102 
103 ScMarkData::~ScMarkData()
104 {
105 	delete[] pMultiSel;
106 }
107 
108 void ScMarkData::ResetMark()
109 {
110 	delete[] pMultiSel;
111 	pMultiSel = NULL;
112 
113 	bMarked = bMultiMarked = sal_False;
114 	bMarking = bMarkIsNeg = sal_False;
115 }
116 
117 void ScMarkData::SetMarkArea( const ScRange& rRange )
118 {
119 	aMarkRange = rRange;
120 	aMarkRange.Justify();
121 	if ( !bMarked )
122 	{
123 		// #77987# Upon creation of a document ScFormatShell GetTextAttrState
124 		// may query (default) attributes although no sheet is marked yet.
125 		// => mark that one.
126 		if ( !GetSelectCount() )
127 			bTabMarked[ aMarkRange.aStart.Tab() ] = sal_True;
128 		bMarked = sal_True;
129 	}
130 }
131 
132 void ScMarkData::GetMarkArea( ScRange& rRange ) const
133 {
134 	rRange = aMarkRange;		//! inline ?
135 }
136 
137 void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const
138 {
139 	rRange = aMultiRange;
140 }
141 
142 void ScMarkData::SetMultiMarkArea( const ScRange& rRange, sal_Bool bMark )
143 {
144 	if (!pMultiSel)
145 	{
146 		pMultiSel = new ScMarkArray[MAXCOL+1];
147 
148 		// if simple mark range is set, copy to multi marks
149 		if ( bMarked && !bMarkIsNeg )
150 		{
151 			bMarked = sal_False;
152 			SetMultiMarkArea( aMarkRange, sal_True );
153 		}
154 	}
155 
156 	SCCOL nStartCol = rRange.aStart.Col();
157 	SCROW nStartRow = rRange.aStart.Row();
158 	SCCOL nEndCol = rRange.aEnd.Col();
159 	SCROW nEndRow = rRange.aEnd.Row();
160 	PutInOrder( nStartRow, nEndRow );
161 	PutInOrder( nStartCol, nEndCol );
162 
163 	SCCOL nCol;
164 	for (nCol=nStartCol; nCol<=nEndCol; nCol++)
165 		pMultiSel[nCol].SetMarkArea( nStartRow, nEndRow, bMark );
166 
167 	if ( bMultiMarked )					// aMultiRange updaten
168 	{
169 		if ( nStartCol < aMultiRange.aStart.Col() )
170 			aMultiRange.aStart.SetCol( nStartCol );
171 		if ( nStartRow < aMultiRange.aStart.Row() )
172 			aMultiRange.aStart.SetRow( nStartRow );
173 		if ( nEndCol > aMultiRange.aEnd.Col() )
174 			aMultiRange.aEnd.SetCol( nEndCol );
175 		if ( nEndRow > aMultiRange.aEnd.Row() )
176 			aMultiRange.aEnd.SetRow( nEndRow );
177 	}
178 	else
179 	{
180 		aMultiRange = rRange;			// neu
181 		bMultiMarked = sal_True;
182 	}
183 }
184 
185 void ScMarkData::SetAreaTab( SCTAB nTab )
186 {
187 	aMarkRange.aStart.SetTab(nTab);
188 	aMarkRange.aEnd.SetTab(nTab);
189 	aMultiRange.aStart.SetTab(nTab);
190 	aMultiRange.aEnd.SetTab(nTab);
191 }
192 
193 void ScMarkData::SelectOneTable( SCTAB nTab )
194 {
195 	for (SCTAB i=0; i<=MAXTAB; i++)
196 		bTabMarked[i] = ( nTab == i );
197 }
198 
199 SCTAB ScMarkData::GetSelectCount() const
200 {
201 	SCTAB nCount = 0;
202 	for (SCTAB i=0; i<=MAXTAB; i++)
203 		if (bTabMarked[i])
204 			++nCount;
205 
206 	return nCount;
207 }
208 
209 SCTAB ScMarkData::GetFirstSelected() const
210 {
211 	for (SCTAB i=0; i<=MAXTAB; i++)
212 		if (bTabMarked[i])
213 			return i;
214 
215 	DBG_ERROR("GetFirstSelected: keine markiert");
216 	return 0;
217 }
218 
219 void ScMarkData::MarkToMulti()
220 {
221 	if ( bMarked && !bMarking )
222 	{
223 		SetMultiMarkArea( aMarkRange, !bMarkIsNeg );
224 		bMarked = sal_False;
225 
226 		//	check if all multi mark ranges have been removed
227 		if ( bMarkIsNeg && !HasAnyMultiMarks() )
228 			ResetMark();
229 	}
230 }
231 
232 void ScMarkData::MarkToSimple()
233 {
234 	if ( bMarking )
235 		return;
236 
237 	if ( bMultiMarked && bMarked )
238 		MarkToMulti();					// may result in bMarked and bMultiMarked reset
239 
240 	if ( bMultiMarked )
241 	{
242 		DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
243 
244 		ScRange aNew = aMultiRange;
245 
246 		sal_Bool bOk = sal_False;
247 		SCCOL nStartCol = aNew.aStart.Col();
248 		SCCOL nEndCol   = aNew.aEnd.Col();
249 
250 		while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() )
251 			++nStartCol;
252 		while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() )
253 			--nEndCol;
254 
255 		//	Zeilen werden nur aus MarkArray genommen
256 		SCROW nStartRow, nEndRow;
257 		if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) )
258 		{
259 			bOk = sal_True;
260 			SCROW nCmpStart, nCmpEnd;
261 			for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++)
262 				if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd )
263 						|| nCmpStart != nStartRow || nCmpEnd != nEndRow )
264 					bOk = sal_False;
265 		}
266 
267 		if (bOk)
268 		{
269 			aNew.aStart.SetCol(nStartCol);
270 			aNew.aStart.SetRow(nStartRow);
271 			aNew.aEnd.SetCol(nEndCol);
272 			aNew.aEnd.SetRow(nEndRow);
273 
274 			ResetMark();
275 			aMarkRange = aNew;
276 			bMarked = sal_True;
277 			bMarkIsNeg = sal_False;
278 		}
279 	}
280 }
281 
282 sal_Bool ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, sal_Bool bNoSimple ) const
283 {
284 	if ( bMarked && !bNoSimple && !bMarkIsNeg )
285 		if ( aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
286 			 aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
287 			return sal_True;
288 
289 	if (bMultiMarked)
290 	{
291 		//!	hier auf negative Markierung testen ?
292 
293 		DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
294 		return pMultiSel[nCol].GetMark( nRow );
295 	}
296 
297 	return sal_False;
298 }
299 
300 sal_Bool ScMarkData::IsColumnMarked( SCCOL nCol ) const
301 {
302 	//	bMarkIsNeg inzwischen auch fuer Spaltenkoepfe
303 	//!	GetMarkColumnRanges fuer komplett markierte Spalten
304 
305 	if ( bMarked && !bMarkIsNeg &&
306 					aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
307 					aMarkRange.aStart.Row() == 0	&& aMarkRange.aEnd.Row() == MAXROW )
308 		return sal_True;
309 
310 	if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) )
311 		return sal_True;
312 
313 	return sal_False;
314 }
315 
316 sal_Bool ScMarkData::IsRowMarked( SCROW nRow ) const
317 {
318 	//	bMarkIsNeg inzwischen auch fuer Zeilenkoepfe
319 	//!	GetMarkRowRanges fuer komplett markierte Zeilen
320 
321 	if ( bMarked && !bMarkIsNeg &&
322 					aMarkRange.aStart.Col() == 0	&& aMarkRange.aEnd.Col() == MAXCOL &&
323 					aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
324 		return sal_True;
325 
326 	if ( bMultiMarked )
327 	{
328 		DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
329 		for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
330 			if (!pMultiSel[nCol].GetMark(nRow))
331 				return sal_False;
332 		return sal_True;
333 	}
334 
335 	return sal_False;
336 }
337 
338 void ScMarkData::MarkFromRangeList( const ScRangeList& rList, sal_Bool bReset )
339 {
340 	if (bReset)
341 	{
342 		for (SCTAB i=0; i<=MAXTAB; i++)
343 			bTabMarked[i] = sal_False;				// Tabellen sind nicht in ResetMark
344 		ResetMark();
345 	}
346 
347 	sal_uLong nCount = rList.Count();
348 	if ( nCount == 1 && !bMarked && !bMultiMarked )
349 	{
350 		ScRange aRange = *rList.GetObject(0);
351 		SetMarkArea( aRange );
352 		SelectTable( aRange.aStart.Tab(), sal_True );
353 	}
354 	else
355 	{
356 		for (sal_uLong i=0; i<nCount; i++)
357 		{
358 			ScRange aRange = *rList.GetObject(i);
359 			SetMultiMarkArea( aRange, sal_True );
360 			SelectTable( aRange.aStart.Tab(), sal_True );
361 		}
362 	}
363 }
364 
365 void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, sal_Bool bClear ) const
366 {
367 	if (!pList)
368 		return;
369 
370 	if (bClear)
371 		pList->RemoveAll();
372 
373 	//!		bei mehreren selektierten Tabellen mehrere Ranges eintragen !!!
374 
375 	if ( bMultiMarked )
376 	{
377 		DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
378 
379 		SCTAB nTab = aMultiRange.aStart.Tab();
380 
381 		SCCOL nStartCol = aMultiRange.aStart.Col();
382 		SCCOL nEndCol = aMultiRange.aEnd.Col();
383 		for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
384 			if (pMultiSel[nCol].HasMarks())
385 			{
386 				SCROW nTop, nBottom;
387 				ScRange aRange( nCol, 0, nTab );
388 				ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
389 				while ( aMarkIter.Next( nTop, nBottom ) )
390 				{
391 					aRange.aStart.SetRow( nTop );
392 					aRange.aEnd.SetRow( nBottom );
393 					pList->Join( aRange );
394 				}
395 			}
396 	}
397 
398 	if ( bMarked )
399 		pList->Append( aMarkRange );
400 }
401 
402 void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const
403 {
404 	if (!pList)
405 		return;
406 
407 	ScRangeList aOldList(*pList);
408 	pList->RemoveAll();					//!	oder die vorhandenen unten weglassen
409 
410 	for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
411 		if (bTabMarked[nTab])
412 		{
413 			sal_uLong nCount = aOldList.Count();
414 			for (sal_uLong i=0; i<nCount; i++)
415 			{
416 				ScRange aRange = *aOldList.GetObject(i);
417 				aRange.aStart.SetTab(nTab);
418 				aRange.aEnd.SetTab(nTab);
419 				pList->Append( aRange );
420 			}
421 		}
422 }
423 
424 SCCOLROW ScMarkData::GetMarkColumnRanges( SCCOLROW* pRanges )
425 {
426 	if (bMarked)
427 		MarkToMulti();
428 
429 	if (!bMultiMarked)
430 		return 0;
431 
432 	DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0");
433 
434     const SCCOLROW nMultiStart = aMultiRange.aStart.Col();
435     const SCCOLROW nMultiEnd = aMultiRange.aEnd.Col();
436     if (nMultiStart == 0 && nMultiEnd == MAXCOL)
437     {
438         // One or more entire rows.
439         pRanges[0] = 0;
440         pRanges[1] = MAXCOL;
441         return 1;
442     }
443 
444 	SCCOLROW nRangeCnt = 0;
445 	SCCOLROW nStart = nMultiStart;
446 	while (nStart <= nMultiEnd)
447 	{
448 		while (nStart < nMultiEnd && !pMultiSel[nStart].HasMarks())
449 			++nStart;
450 		if (pMultiSel[nStart].HasMarks())
451 		{
452 			SCCOLROW nEnd = nStart;
453 			while (nEnd < nMultiEnd && pMultiSel[nEnd].HasMarks())
454 				++nEnd;
455 			if (!pMultiSel[nEnd].HasMarks())
456 				--nEnd;
457 			pRanges[2*nRangeCnt  ] = nStart;
458 			pRanges[2*nRangeCnt+1] = nEnd;
459 			++nRangeCnt;
460 			nStart = nEnd+1;
461 		}
462 		else
463 			nStart = nMultiEnd+1;
464 	}
465 
466 	return nRangeCnt;
467 }
468 
469 SCCOLROW ScMarkData::GetMarkRowRanges( SCCOLROW* pRanges )
470 {
471 	if (bMarked)
472 		MarkToMulti();
473 
474 	if (!bMultiMarked)
475 		return 0;
476 
477 	DBG_ASSERT(pMultiSel, "bMultiMarked, but pMultiSel == 0");
478 
479     // Which rows are marked?
480 
481     // Optimized to not loop over MAXCOL*MAXROW as worst case, i.e. Ctrl+A
482 
483     const SCCOLROW nMultiStart = aMultiRange.aStart.Row();
484     const SCCOLROW nMultiEnd = aMultiRange.aEnd.Row();
485 
486     sal_Bool*   bRowMarked = new sal_Bool[MAXROWCOUNT];
487     memset( bRowMarked, 0, sizeof(sal_Bool) * MAXROWCOUNT);
488 	SCROW  nRow;
489 	SCCOL  nCol;
490 
491     SCROW nTop = -1, nBottom = -1;
492     for (nCol = aMultiRange.aStart.Col(); nCol <= aMultiRange.aEnd.Col(); ++nCol)
493     {
494         ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
495         while (aMarkIter.Next( nTop, nBottom ))
496             for (nRow=nTop; nRow<=nBottom; nRow++)
497                 bRowMarked[nRow] = sal_True;
498         if (nTop == nMultiStart && nBottom == nMultiEnd)
499             break;  // for, all relevant rows marked
500     }
501 
502     if (nTop == nMultiStart && nBottom == nMultiEnd)
503     {
504         pRanges[0] = nTop;
505         pRanges[1] = nBottom;
506         delete[] bRowMarked;
507         return 1;
508     }
509 
510     // Combine to ranges of rows.
511 
512     SCCOLROW nRangeCnt = 0;
513     SCCOLROW nStart = nMultiStart;
514     while (nStart <= nMultiEnd)
515     {
516         while (nStart < nMultiEnd && !bRowMarked[nStart])
517             ++nStart;
518         if (bRowMarked[nStart])
519         {
520             SCCOLROW nEnd = nStart;
521             while (nEnd < nMultiEnd && bRowMarked[nEnd])
522                 ++nEnd;
523             if (!bRowMarked[nEnd])
524                 --nEnd;
525             pRanges[2*nRangeCnt  ] = nStart;
526             pRanges[2*nRangeCnt+1] = nEnd;
527             ++nRangeCnt;
528             nStart = nEnd+1;
529         }
530         else
531             nStart = nMultiEnd+1;
532     }
533 
534 	delete[] bRowMarked;
535 	return nRangeCnt;
536 }
537 
538 sal_Bool ScMarkData::IsAllMarked( const ScRange& rRange ) const
539 {
540 	if ( !bMultiMarked )
541 		return sal_False;
542 
543 	DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
544 
545 	SCCOL nStartCol = rRange.aStart.Col();
546 	SCROW nStartRow = rRange.aStart.Row();
547 	SCCOL nEndCol = rRange.aEnd.Col();
548 	SCROW nEndRow = rRange.aEnd.Row();
549 	sal_Bool bOk = sal_True;
550 	for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
551 		if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) )
552 			bOk = sal_False;
553 
554 	return bOk;
555 }
556 
557 SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, sal_Bool bUp ) const
558 {
559 	if ( !bMultiMarked )
560 		return nRow;
561 
562 	DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
563 
564 	return pMultiSel[nCol].GetNextMarked( nRow, bUp );
565 }
566 
567 sal_Bool ScMarkData::HasMultiMarks( SCCOL nCol ) const
568 {
569 	if ( !bMultiMarked )
570 		return sal_False;
571 
572 	DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
573 
574 	return pMultiSel[nCol].HasMarks();
575 }
576 
577 sal_Bool ScMarkData::HasAnyMultiMarks() const
578 {
579 	if ( !bMultiMarked )
580 		return sal_False;
581 
582 	DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
583 
584 	for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
585 		if ( pMultiSel[nCol].HasMarks() )
586 			return sal_True;
587 
588 	return sal_False;		// nix
589 }
590 
591 void ScMarkData::InsertTab( SCTAB nTab )
592 {
593 	for (SCTAB i=MAXTAB; i>nTab; i--)
594 		bTabMarked[i] = bTabMarked[i-1];
595 	bTabMarked[nTab] = sal_False;
596 }
597 
598 void ScMarkData::DeleteTab( SCTAB nTab )
599 {
600 	for (SCTAB i=nTab; i<MAXTAB; i++)
601 		bTabMarked[i] = bTabMarked[i+1];
602 	bTabMarked[MAXTAB] = sal_False;
603 }
604 
605 
606 
607 
608 
609