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