File: | home/maarten/src/libreoffice/core/sc/inc/attarray.hxx |
Warning: | line 147, column 118 Potential leak of memory pointed to by 'pPattern._M_t._M_t._M_head_impl' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||||
2 | /* | ||||
3 | * This file is part of the LibreOffice project. | ||||
4 | * | ||||
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/. | ||||
8 | * | ||||
9 | * This file incorporates work covered by the following license notice: | ||||
10 | * | ||||
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 . | ||||
18 | */ | ||||
19 | |||||
20 | #include <attarray.hxx> | ||||
21 | #include <scitems.hxx> | ||||
22 | #include <editeng/borderline.hxx> | ||||
23 | #include <editeng/boxitem.hxx> | ||||
24 | #include <editeng/lineitem.hxx> | ||||
25 | #include <editeng/shaditem.hxx> | ||||
26 | #include <editeng/editobj.hxx> | ||||
27 | #include <editeng/justifyitem.hxx> | ||||
28 | #include <osl/diagnose.h> | ||||
29 | #include <svl/poolcach.hxx> | ||||
30 | #include <sfx2/objsh.hxx> | ||||
31 | |||||
32 | #include <global.hxx> | ||||
33 | #include <document.hxx> | ||||
34 | #include <docpool.hxx> | ||||
35 | #include <patattr.hxx> | ||||
36 | #include <stlsheet.hxx> | ||||
37 | #include <stlpool.hxx> | ||||
38 | #include <markarr.hxx> | ||||
39 | #include <globstr.hrc> | ||||
40 | #include <scresid.hxx> | ||||
41 | #include <segmenttree.hxx> | ||||
42 | #include <editdataarray.hxx> | ||||
43 | #include <cellvalue.hxx> | ||||
44 | #include <editutil.hxx> | ||||
45 | #include <mtvelements.hxx> | ||||
46 | #include <memory> | ||||
47 | |||||
48 | using ::editeng::SvxBorderLine; | ||||
49 | |||||
50 | ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, ScAttrArray* pDefaultColAttrArray ) : | ||||
51 | nCol( nNewCol ), | ||||
52 | nTab( nNewTab ), | ||||
53 | rDocument( rDoc ) | ||||
54 | { | ||||
55 | if ( nCol == -1 || !pDefaultColAttrArray || pDefaultColAttrArray->mvData.empty() ) | ||||
56 | return; | ||||
57 | |||||
58 | ScAddress aAdrStart( nCol, 0, nTab ); | ||||
59 | ScAddress aAdrEnd( nCol, 0, nTab ); | ||||
60 | mvData.resize( pDefaultColAttrArray->mvData.size() ); | ||||
61 | for ( size_t nIdx = 0; nIdx < pDefaultColAttrArray->mvData.size(); ++nIdx ) | ||||
62 | { | ||||
63 | mvData[nIdx].nEndRow = pDefaultColAttrArray->mvData[nIdx].nEndRow; | ||||
64 | ScPatternAttr aNewPattern( *(pDefaultColAttrArray->mvData[nIdx].pPattern) ); | ||||
65 | mvData[nIdx].pPattern = &rDocument.GetPool()->Put( aNewPattern ); | ||||
66 | bool bNumFormatChanged = false; | ||||
67 | if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, | ||||
68 | mvData[nIdx].pPattern->GetItemSet(), rDocument.GetDefPattern()->GetItemSet() ) ) | ||||
69 | { | ||||
70 | aAdrStart.SetRow( nIdx ? mvData[nIdx-1].nEndRow+1 : 0 ); | ||||
71 | aAdrEnd.SetRow( mvData[nIdx].nEndRow ); | ||||
72 | rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); | ||||
73 | } | ||||
74 | } | ||||
75 | } | ||||
76 | |||||
77 | ScAttrArray::~ScAttrArray() | ||||
78 | { | ||||
79 | #if DEBUG_SC_TESTATTRARRAY0 | ||||
80 | TestData(); | ||||
81 | #endif | ||||
82 | |||||
83 | ScDocumentPool* pDocPool = rDocument.GetPool(); | ||||
84 | for (auto const & rEntry : mvData) | ||||
85 | pDocPool->Remove(*rEntry.pPattern); | ||||
86 | } | ||||
87 | |||||
88 | #if DEBUG_SC_TESTATTRARRAY0 | ||||
89 | void ScAttrArray::TestData() const | ||||
90 | { | ||||
91 | |||||
92 | sal_uInt16 nErr = 0; | ||||
93 | SCSIZE nPos; | ||||
94 | for (nPos=0; nPos<nCount; nPos++) | ||||
95 | { | ||||
96 | if (nPos > 0) | ||||
97 | if (mvData[nPos].pPattern == mvData[nPos-1].pPattern || mvData[nPos].nRow <= mvData[nPos-1].nRow) | ||||
98 | ++nErr; | ||||
99 | if (mvData[nPos].pPattern->Which() != ATTR_PATTERN) | ||||
100 | ++nErr; | ||||
101 | } | ||||
102 | if ( nPos && mvData[nPos-1].nRow != rDocument.MaxRow() ) | ||||
103 | ++nErr; | ||||
104 | |||||
105 | SAL_WARN_IF( nErr, "sc", nErr << " errors in attribute array, column " << nCol )do { if (true && (nErr)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "sc")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << nErr << " errors in attribute array, column " << nCol) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "105" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << nErr << " errors in attribute array, column " << nCol), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << nErr << " errors in attribute array, column " << nCol; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "105" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << nErr << " errors in attribute array, column " << nCol) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "105" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << nErr << " errors in attribute array, column " << nCol), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << nErr << " errors in attribute array, column " << nCol; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "105" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
106 | } | ||||
107 | #endif | ||||
108 | |||||
109 | void ScAttrArray::SetDefaultIfNotInit( SCSIZE nNeeded ) | ||||
110 | { | ||||
111 | if ( !mvData.empty() ) | ||||
112 | return; | ||||
113 | |||||
114 | SCSIZE nNewLimit = std::max<SCSIZE>( SC_ATTRARRAY_DELTA4, nNeeded ); | ||||
115 | mvData.reserve( nNewLimit ); | ||||
116 | mvData.emplace_back(); | ||||
117 | mvData[0].nEndRow = rDocument.MaxRow(); | ||||
118 | mvData[0].pPattern = rDocument.GetDefPattern(); // no put | ||||
119 | } | ||||
120 | |||||
121 | void ScAttrArray::Reset( const ScPatternAttr* pPattern ) | ||||
122 | { | ||||
123 | ScDocumentPool* pDocPool = rDocument.GetPool(); | ||||
124 | ScAddress aAdrStart( nCol, 0, nTab ); | ||||
125 | ScAddress aAdrEnd ( nCol, 0, nTab ); | ||||
126 | |||||
127 | for (SCSIZE i=0; i<mvData.size(); i++) | ||||
128 | { | ||||
129 | // ensure that attributing changes text width of cell | ||||
130 | const ScPatternAttr* pOldPattern = mvData[i].pPattern; | ||||
131 | if ( nCol != -1 ) | ||||
132 | { | ||||
133 | bool bNumFormatChanged; | ||||
134 | if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, | ||||
135 | pPattern->GetItemSet(), pOldPattern->GetItemSet() ) ) | ||||
136 | { | ||||
137 | aAdrStart.SetRow( i ? mvData[i-1].nEndRow+1 : 0 ); | ||||
138 | aAdrEnd .SetRow( mvData[i].nEndRow ); | ||||
139 | rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); | ||||
140 | } | ||||
141 | } | ||||
142 | pDocPool->Remove(*pOldPattern); | ||||
143 | } | ||||
144 | mvData.resize(0); | ||||
145 | |||||
146 | rDocument.SetStreamValid(nTab, false); | ||||
147 | |||||
148 | mvData.resize(1); | ||||
149 | const ScPatternAttr* pNewPattern = &pDocPool->Put(*pPattern); | ||||
150 | mvData[0].nEndRow = rDocument.MaxRow(); | ||||
151 | mvData[0].pPattern = pNewPattern; | ||||
152 | } | ||||
153 | |||||
154 | bool ScAttrArray::Concat(SCSIZE nPos) | ||||
155 | { | ||||
156 | bool bRet = false; | ||||
157 | if (nPos < mvData.size()) | ||||
158 | { | ||||
159 | if (nPos > 0) | ||||
160 | { | ||||
161 | if (mvData[nPos - 1].pPattern == mvData[nPos].pPattern) | ||||
162 | { | ||||
163 | mvData[nPos - 1].nEndRow = mvData[nPos].nEndRow; | ||||
164 | rDocument.GetPool()->Remove(*mvData[nPos].pPattern); | ||||
165 | mvData.erase(mvData.begin() + nPos); | ||||
166 | nPos--; | ||||
167 | bRet = true; | ||||
168 | } | ||||
169 | } | ||||
170 | if (nPos + 1 < mvData.size()) | ||||
171 | { | ||||
172 | if (mvData[nPos + 1].pPattern == mvData[nPos].pPattern) | ||||
173 | { | ||||
174 | mvData[nPos].nEndRow = mvData[nPos + 1].nEndRow; | ||||
175 | rDocument.GetPool()->Remove(*mvData[nPos].pPattern); | ||||
176 | mvData.erase(mvData.begin() + nPos + 1); | ||||
177 | bRet = true; | ||||
178 | } | ||||
179 | } | ||||
180 | } | ||||
181 | return bRet; | ||||
182 | } | ||||
183 | |||||
184 | /* | ||||
185 | * nCount is the number of runs of different attribute combinations; | ||||
186 | * no attribute in a column => nCount==1, one attribute somewhere => nCount == 3 | ||||
187 | * (ie. one run with no attribute + one attribute + another run with no attribute) | ||||
188 | * so a range of identical attributes is only one entry in ScAttrArray. | ||||
189 | * | ||||
190 | * Iterative implementation of Binary Search | ||||
191 | * The same implementation was used inside ScMarkArray::Search(). | ||||
192 | */ | ||||
193 | |||||
194 | bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const | ||||
195 | { | ||||
196 | /* auto it = std::lower_bound(mvData.begin(), mvData.end(), nRow, | ||||
197 | [] (const ScAttrEntry &r1, SCROW nRow) | ||||
198 | { return r1.nEndRow < nRow; } ); | ||||
199 | if (it != mvData.end()) | ||||
200 | nIndex = it - mvData.begin(); | ||||
201 | return it != mvData.end(); */ | ||||
202 | |||||
203 | if (mvData.size() == 1) | ||||
204 | { | ||||
205 | nIndex = 0; | ||||
206 | return true; | ||||
207 | } | ||||
208 | |||||
209 | long nHi = static_cast<long>(mvData.size()) - 1; | ||||
210 | long i = 0; | ||||
211 | long nLo = 0; | ||||
212 | |||||
213 | while ( nLo <= nHi ) | ||||
214 | { | ||||
215 | i = (nLo + nHi) / 2; | ||||
216 | |||||
217 | if (mvData[i].nEndRow < nRow) | ||||
218 | { | ||||
219 | // If [nRow] greater, ignore left half | ||||
220 | nLo = i + 1; | ||||
221 | } | ||||
222 | else if ((i > 0) && (mvData[i - 1].nEndRow >= nRow)) | ||||
223 | { | ||||
224 | // If [nRow] is smaller, ignore right half | ||||
225 | nHi = i - 1; | ||||
226 | } | ||||
227 | else | ||||
228 | { | ||||
229 | // found | ||||
230 | nIndex=static_cast<SCSIZE>(i); | ||||
231 | return true; | ||||
232 | } | ||||
233 | } | ||||
234 | |||||
235 | nIndex=0; | ||||
236 | return false; | ||||
237 | } | ||||
238 | |||||
239 | const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const | ||||
240 | { | ||||
241 | if ( mvData.empty() ) | ||||
242 | { | ||||
243 | if ( !rDocument.ValidRow(nRow) ) | ||||
244 | return nullptr; | ||||
245 | return rDocument.GetDefPattern(); | ||||
246 | } | ||||
247 | SCSIZE i; | ||||
248 | if (Search( nRow, i )) | ||||
249 | return mvData[i].pPattern; | ||||
250 | else | ||||
251 | return nullptr; | ||||
252 | } | ||||
253 | |||||
254 | const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow, | ||||
255 | SCROW& rEndRow, SCROW nRow ) const | ||||
256 | { | ||||
257 | if ( mvData.empty() ) | ||||
258 | { | ||||
259 | if ( !rDocument.ValidRow( nRow ) ) | ||||
260 | return nullptr; | ||||
261 | rStartRow = 0; | ||||
262 | rEndRow = rDocument.MaxRow(); | ||||
263 | return rDocument.GetDefPattern(); | ||||
264 | } | ||||
265 | SCSIZE nIndex; | ||||
266 | if ( Search( nRow, nIndex ) ) | ||||
267 | { | ||||
268 | if ( nIndex > 0 ) | ||||
269 | rStartRow = mvData[nIndex-1].nEndRow + 1; | ||||
270 | else | ||||
271 | rStartRow = 0; | ||||
272 | rEndRow = mvData[nIndex].nEndRow; | ||||
273 | return mvData[nIndex].pPattern; | ||||
274 | } | ||||
275 | return nullptr; | ||||
276 | } | ||||
277 | |||||
278 | void ScAttrArray::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex ) | ||||
279 | { | ||||
280 | if(!rDocument.ValidRow(nStartRow) || !rDocument.ValidRow(nEndRow)) | ||||
281 | return; | ||||
282 | |||||
283 | if(nEndRow < nStartRow) | ||||
284 | return; | ||||
285 | |||||
286 | SCROW nTempStartRow = nStartRow; | ||||
287 | SCROW nTempEndRow = nEndRow; | ||||
288 | |||||
289 | do | ||||
290 | { | ||||
291 | const ScPatternAttr* pPattern = GetPattern(nTempStartRow); | ||||
292 | |||||
293 | std::unique_ptr<ScPatternAttr> pNewPattern; | ||||
294 | if(pPattern) | ||||
295 | { | ||||
296 | pNewPattern.reset( new ScPatternAttr(*pPattern) ); | ||||
297 | SCROW nPatternStartRow; | ||||
298 | SCROW nPatternEndRow; | ||||
299 | GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow ); | ||||
300 | |||||
301 | nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow ); | ||||
302 | const SfxPoolItem* pItem = nullptr; | ||||
303 | pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem ); | ||||
304 | if(pItem) | ||||
305 | { | ||||
306 | ScCondFormatIndexes const & rCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData(); | ||||
307 | if (rCondFormatData.find(nIndex) == rCondFormatData.end()) | ||||
308 | { | ||||
309 | ScCondFormatIndexes aNewCondFormatData; | ||||
310 | aNewCondFormatData.reserve(rCondFormatData.size()+1); | ||||
311 | aNewCondFormatData = rCondFormatData; | ||||
312 | aNewCondFormatData.insert(nIndex); | ||||
313 | ScCondFormatItem aItem( std::move(aNewCondFormatData) ); | ||||
314 | pNewPattern->GetItemSet().Put( aItem ); | ||||
315 | } | ||||
316 | } | ||||
317 | else | ||||
318 | { | ||||
319 | ScCondFormatItem aItem(nIndex); | ||||
320 | pNewPattern->GetItemSet().Put( aItem ); | ||||
321 | } | ||||
322 | } | ||||
323 | else | ||||
324 | { | ||||
325 | pNewPattern.reset( new ScPatternAttr( rDocument.GetPool() ) ); | ||||
326 | ScCondFormatItem aItem(nIndex); | ||||
327 | pNewPattern->GetItemSet().Put( aItem ); | ||||
328 | nTempEndRow = nEndRow; | ||||
329 | } | ||||
330 | |||||
331 | SetPatternArea( nTempStartRow, nTempEndRow, std::move(pNewPattern), true ); | ||||
332 | nTempStartRow = nTempEndRow + 1; | ||||
333 | } | ||||
334 | while(nTempEndRow < nEndRow); | ||||
335 | |||||
336 | } | ||||
337 | |||||
338 | void ScAttrArray::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex ) | ||||
339 | { | ||||
340 | if(!rDocument.ValidRow(nStartRow) || !rDocument.ValidRow(nEndRow)) | ||||
341 | return; | ||||
342 | |||||
343 | if(nEndRow < nStartRow) | ||||
344 | return; | ||||
345 | |||||
346 | SCROW nTempStartRow = nStartRow; | ||||
347 | SCROW nTempEndRow = nEndRow; | ||||
348 | |||||
349 | do | ||||
350 | { | ||||
351 | const ScPatternAttr* pPattern = GetPattern(nTempStartRow); | ||||
352 | |||||
353 | if(pPattern) | ||||
354 | { | ||||
355 | SCROW nPatternStartRow; | ||||
356 | SCROW nPatternEndRow; | ||||
357 | GetPatternRange( nPatternStartRow, nPatternEndRow, nTempStartRow ); | ||||
358 | |||||
359 | nTempEndRow = std::min<SCROW>( nPatternEndRow, nEndRow ); | ||||
360 | const SfxPoolItem* pItem = nullptr; | ||||
361 | pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, true, &pItem ); | ||||
362 | if(pItem) | ||||
363 | { | ||||
364 | auto pPatternAttr = std::make_unique<ScPatternAttr>( *pPattern ); | ||||
365 | if (nIndex == 0) | ||||
366 | { | ||||
367 | ScCondFormatItem aItem; | ||||
368 | pPatternAttr->GetItemSet().Put( aItem ); | ||||
369 | SetPatternArea( nTempStartRow, nTempEndRow, std::move(pPatternAttr), true ); | ||||
370 | } | ||||
371 | else | ||||
372 | { | ||||
373 | ScCondFormatIndexes const & rCondFormatData = static_cast<const ScCondFormatItem*>(pItem)->GetCondFormatData(); | ||||
374 | auto itr = rCondFormatData.find(nIndex); | ||||
375 | if(itr != rCondFormatData.end()) | ||||
376 | { | ||||
377 | ScCondFormatIndexes aNewCondFormatData(rCondFormatData); | ||||
378 | aNewCondFormatData.erase(nIndex); | ||||
379 | ScCondFormatItem aItem( std::move(aNewCondFormatData) ); | ||||
380 | pPatternAttr->GetItemSet().Put( aItem ); | ||||
381 | SetPatternArea( nTempStartRow, nTempEndRow, std::move(pPatternAttr), true ); | ||||
382 | } | ||||
383 | } | ||||
384 | } | ||||
385 | } | ||||
386 | else | ||||
387 | { | ||||
388 | return; | ||||
389 | } | ||||
390 | |||||
391 | nTempStartRow = nTempEndRow + 1; | ||||
392 | } | ||||
393 | while(nTempEndRow < nEndRow); | ||||
394 | |||||
395 | } | ||||
396 | |||||
397 | void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow, | ||||
398 | const ScPatternAttr* pPattern, ScEditDataArray* pDataArray ) | ||||
399 | { | ||||
400 | assert( nCol != -1 )(static_cast <bool> (nCol != -1) ? void (0) : __assert_fail ("nCol != -1", "/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" , 400, __extension__ __PRETTY_FUNCTION__)); | ||||
401 | // cache mdds position, this doesn't modify the mdds container, just EditTextObject's | ||||
402 | sc::ColumnBlockPosition blockPos; | ||||
403 | rDocument.InitColumnBlockPosition( blockPos, nTab, nCol ); | ||||
404 | for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow) | ||||
405 | { | ||||
406 | ScAddress aPos(nCol, nRow, nTab); | ||||
407 | ScRefCellValue aCell(rDocument, aPos, blockPos); | ||||
408 | if (aCell.meType != CELLTYPE_EDIT || !aCell.mpEditText) | ||||
409 | continue; | ||||
410 | |||||
411 | std::unique_ptr<EditTextObject> pOldData; | ||||
412 | if (pDataArray) | ||||
413 | pOldData = aCell.mpEditText->Clone(); | ||||
414 | |||||
415 | // Direct modification of cell content - something to watch out for if | ||||
416 | // we decide to share edit text instances in the future. | ||||
417 | ScEditUtil::RemoveCharAttribs(const_cast<EditTextObject&>(*aCell.mpEditText), *pPattern); | ||||
418 | |||||
419 | if (pDataArray) | ||||
420 | { | ||||
421 | std::unique_ptr<EditTextObject> pNewData = aCell.mpEditText->Clone(); | ||||
422 | pDataArray->AddItem(nTab, nCol, nRow, std::move(pOldData), std::move(pNewData)); | ||||
423 | } | ||||
424 | } | ||||
425 | } | ||||
426 | |||||
427 | bool ScAttrArray::Reserve( SCSIZE nReserve ) | ||||
428 | { | ||||
429 | if ( mvData.empty() && nReserve ) | ||||
430 | { | ||||
431 | try { | ||||
432 | mvData.reserve(nReserve); | ||||
433 | mvData.emplace_back(); | ||||
434 | mvData[0].nEndRow = rDocument.MaxRow(); | ||||
435 | mvData[0].pPattern = rDocument.GetDefPattern(); // no put | ||||
436 | return true; | ||||
437 | } catch (std::bad_alloc const &) { | ||||
438 | return false; | ||||
439 | } | ||||
440 | } | ||||
441 | else if ( mvData.capacity() < nReserve ) | ||||
442 | { | ||||
443 | try { | ||||
444 | mvData.reserve(nReserve); | ||||
445 | return true; | ||||
446 | } catch (std::bad_alloc const &) { | ||||
447 | return false; | ||||
448 | } | ||||
449 | } | ||||
450 | else | ||||
451 | return false; | ||||
452 | } | ||||
453 | |||||
454 | const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern, | ||||
455 | bool bPutToPool, ScEditDataArray* pDataArray, bool bPassingOwnership ) | ||||
456 | { | ||||
457 | if (rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow)) | ||||
458 | { | ||||
459 | if (bPutToPool) | ||||
460 | { | ||||
461 | if (bPassingOwnership) | ||||
462 | pPattern = &rDocument.GetPool()->Put(std::unique_ptr<ScPatternAttr>(const_cast<ScPatternAttr*>(pPattern))); | ||||
463 | else | ||||
464 | pPattern = &rDocument.GetPool()->Put(*pPattern); | ||||
465 | } | ||||
466 | if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow())) | ||||
467 | Reset(pPattern); | ||||
468 | else | ||||
469 | { | ||||
470 | SCSIZE nNeeded = mvData.size() + 2; | ||||
471 | SetDefaultIfNotInit( nNeeded ); | ||||
472 | |||||
473 | ScAddress aAdrStart( nCol, 0, nTab ); | ||||
474 | ScAddress aAdrEnd ( nCol, 0, nTab ); | ||||
475 | |||||
476 | SCSIZE ni = 0; // number of entries in beginning | ||||
477 | SCSIZE nx = 0; // track position | ||||
478 | SCROW ns = 0; // start row of track position | ||||
479 | if ( nStartRow > 0 ) | ||||
480 | { | ||||
481 | // skip beginning | ||||
482 | SCSIZE nIndex; | ||||
483 | Search( nStartRow, nIndex ); | ||||
484 | ni = nIndex; | ||||
485 | |||||
486 | if ( ni > 0 ) | ||||
487 | { | ||||
488 | nx = ni; | ||||
489 | ns = mvData[ni-1].nEndRow+1; | ||||
490 | } | ||||
491 | } | ||||
492 | |||||
493 | // ensure that attributing changes text width of cell | ||||
494 | // otherwise, conditional formats need to be reset or deleted | ||||
495 | bool bIsLoading = !rDocument.GetDocumentShell() || rDocument.GetDocumentShell()->IsLoading(); | ||||
496 | while ( ns <= nEndRow ) | ||||
497 | { | ||||
498 | if ( nCol != -1 && !bIsLoading ) | ||||
499 | { | ||||
500 | const SfxItemSet& rNewSet = pPattern->GetItemSet(); | ||||
501 | const SfxItemSet& rOldSet = mvData[nx].pPattern->GetItemSet(); | ||||
502 | bool bNumFormatChanged; | ||||
503 | if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, | ||||
504 | rNewSet, rOldSet ) ) | ||||
505 | { | ||||
506 | aAdrStart.SetRow( std::max(nStartRow,ns) ); | ||||
507 | aAdrEnd .SetRow( std::min(nEndRow,mvData[nx].nEndRow) ); | ||||
508 | rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); | ||||
509 | } | ||||
510 | } | ||||
511 | ns = mvData[nx].nEndRow + 1; | ||||
512 | nx++; | ||||
513 | } | ||||
514 | |||||
515 | // continue modifying data array | ||||
516 | |||||
517 | SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert) | ||||
518 | bool bCombined = false; | ||||
519 | bool bSplit = false; | ||||
520 | if ( nStartRow > 0 ) | ||||
521 | { | ||||
522 | nInsert = rDocument.MaxRow() + 1; | ||||
523 | if ( mvData[ni].pPattern != pPattern ) | ||||
524 | { | ||||
525 | if ( ni == 0 || (mvData[ni-1].nEndRow < nStartRow - 1) ) | ||||
526 | { // may be a split or a simple insert or just a shrink, | ||||
527 | // row adjustment is done further down | ||||
528 | if ( mvData[ni].nEndRow > nEndRow ) | ||||
529 | bSplit = true; | ||||
530 | ni++; | ||||
531 | nInsert = ni; | ||||
532 | } | ||||
533 | else if (mvData[ni - 1].nEndRow == nStartRow - 1) | ||||
534 | nInsert = ni; | ||||
535 | } | ||||
536 | if ( ni > 0 && mvData[ni-1].pPattern == pPattern ) | ||||
537 | { // combine | ||||
538 | mvData[ni-1].nEndRow = nEndRow; | ||||
539 | nInsert = rDocument.MaxRow() + 1; | ||||
540 | bCombined = true; | ||||
541 | } | ||||
542 | } | ||||
543 | else | ||||
544 | nInsert = 0; | ||||
545 | |||||
546 | SCSIZE nj = ni; // stop position of range to replace | ||||
547 | while ( nj < mvData.size() && mvData[nj].nEndRow <= nEndRow ) | ||||
548 | nj++; | ||||
549 | if ( !bSplit ) | ||||
550 | { | ||||
551 | if ( nj < mvData.size() && mvData[nj].pPattern == pPattern ) | ||||
552 | { // combine | ||||
553 | if ( ni > 0 ) | ||||
554 | { | ||||
555 | if ( mvData[ni-1].pPattern == pPattern ) | ||||
556 | { // adjacent entries | ||||
557 | mvData[ni-1].nEndRow = mvData[nj].nEndRow; | ||||
558 | nj++; | ||||
559 | } | ||||
560 | else if ( ni == nInsert ) | ||||
561 | mvData[ni-1].nEndRow = nStartRow - 1; // shrink | ||||
562 | } | ||||
563 | nInsert = rDocument.MaxRow() + 1; | ||||
564 | bCombined = true; | ||||
565 | } | ||||
566 | else if ( ni > 0 && ni == nInsert ) | ||||
567 | mvData[ni-1].nEndRow = nStartRow - 1; // shrink | ||||
568 | } | ||||
569 | ScDocumentPool* pDocPool = rDocument.GetPool(); | ||||
570 | if ( bSplit ) | ||||
571 | { // duplicate split entry in pool | ||||
572 | pDocPool->Put( *mvData[ni-1].pPattern ); | ||||
573 | } | ||||
574 | if ( ni < nj ) | ||||
575 | { // remove middle entries | ||||
576 | for ( SCSIZE nk=ni; nk<nj; nk++) | ||||
577 | { // remove entries from pool | ||||
578 | pDocPool->Remove( *mvData[nk].pPattern ); | ||||
579 | } | ||||
580 | if ( !bCombined ) | ||||
581 | { // replace one entry | ||||
582 | mvData[ni].nEndRow = nEndRow; | ||||
583 | mvData[ni].pPattern = pPattern; | ||||
584 | ni++; | ||||
585 | nInsert = rDocument.MaxRow() + 1; | ||||
586 | } | ||||
587 | if ( ni < nj ) | ||||
588 | { // remove entries | ||||
589 | mvData.erase( mvData.begin() + ni, mvData.begin() + nj); | ||||
590 | } | ||||
591 | } | ||||
592 | |||||
593 | if ( nInsert < sal::static_int_cast<SCSIZE>(rDocument.MaxRow() + 1) ) | ||||
594 | { // insert or append new entry | ||||
595 | if ( nInsert <= mvData.size() ) | ||||
596 | { | ||||
597 | if ( !bSplit ) | ||||
598 | mvData.emplace(mvData.begin() + nInsert); | ||||
599 | else | ||||
600 | { | ||||
601 | mvData.insert(mvData.begin() + nInsert, 2, ScAttrEntry()); | ||||
602 | mvData[nInsert+1] = mvData[nInsert-1]; | ||||
603 | } | ||||
604 | } | ||||
605 | if ( nInsert ) | ||||
606 | mvData[nInsert-1].nEndRow = nStartRow - 1; | ||||
607 | mvData[nInsert].nEndRow = nEndRow; | ||||
608 | mvData[nInsert].pPattern = pPattern; | ||||
609 | |||||
610 | // Remove character attributes from these cells if the pattern | ||||
611 | // is applied during normal session. | ||||
612 | if (pDataArray && nCol != -1) | ||||
613 | RemoveCellCharAttribs(nStartRow, nEndRow, pPattern, pDataArray); | ||||
614 | } | ||||
615 | |||||
616 | rDocument.SetStreamValid(nTab, false); | ||||
617 | } | ||||
618 | } | ||||
619 | |||||
620 | #if DEBUG_SC_TESTATTRARRAY0 | ||||
621 | TestData(); | ||||
622 | #endif | ||||
623 | return pPattern; | ||||
624 | } | ||||
625 | |||||
626 | void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle ) | ||||
627 | { | ||||
628 | if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow))) | ||||
629 | return; | ||||
630 | |||||
631 | SetDefaultIfNotInit(); | ||||
632 | SCSIZE nPos; | ||||
633 | SCROW nStart=0; | ||||
634 | if (!Search( nStartRow, nPos )) | ||||
635 | { | ||||
636 | OSL_FAIL("Search Failure")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "636" ": "), "%s", "Search Failure"); } } while (false); | ||||
637 | return; | ||||
638 | } | ||||
639 | |||||
640 | ScAddress aAdrStart( nCol, 0, nTab ); | ||||
641 | ScAddress aAdrEnd ( nCol, 0, nTab ); | ||||
642 | |||||
643 | do | ||||
644 | { | ||||
645 | const ScPatternAttr* pOldPattern = mvData[nPos].pPattern; | ||||
646 | std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pOldPattern)); | ||||
647 | pNewPattern->SetStyleSheet(const_cast<ScStyleSheet*>(&rStyle)); | ||||
648 | SCROW nY1 = nStart; | ||||
649 | SCROW nY2 = mvData[nPos].nEndRow; | ||||
650 | nStart = mvData[nPos].nEndRow + 1; | ||||
651 | |||||
652 | if ( *pNewPattern == *pOldPattern ) | ||||
653 | { | ||||
654 | // keep the original pattern (might be default) | ||||
655 | // pNewPattern is deleted below | ||||
656 | nPos++; | ||||
657 | } | ||||
658 | else if ( nY1 < nStartRow || nY2 > nEndRow ) | ||||
659 | { | ||||
660 | if (nY1 < nStartRow) nY1=nStartRow; | ||||
661 | if (nY2 > nEndRow) nY2=nEndRow; | ||||
662 | SetPatternArea( nY1, nY2, std::move(pNewPattern), true ); | ||||
663 | Search( nStart, nPos ); | ||||
664 | } | ||||
665 | else | ||||
666 | { | ||||
667 | if ( nCol != -1 ) | ||||
668 | { | ||||
669 | // ensure attributing changes text width of cell; otherwise | ||||
670 | // there aren't (yet) template format changes | ||||
671 | const SfxItemSet& rNewSet = pNewPattern->GetItemSet(); | ||||
672 | const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); | ||||
673 | |||||
674 | bool bNumFormatChanged; | ||||
675 | if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, | ||||
676 | rNewSet, rOldSet ) ) | ||||
677 | { | ||||
678 | aAdrStart.SetRow( nPos ? mvData[nPos-1].nEndRow+1 : 0 ); | ||||
679 | aAdrEnd .SetRow( mvData[nPos].nEndRow ); | ||||
680 | rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); | ||||
681 | } | ||||
682 | } | ||||
683 | |||||
684 | rDocument.GetPool()->Remove(*mvData[nPos].pPattern); | ||||
685 | mvData[nPos].pPattern = &rDocument.GetPool()->Put(*pNewPattern); | ||||
686 | if (Concat(nPos)) | ||||
687 | Search(nStart, nPos); | ||||
688 | else | ||||
689 | nPos++; | ||||
690 | } | ||||
691 | } | ||||
692 | while ((nStart <= nEndRow) && (nPos < mvData.size())); | ||||
693 | |||||
694 | rDocument.SetStreamValid(nTab, false); | ||||
695 | |||||
696 | #if DEBUG_SC_TESTATTRARRAY0 | ||||
697 | TestData(); | ||||
698 | #endif | ||||
699 | } | ||||
700 | |||||
701 | // const cast, otherwise it will be too inefficient/complicated | ||||
702 | static void SetLineColor(SvxBorderLine const * dest, Color c) | ||||
703 | { | ||||
704 | if (dest) | ||||
705 | { | ||||
706 | const_cast<SvxBorderLine*>(dest)->SetColor(c); | ||||
707 | } | ||||
708 | } | ||||
709 | |||||
710 | static void SetLine(const SvxBorderLine* dest, const SvxBorderLine* src) | ||||
711 | { | ||||
712 | if (dest) | ||||
713 | { | ||||
714 | SvxBorderLine* pCast = const_cast<SvxBorderLine*>(dest); | ||||
715 | pCast->SetBorderLineStyle( src->GetBorderLineStyle() ); | ||||
716 | pCast->SetWidth( src->GetWidth() ); | ||||
717 | } | ||||
718 | } | ||||
719 | |||||
720 | void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow, | ||||
721 | const SvxBorderLine* pLine, bool bColorOnly ) | ||||
722 | { | ||||
723 | if ( bColorOnly && !pLine ) | ||||
724 | return; | ||||
725 | |||||
726 | if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow))) | ||||
727 | return; | ||||
728 | |||||
729 | SCSIZE nPos; | ||||
730 | SCROW nStart=0; | ||||
731 | SetDefaultIfNotInit(); | ||||
732 | if (!Search( nStartRow, nPos )) | ||||
733 | { | ||||
734 | OSL_FAIL("Search failure")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "734" ": "), "%s", "Search failure"); } } while (false); | ||||
735 | return; | ||||
736 | } | ||||
737 | |||||
738 | do | ||||
739 | { | ||||
740 | const ScPatternAttr* pOldPattern = mvData[nPos].pPattern; | ||||
741 | const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); | ||||
742 | const SfxPoolItem* pBoxItem = nullptr; | ||||
743 | SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, true, &pBoxItem ); | ||||
744 | const SfxPoolItem* pTLBRItem = nullptr; | ||||
745 | SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem ); | ||||
746 | const SfxPoolItem* pBLTRItem = nullptr; | ||||
747 | SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem ); | ||||
748 | |||||
749 | if ( (SfxItemState::SET == eState) || (SfxItemState::SET == eTLBRState) || (SfxItemState::SET == eBLTRState) ) | ||||
750 | { | ||||
751 | std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pOldPattern)); | ||||
752 | SfxItemSet& rNewSet = pNewPattern->GetItemSet(); | ||||
753 | SCROW nY1 = nStart; | ||||
754 | SCROW nY2 = mvData[nPos].nEndRow; | ||||
755 | |||||
756 | std::unique_ptr<SvxBoxItem> pNewBoxItem( pBoxItem ? static_cast<SvxBoxItem*>(pBoxItem->Clone()) : nullptr); | ||||
757 | std::unique_ptr<SvxLineItem> pNewTLBRItem( pTLBRItem ? static_cast<SvxLineItem*>(pTLBRItem->Clone()) : nullptr); | ||||
758 | std::unique_ptr<SvxLineItem> pNewBLTRItem(pBLTRItem ? static_cast<SvxLineItem*>(pBLTRItem->Clone()) : nullptr); | ||||
759 | |||||
760 | // fetch line and update attributes with parameters | ||||
761 | |||||
762 | if ( !pLine ) | ||||
763 | { | ||||
764 | if( pNewBoxItem ) | ||||
765 | { | ||||
766 | if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::TOP ); | ||||
767 | if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::BOTTOM ); | ||||
768 | if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::LEFT ); | ||||
769 | if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( nullptr, SvxBoxItemLine::RIGHT ); | ||||
770 | } | ||||
771 | if( pNewTLBRItem && pNewTLBRItem->GetLine() ) | ||||
772 | pNewTLBRItem->SetLine( nullptr ); | ||||
773 | if( pNewBLTRItem && pNewBLTRItem->GetLine() ) | ||||
774 | pNewBLTRItem->SetLine( nullptr ); | ||||
775 | } | ||||
776 | else | ||||
777 | { | ||||
778 | if ( bColorOnly ) | ||||
779 | { | ||||
780 | Color aColor( pLine->GetColor() ); | ||||
781 | if( pNewBoxItem ) | ||||
782 | { | ||||
783 | SetLineColor( pNewBoxItem->GetTop(), aColor ); | ||||
784 | SetLineColor( pNewBoxItem->GetBottom(), aColor ); | ||||
785 | SetLineColor( pNewBoxItem->GetLeft(), aColor ); | ||||
786 | SetLineColor( pNewBoxItem->GetRight(), aColor ); | ||||
787 | } | ||||
788 | if( pNewTLBRItem ) | ||||
789 | SetLineColor( pNewTLBRItem->GetLine(), aColor ); | ||||
790 | if( pNewBLTRItem ) | ||||
791 | SetLineColor( pNewBLTRItem->GetLine(), aColor ); | ||||
792 | } | ||||
793 | else | ||||
794 | { | ||||
795 | if( pNewBoxItem ) | ||||
796 | { | ||||
797 | SetLine( pNewBoxItem->GetTop(), pLine ); | ||||
798 | SetLine( pNewBoxItem->GetBottom(), pLine ); | ||||
799 | SetLine( pNewBoxItem->GetLeft(), pLine ); | ||||
800 | SetLine( pNewBoxItem->GetRight(), pLine ); | ||||
801 | } | ||||
802 | if( pNewTLBRItem ) | ||||
803 | SetLine( pNewTLBRItem->GetLine(), pLine ); | ||||
804 | if( pNewBLTRItem ) | ||||
805 | SetLine( pNewBLTRItem->GetLine(), pLine ); | ||||
806 | } | ||||
807 | } | ||||
808 | if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem ); | ||||
809 | if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem ); | ||||
810 | if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem ); | ||||
811 | |||||
812 | nStart = mvData[nPos].nEndRow + 1; | ||||
813 | |||||
814 | if ( nY1 < nStartRow || nY2 > nEndRow ) | ||||
815 | { | ||||
816 | if (nY1 < nStartRow) nY1=nStartRow; | ||||
817 | if (nY2 > nEndRow) nY2=nEndRow; | ||||
818 | SetPatternArea( nY1, nY2, std::move(pNewPattern), true ); | ||||
819 | Search( nStart, nPos ); | ||||
820 | } | ||||
821 | else | ||||
822 | { | ||||
823 | // remove from pool ? | ||||
824 | rDocument.GetPool()->Remove(*mvData[nPos].pPattern); | ||||
825 | mvData[nPos].pPattern = | ||||
826 | &rDocument.GetPool()->Put(std::move(pNewPattern)); | ||||
827 | |||||
828 | if (Concat(nPos)) | ||||
829 | Search(nStart, nPos); | ||||
830 | else | ||||
831 | nPos++; | ||||
832 | } | ||||
833 | } | ||||
834 | else | ||||
835 | { | ||||
836 | nStart = mvData[nPos].nEndRow + 1; | ||||
837 | nPos++; | ||||
838 | } | ||||
839 | } | ||||
840 | while ((nStart <= nEndRow) && (nPos < mvData.size())); | ||||
841 | } | ||||
842 | |||||
843 | void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray, bool* const pIsChanged ) | ||||
844 | { | ||||
845 | #if DEBUG_SC_TESTATTRARRAY0 | ||||
846 | TestData(); | ||||
847 | #endif | ||||
848 | |||||
849 | if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow))) | ||||
850 | return; | ||||
851 | |||||
852 | SCSIZE nPos; | ||||
853 | SCROW nStart=0; | ||||
854 | SetDefaultIfNotInit(); | ||||
855 | if (!Search( nStartRow, nPos )) | ||||
856 | { | ||||
857 | OSL_FAIL("Search Failure")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "857" ": "), "%s", "Search Failure"); } } while (false); | ||||
858 | return; | ||||
859 | } | ||||
860 | |||||
861 | ScAddress aAdrStart( nCol, 0, nTab ); | ||||
862 | ScAddress aAdrEnd ( nCol, 0, nTab ); | ||||
863 | |||||
864 | do | ||||
865 | { | ||||
866 | const ScPatternAttr* pOldPattern = mvData[nPos].pPattern; | ||||
867 | const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pCache->ApplyTo( *pOldPattern ) ); | ||||
868 | if (pNewPattern != pOldPattern) | ||||
869 | { | ||||
870 | SCROW nY1 = nStart; | ||||
871 | SCROW nY2 = mvData[nPos].nEndRow; | ||||
872 | nStart = mvData[nPos].nEndRow + 1; | ||||
873 | |||||
874 | if(pIsChanged) | ||||
875 | *pIsChanged = true; | ||||
876 | |||||
877 | if ( nY1 < nStartRow || nY2 > nEndRow ) | ||||
878 | { | ||||
879 | if (nY1 < nStartRow) nY1=nStartRow; | ||||
880 | if (nY2 > nEndRow) nY2=nEndRow; | ||||
881 | SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray ); | ||||
882 | Search( nStart, nPos ); | ||||
883 | } | ||||
884 | else | ||||
885 | { | ||||
886 | if ( nCol != -1 ) | ||||
887 | { | ||||
888 | // ensure attributing changes text-width of cell | ||||
889 | |||||
890 | const SfxItemSet& rNewSet = pNewPattern->GetItemSet(); | ||||
891 | const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); | ||||
892 | |||||
893 | bool bNumFormatChanged; | ||||
894 | if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, | ||||
895 | rNewSet, rOldSet ) ) | ||||
896 | { | ||||
897 | aAdrStart.SetRow( nPos ? mvData[nPos-1].nEndRow+1 : 0 ); | ||||
898 | aAdrEnd .SetRow( mvData[nPos].nEndRow ); | ||||
899 | rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); | ||||
900 | } | ||||
901 | } | ||||
902 | |||||
903 | rDocument.GetPool()->Remove(*mvData[nPos].pPattern); | ||||
904 | mvData[nPos].pPattern = pNewPattern; | ||||
905 | if (Concat(nPos)) | ||||
906 | Search(nStart, nPos); | ||||
907 | else | ||||
908 | ++nPos; | ||||
909 | } | ||||
910 | } | ||||
911 | else | ||||
912 | { | ||||
913 | nStart = mvData[nPos].nEndRow + 1; | ||||
914 | ++nPos; | ||||
915 | } | ||||
916 | } | ||||
917 | while (nStart <= nEndRow); | ||||
918 | |||||
919 | rDocument.SetStreamValid(nTab, false); | ||||
920 | |||||
921 | #if DEBUG_SC_TESTATTRARRAY0 | ||||
922 | TestData(); | ||||
923 | #endif | ||||
924 | } | ||||
925 | |||||
926 | void ScAttrArray::SetAttrEntries(std::vector<ScAttrEntry> && vNewData) | ||||
927 | { | ||||
928 | ScDocumentPool* pDocPool = rDocument.GetPool(); | ||||
929 | for (auto const & rEntry : mvData) | ||||
930 | pDocPool->Remove(*rEntry.pPattern); | ||||
931 | |||||
932 | mvData = std::move(vNewData); | ||||
933 | } | ||||
934 | |||||
935 | static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource ) | ||||
936 | { | ||||
937 | const SfxPoolItem* pNewItem; | ||||
938 | const SfxPoolItem* pOldItem; | ||||
939 | for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++) | ||||
940 | { | ||||
941 | // pMergeSet has no parent | ||||
942 | SfxItemState eOldState = rMergeSet.GetItemState( nId, false, &pOldItem ); | ||||
943 | |||||
944 | if ( eOldState == SfxItemState::DEFAULT ) | ||||
945 | { | ||||
946 | SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem ); | ||||
947 | if ( eNewState == SfxItemState::SET ) | ||||
948 | { | ||||
949 | if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) ) | ||||
950 | rMergeSet.InvalidateItem( nId ); | ||||
951 | } | ||||
952 | } | ||||
953 | else if ( eOldState == SfxItemState::SET ) // Item set | ||||
954 | { | ||||
955 | SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem ); | ||||
956 | if ( eNewState == SfxItemState::SET ) | ||||
957 | { | ||||
958 | if ( pNewItem != pOldItem ) // Both pulled | ||||
959 | rMergeSet.InvalidateItem( nId ); | ||||
960 | } | ||||
961 | else // Default | ||||
962 | { | ||||
963 | if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) ) | ||||
964 | rMergeSet.InvalidateItem( nId ); | ||||
965 | } | ||||
966 | } | ||||
967 | // Dontcare remains Dontcare | ||||
968 | } | ||||
969 | } | ||||
970 | |||||
971 | void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow, | ||||
972 | ScMergePatternState& rState, bool bDeep ) const | ||||
973 | { | ||||
974 | if (!(rDocument.ValidRow(nStartRow) && rDocument.ValidRow(nEndRow))) | ||||
975 | return; | ||||
976 | |||||
977 | SCSIZE nPos = 0; | ||||
978 | SCROW nStart=0; | ||||
979 | if ( !mvData.empty() && !Search( nStartRow, nPos ) ) | ||||
980 | { | ||||
981 | OSL_FAIL("Search failure")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "981" ": "), "%s", "Search failure"); } } while (false); | ||||
982 | return; | ||||
983 | } | ||||
984 | |||||
985 | do | ||||
986 | { | ||||
987 | // similar patterns must not be repeated | ||||
988 | const ScPatternAttr* pPattern = nullptr; | ||||
989 | if ( !mvData.empty() ) | ||||
990 | pPattern = mvData[nPos].pPattern; | ||||
991 | else | ||||
992 | pPattern = rDocument.GetDefPattern(); | ||||
993 | if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 ) | ||||
994 | { | ||||
995 | const SfxItemSet& rThisSet = pPattern->GetItemSet(); | ||||
996 | if (rState.pItemSet) | ||||
997 | { | ||||
998 | rState.mbValidPatternId = false; | ||||
999 | if (bDeep) | ||||
1000 | lcl_MergeDeep( *rState.pItemSet, rThisSet ); | ||||
1001 | else | ||||
1002 | rState.pItemSet->MergeValues( rThisSet ); | ||||
1003 | } | ||||
1004 | else | ||||
1005 | { | ||||
1006 | // first pattern - copied from parent | ||||
1007 | rState.pItemSet = std::make_unique<SfxItemSet>( *rThisSet.GetPool(), rThisSet.GetRanges() ); | ||||
1008 | rState.pItemSet->Set( rThisSet, bDeep ); | ||||
1009 | rState.mnPatternId = pPattern->GetKey(); | ||||
1010 | } | ||||
1011 | |||||
1012 | rState.pOld2 = rState.pOld1; | ||||
1013 | rState.pOld1 = pPattern; | ||||
1014 | } | ||||
1015 | |||||
1016 | if ( !mvData.empty() ) | ||||
1017 | nStart = mvData[nPos].nEndRow + 1; | ||||
1018 | else | ||||
1019 | nStart = rDocument.MaxRow() + 1; | ||||
1020 | ++nPos; | ||||
1021 | } | ||||
1022 | while (nStart <= nEndRow); | ||||
1023 | } | ||||
1024 | |||||
1025 | // assemble border | ||||
1026 | |||||
1027 | static bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine, | ||||
1028 | sal_uInt8& rModified, const SvxBorderLine*& rpNew ) | ||||
1029 | { | ||||
1030 | if (rModified == SC_LINE_DONTCARE2) | ||||
1031 | return false; // don't go again | ||||
1032 | |||||
1033 | if (rModified == SC_LINE_EMPTY0) | ||||
1034 | { | ||||
1035 | rModified = SC_LINE_SET1; | ||||
1036 | rpNew = pNewLine; | ||||
1037 | return true; // initial value | ||||
1038 | } | ||||
1039 | |||||
1040 | if (pOldLine == pNewLine) | ||||
1041 | { | ||||
1042 | rpNew = pOldLine; | ||||
1043 | return false; | ||||
1044 | } | ||||
1045 | |||||
1046 | if (pOldLine && pNewLine) | ||||
1047 | if (*pOldLine == *pNewLine) | ||||
1048 | { | ||||
1049 | rpNew = pOldLine; | ||||
1050 | return false; | ||||
1051 | } | ||||
1052 | |||||
1053 | rModified = SC_LINE_DONTCARE2; | ||||
1054 | rpNew = nullptr; | ||||
1055 | return true; // another line -> don't care | ||||
1056 | } | ||||
1057 | |||||
1058 | static void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, | ||||
1059 | ScLineFlags& rFlags, const ScPatternAttr* pPattern, | ||||
1060 | bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom ) | ||||
1061 | { | ||||
1062 | // right/bottom border set when connected together | ||||
1063 | const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE); | ||||
1064 | if ( rMerge.GetColMerge() == nDistRight + 1 ) | ||||
1065 | nDistRight = 0; | ||||
1066 | if ( rMerge.GetRowMerge() == nDistBottom + 1 ) | ||||
1067 | nDistBottom = 0; | ||||
1068 | |||||
1069 | const SvxBoxItem* pCellFrame = &pPattern->GetItemSet().Get( ATTR_BORDER ); | ||||
1070 | const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft(); | ||||
1071 | const SvxBorderLine* pRightAttr = pCellFrame->GetRight(); | ||||
1072 | const SvxBorderLine* pTopAttr = pCellFrame->GetTop(); | ||||
1073 | const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom(); | ||||
1074 | const SvxBorderLine* pNew; | ||||
1075 | |||||
1076 | if (bTop) | ||||
1077 | { | ||||
1078 | if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew )) | ||||
1079 | pLineOuter->SetLine( pNew, SvxBoxItemLine::TOP ); | ||||
1080 | } | ||||
1081 | else | ||||
1082 | { | ||||
1083 | if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew )) | ||||
1084 | pLineInner->SetLine( pNew, SvxBoxInfoItemLine::HORI ); | ||||
1085 | } | ||||
1086 | |||||
1087 | if (nDistBottom == 0) | ||||
1088 | { | ||||
1089 | if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew )) | ||||
1090 | pLineOuter->SetLine( pNew, SvxBoxItemLine::BOTTOM ); | ||||
1091 | } | ||||
1092 | else | ||||
1093 | { | ||||
1094 | if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew )) | ||||
1095 | pLineInner->SetLine( pNew, SvxBoxInfoItemLine::HORI ); | ||||
1096 | } | ||||
1097 | |||||
1098 | if (bLeft) | ||||
1099 | { | ||||
1100 | if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew )) | ||||
1101 | pLineOuter->SetLine( pNew, SvxBoxItemLine::LEFT ); | ||||
1102 | } | ||||
1103 | else | ||||
1104 | { | ||||
1105 | if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew )) | ||||
1106 | pLineInner->SetLine( pNew, SvxBoxInfoItemLine::VERT ); | ||||
1107 | } | ||||
1108 | |||||
1109 | if (nDistRight == 0) | ||||
1110 | { | ||||
1111 | if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew )) | ||||
1112 | pLineOuter->SetLine( pNew, SvxBoxItemLine::RIGHT ); | ||||
1113 | } | ||||
1114 | else | ||||
1115 | { | ||||
1116 | if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew )) | ||||
1117 | pLineInner->SetLine( pNew, SvxBoxInfoItemLine::VERT ); | ||||
1118 | } | ||||
1119 | } | ||||
1120 | |||||
1121 | void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, | ||||
1122 | ScLineFlags& rFlags, | ||||
1123 | SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const | ||||
1124 | { | ||||
1125 | const ScPatternAttr* pPattern; | ||||
1126 | |||||
1127 | if (nStartRow == nEndRow) | ||||
1128 | { | ||||
1129 | pPattern = GetPattern( nStartRow ); | ||||
1130 | lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, 0 ); | ||||
1131 | } | ||||
1132 | else if ( !mvData.empty() ) // non-default pattern | ||||
1133 | { | ||||
1134 | pPattern = GetPattern( nStartRow ); | ||||
1135 | lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, true, | ||||
1136 | nEndRow-nStartRow ); | ||||
1137 | |||||
1138 | SCSIZE nStartIndex; | ||||
1139 | SCSIZE nEndIndex; | ||||
1140 | Search( nStartRow+1, nStartIndex ); | ||||
1141 | Search( nEndRow-1, nEndIndex ); | ||||
1142 | for (SCSIZE i=nStartIndex; i<=nEndIndex; i++) | ||||
1143 | { | ||||
1144 | pPattern = mvData[i].pPattern; | ||||
1145 | lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, | ||||
1146 | nEndRow - std::min( mvData[i].nEndRow, static_cast<SCROW>(nEndRow-1) ) ); | ||||
1147 | // nDistBottom here always > 0 | ||||
1148 | } | ||||
1149 | |||||
1150 | pPattern = GetPattern( nEndRow ); | ||||
1151 | lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, false, 0 ); | ||||
1152 | } | ||||
1153 | else | ||||
1154 | { | ||||
1155 | lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, rDocument.GetDefPattern(), bLeft, nDistRight, true, 0 ); | ||||
1156 | } | ||||
1157 | } | ||||
1158 | |||||
1159 | // apply border | ||||
1160 | |||||
1161 | // ApplyFrame - on an entry into the array | ||||
1162 | |||||
1163 | bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem, | ||||
1164 | const SvxBoxInfoItem* pBoxInfoItem, | ||||
1165 | SCROW nStartRow, SCROW nEndRow, | ||||
1166 | bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom ) | ||||
1167 | { | ||||
1168 | OSL_ENSURE( pBoxItem && pBoxInfoItem, "Missing line attributes!" )do { if (true && (!(pBoxItem && pBoxInfoItem) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "1168" ": "), "%s", "Missing line attributes!"); } } while (false); | ||||
1169 | |||||
1170 | const ScPatternAttr* pPattern = GetPattern( nStartRow ); | ||||
1171 | const SvxBoxItem* pOldFrame = &pPattern->GetItemSet().Get( ATTR_BORDER ); | ||||
1172 | |||||
1173 | // right/bottom border set when connected together | ||||
1174 | const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE); | ||||
1175 | if ( rMerge.GetColMerge() == nDistRight + 1 ) | ||||
1176 | nDistRight = 0; | ||||
1177 | if ( rMerge.GetRowMerge() == nDistBottom + 1 ) | ||||
1178 | nDistBottom = 0; | ||||
1179 | |||||
1180 | SvxBoxItem aNewFrame( *pOldFrame ); | ||||
1181 | bool bRTL=rDocument.IsLayoutRTL(nTab); | ||||
1182 | // fdo#37464 check if the sheet are RTL then replace right <=> left | ||||
1183 | if (bRTL) | ||||
1184 | { | ||||
1185 | if( bLeft && nDistRight==0) | ||||
1186 | { | ||||
1187 | if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) ) | ||||
1188 | aNewFrame.SetLine( pBoxItem->GetLeft(), SvxBoxItemLine::RIGHT ); | ||||
1189 | if ( pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) ) | ||||
1190 | aNewFrame.SetLine( pBoxItem->GetRight(), SvxBoxItemLine::LEFT ); | ||||
1191 | } | ||||
1192 | else | ||||
1193 | { | ||||
1194 | if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) ) | ||||
1195 | aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), | ||||
1196 | SvxBoxItemLine::RIGHT ); | ||||
1197 | if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) ) | ||||
1198 | aNewFrame.SetLine( bLeft ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), | ||||
1199 | SvxBoxItemLine::LEFT ); | ||||
1200 | } | ||||
1201 | } | ||||
1202 | else | ||||
1203 | { | ||||
1204 | if ( bLeft ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::LEFT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) ) | ||||
1205 | aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), | ||||
1206 | SvxBoxItemLine::LEFT ); | ||||
1207 | if ( (nDistRight==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::RIGHT) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::VERT) ) | ||||
1208 | aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), | ||||
1209 | SvxBoxItemLine::RIGHT ); | ||||
1210 | } | ||||
1211 | if ( bTop ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::TOP) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) ) | ||||
1212 | aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), | ||||
1213 | SvxBoxItemLine::TOP ); | ||||
1214 | if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::BOTTOM) : pBoxInfoItem->IsValid(SvxBoxInfoItemValidFlags::HORI) ) | ||||
1215 | aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), | ||||
1216 | SvxBoxItemLine::BOTTOM ); | ||||
1217 | |||||
1218 | if (aNewFrame == *pOldFrame) | ||||
1219 | { | ||||
1220 | // nothing to do | ||||
1221 | return false; | ||||
1222 | } | ||||
1223 | else | ||||
1224 | { | ||||
1225 | SfxItemPoolCache aCache( rDocument.GetPool(), &aNewFrame ); | ||||
1226 | ApplyCacheArea( nStartRow, nEndRow, &aCache ); | ||||
1227 | |||||
1228 | return true; | ||||
1229 | } | ||||
1230 | } | ||||
1231 | |||||
1232 | void ScAttrArray::ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner, | ||||
1233 | SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight) | ||||
1234 | { | ||||
1235 | if (nStartRow == nEndRow) | ||||
1236 | ApplyFrame(&rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0); | ||||
1237 | else if ( !mvData.empty() ) | ||||
1238 | { | ||||
1239 | ApplyFrame(&rLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight, | ||||
1240 | true, nEndRow-nStartRow); | ||||
1241 | |||||
1242 | if ( nEndRow > nStartRow+1 ) // inner part available? | ||||
1243 | { | ||||
1244 | SCSIZE nStartIndex; | ||||
1245 | SCSIZE nEndIndex; | ||||
1246 | Search( nStartRow+1, nStartIndex ); | ||||
1247 | Search( nEndRow-1, nEndIndex ); | ||||
1248 | SCROW nTmpStart = nStartRow+1; | ||||
1249 | SCROW nTmpEnd; | ||||
1250 | for (SCSIZE i=nStartIndex; i<=nEndIndex;) | ||||
1251 | { | ||||
1252 | nTmpEnd = std::min( static_cast<SCROW>(nEndRow-1), mvData[i].nEndRow ); | ||||
1253 | bool bChanged = ApplyFrame(&rLineOuter, pLineInner, nTmpStart, nTmpEnd, | ||||
1254 | bLeft, nDistRight, false, nEndRow - nTmpEnd); | ||||
1255 | nTmpStart = nTmpEnd+1; | ||||
1256 | if (bChanged) | ||||
1257 | { | ||||
1258 | Search(nTmpStart, i); | ||||
1259 | Search(nEndRow-1, nEndIndex); | ||||
1260 | } | ||||
1261 | else | ||||
1262 | i++; | ||||
1263 | } | ||||
1264 | } | ||||
1265 | |||||
1266 | ApplyFrame(&rLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, false, 0); | ||||
1267 | } | ||||
1268 | else | ||||
1269 | { | ||||
1270 | ApplyFrame(&rLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, true, 0); | ||||
1271 | } | ||||
1272 | } | ||||
1273 | |||||
1274 | bool ScAttrArray::HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const | ||||
1275 | { | ||||
1276 | bool bFound = false; | ||||
1277 | if ( nMask & HasAttrFlags::Merged ) | ||||
1278 | { | ||||
1279 | const ScMergeAttr* pMerge = &pPattern->GetItem( ATTR_MERGE ); | ||||
1280 | if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 ) | ||||
1281 | bFound = true; | ||||
1282 | } | ||||
1283 | if ( nMask & ( HasAttrFlags::Overlapped | HasAttrFlags::NotOverlapped | HasAttrFlags::AutoFilter ) ) | ||||
1284 | { | ||||
1285 | const ScMergeFlagAttr* pMergeFlag = &pPattern->GetItem( ATTR_MERGE_FLAG ); | ||||
1286 | if ( (nMask & HasAttrFlags::Overlapped) && pMergeFlag->IsOverlapped() ) | ||||
1287 | bFound = true; | ||||
1288 | if ( (nMask & HasAttrFlags::NotOverlapped) && !pMergeFlag->IsOverlapped() ) | ||||
1289 | bFound = true; | ||||
1290 | if ( (nMask & HasAttrFlags::AutoFilter) && pMergeFlag->HasAutoFilter() ) | ||||
1291 | bFound = true; | ||||
1292 | } | ||||
1293 | if ( nMask & HasAttrFlags::Lines ) | ||||
1294 | { | ||||
1295 | const SvxBoxItem* pBox = &pPattern->GetItem( ATTR_BORDER ); | ||||
1296 | if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() ) | ||||
1297 | bFound = true; | ||||
1298 | } | ||||
1299 | if ( nMask & HasAttrFlags::Shadow ) | ||||
1300 | { | ||||
1301 | const SvxShadowItem* pShadow = &pPattern->GetItem( ATTR_SHADOW ); | ||||
1302 | if ( pShadow->GetLocation() != SvxShadowLocation::NONE ) | ||||
1303 | bFound = true; | ||||
1304 | } | ||||
1305 | if ( nMask & HasAttrFlags::Conditional ) | ||||
1306 | { | ||||
1307 | bool bContainsCondFormat = pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty(); | ||||
1308 | if ( bContainsCondFormat ) | ||||
1309 | bFound = true; | ||||
1310 | } | ||||
1311 | if ( nMask & HasAttrFlags::Protected ) | ||||
1312 | { | ||||
1313 | const ScProtectionAttr* pProtect = &pPattern->GetItem( ATTR_PROTECTION ); | ||||
1314 | bool bFoundTemp = false; | ||||
1315 | if ( pProtect->GetProtection() || pProtect->GetHideCell() ) | ||||
1316 | bFoundTemp = true; | ||||
1317 | |||||
1318 | bool bContainsCondFormat = !mvData.empty() && | ||||
1319 | !pPattern->GetItem( ATTR_CONDITIONAL ).GetCondFormatData().empty(); | ||||
1320 | if ( bContainsCondFormat && nCol != -1 ) // rDocument.GetCondResult() is valid only for real columns. | ||||
1321 | { | ||||
1322 | SCROW nRowStartCond = std::max<SCROW>( nRow1, i ? mvData[i-1].nEndRow + 1: 0 ); | ||||
1323 | SCROW nRowEndCond = std::min<SCROW>( nRow2, mvData[i].nEndRow ); | ||||
1324 | bool bFoundCond = false; | ||||
1325 | for(SCROW nRowCond = nRowStartCond; nRowCond <= nRowEndCond && !bFoundCond; ++nRowCond) | ||||
1326 | { | ||||
1327 | const SfxItemSet* pSet = rDocument.GetCondResult( nCol, nRowCond, nTab ); | ||||
1328 | |||||
1329 | const SfxPoolItem* pItem; | ||||
1330 | if( pSet && pSet->GetItemState( ATTR_PROTECTION, true, &pItem ) == SfxItemState::SET ) | ||||
1331 | { | ||||
1332 | const ScProtectionAttr* pCondProtect = static_cast<const ScProtectionAttr*>(pItem); | ||||
1333 | if( pCondProtect->GetProtection() || pCondProtect->GetHideCell() ) | ||||
1334 | bFoundCond = true; | ||||
1335 | else | ||||
1336 | break; | ||||
1337 | } | ||||
1338 | else | ||||
1339 | { | ||||
1340 | // well it is not true that we found one | ||||
1341 | // but existing one + cell where conditional | ||||
1342 | // formatting does not remove it | ||||
1343 | // => we should use the existing protection setting | ||||
1344 | bFoundCond = bFoundTemp; | ||||
1345 | } | ||||
1346 | } | ||||
1347 | bFoundTemp = bFoundCond; | ||||
1348 | } | ||||
1349 | |||||
1350 | if(bFoundTemp) | ||||
1351 | bFound = true; | ||||
1352 | } | ||||
1353 | if ( nMask & HasAttrFlags::Rotate ) | ||||
1354 | { | ||||
1355 | const ScRotateValueItem* pRotate = &pPattern->GetItem( ATTR_ROTATE_VALUE ); | ||||
1356 | // 90 or 270 degrees is former SvxOrientationItem - only look for other values | ||||
1357 | // (see ScPatternAttr::GetCellOrientation) | ||||
1358 | sal_Int32 nAngle = pRotate->GetValue(); | ||||
1359 | if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 ) | ||||
1360 | bFound = true; | ||||
1361 | } | ||||
1362 | if ( nMask & HasAttrFlags::NeedHeight ) | ||||
1363 | { | ||||
1364 | if (pPattern->GetCellOrientation() != SvxCellOrientation::Standard) | ||||
1365 | bFound = true; | ||||
1366 | else if (pPattern->GetItem( ATTR_LINEBREAK ).GetValue()) | ||||
1367 | bFound = true; | ||||
1368 | else if (pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Block) | ||||
1369 | bFound = true; | ||||
1370 | |||||
1371 | else if (!pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData().empty()) | ||||
1372 | bFound = true; | ||||
1373 | else if (pPattern->GetItem( ATTR_ROTATE_VALUE ).GetValue()) | ||||
1374 | bFound = true; | ||||
1375 | } | ||||
1376 | if ( nMask & ( HasAttrFlags::ShadowRight | HasAttrFlags::ShadowDown ) ) | ||||
1377 | { | ||||
1378 | const SvxShadowItem* pShadow = &pPattern->GetItem( ATTR_SHADOW ); | ||||
1379 | SvxShadowLocation eLoc = pShadow->GetLocation(); | ||||
1380 | if ( nMask & HasAttrFlags::ShadowRight ) | ||||
1381 | if ( eLoc == SvxShadowLocation::TopRight || eLoc == SvxShadowLocation::BottomRight ) | ||||
1382 | bFound = true; | ||||
1383 | if ( nMask & HasAttrFlags::ShadowDown ) | ||||
1384 | if ( eLoc == SvxShadowLocation::BottomLeft || eLoc == SvxShadowLocation::BottomRight ) | ||||
1385 | bFound = true; | ||||
1386 | } | ||||
1387 | if ( nMask & HasAttrFlags::RightOrCenter ) | ||||
1388 | { | ||||
1389 | // called only if the sheet is LTR, so physical=logical alignment can be assumed | ||||
1390 | SvxCellHorJustify eHorJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue(); | ||||
1391 | if ( eHorJust == SvxCellHorJustify::Right || eHorJust == SvxCellHorJustify::Center ) | ||||
1392 | bFound = true; | ||||
1393 | } | ||||
1394 | |||||
1395 | return bFound; | ||||
1396 | } | ||||
1397 | |||||
1398 | // Test if field contains specific attribute | ||||
1399 | bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const | ||||
1400 | { | ||||
1401 | if (mvData.empty()) | ||||
1402 | { | ||||
1403 | return HasAttrib_Impl(rDocument.GetDefPattern(), nMask, 0, rDocument.MaxRow(), 0); | ||||
1404 | } | ||||
1405 | |||||
1406 | SCSIZE nStartIndex; | ||||
1407 | SCSIZE nEndIndex; | ||||
1408 | Search( nRow1, nStartIndex ); | ||||
1409 | if (nRow1 != nRow2) | ||||
1410 | Search( nRow2, nEndIndex ); | ||||
1411 | else | ||||
1412 | nEndIndex = nStartIndex; | ||||
1413 | bool bFound = false; | ||||
1414 | |||||
1415 | for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++) | ||||
1416 | { | ||||
1417 | const ScPatternAttr* pPattern = mvData[i].pPattern; | ||||
1418 | bFound = HasAttrib_Impl(pPattern, nMask, nRow1, nRow2, i); | ||||
1419 | } | ||||
1420 | |||||
1421 | return bFound; | ||||
1422 | } | ||||
1423 | |||||
1424 | bool ScAttrArray::IsMerged( SCROW nRow ) const | ||||
1425 | { | ||||
1426 | if ( !mvData.empty() ) | ||||
1427 | { | ||||
1428 | SCSIZE nIndex; | ||||
1429 | Search(nRow, nIndex); | ||||
1430 | const ScMergeAttr& rItem = mvData[nIndex].pPattern->GetItem(ATTR_MERGE); | ||||
1431 | |||||
1432 | return rItem.IsMerged(); | ||||
1433 | } | ||||
1434 | |||||
1435 | return rDocument.GetDefPattern()->GetItem(ATTR_MERGE).IsMerged(); | ||||
1436 | } | ||||
1437 | |||||
1438 | /** | ||||
1439 | * Area around any given summaries expand and adapt any MergeFlag (bRefresh) | ||||
1440 | */ | ||||
1441 | bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow, | ||||
1442 | SCCOL& rPaintCol, SCROW& rPaintRow, | ||||
1443 | bool bRefresh ) | ||||
1444 | { | ||||
1445 | assert( nCol != -1 )(static_cast <bool> (nCol != -1) ? void (0) : __assert_fail ("nCol != -1", "/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" , 1445, __extension__ __PRETTY_FUNCTION__)); | ||||
1446 | SetDefaultIfNotInit(); | ||||
1447 | const ScPatternAttr* pPattern; | ||||
1448 | const ScMergeAttr* pItem; | ||||
1449 | SCSIZE nStartIndex; | ||||
1450 | SCSIZE nEndIndex; | ||||
1451 | Search( nStartRow, nStartIndex ); | ||||
1452 | Search( nEndRow, nEndIndex ); | ||||
1453 | bool bFound = false; | ||||
1454 | |||||
1455 | for (SCSIZE i=nStartIndex; i<=nEndIndex; i++) | ||||
1456 | { | ||||
1457 | pPattern = mvData[i].pPattern; | ||||
1458 | pItem = &pPattern->GetItem( ATTR_MERGE ); | ||||
1459 | SCCOL nCountX = pItem->GetColMerge(); | ||||
1460 | SCROW nCountY = pItem->GetRowMerge(); | ||||
1461 | if (nCountX>1 || nCountY>1) | ||||
1462 | { | ||||
1463 | SCROW nThisRow = (i>0) ? mvData[i-1].nEndRow+1 : 0; | ||||
1464 | SCCOL nMergeEndCol = nThisCol + nCountX - 1; | ||||
1465 | SCROW nMergeEndRow = nThisRow + nCountY - 1; | ||||
1466 | if (nMergeEndCol > rPaintCol && nMergeEndCol <= rDocument.MaxCol()) | ||||
1467 | rPaintCol = nMergeEndCol; | ||||
1468 | if (nMergeEndRow > rPaintRow && nMergeEndRow <= rDocument.MaxRow()) | ||||
1469 | rPaintRow = nMergeEndRow; | ||||
1470 | bFound = true; | ||||
1471 | |||||
1472 | if (bRefresh) | ||||
1473 | { | ||||
1474 | if ( nMergeEndCol > nThisCol ) | ||||
1475 | rDocument.ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, mvData[i].nEndRow, | ||||
1476 | nTab, ScMF::Hor ); | ||||
1477 | if ( nMergeEndRow > nThisRow ) | ||||
1478 | rDocument.ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow, | ||||
1479 | nTab, ScMF::Ver ); | ||||
1480 | if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow ) | ||||
1481 | rDocument.ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow, | ||||
1482 | nTab, ScMF::Hor | ScMF::Ver ); | ||||
1483 | |||||
1484 | Search( nThisRow, i ); // Data changed | ||||
1485 | Search( nStartRow, nStartIndex ); | ||||
1486 | Search( nEndRow, nEndIndex ); | ||||
1487 | } | ||||
1488 | } | ||||
1489 | } | ||||
1490 | |||||
1491 | return bFound; | ||||
1492 | } | ||||
1493 | |||||
1494 | void ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow) | ||||
1495 | { | ||||
1496 | assert( nCol != -1 )(static_cast <bool> (nCol != -1) ? void (0) : __assert_fail ("nCol != -1", "/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" , 1496, __extension__ __PRETTY_FUNCTION__)); | ||||
1497 | SetDefaultIfNotInit(); | ||||
1498 | const ScPatternAttr* pPattern; | ||||
1499 | const ScMergeAttr* pItem; | ||||
1500 | SCSIZE nIndex; | ||||
1501 | |||||
1502 | Search( nStartRow, nIndex ); | ||||
1503 | SCROW nThisStart = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
1504 | if (nThisStart < nStartRow) | ||||
1505 | nThisStart = nStartRow; | ||||
1506 | |||||
1507 | while ( nThisStart <= nEndRow ) | ||||
1508 | { | ||||
1509 | SCROW nThisEnd = mvData[nIndex].nEndRow; | ||||
1510 | if (nThisEnd > nEndRow) | ||||
1511 | nThisEnd = nEndRow; | ||||
1512 | |||||
1513 | pPattern = mvData[nIndex].pPattern; | ||||
1514 | pItem = &pPattern->GetItem( ATTR_MERGE ); | ||||
1515 | SCCOL nCountX = pItem->GetColMerge(); | ||||
1516 | SCROW nCountY = pItem->GetRowMerge(); | ||||
1517 | if (nCountX>1 || nCountY>1) | ||||
1518 | { | ||||
1519 | const ScMergeAttr* pAttr = &rDocument.GetPool()->GetDefaultItem( ATTR_MERGE ); | ||||
1520 | const ScMergeFlagAttr* pFlagAttr = &rDocument.GetPool()->GetDefaultItem( ATTR_MERGE_FLAG ); | ||||
1521 | |||||
1522 | OSL_ENSURE( nCountY==1 || nThisStart==nThisEnd, "What's up?" )do { if (true && (!(nCountY==1 || nThisStart==nThisEnd ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "1522" ": "), "%s", "What's up?"); } } while (false); | ||||
1523 | |||||
1524 | SCCOL nThisCol = nCol; | ||||
1525 | SCCOL nMergeEndCol = nThisCol + nCountX - 1; | ||||
1526 | SCROW nMergeEndRow = nThisEnd + nCountY - 1; | ||||
1527 | |||||
1528 | // ApplyAttr for areas | ||||
1529 | for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++) | ||||
1530 | rDocument.ApplyAttr( nThisCol, nThisRow, nTab, *pAttr ); | ||||
1531 | |||||
1532 | std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( rDocument.GetPool() )); | ||||
1533 | SfxItemSet* pSet = &pNewPattern->GetItemSet(); | ||||
1534 | pSet->Put( *pFlagAttr ); | ||||
1535 | rDocument.ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow, | ||||
1536 | nTab, *pNewPattern ); | ||||
1537 | pNewPattern.reset(); | ||||
1538 | |||||
1539 | Search( nThisEnd, nIndex ); // data changed | ||||
1540 | } | ||||
1541 | |||||
1542 | ++nIndex; | ||||
1543 | if ( nIndex < mvData.size() ) | ||||
1544 | nThisStart = mvData[nIndex-1].nEndRow+1; | ||||
1545 | else | ||||
1546 | nThisStart = rDocument.MaxRow()+1; // End | ||||
1547 | } | ||||
1548 | } | ||||
1549 | |||||
1550 | void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow, | ||||
1551 | const ScPatternAttr* pWantedPattern, bool bDefault ) | ||||
1552 | { | ||||
1553 | SetDefaultIfNotInit(); | ||||
1554 | const ScPatternAttr* pOldPattern; | ||||
1555 | const ScMergeFlagAttr* pItem; | ||||
1556 | |||||
1557 | SCSIZE nIndex; | ||||
1558 | SCROW nRow; | ||||
1559 | SCROW nThisRow; | ||||
1560 | bool bFirstUse = true; | ||||
1561 | |||||
1562 | Search( nStartRow, nIndex ); | ||||
1563 | nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
1564 | while ( nThisRow <= nEndRow ) | ||||
1565 | { | ||||
1566 | pOldPattern = mvData[nIndex].pPattern; | ||||
1567 | if (pOldPattern != pWantedPattern) // FIXME: else-branch? | ||||
1568 | { | ||||
1569 | if (nThisRow < nStartRow) nThisRow = nStartRow; | ||||
1570 | nRow = mvData[nIndex].nEndRow; | ||||
1571 | SCROW nAttrRow = std::min( nRow, nEndRow ); | ||||
1572 | pItem = &pOldPattern->GetItem( ATTR_MERGE_FLAG ); | ||||
1573 | |||||
1574 | if (pItem->IsOverlapped() || pItem->HasAutoFilter()) | ||||
1575 | { | ||||
1576 | // default-constructing a ScPatternAttr for DeleteArea doesn't work | ||||
1577 | // because it would have no cell style information. | ||||
1578 | // Instead, the document's GetDefPattern is copied. Since it is passed as | ||||
1579 | // pWantedPattern, no special treatment of default is needed here anymore. | ||||
1580 | std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pWantedPattern )); | ||||
1581 | pNewPattern->GetItemSet().Put( *pItem ); | ||||
1582 | SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true ); | ||||
1583 | } | ||||
1584 | else | ||||
1585 | { | ||||
1586 | if ( !bDefault ) | ||||
1587 | { | ||||
1588 | if (bFirstUse) | ||||
1589 | bFirstUse = false; | ||||
1590 | else | ||||
1591 | // it's in the pool | ||||
1592 | rDocument.GetPool()->Put( *pWantedPattern ); | ||||
1593 | } | ||||
1594 | SetPatternArea( nThisRow, nAttrRow, pWantedPattern ); | ||||
1595 | } | ||||
1596 | |||||
1597 | Search( nThisRow, nIndex ); // data changed | ||||
1598 | } | ||||
1599 | |||||
1600 | ++nIndex; | ||||
1601 | nThisRow = mvData[nIndex-1].nEndRow+1; | ||||
1602 | } | ||||
1603 | } | ||||
1604 | |||||
1605 | bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags ) | ||||
1606 | { | ||||
1607 | SetDefaultIfNotInit(); | ||||
1608 | const ScPatternAttr* pOldPattern; | ||||
1609 | |||||
1610 | ScMF nOldValue; | ||||
1611 | SCSIZE nIndex; | ||||
1612 | SCROW nRow; | ||||
1613 | SCROW nThisRow; | ||||
1614 | bool bChanged = false; | ||||
1615 | |||||
1616 | Search( nStartRow, nIndex ); | ||||
1617 | nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
1618 | if (nThisRow < nStartRow) nThisRow = nStartRow; | ||||
1619 | |||||
1620 | while ( nThisRow <= nEndRow ) | ||||
1621 | { | ||||
1622 | pOldPattern = mvData[nIndex].pPattern; | ||||
1623 | nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue(); | ||||
1624 | if ( (nOldValue | nFlags) != nOldValue ) | ||||
1625 | { | ||||
1626 | nRow = mvData[nIndex].nEndRow; | ||||
1627 | SCROW nAttrRow = std::min( nRow, nEndRow ); | ||||
1628 | auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern); | ||||
1629 | pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) ); | ||||
1630 | SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true ); | ||||
1631 | Search( nThisRow, nIndex ); // data changed | ||||
1632 | bChanged = true; | ||||
1633 | } | ||||
1634 | |||||
1635 | ++nIndex; | ||||
1636 | nThisRow = mvData[nIndex-1].nEndRow+1; | ||||
1637 | } | ||||
1638 | |||||
1639 | return bChanged; | ||||
1640 | } | ||||
1641 | |||||
1642 | bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags ) | ||||
1643 | { | ||||
1644 | SetDefaultIfNotInit(); | ||||
1645 | const ScPatternAttr* pOldPattern; | ||||
1646 | |||||
1647 | ScMF nOldValue; | ||||
1648 | SCSIZE nIndex; | ||||
1649 | SCROW nRow; | ||||
1650 | SCROW nThisRow; | ||||
1651 | bool bChanged = false; | ||||
1652 | |||||
1653 | Search( nStartRow, nIndex ); | ||||
1654 | nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
1655 | if (nThisRow < nStartRow) nThisRow = nStartRow; | ||||
1656 | |||||
1657 | while ( nThisRow <= nEndRow ) | ||||
1658 | { | ||||
1659 | pOldPattern = mvData[nIndex].pPattern; | ||||
1660 | nOldValue = pOldPattern->GetItem( ATTR_MERGE_FLAG ).GetValue(); | ||||
1661 | if ( (nOldValue & ~nFlags) != nOldValue ) | ||||
1662 | { | ||||
1663 | nRow = mvData[nIndex].nEndRow; | ||||
1664 | SCROW nAttrRow = std::min( nRow, nEndRow ); | ||||
1665 | auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern); | ||||
1666 | pNewPattern->GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) ); | ||||
1667 | SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true ); | ||||
1668 | Search( nThisRow, nIndex ); // data changed | ||||
1669 | bChanged = true; | ||||
1670 | } | ||||
1671 | |||||
1672 | ++nIndex; | ||||
1673 | nThisRow = mvData[nIndex-1].nEndRow+1; | ||||
1674 | } | ||||
1675 | |||||
1676 | return bChanged; | ||||
1677 | } | ||||
1678 | |||||
1679 | void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich ) | ||||
1680 | { | ||||
1681 | SetDefaultIfNotInit(); | ||||
1682 | SCSIZE nIndex; | ||||
1683 | SCROW nRow; | ||||
1684 | SCROW nThisRow; | ||||
1685 | |||||
1686 | Search( nStartRow, nIndex ); | ||||
1687 | nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
1688 | if (nThisRow < nStartRow) nThisRow = nStartRow; | ||||
1689 | |||||
1690 | while ( nThisRow <= nEndRow ) | ||||
1691 | { | ||||
1692 | const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern; | ||||
1693 | if ( pOldPattern->HasItemsSet( pWhich ) ) | ||||
1694 | { | ||||
1695 | auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern); | ||||
1696 | pNewPattern->ClearItems( pWhich ); | ||||
1697 | |||||
1698 | nRow = mvData[nIndex].nEndRow; | ||||
1699 | SCROW nAttrRow = std::min( nRow, nEndRow ); | ||||
1700 | SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true ); | ||||
1701 | Search( nThisRow, nIndex ); // data changed | ||||
1702 | } | ||||
1703 | |||||
1704 | ++nIndex; | ||||
1705 | nThisRow = mvData[nIndex-1].nEndRow+1; | ||||
1706 | } | ||||
1707 | } | ||||
1708 | |||||
1709 | void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement ) | ||||
1710 | { | ||||
1711 | SetDefaultIfNotInit(); | ||||
1712 | SCSIZE nIndex; | ||||
1713 | Search( nStartRow, nIndex ); | ||||
1714 | SCROW nThisStart = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
1715 | if (nThisStart < nStartRow) nThisStart = nStartRow; | ||||
1716 | |||||
1717 | while ( nThisStart <= nEndRow ) | ||||
1718 | { | ||||
1719 | const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern; | ||||
1720 | const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); | ||||
1721 | const SfxPoolItem* pItem; | ||||
1722 | |||||
1723 | bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, false, &pItem ) != SfxItemState::SET | ||||
1724 | || (static_cast<const SvxHorJustifyItem*>(pItem)->GetValue() != SvxCellHorJustify::Left && | ||||
1725 | static_cast<const SvxHorJustifyItem*>(pItem)->GetValue() != SvxCellHorJustify::Right )); | ||||
1726 | sal_uInt16 nOldValue = rOldSet.Get( ATTR_INDENT ).GetValue(); | ||||
1727 | sal_uInt16 nNewValue = nOldValue; | ||||
1728 | // To keep Increment indent from running outside the cell1659 | ||||
1729 | long nColWidth = static_cast<long>(rDocument.GetColWidth(nCol,nTab)); | ||||
1730 | if ( bIncrement ) | ||||
1731 | { | ||||
1732 | if ( nNewValue < nColWidth-SC_INDENT_STEP200 ) | ||||
1733 | { | ||||
1734 | nNewValue += SC_INDENT_STEP200; | ||||
1735 | if ( nNewValue > nColWidth-SC_INDENT_STEP200 ) nNewValue = nColWidth-SC_INDENT_STEP200; | ||||
1736 | } | ||||
1737 | } | ||||
1738 | else | ||||
1739 | { | ||||
1740 | if ( nNewValue > 0 ) | ||||
1741 | { | ||||
1742 | if ( nNewValue > SC_INDENT_STEP200 ) | ||||
1743 | nNewValue -= SC_INDENT_STEP200; | ||||
1744 | else | ||||
1745 | nNewValue = 0; | ||||
1746 | } | ||||
1747 | } | ||||
1748 | |||||
1749 | if ( bNeedJust || nNewValue != nOldValue ) | ||||
1750 | { | ||||
1751 | SCROW nThisEnd = mvData[nIndex].nEndRow; | ||||
1752 | SCROW nAttrRow = std::min( nThisEnd, nEndRow ); | ||||
1753 | auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern); | ||||
1754 | pNewPattern->GetItemSet().Put( ScIndentItem( nNewValue ) ); | ||||
1755 | if ( bNeedJust ) | ||||
1756 | pNewPattern->GetItemSet().Put( | ||||
1757 | SvxHorJustifyItem( SvxCellHorJustify::Left, ATTR_HOR_JUSTIFY ) ); | ||||
1758 | SetPatternArea( nThisStart, nAttrRow, std::move(pNewPattern), true ); | ||||
1759 | |||||
1760 | nThisStart = nThisEnd + 1; | ||||
1761 | Search( nThisStart, nIndex ); // data changed | ||||
1762 | } | ||||
1763 | else | ||||
1764 | { | ||||
1765 | nThisStart = mvData[nIndex].nEndRow + 1; | ||||
1766 | ++nIndex; | ||||
1767 | } | ||||
1768 | } | ||||
1769 | } | ||||
1770 | |||||
1771 | SCROW ScAttrArray::GetNextUnprotected( SCROW nRow, bool bUp ) const | ||||
1772 | { | ||||
1773 | long nRet = nRow; | ||||
1774 | if (rDocument.ValidRow(nRow)) | ||||
1775 | { | ||||
1776 | if ( mvData.empty() ) | ||||
1777 | { | ||||
1778 | if ( bUp ) | ||||
1779 | return -1; | ||||
1780 | else | ||||
1781 | return rDocument.MaxRow()+1; | ||||
1782 | } | ||||
1783 | |||||
1784 | SCSIZE nIndex; | ||||
1785 | Search(nRow, nIndex); | ||||
1786 | while (mvData[nIndex].pPattern-> | ||||
1787 | GetItem(ATTR_PROTECTION).GetProtection()) | ||||
1788 | { | ||||
1789 | if (bUp) | ||||
1790 | { | ||||
1791 | if (nIndex==0) | ||||
1792 | return -1; // not found | ||||
1793 | --nIndex; | ||||
1794 | nRet = mvData[nIndex].nEndRow; | ||||
1795 | } | ||||
1796 | else | ||||
1797 | { | ||||
1798 | nRet = mvData[nIndex].nEndRow+1; | ||||
1799 | ++nIndex; | ||||
1800 | if (nIndex >= mvData.size()) | ||||
1801 | return rDocument.MaxRow()+1; // not found | ||||
1802 | } | ||||
1803 | } | ||||
1804 | } | ||||
1805 | return nRet; | ||||
1806 | } | ||||
1807 | |||||
1808 | void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset ) | ||||
1809 | { | ||||
1810 | SetDefaultIfNotInit(); | ||||
1811 | SCROW nStart = 0; | ||||
1812 | SCSIZE nPos = 0; | ||||
1813 | while (nPos < mvData.size()) | ||||
1814 | { | ||||
1815 | SCROW nEnd = mvData[nPos].nEndRow; | ||||
1816 | if (mvData[nPos].pPattern->GetStyleSheet() == pStyleSheet) | ||||
1817 | { | ||||
1818 | rUsedRows.setTrue(nStart, nEnd); | ||||
1819 | |||||
1820 | if (bReset) | ||||
1821 | { | ||||
1822 | std::unique_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*mvData[nPos].pPattern)); | ||||
1823 | rDocument.GetPool()->Remove(*mvData[nPos].pPattern); | ||||
1824 | pNewPattern->SetStyleSheet( static_cast<ScStyleSheet*>( | ||||
1825 | rDocument.GetStyleSheetPool()-> | ||||
1826 | Find( ScResId(STR_STYLENAME_STANDARD_CELLreinterpret_cast<char const *>("STR_STYLENAME_STANDARD" "\004" u8"Default Cell Style")), | ||||
1827 | SfxStyleFamily::Para, | ||||
1828 | SfxStyleSearchBits::Auto | SfxStyleSearchBits::ScStandard ) ) ); | ||||
1829 | mvData[nPos].pPattern = &rDocument.GetPool()->Put(*pNewPattern); | ||||
1830 | pNewPattern.reset(); | ||||
1831 | |||||
1832 | if (Concat(nPos)) | ||||
1833 | { | ||||
1834 | Search(nStart, nPos); | ||||
1835 | --nPos; // because ++ at end | ||||
1836 | } | ||||
1837 | } | ||||
1838 | } | ||||
1839 | nStart = nEnd + 1; | ||||
1840 | ++nPos; | ||||
1841 | } | ||||
1842 | } | ||||
1843 | |||||
1844 | bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle ) const | ||||
1845 | { | ||||
1846 | if ( mvData.empty() ) | ||||
1847 | { | ||||
1848 | const ScStyleSheet* pStyle = rDocument.GetDefPattern()->GetStyleSheet(); | ||||
1849 | if ( pStyle ) | ||||
1850 | { | ||||
1851 | pStyle->SetUsage( ScStyleSheet::Usage::USED ); | ||||
1852 | if ( pStyle == &rStyle ) | ||||
1853 | return true; | ||||
1854 | } | ||||
1855 | return false; | ||||
1856 | } | ||||
1857 | |||||
1858 | bool bIsUsed = false; | ||||
1859 | SCSIZE nPos = 0; | ||||
1860 | |||||
1861 | while ( nPos < mvData.size() ) | ||||
1862 | { | ||||
1863 | const ScStyleSheet* pStyle = mvData[nPos].pPattern->GetStyleSheet(); | ||||
1864 | if ( pStyle ) | ||||
1865 | { | ||||
1866 | pStyle->SetUsage( ScStyleSheet::Usage::USED ); | ||||
1867 | if ( pStyle == &rStyle ) | ||||
1868 | { | ||||
1869 | bIsUsed = true; | ||||
1870 | } | ||||
1871 | } | ||||
1872 | nPos++; | ||||
1873 | } | ||||
1874 | |||||
1875 | return bIsUsed; | ||||
1876 | } | ||||
1877 | |||||
1878 | bool ScAttrArray::IsEmpty() const | ||||
1879 | { | ||||
1880 | if ( mvData.empty() ) | ||||
1881 | return true; | ||||
1882 | |||||
1883 | if (mvData.size() == 1) | ||||
1884 | { | ||||
1885 | return mvData[0].pPattern == rDocument.GetDefPattern(); | ||||
1886 | } | ||||
1887 | else | ||||
1888 | return false; | ||||
1889 | } | ||||
1890 | |||||
1891 | bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const | ||||
1892 | { | ||||
1893 | if ( mvData.empty() ) | ||||
1894 | return false; | ||||
1895 | |||||
1896 | bool bFound = false; | ||||
1897 | SCSIZE nStart = 0; | ||||
1898 | |||||
1899 | // Skip first entry if more than 1 row. | ||||
1900 | // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr. | ||||
1901 | |||||
1902 | SCSIZE nVisStart = 1; | ||||
1903 | while ( nVisStart < mvData.size() && mvData[nVisStart].pPattern->IsVisibleEqual(*mvData[nVisStart-1].pPattern) ) | ||||
1904 | ++nVisStart; | ||||
1905 | if ( nVisStart >= mvData.size() || mvData[nVisStart-1].nEndRow > 0 ) // more than 1 row? | ||||
1906 | nStart = nVisStart; | ||||
1907 | |||||
1908 | while ( nStart < mvData.size() && !bFound ) | ||||
1909 | { | ||||
1910 | if ( mvData[nStart].pPattern->IsVisible() ) | ||||
1911 | { | ||||
1912 | rFirstRow = nStart ? ( mvData[nStart-1].nEndRow + 1 ) : 0; | ||||
1913 | bFound = true; | ||||
1914 | } | ||||
1915 | else | ||||
1916 | ++nStart; | ||||
1917 | } | ||||
1918 | |||||
1919 | return bFound; | ||||
1920 | } | ||||
1921 | |||||
1922 | // size (rows) of a range of attributes after cell content where the search is stopped | ||||
1923 | // (more than a default page size, 2*42 because it's as good as any number) | ||||
1924 | |||||
1925 | const SCROW SC_VISATTR_STOP = 84; | ||||
1926 | |||||
1927 | bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const | ||||
1928 | { | ||||
1929 | if ( mvData.empty() ) | ||||
1930 | { | ||||
1931 | rLastRow = nLastData; | ||||
1932 | return false; | ||||
1933 | } | ||||
1934 | |||||
1935 | // #i30830# changed behavior: | ||||
1936 | // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows | ||||
1937 | // below the last content cell | ||||
1938 | |||||
1939 | if ( nLastData == rDocument.MaxRow() ) | ||||
1940 | { | ||||
1941 | rLastRow = rDocument.MaxRow(); // can't look for attributes below rDocument.MaxRow() | ||||
1942 | return true; | ||||
1943 | } | ||||
1944 | |||||
1945 | // Quick check: last data row in or immediately preceding a run that is the | ||||
1946 | // last attribution down to the end, e.g. default style or column style. | ||||
1947 | SCSIZE nPos = mvData.size() - 1; | ||||
1948 | SCROW nStartRow = (nPos ? mvData[nPos-1].nEndRow + 1 : 0); | ||||
1949 | if (nStartRow <= nLastData + 1) | ||||
1950 | { | ||||
1951 | // Ignore here a few rows if data happens to end within | ||||
1952 | // SC_VISATTR_STOP rows before rDocument.MaxRow(). | ||||
1953 | rLastRow = nLastData; | ||||
1954 | return false; | ||||
1955 | } | ||||
1956 | |||||
1957 | // Find a run below last data row. | ||||
1958 | bool bFound = false; | ||||
1959 | Search( nLastData, nPos ); | ||||
1960 | while ( nPos < mvData.size() ) | ||||
1961 | { | ||||
1962 | // find range of visually equal formats | ||||
1963 | SCSIZE nEndPos = nPos; | ||||
1964 | while ( nEndPos < mvData.size()-1 && | ||||
1965 | mvData[nEndPos].pPattern->IsVisibleEqual( *mvData[nEndPos+1].pPattern)) | ||||
1966 | ++nEndPos; | ||||
1967 | SCROW nAttrStartRow = ( nPos > 0 ) ? ( mvData[nPos-1].nEndRow + 1 ) : 0; | ||||
1968 | if ( nAttrStartRow <= nLastData ) | ||||
1969 | nAttrStartRow = nLastData + 1; | ||||
1970 | SCROW nAttrSize = mvData[nEndPos].nEndRow + 1 - nAttrStartRow; | ||||
1971 | if ( nAttrSize >= SC_VISATTR_STOP ) | ||||
1972 | break; // while, ignore this range and below | ||||
1973 | else if ( mvData[nEndPos].pPattern->IsVisible() ) | ||||
1974 | { | ||||
1975 | rLastRow = mvData[nEndPos].nEndRow; | ||||
1976 | bFound = true; | ||||
1977 | } | ||||
1978 | nPos = nEndPos + 1; | ||||
1979 | } | ||||
1980 | |||||
1981 | return bFound; | ||||
1982 | } | ||||
1983 | |||||
1984 | bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const | ||||
1985 | { | ||||
1986 | if ( mvData.empty() ) | ||||
1987 | return rDocument.GetDefPattern()->IsVisible(); | ||||
1988 | |||||
1989 | SCSIZE nIndex; | ||||
1990 | Search( nStartRow, nIndex ); | ||||
1991 | SCROW nThisStart = nStartRow; | ||||
1992 | bool bFound = false; | ||||
1993 | while ( nIndex < mvData.size() && nThisStart <= nEndRow && !bFound ) | ||||
1994 | { | ||||
1995 | if ( mvData[nIndex].pPattern->IsVisible() ) | ||||
1996 | bFound = true; | ||||
1997 | |||||
1998 | nThisStart = mvData[nIndex].nEndRow + 1; | ||||
1999 | ++nIndex; | ||||
2000 | } | ||||
2001 | |||||
2002 | return bFound; | ||||
2003 | } | ||||
2004 | |||||
2005 | bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther, | ||||
2006 | SCROW nStartRow, SCROW nEndRow ) const | ||||
2007 | { | ||||
2008 | if ( mvData.empty() && rOther.mvData.empty() ) | ||||
2009 | { | ||||
2010 | const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern(); | ||||
2011 | const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern(); | ||||
2012 | return ( pDefPattern1 == pDefPattern2 || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) ); | ||||
2013 | } | ||||
2014 | |||||
2015 | { | ||||
2016 | const ScAttrArray* pNonDefault = nullptr; | ||||
2017 | const ScPatternAttr* pDefPattern = nullptr; | ||||
2018 | bool bDefNonDefCase = false; | ||||
2019 | if ( mvData.empty() && !rOther.mvData.empty() ) | ||||
2020 | { | ||||
2021 | pNonDefault = &rOther; | ||||
2022 | pDefPattern = rDocument.GetDefPattern(); | ||||
2023 | bDefNonDefCase = true; | ||||
2024 | } | ||||
2025 | else if ( !mvData.empty() && rOther.mvData.empty() ) | ||||
2026 | { | ||||
2027 | pNonDefault = this; | ||||
2028 | pDefPattern = rOther.rDocument.GetDefPattern(); | ||||
2029 | bDefNonDefCase = true; | ||||
2030 | } | ||||
2031 | |||||
2032 | if ( bDefNonDefCase ) | ||||
2033 | { | ||||
2034 | bool bEqual = true; | ||||
2035 | SCSIZE nPos = 0; | ||||
2036 | if ( nStartRow > 0 ) | ||||
2037 | pNonDefault->Search( nStartRow, nPos ); | ||||
2038 | |||||
2039 | while ( nPos < pNonDefault->Count() && bEqual ) | ||||
2040 | { | ||||
2041 | const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern; | ||||
2042 | bEqual = ( pNonDefPattern == pDefPattern || | ||||
2043 | pNonDefPattern->IsVisibleEqual( *pDefPattern ) ); | ||||
2044 | |||||
2045 | if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break; | ||||
2046 | ++nPos; | ||||
2047 | } | ||||
2048 | return bEqual; | ||||
2049 | } | ||||
2050 | } | ||||
2051 | |||||
2052 | bool bEqual = true; | ||||
2053 | SCSIZE nThisPos = 0; | ||||
2054 | SCSIZE nOtherPos = 0; | ||||
2055 | if ( nStartRow > 0 ) | ||||
2056 | { | ||||
2057 | Search( nStartRow, nThisPos ); | ||||
2058 | rOther.Search( nStartRow, nOtherPos ); | ||||
2059 | } | ||||
2060 | |||||
2061 | while ( nThisPos<mvData.size() && nOtherPos<rOther.Count() && bEqual ) | ||||
2062 | { | ||||
2063 | SCROW nThisRow = mvData[nThisPos].nEndRow; | ||||
2064 | SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow; | ||||
2065 | const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern; | ||||
2066 | const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern; | ||||
2067 | bEqual = ( pThisPattern == pOtherPattern || | ||||
2068 | pThisPattern->IsVisibleEqual(*pOtherPattern) ); | ||||
2069 | |||||
2070 | if ( nThisRow >= nOtherRow ) | ||||
2071 | { | ||||
2072 | if ( nOtherRow >= nEndRow ) break; | ||||
2073 | ++nOtherPos; | ||||
2074 | } | ||||
2075 | if ( nThisRow <= nOtherRow ) | ||||
2076 | { | ||||
2077 | if ( nThisRow >= nEndRow ) break; | ||||
2078 | ++nThisPos; | ||||
2079 | } | ||||
2080 | } | ||||
2081 | |||||
2082 | return bEqual; | ||||
2083 | } | ||||
2084 | |||||
2085 | bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const | ||||
2086 | { | ||||
2087 | // summarised with IsVisibleEqual | ||||
2088 | if ( mvData.empty() && rOther.mvData.empty() ) | ||||
2089 | { | ||||
2090 | const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern(); | ||||
2091 | const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern(); | ||||
2092 | return ( pDefPattern1 == pDefPattern2 ); | ||||
2093 | } | ||||
2094 | |||||
2095 | { | ||||
2096 | const ScAttrArray* pNonDefault = nullptr; | ||||
2097 | const ScPatternAttr* pDefPattern = nullptr; | ||||
2098 | bool bDefNonDefCase = false; | ||||
2099 | if ( mvData.empty() && !rOther.mvData.empty() ) | ||||
2100 | { | ||||
2101 | pNonDefault = &rOther; | ||||
2102 | pDefPattern = rDocument.GetDefPattern(); | ||||
2103 | bDefNonDefCase = true; | ||||
2104 | } | ||||
2105 | else if ( !mvData.empty() && rOther.mvData.empty() ) | ||||
2106 | { | ||||
2107 | pNonDefault = this; | ||||
2108 | pDefPattern = rOther.rDocument.GetDefPattern(); | ||||
2109 | bDefNonDefCase = true; | ||||
2110 | } | ||||
2111 | |||||
2112 | if ( bDefNonDefCase ) | ||||
2113 | { | ||||
2114 | bool bEqual = true; | ||||
2115 | SCSIZE nPos = 0; | ||||
2116 | if ( nStartRow > 0 ) | ||||
2117 | pNonDefault->Search( nStartRow, nPos ); | ||||
2118 | |||||
2119 | while ( nPos < pNonDefault->Count() && bEqual ) | ||||
2120 | { | ||||
2121 | const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern; | ||||
2122 | bEqual = ( pNonDefPattern == pDefPattern ); | ||||
2123 | |||||
2124 | if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break; | ||||
2125 | ++nPos; | ||||
2126 | } | ||||
2127 | return bEqual; | ||||
2128 | } | ||||
2129 | } | ||||
2130 | |||||
2131 | bool bEqual = true; | ||||
2132 | SCSIZE nThisPos = 0; | ||||
2133 | SCSIZE nOtherPos = 0; | ||||
2134 | if ( nStartRow > 0 ) | ||||
2135 | { | ||||
2136 | Search( nStartRow, nThisPos ); | ||||
2137 | rOther.Search( nStartRow, nOtherPos ); | ||||
2138 | } | ||||
2139 | |||||
2140 | while ( nThisPos<mvData.size() && nOtherPos<rOther.Count() && bEqual ) | ||||
2141 | { | ||||
2142 | SCROW nThisRow = mvData[nThisPos].nEndRow; | ||||
2143 | SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow; | ||||
2144 | const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern; | ||||
2145 | const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern; | ||||
2146 | bEqual = ( pThisPattern == pOtherPattern ); | ||||
2147 | |||||
2148 | if ( nThisRow >= nOtherRow ) | ||||
2149 | { | ||||
2150 | if ( nOtherRow >= nEndRow ) break; | ||||
2151 | ++nOtherPos; | ||||
2152 | } | ||||
2153 | if ( nThisRow <= nOtherRow ) | ||||
2154 | { | ||||
2155 | if ( nThisRow >= nEndRow ) break; | ||||
2156 | ++nThisPos; | ||||
2157 | } | ||||
2158 | } | ||||
2159 | |||||
2160 | return bEqual; | ||||
2161 | } | ||||
2162 | |||||
2163 | bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const | ||||
2164 | { | ||||
2165 | // Horizontal aggregate are not allowed to be moved out; if whole summary, | ||||
2166 | // here is not recognized | ||||
2167 | |||||
2168 | bool bTest = true; | ||||
2169 | if (!IsEmpty()) | ||||
2170 | { | ||||
2171 | SCSIZE nIndex = 0; | ||||
2172 | if ( nStartRow > 0 ) | ||||
2173 | Search( nStartRow, nIndex ); | ||||
2174 | |||||
2175 | for ( ; nIndex < mvData.size(); nIndex++ ) | ||||
2176 | { | ||||
2177 | if ( mvData[nIndex].pPattern-> | ||||
2178 | GetItem(ATTR_MERGE_FLAG).IsHorOverlapped() ) | ||||
2179 | { | ||||
2180 | bTest = false; // may not be pushed out | ||||
2181 | break; | ||||
2182 | } | ||||
2183 | if ( mvData[nIndex].nEndRow >= nEndRow ) // end of range | ||||
2184 | break; | ||||
2185 | } | ||||
2186 | } | ||||
2187 | return bTest; | ||||
2188 | } | ||||
2189 | |||||
2190 | bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const | ||||
2191 | { | ||||
2192 | // if 1st row pushed out is vertically overlapped, summary would be broken | ||||
2193 | |||||
2194 | // rDocument.MaxRow() + 1 - nSize = 1st row pushed out | ||||
2195 | |||||
2196 | if ( mvData.empty() ) | ||||
2197 | return !rDocument.GetDefPattern()-> | ||||
2198 | GetItem(ATTR_MERGE_FLAG).IsVerOverlapped(); | ||||
2199 | |||||
2200 | SCSIZE nFirstLost = mvData.size()-1; | ||||
2201 | while ( nFirstLost && mvData[nFirstLost-1].nEndRow >= sal::static_int_cast<SCROW>(rDocument.MaxRow() + 1 - nSize) ) | ||||
2202 | --nFirstLost; | ||||
2203 | |||||
2204 | return !mvData[nFirstLost].pPattern-> | ||||
2205 | GetItem(ATTR_MERGE_FLAG).IsVerOverlapped(); | ||||
2206 | } | ||||
2207 | |||||
2208 | void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize ) | ||||
2209 | { | ||||
2210 | SetDefaultIfNotInit(); | ||||
2211 | |||||
2212 | SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // expand predecessor | ||||
2213 | SCSIZE nIndex; | ||||
2214 | Search( nSearch, nIndex ); | ||||
2215 | |||||
2216 | // set ScMergeAttr may not be extended (so behind delete again) | ||||
2217 | |||||
2218 | bool bDoMerge = mvData[nIndex].pPattern->GetItem(ATTR_MERGE).IsMerged(); | ||||
2219 | |||||
2220 | assert( !bDoMerge || nCol != -1 )(static_cast <bool> (!bDoMerge || nCol != -1) ? void (0 ) : __assert_fail ("!bDoMerge || nCol != -1", "/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" , 2220, __extension__ __PRETTY_FUNCTION__)); | ||||
2221 | |||||
2222 | SCSIZE nRemove = 0; | ||||
2223 | SCSIZE i; | ||||
2224 | for (i = nIndex; i < mvData.size()-1; i++) | ||||
2225 | { | ||||
2226 | SCROW nNew = mvData[i].nEndRow + nSize; | ||||
2227 | if ( nNew >= rDocument.MaxRow() ) // at end? | ||||
2228 | { | ||||
2229 | nNew = rDocument.MaxRow(); | ||||
2230 | if (!nRemove) | ||||
2231 | nRemove = i+1; // remove the following? | ||||
2232 | } | ||||
2233 | mvData[i].nEndRow = nNew; | ||||
2234 | } | ||||
2235 | |||||
2236 | // Remove entries at end ? | ||||
2237 | |||||
2238 | if (nRemove && nRemove < mvData.size()) | ||||
2239 | DeleteRange( nRemove, mvData.size()-1 ); | ||||
2240 | |||||
2241 | if (bDoMerge) // extensively repair (again) ScMergeAttr | ||||
2242 | { | ||||
2243 | // ApplyAttr for areas | ||||
2244 | |||||
2245 | const SfxPoolItem& rDef = rDocument.GetPool()->GetDefaultItem( ATTR_MERGE ); | ||||
2246 | for (SCSIZE nAdd=0; nAdd<nSize; nAdd++) | ||||
2247 | rDocument.ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef ); | ||||
2248 | |||||
2249 | // reply inserts in this area not summarized | ||||
2250 | } | ||||
2251 | |||||
2252 | // Don't duplicate the merge flags in the inserted row. | ||||
2253 | // #i108488# ScMF::Scenario has to be allowed. | ||||
2254 | RemoveFlags( nStartRow, nStartRow+nSize-1, ScMF::Hor | ScMF::Ver | ScMF::Auto | ScMF::Button ); | ||||
2255 | } | ||||
2256 | |||||
2257 | void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize ) | ||||
2258 | { | ||||
2259 | SetDefaultIfNotInit(); | ||||
2260 | bool bFirst=true; | ||||
2261 | SCSIZE nStartIndex = 0; | ||||
2262 | SCSIZE nEndIndex = 0; | ||||
2263 | SCSIZE i; | ||||
2264 | |||||
2265 | for ( i = 0; i < mvData.size()-1; i++) | ||||
2266 | if (mvData[i].nEndRow >= nStartRow && mvData[i].nEndRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1)) | ||||
2267 | { | ||||
2268 | if (bFirst) | ||||
2269 | { | ||||
2270 | nStartIndex = i; | ||||
2271 | bFirst = false; | ||||
2272 | } | ||||
2273 | nEndIndex = i; | ||||
2274 | } | ||||
2275 | if (!bFirst) | ||||
2276 | { | ||||
2277 | SCROW nStart; | ||||
2278 | if (nStartIndex==0) | ||||
2279 | nStart = 0; | ||||
2280 | else | ||||
2281 | nStart = mvData[nStartIndex-1].nEndRow + 1; | ||||
2282 | |||||
2283 | if (nStart < nStartRow) | ||||
2284 | { | ||||
2285 | mvData[nStartIndex].nEndRow = nStartRow - 1; | ||||
2286 | ++nStartIndex; | ||||
2287 | } | ||||
2288 | if (nEndIndex >= nStartIndex) | ||||
2289 | { | ||||
2290 | DeleteRange( nStartIndex, nEndIndex ); | ||||
2291 | if (nStartIndex > 0) | ||||
2292 | if ( mvData[nStartIndex-1].pPattern == mvData[nStartIndex].pPattern ) | ||||
2293 | DeleteRange( nStartIndex-1, nStartIndex-1 ); | ||||
2294 | } | ||||
2295 | } | ||||
2296 | for (i = 0; i < mvData.size()-1; i++) | ||||
2297 | if (mvData[i].nEndRow >= nStartRow) | ||||
2298 | mvData[i].nEndRow -= nSize; | ||||
2299 | |||||
2300 | // Below does not follow the pattern to detect pressure ranges; | ||||
2301 | // instead, only remove merge flags. | ||||
2302 | RemoveFlags( rDocument.MaxRow()-nSize+1, rDocument.MaxRow(), ScMF::Hor | ScMF::Ver | ScMF::Auto ); | ||||
2303 | } | ||||
2304 | |||||
2305 | void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex ) | ||||
2306 | { | ||||
2307 | SetDefaultIfNotInit(); | ||||
2308 | ScDocumentPool* pDocPool = rDocument.GetPool(); | ||||
2309 | for (SCSIZE i = nStartIndex; i <= nEndIndex; i++) | ||||
2310 | pDocPool->Remove(*mvData[i].pPattern); | ||||
2311 | |||||
2312 | mvData.erase(mvData.begin() + nStartIndex, mvData.begin() + nEndIndex + 1); | ||||
2313 | } | ||||
2314 | |||||
2315 | void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow) | ||||
2316 | { | ||||
2317 | SetDefaultIfNotInit(); | ||||
2318 | if ( nCol != -1 ) | ||||
2319 | RemoveAreaMerge( nStartRow, nEndRow ); // remove from combined flags | ||||
2320 | |||||
2321 | if ( !HasAttrib( nStartRow, nEndRow, HasAttrFlags::Overlapped | HasAttrFlags::AutoFilter) ) | ||||
2322 | SetPatternArea( nStartRow, nEndRow, rDocument.GetDefPattern() ); | ||||
2323 | else | ||||
2324 | SetPatternAreaSafe( nStartRow, nEndRow, rDocument.GetDefPattern(), true ); // leave merge flags | ||||
2325 | } | ||||
2326 | |||||
2327 | void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow) | ||||
2328 | { | ||||
2329 | SetDefaultIfNotInit(); | ||||
2330 | const ScPatternAttr* pDefPattern = rDocument.GetDefPattern(); | ||||
2331 | |||||
2332 | SCSIZE nIndex; | ||||
2333 | SCROW nRow; | ||||
2334 | SCROW nThisRow; | ||||
2335 | |||||
2336 | Search( nStartRow, nIndex ); | ||||
2337 | nThisRow = (nIndex>0) ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
2338 | if (nThisRow < nStartRow) nThisRow = nStartRow; | ||||
2339 | |||||
2340 | while ( nThisRow <= nEndRow ) | ||||
2341 | { | ||||
2342 | const ScPatternAttr* pOldPattern = mvData[nIndex].pPattern; | ||||
2343 | |||||
2344 | if ( pOldPattern->GetItemSet().Count() ) // hard attributes ? | ||||
2345 | { | ||||
2346 | nRow = mvData[nIndex].nEndRow; | ||||
2347 | SCROW nAttrRow = std::min( nRow, nEndRow ); | ||||
2348 | |||||
2349 | auto pNewPattern = std::make_unique<ScPatternAttr>(*pOldPattern); | ||||
2350 | SfxItemSet& rSet = pNewPattern->GetItemSet(); | ||||
2351 | for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++) | ||||
2352 | if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG) | ||||
2353 | rSet.ClearItem(nId); | ||||
2354 | |||||
2355 | if ( *pNewPattern == *pDefPattern ) | ||||
2356 | SetPatternArea( nThisRow, nAttrRow, pDefPattern ); | ||||
2357 | else | ||||
2358 | SetPatternArea( nThisRow, nAttrRow, std::move(pNewPattern), true ); | ||||
2359 | |||||
2360 | Search( nThisRow, nIndex ); // data changed | ||||
2361 | } | ||||
2362 | |||||
2363 | ++nIndex; | ||||
2364 | nThisRow = mvData[nIndex-1].nEndRow+1; | ||||
2365 | } | ||||
2366 | } | ||||
2367 | |||||
2368 | /** | ||||
2369 | * Move within a document | ||||
2370 | */ | ||||
2371 | void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray) | ||||
2372 | { | ||||
2373 | SetDefaultIfNotInit(); | ||||
2374 | SCROW nStart = nStartRow; | ||||
2375 | for (SCSIZE i = 0; i < mvData.size(); i++) | ||||
2376 | { | ||||
2377 | if ((mvData[i].nEndRow >= nStartRow) && (i == 0 || mvData[i-1].nEndRow < nEndRow)) | ||||
2378 | { | ||||
2379 | // copy (bPutToPool=TRUE) | ||||
2380 | rAttrArray.SetPatternArea( nStart, std::min( mvData[i].nEndRow, nEndRow ), | ||||
2381 | mvData[i].pPattern, true ); | ||||
2382 | } | ||||
2383 | nStart = std::max( nStart, mvData[i].nEndRow + 1 ); | ||||
2384 | } | ||||
2385 | DeleteArea(nStartRow, nEndRow); | ||||
2386 | } | ||||
2387 | |||||
2388 | /** | ||||
2389 | * Copy between documents (Clipboard) | ||||
2390 | */ | ||||
2391 | void ScAttrArray::CopyArea( | ||||
2392 | SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, ScMF nStripFlags) const | ||||
2393 | { | ||||
2394 | nStartRow -= nDy; // Source | ||||
2395 | nEndRow -= nDy; | ||||
2396 | |||||
2397 | SCROW nDestStart = std::max(static_cast<long>(static_cast<long>(nStartRow) + nDy), long(0)); | ||||
2398 | SCROW nDestEnd = std::min(static_cast<long>(static_cast<long>(nEndRow) + nDy), long(rDocument.MaxRow())); | ||||
2399 | |||||
2400 | ScDocumentPool* pSourceDocPool = rDocument.GetPool(); | ||||
2401 | ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool(); | ||||
2402 | bool bSamePool = (pSourceDocPool==pDestDocPool); | ||||
2403 | |||||
2404 | if ( mvData.empty() ) | ||||
2405 | { | ||||
2406 | const ScPatternAttr* pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN ); | ||||
2407 | rAttrArray.SetPatternArea(nDestStart, nDestEnd, pNewPattern); | ||||
2408 | return; | ||||
2409 | } | ||||
2410 | |||||
2411 | for (SCSIZE i = 0; (i < mvData.size()) && (nDestStart <= nDestEnd); i++) | ||||
2412 | { | ||||
2413 | if (mvData[i].nEndRow >= nStartRow) | ||||
2414 | { | ||||
2415 | const ScPatternAttr* pOldPattern = mvData[i].pPattern; | ||||
2416 | const ScPatternAttr* pNewPattern; | ||||
2417 | |||||
2418 | if (IsDefaultItem( pOldPattern )) | ||||
2419 | { | ||||
2420 | // default: nothing changed | ||||
2421 | |||||
2422 | pNewPattern = &pDestDocPool->GetDefaultItem( ATTR_PATTERN ); | ||||
2423 | } | ||||
2424 | else if ( nStripFlags != ScMF::NONE ) | ||||
2425 | { | ||||
2426 | std::unique_ptr<ScPatternAttr> pTmpPattern(new ScPatternAttr( *pOldPattern )); | ||||
2427 | ScMF nNewFlags = ScMF::NONE; | ||||
2428 | if ( nStripFlags != ScMF::All ) | ||||
2429 | nNewFlags = pTmpPattern->GetItem(ATTR_MERGE_FLAG).GetValue() & ~nStripFlags; | ||||
2430 | |||||
2431 | if ( nNewFlags != ScMF::NONE ) | ||||
2432 | pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) ); | ||||
2433 | else | ||||
2434 | pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG ); | ||||
2435 | |||||
2436 | if (bSamePool) | ||||
2437 | pNewPattern = &pDestDocPool->Put(*pTmpPattern); | ||||
2438 | else | ||||
2439 | pNewPattern = pTmpPattern->PutInPool( &rAttrArray.rDocument, &rDocument ); | ||||
2440 | } | ||||
2441 | else | ||||
2442 | { | ||||
2443 | if (bSamePool) | ||||
2444 | pNewPattern = &pDestDocPool->Put(*pOldPattern); | ||||
2445 | else | ||||
2446 | pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument ); | ||||
2447 | } | ||||
2448 | |||||
2449 | rAttrArray.SetPatternArea(nDestStart, | ||||
2450 | std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern); | ||||
2451 | } | ||||
2452 | |||||
2453 | // when pasting from clipboard and skipping filtered rows, the adjusted | ||||
2454 | // end position can be negative | ||||
2455 | nDestStart = std::max(static_cast<long>(nDestStart), static_cast<long>(mvData[i].nEndRow + nDy + 1)); | ||||
2456 | } | ||||
2457 | } | ||||
2458 | |||||
2459 | /** | ||||
2460 | * Leave flags | ||||
2461 | * summarized with CopyArea | ||||
2462 | */ | ||||
2463 | void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray ) | ||||
2464 | { | ||||
2465 | nStartRow -= nDy; // Source | ||||
2466 | nEndRow -= nDy; | ||||
2467 | |||||
2468 | SCROW nDestStart = std::max(static_cast<long>(static_cast<long>(nStartRow) + nDy), long(0)); | ||||
2469 | SCROW nDestEnd = std::min(static_cast<long>(static_cast<long>(nEndRow) + nDy), long(rDocument.MaxRow())); | ||||
2470 | |||||
2471 | if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HasAttrFlags::Overlapped ) ) | ||||
| |||||
2472 | { | ||||
2473 | CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray ); | ||||
2474 | return; | ||||
2475 | } | ||||
2476 | |||||
2477 | ScDocumentPool* pSourceDocPool = rDocument.GetPool(); | ||||
2478 | ScDocumentPool* pDestDocPool = rAttrArray.rDocument.GetPool(); | ||||
2479 | bool bSamePool = (pSourceDocPool==pDestDocPool); | ||||
2480 | |||||
2481 | if ( mvData.empty() ) | ||||
2482 | { | ||||
2483 | const ScPatternAttr* pNewPattern; | ||||
2484 | if (bSamePool
| ||||
2485 | pNewPattern = &pDestDocPool->Put(*rDocument.GetDefPattern()); | ||||
2486 | else | ||||
2487 | pNewPattern = rDocument.GetDefPattern()->PutInPool( &rAttrArray.rDocument, &rDocument ); | ||||
2488 | |||||
2489 | rAttrArray.SetPatternAreaSafe(nDestStart, nDestEnd, pNewPattern, false); | ||||
2490 | return; | ||||
2491 | } | ||||
2492 | |||||
2493 | |||||
2494 | for (SCSIZE i = 0; (i < mvData.size()) && (nDestStart <= nDestEnd); i++) | ||||
2495 | { | ||||
2496 | if (mvData[i].nEndRow >= nStartRow) | ||||
2497 | { | ||||
2498 | const ScPatternAttr* pOldPattern = mvData[i].pPattern; | ||||
2499 | const ScPatternAttr* pNewPattern; | ||||
2500 | |||||
2501 | if (bSamePool) | ||||
2502 | pNewPattern = &pDestDocPool->Put(*pOldPattern); | ||||
2503 | else | ||||
2504 | pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument ); | ||||
2505 | |||||
2506 | rAttrArray.SetPatternAreaSafe(nDestStart, | ||||
2507 | std::min(static_cast<SCROW>(mvData[i].nEndRow + nDy), nDestEnd), pNewPattern, false); | ||||
2508 | } | ||||
2509 | |||||
2510 | // when pasting from clipboard and skipping filtered rows, the adjusted | ||||
2511 | // end position can be negative | ||||
2512 | nDestStart = std::max(static_cast<long>(nDestStart), static_cast<long>(mvData[i].nEndRow + nDy + 1)); | ||||
2513 | } | ||||
2514 | } | ||||
2515 | |||||
2516 | SCROW ScAttrArray::SearchStyle( | ||||
2517 | SCROW nRow, const ScStyleSheet* pSearchStyle, bool bUp, | ||||
2518 | const ScMarkArray* pMarkArray) const | ||||
2519 | { | ||||
2520 | bool bFound = false; | ||||
2521 | |||||
2522 | if (pMarkArray) | ||||
2523 | { | ||||
2524 | nRow = pMarkArray->GetNextMarked( nRow, bUp ); | ||||
2525 | if (!rDocument.ValidRow(nRow)) | ||||
2526 | return nRow; | ||||
2527 | } | ||||
2528 | |||||
2529 | if ( mvData.empty() ) | ||||
2530 | { | ||||
2531 | if (rDocument.GetDefPattern()->GetStyleSheet() == pSearchStyle) | ||||
2532 | return nRow; | ||||
2533 | |||||
2534 | nRow = bUp ? -1 : rDocument.MaxRow() + 1; | ||||
2535 | return nRow; | ||||
2536 | } | ||||
2537 | |||||
2538 | SCSIZE nIndex; | ||||
2539 | Search(nRow, nIndex); | ||||
2540 | const ScPatternAttr* pPattern = mvData[nIndex].pPattern; | ||||
2541 | |||||
2542 | while (nIndex < mvData.size() && !bFound) | ||||
2543 | { | ||||
2544 | if (pPattern->GetStyleSheet() == pSearchStyle) | ||||
2545 | { | ||||
2546 | if (pMarkArray) | ||||
2547 | { | ||||
2548 | nRow = pMarkArray->GetNextMarked( nRow, bUp ); | ||||
2549 | SCROW nStart = nIndex ? mvData[nIndex-1].nEndRow+1 : 0; | ||||
2550 | if (nRow >= nStart && nRow <= mvData[nIndex].nEndRow) | ||||
2551 | bFound = true; | ||||
2552 | } | ||||
2553 | else | ||||
2554 | bFound = true; | ||||
2555 | } | ||||
2556 | |||||
2557 | if (!bFound) | ||||
2558 | { | ||||
2559 | if (bUp) | ||||
2560 | { | ||||
2561 | if (nIndex==0) | ||||
2562 | { | ||||
2563 | nIndex = mvData.size(); | ||||
2564 | nRow = -1; | ||||
2565 | } | ||||
2566 | else | ||||
2567 | { | ||||
2568 | --nIndex; | ||||
2569 | nRow = mvData[nIndex].nEndRow; | ||||
2570 | pPattern = mvData[nIndex].pPattern; | ||||
2571 | } | ||||
2572 | } | ||||
2573 | else | ||||
2574 | { | ||||
2575 | nRow = mvData[nIndex].nEndRow+1; | ||||
2576 | ++nIndex; | ||||
2577 | if (nIndex<mvData.size()) | ||||
2578 | pPattern = mvData[nIndex].pPattern; | ||||
2579 | } | ||||
2580 | } | ||||
2581 | } | ||||
2582 | |||||
2583 | OSL_ENSURE( bFound || !rDocument.ValidRow(nRow), "Internal failure in ScAttrArray::SearchStyle" )do { if (true && (!(bFound || !rDocument.ValidRow(nRow )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/sc/source/core/data/attarray.cxx" ":" "2583" ": "), "%s", "Internal failure in ScAttrArray::SearchStyle" ); } } while (false); | ||||
2584 | |||||
2585 | return nRow; | ||||
2586 | } | ||||
2587 | |||||
2588 | bool ScAttrArray::SearchStyleRange( | ||||
2589 | SCROW& rRow, SCROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp, | ||||
2590 | const ScMarkArray* pMarkArray) const | ||||
2591 | { | ||||
2592 | SCROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray ); | ||||
2593 | if (rDocument.ValidRow(nStartRow)) | ||||
2594 | { | ||||
2595 | if ( mvData.empty() ) | ||||
2596 | { | ||||
2597 | rRow = nStartRow; | ||||
2598 | if (bUp) | ||||
2599 | { | ||||
2600 | rEndRow = 0; | ||||
2601 | if (pMarkArray) | ||||
2602 | { | ||||
2603 | SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true ); | ||||
2604 | if (nMarkEnd>rEndRow) | ||||
2605 | rEndRow = nMarkEnd; | ||||
2606 | } | ||||
2607 | } | ||||
2608 | else | ||||
2609 | { | ||||
2610 | rEndRow = rDocument.MaxRow(); | ||||
2611 | if (pMarkArray) | ||||
2612 | { | ||||
2613 | SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false ); | ||||
2614 | if (nMarkEnd<rEndRow) | ||||
2615 | rEndRow = nMarkEnd; | ||||
2616 | } | ||||
2617 | } | ||||
2618 | |||||
2619 | return true; | ||||
2620 | } | ||||
2621 | |||||
2622 | SCSIZE nIndex; | ||||
2623 | Search(nStartRow,nIndex); | ||||
2624 | |||||
2625 | rRow = nStartRow; | ||||
2626 | if (bUp) | ||||
2627 | { | ||||
2628 | if (nIndex>0) | ||||
2629 | rEndRow = mvData[nIndex-1].nEndRow + 1; | ||||
2630 | else | ||||
2631 | rEndRow = 0; | ||||
2632 | if (pMarkArray) | ||||
2633 | { | ||||
2634 | SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, true ); | ||||
2635 | if (nMarkEnd>rEndRow) | ||||
2636 | rEndRow = nMarkEnd; | ||||
2637 | } | ||||
2638 | } | ||||
2639 | else | ||||
2640 | { | ||||
2641 | rEndRow = mvData[nIndex].nEndRow; | ||||
2642 | if (pMarkArray) | ||||
2643 | { | ||||
2644 | SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, false ); | ||||
2645 | if (nMarkEnd<rEndRow) | ||||
2646 | rEndRow = nMarkEnd; | ||||
2647 | } | ||||
2648 | } | ||||
2649 | |||||
2650 | return true; | ||||
2651 | } | ||||
2652 | else | ||||
2653 | return false; | ||||
2654 | } | ||||
2655 | |||||
2656 | SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) const | ||||
2657 | { | ||||
2658 | if ( mvData.empty() ) | ||||
2659 | return 1; | ||||
2660 | |||||
2661 | SCSIZE nIndex1, nIndex2; | ||||
2662 | |||||
2663 | if( !Search( nStartRow, nIndex1 ) ) | ||||
2664 | return 0; | ||||
2665 | |||||
2666 | if( !Search( nEndRow, nIndex2 ) ) | ||||
2667 | nIndex2 = mvData.size() - 1; | ||||
2668 | |||||
2669 | return nIndex2 - nIndex1 + 1; | ||||
2670 | } | ||||
2671 | |||||
2672 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
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/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
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 . | |||
18 | */ | |||
19 | ||||
20 | #ifndef INCLUDED_SC_INC_ATTARRAY_HXX | |||
21 | #define INCLUDED_SC_INC_ATTARRAY_HXX | |||
22 | ||||
23 | #include "global.hxx" | |||
24 | #include "attrib.hxx" | |||
25 | #include "patattr.hxx" | |||
26 | ||||
27 | #include <algorithm> | |||
28 | #include <memory> | |||
29 | ||||
30 | #include <svl/itemset.hxx> | |||
31 | ||||
32 | class ScDocument; | |||
33 | class ScEditDataArray; | |||
34 | class ScMarkArray; | |||
35 | class ScStyleSheet; | |||
36 | class ScFlatBoolRowSegments; | |||
37 | ||||
38 | class SfxItemPoolCache; | |||
39 | class SfxStyleSheetBase; | |||
40 | class SvxBoxItem; | |||
41 | class SvxBoxInfoItem; | |||
42 | ||||
43 | namespace editeng { class SvxBorderLine; } | |||
44 | ||||
45 | #define SC_LINE_EMPTY0 0 | |||
46 | #define SC_LINE_SET1 1 | |||
47 | #define SC_LINE_DONTCARE2 2 | |||
48 | ||||
49 | #define SC_ATTRARRAY_DELTA4 4 | |||
50 | ||||
51 | #define DEBUG_SC_TESTATTRARRAY0 0 | |||
52 | ||||
53 | struct ScLineFlags | |||
54 | { | |||
55 | sal_uInt8 nLeft; | |||
56 | sal_uInt8 nRight; | |||
57 | sal_uInt8 nTop; | |||
58 | sal_uInt8 nBottom; | |||
59 | sal_uInt8 nHori; | |||
60 | sal_uInt8 nVert; | |||
61 | ||||
62 | ScLineFlags() : nLeft(SC_LINE_EMPTY0),nRight(SC_LINE_EMPTY0),nTop(SC_LINE_EMPTY0), | |||
63 | nBottom(SC_LINE_EMPTY0),nHori(SC_LINE_EMPTY0),nVert(SC_LINE_EMPTY0) {} | |||
64 | }; | |||
65 | ||||
66 | struct ScMergePatternState | |||
67 | { | |||
68 | std::unique_ptr<SfxItemSet> pItemSet; | |||
69 | const ScPatternAttr* pOld1; ///< existing objects, temporary | |||
70 | const ScPatternAttr* pOld2; | |||
71 | ||||
72 | bool mbValidPatternId; | |||
73 | sal_uInt64 mnPatternId; | |||
74 | ||||
75 | ScMergePatternState() : pOld1(nullptr), pOld2(nullptr), | |||
76 | mbValidPatternId(true), mnPatternId(0) {} | |||
77 | }; | |||
78 | ||||
79 | // we store an array of these where the pattern applies to all rows up till nEndRow | |||
80 | struct ScAttrEntry | |||
81 | { | |||
82 | SCROW nEndRow; | |||
83 | const ScPatternAttr* pPattern; | |||
84 | }; | |||
85 | ||||
86 | class ScAttrArray | |||
87 | { | |||
88 | private: | |||
89 | SCCOL nCol; | |||
90 | SCTAB nTab; | |||
91 | ScDocument& rDocument; | |||
92 | ||||
93 | std::vector<ScAttrEntry> mvData; | |||
94 | ||||
95 | friend class ScDocument; // for FillInfo | |||
96 | friend class ScDocumentIterator; | |||
97 | friend class ScAttrIterator; | |||
98 | friend class ScHorizontalAttrIterator; | |||
99 | ||||
100 | bool ApplyFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner, | |||
101 | SCROW nStartRow, SCROW nEndRow, | |||
102 | bool bLeft, SCCOL nDistRight, bool bTop, SCROW nDistBottom ); | |||
103 | ||||
104 | void RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow, | |||
105 | const ScPatternAttr* pPattern, ScEditDataArray* pDataArray ); | |||
106 | void SetDefaultIfNotInit( SCSIZE nNeeded = 1 ); | |||
107 | bool HasAttrib_Impl(const ScPatternAttr* pPattern, HasAttrFlags nMask, SCROW nRow1, SCROW nRow2, SCSIZE i) const; | |||
108 | ||||
109 | ScAttrArray(const ScAttrArray&) = delete; | |||
110 | ScAttrArray& operator=(const ScAttrArray&) = delete; | |||
111 | ||||
112 | public: | |||
113 | ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, ScAttrArray* pNextColAttrArray ); | |||
114 | ~ScAttrArray(); | |||
115 | ||||
116 | ScDocument& GetDoc() { return rDocument; } | |||
117 | void SetTab(SCTAB nNewTab) { nTab = nNewTab; } | |||
118 | void SetCol(SCCOL nNewCol) { nCol = nNewCol; } | |||
119 | #if DEBUG_SC_TESTATTRARRAY0 | |||
120 | void TestData() const; | |||
121 | #endif | |||
122 | void Reset( const ScPatternAttr* pPattern); | |||
123 | bool Concat(SCSIZE nPos); | |||
124 | ||||
125 | const ScPatternAttr* GetPattern( SCROW nRow ) const; | |||
126 | ||||
127 | /** Returns if you search for attributes at nRow the range from rStartRow | |||
128 | to rEndRow where that attribute combination (ScPatternAttr) is applied. | |||
129 | The next ScPatternAttr different from this one starts at rEndRow+1 | |||
130 | (if that is <= MAXROW). | |||
131 | */ | |||
132 | const ScPatternAttr* GetPatternRange( SCROW& rStartRow, SCROW& rEndRow, SCROW nRow ) const; | |||
133 | ||||
134 | void MergePatternArea( SCROW nStartRow, SCROW nEndRow, ScMergePatternState& rState, bool bDeep ) const; | |||
135 | ||||
136 | void MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags, | |||
137 | SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const; | |||
138 | void ApplyBlockFrame(const SvxBoxItem& rLineOuter, const SvxBoxInfoItem* pLineInner, | |||
139 | SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight); | |||
140 | ||||
141 | void SetPattern( SCROW nRow, const ScPatternAttr* pPattern, bool bPutToPool = false ) | |||
142 | { SetPatternAreaImpl(nRow, nRow, pPattern, bPutToPool, nullptr, /*bPassingOwnership*/false); } | |||
143 | const ScPatternAttr* SetPattern( SCROW nRow, std::unique_ptr<ScPatternAttr> pPattern, bool bPutToPool = false ) | |||
144 | { return SetPatternAreaImpl(nRow, nRow, pPattern.release(), bPutToPool, nullptr, /*bPassingOwnership*/true); } | |||
145 | void SetPatternArea( SCROW nStartRow, SCROW nEndRow, std::unique_ptr<ScPatternAttr> pPattern, | |||
146 | bool bPutToPool = false, ScEditDataArray* pDataArray = nullptr) | |||
147 | { SetPatternAreaImpl(nStartRow, nEndRow, pPattern.release(), bPutToPool, pDataArray, /*bPassingOwnership*/true); } | |||
| ||||
148 | void SetPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern, | |||
149 | bool bPutToPool = false, ScEditDataArray* pDataArray = nullptr) | |||
150 | { SetPatternAreaImpl(nStartRow, nEndRow, pPattern, bPutToPool, pDataArray, /*bPassingOwnership*/false); } | |||
151 | void ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle ); | |||
152 | void ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, | |||
153 | ScEditDataArray* pDataArray = nullptr, bool* const pIsChanged = nullptr ); | |||
154 | void SetAttrEntries(std::vector<ScAttrEntry> && vNewData); | |||
155 | void ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow, | |||
156 | const ::editeng::SvxBorderLine* pLine, bool bColorOnly ); | |||
157 | ||||
158 | void AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex ); | |||
159 | /// if nIndex == 0, remove all conditional format data | |||
160 | void RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex ); | |||
161 | ||||
162 | void ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich ); | |||
163 | void ChangeIndent( SCROW nStartRow, SCROW nEndRow, bool bIncrement ); | |||
164 | ||||
165 | /// Including current, may return -1 | |||
166 | SCROW GetNextUnprotected( SCROW nRow, bool bUp ) const; | |||
167 | ||||
168 | /// May return -1 if not found | |||
169 | SCROW SearchStyle( | |||
170 | SCROW nRow, const ScStyleSheet* pSearchStyle, bool bUp, | |||
171 | const ScMarkArray* pMarkArray = nullptr) const; | |||
172 | ||||
173 | bool SearchStyleRange( | |||
174 | SCROW& rRow, SCROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp, | |||
175 | const ScMarkArray* pMarkArray = nullptr) const; | |||
176 | ||||
177 | bool ApplyFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags ); | |||
178 | bool RemoveFlags( SCROW nStartRow, SCROW nEndRow, ScMF nFlags ); | |||
179 | ||||
180 | bool Search( SCROW nRow, SCSIZE& nIndex ) const; | |||
181 | ||||
182 | bool HasAttrib( SCROW nRow1, SCROW nRow2, HasAttrFlags nMask ) const; | |||
183 | bool IsMerged( SCROW nRow ) const; | |||
184 | bool ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow, | |||
185 | SCCOL& rPaintCol, SCROW& rPaintRow, | |||
186 | bool bRefresh ); | |||
187 | void RemoveAreaMerge( SCROW nStartRow, SCROW nEndRow ); | |||
188 | ||||
189 | void FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset ); | |||
190 | bool IsStyleSheetUsed( const ScStyleSheet& rStyle ) const; | |||
191 | ||||
192 | void SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow, | |||
193 | const ScPatternAttr* pWantedPattern, bool bDefault ); | |||
194 | void CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray ); | |||
195 | ||||
196 | bool IsEmpty() const; | |||
197 | ||||
198 | bool GetFirstVisibleAttr( SCROW& rFirstRow ) const; | |||
199 | bool GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const; | |||
200 | bool HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const; | |||
201 | bool IsVisibleEqual( const ScAttrArray& rOther, | |||
202 | SCROW nStartRow, SCROW nEndRow ) const; | |||
203 | bool IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const; | |||
204 | ||||
205 | bool TestInsertCol( SCROW nStartRow, SCROW nEndRow) const; | |||
206 | bool TestInsertRow( SCSIZE nSize ) const; | |||
207 | void InsertRow( SCROW nStartRow, SCSIZE nSize ); | |||
208 | void DeleteRow( SCROW nStartRow, SCSIZE nSize ); | |||
209 | void DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex ); | |||
210 | void DeleteArea( SCROW nStartRow, SCROW nEndRow ); | |||
211 | void MoveTo( SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray ); | |||
212 | void CopyArea( | |||
213 | SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, ScMF nStripFlags = ScMF::NONE) const; | |||
214 | ||||
215 | void DeleteHardAttr( SCROW nStartRow, SCROW nEndRow ); | |||
216 | ||||
217 | /* i123909: Pre-calculate needed memory, and pre-reserve enough memory */ | |||
218 | bool Reserve( SCSIZE nReserve ); | |||
219 | SCSIZE Count() const { return mvData.size(); } | |||
220 | SCSIZE Count( SCROW nRow1, SCROW nRow2 ) const; | |||
221 | ||||
222 | private: | |||
223 | const ScPatternAttr* SetPatternAreaImpl( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr* pPattern, | |||
224 | bool bPutToPool = false, ScEditDataArray* pDataArray = nullptr, | |||
225 | bool bPassingPatternOwnership = false ); | |||
226 | }; | |||
227 | ||||
228 | // Iterator for attributes | |||
229 | ||||
230 | class ScAttrIterator | |||
231 | { | |||
232 | const ScAttrArray* pArray; | |||
233 | const ScPatternAttr* pDefPattern; | |||
234 | SCSIZE nPos; | |||
235 | SCROW nRow; | |||
236 | SCROW nEndRow; | |||
237 | public: | |||
238 | inline ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern ); | |||
239 | inline const ScPatternAttr* Next( SCROW& rTop, SCROW& rBottom ); | |||
240 | inline const ScPatternAttr* Resync( SCROW nRow, SCROW& rTop, SCROW& rBottom ); | |||
241 | SCROW GetNextRow() const { return nRow; } | |||
242 | }; | |||
243 | ||||
244 | inline ScAttrIterator::ScAttrIterator( const ScAttrArray* pNewArray, SCROW nStart, SCROW nEnd, const ScPatternAttr* pDefaultPattern ) : | |||
245 | pArray( pNewArray ), | |||
246 | pDefPattern( pDefaultPattern ), | |||
247 | nRow( nStart ), | |||
248 | nEndRow( nEnd ) | |||
249 | { | |||
250 | if ( pArray->Count() ) | |||
251 | { | |||
252 | if ( nStart > 0 ) | |||
253 | pArray->Search( nStart, nPos ); | |||
254 | else | |||
255 | nPos = 0; | |||
256 | } | |||
257 | else | |||
258 | nPos = 0; | |||
259 | } | |||
260 | ||||
261 | inline const ScPatternAttr* ScAttrIterator::Next( SCROW& rTop, SCROW& rBottom ) | |||
262 | { | |||
263 | const ScPatternAttr* pRet; | |||
264 | if ( !pArray->Count() ) | |||
265 | { | |||
266 | if ( !nPos ) | |||
267 | { | |||
268 | ++nPos; | |||
269 | if ( nRow > MAXROW ) | |||
270 | return nullptr; | |||
271 | rTop = nRow; | |||
272 | rBottom = std::min( nEndRow, MAXROW ); | |||
273 | nRow = rBottom + 1; | |||
274 | return pDefPattern; | |||
275 | } | |||
276 | return nullptr; | |||
277 | } | |||
278 | ||||
279 | if ( nPos < pArray->Count() && nRow <= nEndRow ) | |||
280 | { | |||
281 | rTop = nRow; | |||
282 | rBottom = std::min( pArray->mvData[nPos].nEndRow, nEndRow ); | |||
283 | pRet = pArray->mvData[nPos].pPattern; | |||
284 | nRow = rBottom + 1; | |||
285 | ++nPos; | |||
286 | } | |||
287 | else | |||
288 | pRet = nullptr; | |||
289 | return pRet; | |||
290 | } | |||
291 | ||||
292 | inline const ScPatternAttr* ScAttrIterator::Resync( SCROW nRowP, SCROW& rTop, SCROW& rBottom ) | |||
293 | { | |||
294 | nRow = nRowP; | |||
295 | if ( !pArray->Count() ) | |||
296 | { | |||
297 | nPos = 0; | |||
298 | return Next( rTop, rBottom ); | |||
299 | } | |||
300 | // Chances are high that the pattern changed on nRowP introduced a span | |||
301 | // starting right there. Assume that Next() was called so nPos already | |||
302 | // advanced. Another high chance is that the change extended a previous or | |||
303 | // next pattern. In all these cases we don't need to search. | |||
304 | if (3 <= nPos && nPos <= pArray->Count() && pArray->mvData[nPos-3].nEndRow < nRowP && | |||
305 | nRowP <= pArray->mvData[nPos-2].nEndRow) | |||
306 | nPos -= 2; | |||
307 | else if (2 <= nPos && nPos <= pArray->Count() && pArray->mvData[nPos-2].nEndRow < nRowP && | |||
308 | nRowP <= pArray->mvData[nPos-1].nEndRow) | |||
309 | --nPos; | |||
310 | else if (pArray->Count() > 0 && nRowP <= pArray->mvData[0].nEndRow) | |||
311 | nPos = 0; | |||
312 | else | |||
313 | pArray->Search( nRowP, nPos ); | |||
314 | return Next( rTop, rBottom); | |||
315 | } | |||
316 | ||||
317 | #endif | |||
318 | ||||
319 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |