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 <scitems.hxx>
21 #include <editeng/brushitem.hxx>
22 #include <svtools/colorcfg.hxx>
23 #include <svx/rotmodit.hxx>
24 #include <editeng/shaditem.hxx>
25 #include <editeng/svxfont.hxx>
26 #include <tools/poly.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/pdfextoutdevdata.hxx>
29 #include <svtools/accessibilityoptions.hxx>
30 #include <svx/framelinkarray.hxx>
31 #include <drawinglayer/geometry/viewinformation2d.hxx>
32 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
35 #include <vcl/lineinfo.hxx>
36 #include <vcl/gradient.hxx>
37 #include <vcl/settings.hxx>
38 #include <svx/unoapi.hxx>
39 #include <sal/log.hxx>
40 #include <comphelper/lok.hxx>
41 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
42
43 #include <output.hxx>
44 #include <document.hxx>
45 #include <drwlayer.hxx>
46 #include <formulacell.hxx>
47 #include <attrib.hxx>
48 #include <patattr.hxx>
49 #include <progress.hxx>
50 #include <pagedata.hxx>
51 #include <chgtrack.hxx>
52 #include <chgviset.hxx>
53 #include <viewutil.hxx>
54 #include <gridmerg.hxx>
55 #include <fillinfo.hxx>
56 #include <scmod.hxx>
57 #include <appoptio.hxx>
58 #include <postit.hxx>
59
60 #include <colorscale.hxx>
61
62 #include <math.h>
63 #include <memory>
64
65 using namespace com::sun::star;
66
67 // Static Data
68
69 // color for ChangeTracking "by author" as in the writer (swmodul1.cxx)
70
71 #define SC_AUTHORCOLORCOUNT 9
72
73 static const Color nAuthorColor[ SC_AUTHORCOLORCOUNT ] = {
74 COL_LIGHTRED, COL_LIGHTBLUE, COL_LIGHTMAGENTA,
75 COL_GREEN, COL_RED, COL_BLUE,
76 COL_BROWN, COL_MAGENTA, COL_CYAN };
77
78 // Helper class for color assignment to avoid repeated lookups for the same user
79
ScActionColorChanger(const ScChangeTrack & rTrack)80 ScActionColorChanger::ScActionColorChanger( const ScChangeTrack& rTrack ) :
81 rOpt( SC_MOD()->GetAppOptions() ),
82 rUsers( rTrack.GetUserCollection() ),
83 nLastUserIndex( 0 ),
84 nColor( COL_BLACK )
85 {
86 }
87
Update(const ScChangeAction & rAction)88 void ScActionColorChanger::Update( const ScChangeAction& rAction )
89 {
90 Color nSetColor;
91 switch (rAction.GetType())
92 {
93 case SC_CAT_INSERT_COLS:
94 case SC_CAT_INSERT_ROWS:
95 case SC_CAT_INSERT_TABS:
96 nSetColor = rOpt.GetTrackInsertColor();
97 break;
98 case SC_CAT_DELETE_COLS:
99 case SC_CAT_DELETE_ROWS:
100 case SC_CAT_DELETE_TABS:
101 nSetColor = rOpt.GetTrackDeleteColor();
102 break;
103 case SC_CAT_MOVE:
104 nSetColor = rOpt.GetTrackMoveColor();
105 break;
106 default:
107 nSetColor = rOpt.GetTrackContentColor();
108 break;
109 }
110 if ( nSetColor != COL_TRANSPARENT ) // color assigned
111 nColor = nSetColor;
112 else // by author
113 {
114 if (aLastUserName != rAction.GetUser())
115 {
116 aLastUserName = rAction.GetUser();
117 std::set<OUString>::const_iterator it = rUsers.find(aLastUserName);
118 if (it == rUsers.end())
119 {
120 // empty string is possible if a name wasn't found while saving a 5.0 file
121 SAL_INFO_IF( aLastUserName.isEmpty(), "sc.ui", "Author not found" );
122 nLastUserIndex = 0;
123 }
124 else
125 {
126 size_t nPos = std::distance(rUsers.begin(), it);
127 nLastUserIndex = nPos % SC_AUTHORCOLORCOUNT;
128 }
129 }
130 nColor = nAuthorColor[nLastUserIndex];
131 }
132 }
133
ScOutputData(OutputDevice * pNewDev,ScOutputType eNewType,ScTableInfo & rTabInfo,ScDocument * pNewDoc,SCTAB nNewTab,long nNewScrX,long nNewScrY,SCCOL nNewX1,SCROW nNewY1,SCCOL nNewX2,SCROW nNewY2,double nPixelPerTwipsX,double nPixelPerTwipsY,const Fraction * pZoomX,const Fraction * pZoomY)134 ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
135 ScTableInfo& rTabInfo, ScDocument* pNewDoc,
136 SCTAB nNewTab, long nNewScrX, long nNewScrY,
137 SCCOL nNewX1, SCROW nNewY1, SCCOL nNewX2, SCROW nNewY2,
138 double nPixelPerTwipsX, double nPixelPerTwipsY,
139 const Fraction* pZoomX, const Fraction* pZoomY ) :
140 mpDev( pNewDev ),
141 mpRefDevice( pNewDev ), // default is output device
142 pFmtDevice( pNewDev ), // default is output device
143 mrTabInfo( rTabInfo ),
144 pRowInfo( rTabInfo.mpRowInfo.get() ),
145 nArrCount( rTabInfo.mnArrCount ),
146 mpDoc( pNewDoc ),
147 nTab( nNewTab ),
148 nScrX( nNewScrX ),
149 nScrY( nNewScrY ),
150 nX1( nNewX1 ),
151 nY1( nNewY1 ),
152 nX2( nNewX2 ),
153 nY2( nNewY2 ),
154 eType( eNewType ),
155 mnPPTX( nPixelPerTwipsX ),
156 mnPPTY( nPixelPerTwipsY ),
157 pViewShell( nullptr ),
158 pDrawView( nullptr ),
159 bEditMode( false ),
160 nEditCol( 0 ),
161 nEditRow( 0 ),
162 bMetaFile( false ),
163 bPagebreakMode( false ),
164 bSolidBackground( false ),
165 mbUseStyleColor( false ),
166 mbForceAutoColor( SC_MOD()->GetAccessOptions().GetIsAutomaticFontColor() ),
167 mbSyntaxMode( false ),
168 aGridColor( COL_BLACK ),
169 mbShowNullValues( true ),
170 mbShowFormulas( false ),
171 bShowSpellErrors( false ),
172 bMarkClipped( false ), // sal_False for printer/metafile etc.
173 bSnapPixel( false ),
174 bAnyClipped( false ),
175 mpTargetPaintWindow(nullptr), // #i74769# use SdrPaintWindow direct
176 mpSpellCheckCxt(nullptr)
177 {
178 if (pZoomX)
179 aZoomX = *pZoomX;
180 else
181 aZoomX = Fraction(1,1);
182 if (pZoomY)
183 aZoomY = *pZoomY;
184 else
185 aZoomY = Fraction(1,1);
186
187 nVisX1 = nX1;
188 nVisY1 = nY1;
189 nVisX2 = nX2;
190 nVisY2 = nY2;
191 mpDoc->StripHidden( nVisX1, nVisY1, nVisX2, nVisY2, nTab );
192
193 nScrW = 0;
194 for (SCCOL nX=nVisX1; nX<=nVisX2; nX++)
195 nScrW += pRowInfo[0].pCellInfo[nX+1].nWidth;
196
197 nMirrorW = nScrW;
198
199 nScrH = 0;
200 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
201 nScrH += pRowInfo[nArrY].nHeight;
202
203 bTabProtected = mpDoc->IsTabProtected( nTab );
204 bLayoutRTL = mpDoc->IsLayoutRTL( nTab );
205
206 // always needed, so call at the end of the constructor
207 SetCellRotations();
208 }
209
~ScOutputData()210 ScOutputData::~ScOutputData()
211 {
212 }
213
SetSpellCheckContext(const sc::SpellCheckContext * pCxt)214 void ScOutputData::SetSpellCheckContext( const sc::SpellCheckContext* pCxt )
215 {
216 mpSpellCheckCxt = pCxt;
217 }
218
SetContentDevice(OutputDevice * pContentDev)219 void ScOutputData::SetContentDevice( OutputDevice* pContentDev )
220 {
221 // use pContentDev instead of pDev where used
222
223 if ( mpRefDevice == mpDev )
224 mpRefDevice = pContentDev;
225 if ( pFmtDevice == mpDev )
226 pFmtDevice = pContentDev;
227 mpDev = pContentDev;
228 }
229
SetMirrorWidth(long nNew)230 void ScOutputData::SetMirrorWidth( long nNew )
231 {
232 nMirrorW = nNew;
233 }
234
SetGridColor(const Color & rColor)235 void ScOutputData::SetGridColor( const Color& rColor )
236 {
237 aGridColor = rColor;
238 }
239
SetMarkClipped(bool bSet)240 void ScOutputData::SetMarkClipped( bool bSet )
241 {
242 bMarkClipped = bSet;
243 }
244
SetShowNullValues(bool bSet)245 void ScOutputData::SetShowNullValues( bool bSet )
246 {
247 mbShowNullValues = bSet;
248 }
249
SetShowFormulas(bool bSet)250 void ScOutputData::SetShowFormulas( bool bSet )
251 {
252 mbShowFormulas = bSet;
253 }
254
SetShowSpellErrors(bool bSet)255 void ScOutputData::SetShowSpellErrors( bool bSet )
256 {
257 bShowSpellErrors = bSet;
258 }
259
SetSnapPixel()260 void ScOutputData::SetSnapPixel()
261 {
262 bSnapPixel = true;
263 }
264
SetEditCell(SCCOL nCol,SCROW nRow)265 void ScOutputData::SetEditCell( SCCOL nCol, SCROW nRow )
266 {
267 nEditCol = nCol;
268 nEditRow = nRow;
269 bEditMode = true;
270 }
271
SetMetaFileMode(bool bNewMode)272 void ScOutputData::SetMetaFileMode( bool bNewMode )
273 {
274 bMetaFile = bNewMode;
275 }
276
SetSyntaxMode(bool bNewMode)277 void ScOutputData::SetSyntaxMode( bool bNewMode )
278 {
279 mbSyntaxMode = bNewMode;
280 if ( bNewMode && !pValueColor )
281 {
282 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
283 pValueColor.reset( new Color( rColorCfg.GetColorValue( svtools::CALCVALUE ).nColor ) );
284 pTextColor.reset( new Color( rColorCfg.GetColorValue( svtools::CALCTEXT ).nColor ) );
285 pFormulaColor.reset( new Color( rColorCfg.GetColorValue( svtools::CALCFORMULA ).nColor ) );
286 }
287 }
288
DrawGrid(vcl::RenderContext & rRenderContext,bool bGrid,bool bPage)289 void ScOutputData::DrawGrid(vcl::RenderContext& rRenderContext, bool bGrid, bool bPage)
290 {
291 SCCOL nX;
292 SCROW nY;
293 long nPosX;
294 long nPosY;
295 SCSIZE nArrY;
296 ScBreakType nBreak = ScBreakType::NONE;
297 ScBreakType nBreakOld = ScBreakType::NONE;
298
299 bool bSingle;
300 bool bDashed = false;
301 Color aPageColor;
302 Color aManualColor;
303
304 if (bPagebreakMode)
305 bPage = false; // no "normal" breaks over the whole width/height
306
307 // It is a big mess to distinguish when we are using pixels and when logic
308 // units for drawing. Ultimately we want to work only in the logic units,
309 // but until that happens, we need to special-case:
310 //
311 // * metafile
312 // * drawing to the screen - everything is internally counted in pixels there
313 //
314 // 'Internally' in the above means the pCellInfo[...].nWidth and
315 // pRowInfo[...]->nHeight:
316 //
317 // * when bWorksInPixels is true: these are in pixels
318 // * when bWorksInPixels is false: these are in the logic units
319 //
320 // This is where all the confusion comes from, ultimately we want them
321 // always in the logic units (100th of millimeters), but we need to get
322 // there gradually (get rid of setting MapUnit::MapPixel first), otherwise we'd
323 // break all the drawing by one change.
324 // So until that happens, we need to special case.
325 bool bWorksInPixels = bMetaFile;
326
327 if ( eType == OUTTYPE_WINDOW )
328 {
329 bWorksInPixels = true;
330 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
331 aPageColor = rColorCfg.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
332 aManualColor = rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor;
333 }
334 else
335 {
336 aPageColor = aGridColor;
337 aManualColor = aGridColor;
338 }
339
340 long nOneX = 1;
341 long nOneY = 1;
342 if (!bWorksInPixels)
343 {
344 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
345 nOneX = aOnePixel.Width();
346 nOneY = aOnePixel.Height();
347 }
348
349 long nLayoutSign = bLayoutRTL ? -1 : 1;
350 long nSignedOneX = nOneX * nLayoutSign;
351
352 rRenderContext.SetLineColor(aGridColor);
353 ScGridMerger aGrid(&rRenderContext, nOneX, nOneY);
354
355 // vertical lines
356
357 nPosX = nScrX;
358 if ( bLayoutRTL )
359 nPosX += nMirrorW - nOneX;
360
361 for (nX=nX1; nX<=nX2; nX++)
362 {
363 SCCOL nXplus1 = nX+1;
364 SCCOL nXplus2 = nX+2;
365 sal_uInt16 nWidth = pRowInfo[0].pCellInfo[nXplus1].nWidth;
366 if (nWidth)
367 {
368 nPosX += nWidth * nLayoutSign;
369
370 if ( bPage )
371 {
372 // Search also in hidden part for page breaks
373 SCCOL nCol = nXplus1;
374 while (nCol <= mpDoc->MaxCol())
375 {
376 nBreak = mpDoc->HasColBreak(nCol, nTab);
377 bool bHidden = mpDoc->ColHidden(nCol, nTab);
378
379 if ( nBreak != ScBreakType::NONE || !bHidden )
380 break;
381 ++nCol;
382 }
383
384 if (nBreak != nBreakOld)
385 {
386 aGrid.Flush();
387
388 if (static_cast<int>(nBreak))
389 {
390 rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
391 aPageColor );
392 bDashed = true;
393 }
394 else
395 {
396 rRenderContext.SetLineColor( aGridColor );
397 bDashed = false;
398 }
399
400 nBreakOld = nBreak;
401 }
402 }
403
404 bool bDraw = bGrid || nBreakOld != ScBreakType::NONE; // simple grid only if set that way
405
406 sal_uInt16 nWidthXplus2 = pRowInfo[0].pCellInfo[nXplus2].nWidth;
407 bSingle = false; //! get into Fillinfo !!!!!
408 if ( nX<mpDoc->MaxCol() && !bSingle )
409 {
410 bSingle = ( nWidthXplus2 == 0 );
411 for (nArrY=1; nArrY+1<nArrCount && !bSingle; nArrY++)
412 {
413 if (pRowInfo[nArrY].pCellInfo[nXplus2].bHOverlapped)
414 bSingle = true;
415 if (pRowInfo[nArrY].pCellInfo[nXplus1].bHideGrid)
416 bSingle = true;
417 }
418 }
419
420 if (bDraw)
421 {
422 if ( nX<mpDoc->MaxCol() && bSingle )
423 {
424 SCCOL nVisX = nXplus1;
425 while ( nVisX < mpDoc->MaxCol() && !mpDoc->GetColWidth(nVisX,nTab) )
426 ++nVisX;
427
428 nPosY = nScrY;
429 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
430 {
431 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
432 const long nNextY = nPosY + pThisRowInfo->nHeight;
433
434 bool bHOver = pThisRowInfo->pCellInfo[nXplus1].bHideGrid;
435 if (!bHOver)
436 {
437 if (nWidthXplus2)
438 bHOver = pThisRowInfo->pCellInfo[nXplus2].bHOverlapped;
439 else
440 {
441 if (nVisX <= nX2)
442 bHOver = pThisRowInfo->pCellInfo[nVisX+1].bHOverlapped;
443 else
444 bHOver = mpDoc->GetAttr(
445 nVisX,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG)
446 ->IsHorOverlapped();
447 if (bHOver)
448 bHOver = mpDoc->GetAttr(
449 nXplus1,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG)
450 ->IsHorOverlapped();
451 }
452 }
453
454 if (pThisRowInfo->bChanged && !bHOver)
455 {
456 aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nPosY, nNextY-nOneY, bDashed);
457 }
458 nPosY = nNextY;
459 }
460 }
461 else
462 {
463 aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nScrY, nScrY+nScrH-nOneY, bDashed);
464 }
465 }
466 }
467 }
468
469 // horizontal lines
470
471 bool bHiddenRow = true;
472 SCROW nHiddenEndRow = -1;
473 nPosY = nScrY;
474 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
475 {
476 SCSIZE nArrYplus1 = nArrY+1;
477 nY = pRowInfo[nArrY].nRowNo;
478 SCROW nYplus1 = nY+1;
479 nPosY += pRowInfo[nArrY].nHeight;
480
481 if (pRowInfo[nArrY].bChanged)
482 {
483 if ( bPage )
484 {
485 for (SCROW i = nYplus1; i <= mpDoc->MaxRow(); ++i)
486 {
487 if (i > nHiddenEndRow)
488 bHiddenRow = mpDoc->RowHidden(i, nTab, nullptr, &nHiddenEndRow);
489 /* TODO: optimize the row break thing for large hidden
490 * segments where HasRowBreak() has to be called
491 * nevertheless for each row, as a row break is drawn also
492 * for hidden rows, above them. This needed to be done only
493 * once per hidden segment, maybe giving manual breaks
494 * priority. Something like GetNextRowBreak() and
495 * GetNextManualRowBreak(). */
496 nBreak = mpDoc->HasRowBreak(i, nTab);
497 if (!bHiddenRow || nBreak != ScBreakType::NONE)
498 break;
499 }
500
501 if (nBreakOld != nBreak)
502 {
503 aGrid.Flush();
504
505 if (static_cast<int>(nBreak))
506 {
507 rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
508 aPageColor );
509 bDashed = true;
510 }
511 else
512 {
513 rRenderContext.SetLineColor( aGridColor );
514 bDashed = false;
515 }
516
517 nBreakOld = nBreak;
518 }
519 }
520
521 bool bDraw = bGrid || nBreakOld != ScBreakType::NONE; // simple grid only if set so
522
523 bool bNextYisNextRow = (pRowInfo[nArrYplus1].nRowNo == nYplus1);
524 bSingle = !bNextYisNextRow; // Hidden
525 for (SCCOL i=nX1; i<=nX2 && !bSingle; i++)
526 {
527 if (pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped)
528 bSingle = true;
529 }
530
531 if (bDraw)
532 {
533 if ( bSingle && nY<mpDoc->MaxRow() )
534 {
535 SCROW nVisY = pRowInfo[nArrYplus1].nRowNo;
536
537 nPosX = nScrX;
538 if ( bLayoutRTL )
539 nPosX += nMirrorW - nOneX;
540
541 for (SCCOL i=nX1; i<=nX2; i++)
542 {
543 const long nNextX = nPosX + pRowInfo[0].pCellInfo[i+1].nWidth * nLayoutSign;
544 if (nNextX != nPosX) // visible
545 {
546 bool bVOver;
547 if ( bNextYisNextRow )
548 bVOver = pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped;
549 else
550 {
551 bVOver = mpDoc->GetAttr(
552 i,nYplus1,nTab,ATTR_MERGE_FLAG)
553 ->IsVerOverlapped()
554 && mpDoc->GetAttr(
555 i,nVisY,nTab,ATTR_MERGE_FLAG)
556 ->IsVerOverlapped();
557 //! nVisY from Array ??
558 }
559 if (!bVOver)
560 {
561 aGrid.AddHorLine(bWorksInPixels, nPosX, nNextX-nSignedOneX, nPosY-nOneY, bDashed);
562 }
563 }
564 nPosX = nNextX;
565 }
566 }
567 else
568 {
569 aGrid.AddHorLine(bWorksInPixels, nScrX, nScrX+nScrW-nOneX, nPosY-nOneY, bDashed);
570 }
571 }
572 }
573 }
574 }
575
SetPagebreakMode(ScPageBreakData * pPageData)576 void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
577 {
578 bPagebreakMode = true;
579 if (!pPageData)
580 return; // not yet initialized -> everything "not printed"
581
582 // mark printed range
583 // (everything in FillInfo is already initialized to sal_False)
584
585 sal_uInt16 nRangeCount = sal::static_int_cast<sal_uInt16>(pPageData->GetCount());
586 for (sal_uInt16 nPos=0; nPos<nRangeCount; nPos++)
587 {
588 ScRange aRange = pPageData->GetData( nPos ).GetPrintRange();
589
590 SCCOL nStartX = std::max( aRange.aStart.Col(), nX1 );
591 SCCOL nEndX = std::min( aRange.aEnd.Col(), nX2 );
592 SCROW nStartY = std::max( aRange.aStart.Row(), nY1 );
593 SCROW nEndY = std::min( aRange.aEnd.Row(), nY2 );
594
595 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
596 {
597 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
598 if ( pThisRowInfo->bChanged && pThisRowInfo->nRowNo >= nStartY &&
599 pThisRowInfo->nRowNo <= nEndY )
600 {
601 for (SCCOL nX=nStartX; nX<=nEndX; nX++)
602 pThisRowInfo->pCellInfo[nX+1].bPrinted = true;
603 }
604 }
605 }
606 }
607
SetCellRotations()608 void ScOutputData::SetCellRotations()
609 {
610 //! save nRotMax
611 SCCOL nRotMax = nX2;
612 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
613 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
614 nRotMax = pRowInfo[nRotY].nRotMaxCol;
615
616 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
617 {
618 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
619 if ( pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE &&
620 ( pThisRowInfo->bChanged || pRowInfo[nArrY-1].bChanged ||
621 ( nArrY+1<nArrCount && pRowInfo[nArrY+1].bChanged ) ) )
622 {
623 SCROW nY = pThisRowInfo->nRowNo;
624
625 for (SCCOL nX=0; nX<=nRotMax; nX++)
626 {
627 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
628 const ScPatternAttr* pPattern = pInfo->pPatternAttr;
629 const SfxItemSet* pCondSet = pInfo->pConditionSet;
630
631 if ( !pPattern && !mpDoc->ColHidden(nX, nTab) )
632 {
633 pPattern = mpDoc->GetPattern( nX, nY, nTab );
634 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
635 }
636
637 if ( pPattern ) // column isn't hidden
638 {
639 ScRotateDir nDir = pPattern->GetRotateDir( pCondSet );
640 if (nDir != ScRotateDir::NONE)
641 {
642 // Needed for CellInfo internal decisions (bg fill, ...)
643 pInfo->nRotateDir = nDir;
644
645 // create target coordinates
646 const SCCOL nTargetX(nX - nVisX1 + 1);
647 const SCROW nTargetY(nY - nVisY1 + 1);
648
649 // Check for values - below in SetCellRotation these will
650 // be converted to size_t and thus may not be negative
651 if(nTargetX >= 0 && nTargetY >= 0)
652 {
653 // add rotation info to Array information
654 const long nAttrRotate(pPattern->GetRotateVal(pCondSet));
655 const SvxRotateMode eRotMode(pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue());
656 const double fOrient((bLayoutRTL ? -1.0 : 1.0) * nAttrRotate * F_PI18000); // 1/100th degrees -> [0..2PI]
657 svx::frame::Array& rArray = mrTabInfo.maArray;
658
659 rArray.SetCellRotation(nTargetX, nTargetY, eRotMode, fOrient);
660 }
661 }
662 }
663 }
664 }
665 }
666 }
667
lcl_GetRotateDir(const ScDocument * pDoc,SCCOL nCol,SCROW nRow,SCTAB nTab)668 static ScRotateDir lcl_GetRotateDir( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
669 {
670 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
671 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
672
673 ScRotateDir nRet = ScRotateDir::NONE;
674
675 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
676 if ( nAttrRotate )
677 {
678 SvxRotateMode eRotMode =
679 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
680
681 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
682 nRet = ScRotateDir::Standard;
683 else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
684 nRet = ScRotateDir::Center;
685 else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
686 {
687 long nRot180 = nAttrRotate % 18000; // 1/100 degree
688 if ( nRot180 == 9000 )
689 nRet = ScRotateDir::Center;
690 else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
691 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
692 nRet = ScRotateDir::Left;
693 else
694 nRet = ScRotateDir::Right;
695 }
696 }
697
698 return nRet;
699 }
700
lcl_FindBackground(const ScDocument * pDoc,SCCOL nCol,SCROW nRow,SCTAB nTab)701 static const SvxBrushItem* lcl_FindBackground( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
702 {
703 const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
704 const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
705 const SvxBrushItem* pBackground =
706 &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
707
708 ScRotateDir nDir = lcl_GetRotateDir( pDoc, nCol, nRow, nTab );
709
710 // treat CENTER like RIGHT
711 if ( nDir == ScRotateDir::Right || nDir == ScRotateDir::Center )
712 {
713 // text goes to the right -> take background from the left
714 while ( nCol > 0 && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
715 pBackground->GetColor().GetTransparency() != 255 )
716 {
717 --nCol;
718 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
719 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
720 pBackground = &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
721 }
722 }
723 else if ( nDir == ScRotateDir::Left )
724 {
725 // text goes to the left -> take background from the right
726 while ( nCol < pDoc->MaxCol() && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
727 pBackground->GetColor().GetTransparency() != 255 )
728 {
729 ++nCol;
730 pPattern = pDoc->GetPattern( nCol, nRow, nTab );
731 pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
732 pBackground = &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
733 }
734 }
735
736 return pBackground;
737 }
738
lcl_EqualBack(const RowInfo & rFirst,const RowInfo & rOther,SCCOL nX1,SCCOL nX2,bool bShowProt,bool bPagebreakMode)739 static bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
740 SCCOL nX1, SCCOL nX2, bool bShowProt, bool bPagebreakMode )
741 {
742 if ( rFirst.bChanged != rOther.bChanged ||
743 rFirst.bEmptyBack != rOther.bEmptyBack )
744 return false;
745
746 SCCOL nX;
747 if ( bShowProt )
748 {
749 for ( nX=nX1; nX<=nX2; nX++ )
750 {
751 const ScPatternAttr* pPat1 = rFirst.pCellInfo[nX+1].pPatternAttr;
752 const ScPatternAttr* pPat2 = rOther.pCellInfo[nX+1].pPatternAttr;
753 if ( !pPat1 || !pPat2 ||
754 &pPat1->GetItem(ATTR_PROTECTION) != &pPat2->GetItem(ATTR_PROTECTION) )
755 return false;
756 }
757 }
758 else
759 {
760 for ( nX=nX1; nX<=nX2; nX++ )
761 if ( rFirst.pCellInfo[nX+1].pBackground != rOther.pCellInfo[nX+1].pBackground )
762 return false;
763 }
764
765 if ( rFirst.nRotMaxCol != SC_ROTMAX_NONE || rOther.nRotMaxCol != SC_ROTMAX_NONE )
766 for ( nX=nX1; nX<=nX2; nX++ )
767 if ( rFirst.pCellInfo[nX+1].nRotateDir != rOther.pCellInfo[nX+1].nRotateDir )
768 return false;
769
770 if ( bPagebreakMode )
771 for ( nX=nX1; nX<=nX2; nX++ )
772 if ( rFirst.pCellInfo[nX+1].bPrinted != rOther.pCellInfo[nX+1].bPrinted )
773 return false;
774
775 for ( nX=nX1; nX<=nX2; nX++ )
776 {
777 boost::optional<Color> const & pCol1 = rFirst.pCellInfo[nX+1].mxColorScale;
778 boost::optional<Color> const & pCol2 = rOther.pCellInfo[nX+1].mxColorScale;
779 if( (pCol1 && !pCol2) || (!pCol1 && pCol2) )
780 return false;
781
782 if (pCol1 && (*pCol1 != *pCol2))
783 return false;
784
785 const ScDataBarInfo* pInfo1 = rFirst.pCellInfo[nX+1].pDataBar.get();
786 const ScDataBarInfo* pInfo2 = rOther.pCellInfo[nX+1].pDataBar.get();
787
788 if( (pInfo1 && !pInfo2) || (!pInfo1 && pInfo2) )
789 return false;
790
791 if (pInfo1 && (*pInfo1 != *pInfo2))
792 return false;
793
794 // each cell with an icon set should be painted the same way
795 const ScIconSetInfo* pIconSet1 = rFirst.pCellInfo[nX+1].pIconSet.get();
796 const ScIconSetInfo* pIconSet2 = rOther.pCellInfo[nX+1].pIconSet.get();
797
798 if(pIconSet1 || pIconSet2)
799 return false;
800 }
801
802 return true;
803 }
804
DrawDocumentBackground()805 void ScOutputData::DrawDocumentBackground()
806 {
807 if ( !bSolidBackground )
808 return;
809
810 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
811 mpDev->SetLineColor(aBgColor);
812 mpDev->SetFillColor(aBgColor);
813
814 Point aScreenPos = mpDev->PixelToLogic(Point(nScrX, nScrY));
815 Size aScreenSize = mpDev->PixelToLogic(Size(nScrW - 1,nScrH - 1));
816
817 mpDev->DrawRect(tools::Rectangle(aScreenPos, aScreenSize));
818 }
819
820 namespace {
821
822 static const double lclCornerRectTransparency = 40.0;
823
drawDataBars(vcl::RenderContext & rRenderContext,const ScDataBarInfo * pOldDataBarInfo,const tools::Rectangle & rRect,long nOneX,long nOneY)824 void drawDataBars(vcl::RenderContext& rRenderContext, const ScDataBarInfo* pOldDataBarInfo, const tools::Rectangle& rRect, long nOneX, long nOneY)
825 {
826 long nPosZero = 0;
827 tools::Rectangle aPaintRect = rRect;
828 aPaintRect.AdjustTop(2 * nOneY );
829 aPaintRect.AdjustBottom( -(2 * nOneY) );
830 aPaintRect.AdjustLeft( 2 * nOneX );
831 aPaintRect.AdjustRight( -(2 * nOneX) );
832 if(pOldDataBarInfo->mnZero)
833 {
834 // need to calculate null point in cell
835 long nLength = aPaintRect.Right() - aPaintRect.Left();
836 nPosZero = static_cast<long>(aPaintRect.Left() + nLength*pOldDataBarInfo->mnZero/100.0);
837 }
838 else
839 {
840 nPosZero = aPaintRect.Left();
841 }
842
843 if(pOldDataBarInfo->mnLength < 0)
844 {
845 aPaintRect.SetRight( nPosZero );
846 long nLength = nPosZero - aPaintRect.Left();
847 aPaintRect.SetLeft( nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0) );
848 }
849 else if(pOldDataBarInfo->mnLength > 0)
850 {
851 aPaintRect.SetLeft( nPosZero );
852 long nLength = aPaintRect.Right() - nPosZero;
853 aPaintRect.SetRight( nPosZero + static_cast<long>(nLength * pOldDataBarInfo->mnLength/100.0) );
854 }
855 else
856 return;
857
858 if(pOldDataBarInfo->mbGradient)
859 {
860 rRenderContext.SetLineColor(pOldDataBarInfo->maColor);
861 Gradient aGradient(GradientStyle::Linear, pOldDataBarInfo->maColor, COL_TRANSPARENT);
862 aGradient.SetSteps(255);
863
864 if(pOldDataBarInfo->mnLength < 0)
865 aGradient.SetAngle(2700);
866 else
867 aGradient.SetAngle(900);
868
869 rRenderContext.DrawGradient(aPaintRect, aGradient);
870
871 rRenderContext.SetLineColor();
872 }
873 else
874 {
875 rRenderContext.SetFillColor(pOldDataBarInfo->maColor);
876 rRenderContext.DrawRect(aPaintRect);
877 }
878
879 //draw axis
880 if(pOldDataBarInfo->mnZero && pOldDataBarInfo->mnZero != 100)
881 {
882 Point aPoint1(nPosZero, rRect.Top());
883 Point aPoint2(nPosZero, rRect.Bottom());
884 LineInfo aLineInfo(LineStyle::Dash, 1);
885 aLineInfo.SetDashCount( 4 );
886 aLineInfo.SetDistance( 3 );
887 aLineInfo.SetDashLen( 3 );
888 rRenderContext.SetFillColor(pOldDataBarInfo->maAxisColor);
889 rRenderContext.SetLineColor(pOldDataBarInfo->maAxisColor);
890 rRenderContext.DrawLine(aPoint1, aPoint2, aLineInfo);
891 rRenderContext.SetLineColor();
892 rRenderContext.SetFillColor();
893 }
894 }
895
getIcon(sc::IconSetBitmapMap & rIconSetBitmapMap,ScIconSetType eType,sal_Int32 nIndex)896 const BitmapEx& getIcon(sc::IconSetBitmapMap & rIconSetBitmapMap, ScIconSetType eType, sal_Int32 nIndex)
897 {
898 return ScIconSetFormat::getBitmap(rIconSetBitmapMap, eType, nIndex);
899 }
900
drawIconSets(vcl::RenderContext & rRenderContext,const ScIconSetInfo * pOldIconSetInfo,const tools::Rectangle & rRect,long nOneX,long nOneY,sc::IconSetBitmapMap & rIconSetBitmapMap)901 void drawIconSets(vcl::RenderContext& rRenderContext, const ScIconSetInfo* pOldIconSetInfo, const tools::Rectangle& rRect, long nOneX, long nOneY,
902 sc::IconSetBitmapMap & rIconSetBitmapMap)
903 {
904 //long nSize = 16;
905 ScIconSetType eType = pOldIconSetInfo->eIconSetType;
906 sal_Int32 nIndex = pOldIconSetInfo->nIconIndex;
907 const BitmapEx& rIcon = getIcon(rIconSetBitmapMap, eType, nIndex);
908 long aOrigSize = std::max<long>(0,std::min(rRect.GetSize().getWidth() - 4 * nOneX, rRect.GetSize().getHeight() -4 * nOneY));
909 rRenderContext.DrawBitmapEx( Point( rRect.Left() + 2 * nOneX, rRect.Top() + 2 * nOneY), Size(aOrigSize, aOrigSize), rIcon );
910 }
911
drawCells(vcl::RenderContext & rRenderContext,boost::optional<Color> const & pColor,const SvxBrushItem * pBackground,boost::optional<Color> & pOldColor,const SvxBrushItem * & pOldBackground,tools::Rectangle & rRect,long nPosX,long nLayoutSign,long nOneX,long nOneY,const ScDataBarInfo * pDataBarInfo,const ScDataBarInfo * & pOldDataBarInfo,const ScIconSetInfo * pIconSetInfo,const ScIconSetInfo * & pOldIconSetInfo,sc::IconSetBitmapMap & rIconSetBitmapMap)912 void drawCells(vcl::RenderContext& rRenderContext, boost::optional<Color> const & pColor, const SvxBrushItem* pBackground, boost::optional<Color>& pOldColor, const SvxBrushItem*& pOldBackground,
913 tools::Rectangle& rRect, long nPosX, long nLayoutSign, long nOneX, long nOneY, const ScDataBarInfo* pDataBarInfo, const ScDataBarInfo*& pOldDataBarInfo,
914 const ScIconSetInfo* pIconSetInfo, const ScIconSetInfo*& pOldIconSetInfo,
915 sc::IconSetBitmapMap & rIconSetBitmapMap)
916 {
917 long nSignedOneX = nOneX * nLayoutSign;
918 // need to paint if old color scale has been used and now
919 // we have a different color or a style based background
920 // we can here fall back to pointer comparison
921 if (pOldColor && (pBackground || pOldColor != pColor || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo))
922 {
923 rRect.SetRight( nPosX-nSignedOneX );
924 if( !pOldColor->GetTransparency() )
925 {
926 rRenderContext.SetFillColor( *pOldColor );
927 rRenderContext.DrawRect( rRect );
928 }
929 if( pOldDataBarInfo )
930 drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
931 if( pOldIconSetInfo )
932 drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
933
934 rRect.SetLeft( nPosX - nSignedOneX );
935 }
936
937 if ( pOldBackground && (pColor ||pBackground != pOldBackground || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
938 {
939 rRect.SetRight( nPosX-nSignedOneX );
940 if (pOldBackground) // ==0 if hidden
941 {
942 Color aBackCol = pOldBackground->GetColor();
943 if ( !aBackCol.GetTransparency() ) //! partial transparency?
944 {
945 rRenderContext.SetFillColor( aBackCol );
946 rRenderContext.DrawRect( rRect );
947 }
948 }
949 if( pOldDataBarInfo )
950 drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
951 if( pOldIconSetInfo )
952 drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
953
954 rRect.SetLeft( nPosX - nSignedOneX );
955 }
956
957 if (!pOldBackground && !pOldColor && (pDataBarInfo || pIconSetInfo))
958 {
959 rRect.SetRight( nPosX -nSignedOneX );
960 rRect.SetLeft( nPosX - nSignedOneX );
961 }
962
963 if(pColor)
964 {
965 // only update pOldColor if the colors changed
966 if (!pOldColor || *pOldColor != *pColor)
967 pOldColor = pColor;
968
969 pOldBackground = nullptr;
970 }
971 else if(pBackground)
972 {
973 pOldBackground = pBackground;
974 pOldColor.reset();
975 }
976
977 if(pDataBarInfo)
978 pOldDataBarInfo = pDataBarInfo;
979 else
980 pOldDataBarInfo = nullptr;
981
982 if(pIconSetInfo)
983 pOldIconSetInfo = pIconSetInfo;
984 else
985 pOldIconSetInfo = nullptr;
986 }
987
988 }
989
DrawBackground(vcl::RenderContext & rRenderContext)990 void ScOutputData::DrawBackground(vcl::RenderContext& rRenderContext)
991 {
992 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
993 long nOneXLogic = aOnePixel.Width();
994 long nOneYLogic = aOnePixel.Height();
995
996 // See more about bWorksInPixels in ScOutputData::DrawGrid
997 bool bWorksInPixels = false;
998 if (eType == OUTTYPE_WINDOW)
999 bWorksInPixels = true;
1000
1001 long nOneX = 1;
1002 long nOneY = 1;
1003 if (!bWorksInPixels)
1004 {
1005 nOneX = nOneXLogic;
1006 nOneY = nOneYLogic;
1007 }
1008
1009 tools::Rectangle aRect;
1010
1011 long nLayoutSign = bLayoutRTL ? -1 : 1;
1012
1013 rRenderContext.SetLineColor();
1014
1015 bool bShowProt = mbSyntaxMode && mpDoc->IsTabProtected(nTab);
1016 bool bDoAll = bShowProt || bPagebreakMode || bSolidBackground;
1017
1018 bool bCellContrast = mbUseStyleColor &&
1019 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
1020
1021 long nPosY = nScrY;
1022
1023 const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
1024 Color aProtectedColor( rColorCfg.GetColorValue( svtools::CALCPROTECTEDBACKGROUND ).nColor );
1025 std::shared_ptr<SvxBrushItem> pProtectedBackground( new SvxBrushItem( aProtectedColor, ATTR_BACKGROUND ) );
1026
1027 // iterate through the rows to show
1028 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1029 {
1030 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1031 long nRowHeight = pThisRowInfo->nHeight;
1032
1033 if ( pThisRowInfo->bChanged )
1034 {
1035 if ( ( ( pThisRowInfo->bEmptyBack ) || mbSyntaxMode ) && !bDoAll )
1036 {
1037 // nothing
1038 }
1039 else
1040 {
1041 // scan for rows with the same background:
1042 SCSIZE nSkip = 0;
1043 while ( nArrY+nSkip+2<nArrCount &&
1044 lcl_EqualBack( *pThisRowInfo, pRowInfo[nArrY+nSkip+1],
1045 nX1, nX2, bShowProt, bPagebreakMode ) )
1046 {
1047 ++nSkip;
1048 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1049 }
1050
1051 long nPosX = nScrX;
1052
1053 if ( bLayoutRTL )
1054 nPosX += nMirrorW - nOneX;
1055
1056 aRect = tools::Rectangle(nPosX, nPosY - nOneY, nPosX, nPosY - nOneY + nRowHeight);
1057 if (bWorksInPixels)
1058 aRect = rRenderContext.PixelToLogic(aRect); // internal data in pixels, but we'll be drawing in logic units
1059
1060 const SvxBrushItem* pOldBackground = nullptr;
1061 const SvxBrushItem* pBackground = nullptr;
1062 boost::optional<Color> pOldColor;
1063 const ScDataBarInfo* pOldDataBarInfo = nullptr;
1064 const ScIconSetInfo* pOldIconSetInfo = nullptr;
1065 SCCOL nMergedCols = 1;
1066 SCCOL nOldMerged = 0;
1067
1068 for (SCCOL nX=nX1; nX + nMergedCols <= nX2 + 1; nX += nOldMerged)
1069 {
1070 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+nMergedCols];
1071
1072 nOldMerged = nMergedCols;
1073
1074 if (bCellContrast)
1075 {
1076 // high contrast for cell borders and backgrounds -> empty background
1077 pBackground = ScGlobal::GetEmptyBrushItem();
1078 }
1079 else if (bShowProt) // show cell protection in syntax mode
1080 {
1081 const ScPatternAttr* pP = pInfo->pPatternAttr;
1082 if (pP)
1083 {
1084 const ScProtectionAttr& rProt = pP->GetItem(ATTR_PROTECTION);
1085 if (rProt.GetProtection() || rProt.GetHideCell())
1086 pBackground = pProtectedBackground.get();
1087 else
1088 pBackground = ScGlobal::GetEmptyBrushItem();
1089 }
1090 else
1091 pBackground = nullptr;
1092 }
1093 else
1094 pBackground = pInfo->pBackground;
1095
1096 if ( bPagebreakMode && !pInfo->bPrinted )
1097 pBackground = pProtectedBackground.get();
1098
1099 if ( pInfo->nRotateDir > ScRotateDir::Standard &&
1100 pBackground->GetColor().GetTransparency() != 255 &&
1101 !bCellContrast )
1102 {
1103 SCROW nY = pRowInfo[nArrY].nRowNo;
1104 pBackground = lcl_FindBackground( mpDoc, nX, nY, nTab );
1105 }
1106
1107 boost::optional<Color> const & pColor = pInfo->mxColorScale;
1108 const ScDataBarInfo* pDataBarInfo = pInfo->pDataBar.get();
1109 const ScIconSetInfo* pIconSetInfo = pInfo->pIconSet.get();
1110
1111 long nPosXLogic = nPosX;
1112 if (bWorksInPixels)
1113 nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
1114
1115 drawCells(rRenderContext, pColor, pBackground, pOldColor, pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneXLogic, nOneYLogic, pDataBarInfo, pOldDataBarInfo, pIconSetInfo, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
1116
1117 // extend for all merged cells
1118 nMergedCols = 1;
1119 if (pInfo->bMerged && pInfo->pPatternAttr)
1120 {
1121 const ScMergeAttr* pMerge =
1122 &pInfo->pPatternAttr->GetItem(ATTR_MERGE);
1123 nMergedCols = std::max<SCCOL>(1, pMerge->GetColMerge());
1124 }
1125
1126 for (SCCOL nMerged = 0; nMerged < nMergedCols; ++nMerged)
1127 {
1128 SCCOL nCol = nX+nOldMerged+nMerged;
1129 if (nCol > nX2+2)
1130 break;
1131 nPosX += pRowInfo[0].pCellInfo[nCol].nWidth * nLayoutSign;
1132 }
1133 }
1134
1135 long nPosXLogic = nPosX;
1136 if (bWorksInPixels)
1137 nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
1138
1139 drawCells(rRenderContext, boost::optional<Color>(), nullptr, pOldColor, pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneXLogic, nOneYLogic, nullptr, pOldDataBarInfo, nullptr, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
1140
1141 nArrY += nSkip;
1142 }
1143 }
1144 nPosY += nRowHeight;
1145 }
1146 }
1147
DrawShadow()1148 void ScOutputData::DrawShadow()
1149 {
1150 DrawExtraShadow( false, false, false, false );
1151 }
1152
DrawExtraShadow(bool bLeft,bool bTop,bool bRight,bool bBottom)1153 void ScOutputData::DrawExtraShadow(bool bLeft, bool bTop, bool bRight, bool bBottom)
1154 {
1155 mpDev->SetLineColor();
1156
1157 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1158 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1159 Color aAutoTextColor;
1160 if ( bCellContrast )
1161 aAutoTextColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
1162
1163 long nInitPosX = nScrX;
1164 if ( bLayoutRTL )
1165 {
1166 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1167 long nOneX = aOnePixel.Width();
1168 nInitPosX += nMirrorW - nOneX;
1169 }
1170 long nLayoutSign = bLayoutRTL ? -1 : 1;
1171
1172 long nPosY = nScrY - pRowInfo[0].nHeight;
1173 for (SCSIZE nArrY=0; nArrY<nArrCount; nArrY++)
1174 {
1175 bool bCornerY = ( nArrY == 0 ) || ( nArrY+1 == nArrCount );
1176 bool bSkipY = ( nArrY==0 && !bTop ) || ( nArrY+1 == nArrCount && !bBottom );
1177
1178 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1179 long nRowHeight = pThisRowInfo->nHeight;
1180
1181 if ( pThisRowInfo->bChanged && !bSkipY )
1182 {
1183 long nPosX = nInitPosX - pRowInfo[0].pCellInfo[nX1].nWidth * nLayoutSign;
1184 for (SCCOL nArrX=nX1; nArrX<=nX2+2; nArrX++)
1185 {
1186 bool bCornerX = ( nArrX==nX1 || nArrX==nX2+2 );
1187 bool bSkipX = ( nArrX==nX1 && !bLeft ) || ( nArrX==nX2+2 && !bRight );
1188
1189 for (sal_uInt16 nPass=0; nPass<2; nPass++) // horizontal / vertical
1190 {
1191 const SvxShadowItem* pAttr = nPass ?
1192 pThisRowInfo->pCellInfo[nArrX].pVShadowOrigin :
1193 pThisRowInfo->pCellInfo[nArrX].pHShadowOrigin;
1194 if ( pAttr && !bSkipX )
1195 {
1196 ScShadowPart ePart = nPass ?
1197 pThisRowInfo->pCellInfo[nArrX].eVShadowPart :
1198 pThisRowInfo->pCellInfo[nArrX].eHShadowPart;
1199
1200 bool bDo = true;
1201 if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
1202 if ( ePart != SC_SHADOW_CORNER )
1203 bDo = false;
1204
1205 if (bDo)
1206 {
1207 long nThisWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1208 long nMaxWidth = nThisWidth;
1209 if (!nMaxWidth)
1210 {
1211 //! direction must depend on shadow location
1212 SCCOL nWx = nArrX; // nX+1
1213 while (nWx<nX2 && !pRowInfo[0].pCellInfo[nWx+1].nWidth)
1214 ++nWx;
1215 nMaxWidth = pRowInfo[0].pCellInfo[nWx+1].nWidth;
1216 }
1217
1218 // rectangle is in logical orientation
1219 tools::Rectangle aRect( nPosX, nPosY,
1220 nPosX + ( nThisWidth - 1 ) * nLayoutSign,
1221 nPosY + pRowInfo[nArrY].nHeight - 1 );
1222
1223 long nSize = pAttr->GetWidth();
1224 long nSizeX = static_cast<long>(nSize*mnPPTX);
1225 if (nSizeX >= nMaxWidth) nSizeX = nMaxWidth-1;
1226 long nSizeY = static_cast<long>(nSize*mnPPTY);
1227 if (nSizeY >= nRowHeight) nSizeY = nRowHeight-1;
1228
1229 nSizeX *= nLayoutSign; // used only to add to rectangle values
1230
1231 SvxShadowLocation eLoc = pAttr->GetLocation();
1232 if ( bLayoutRTL )
1233 {
1234 // Shadow location is specified as "visual" (right is always right),
1235 // so the attribute's location value is mirrored here and in FillInfo.
1236 switch (eLoc)
1237 {
1238 case SvxShadowLocation::BottomRight: eLoc = SvxShadowLocation::BottomLeft; break;
1239 case SvxShadowLocation::BottomLeft: eLoc = SvxShadowLocation::BottomRight; break;
1240 case SvxShadowLocation::TopRight: eLoc = SvxShadowLocation::TopLeft; break;
1241 case SvxShadowLocation::TopLeft: eLoc = SvxShadowLocation::TopRight; break;
1242 default:
1243 {
1244 // added to avoid warnings
1245 }
1246 }
1247 }
1248
1249 if (ePart == SC_SHADOW_HORIZ || ePart == SC_SHADOW_HSTART ||
1250 ePart == SC_SHADOW_CORNER)
1251 {
1252 if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::TopRight)
1253 aRect.SetTop( aRect.Bottom() - nSizeY );
1254 else
1255 aRect.SetBottom( aRect.Top() + nSizeY );
1256 }
1257 if (ePart == SC_SHADOW_VERT || ePart == SC_SHADOW_VSTART ||
1258 ePart == SC_SHADOW_CORNER)
1259 {
1260 if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::BottomLeft)
1261 aRect.SetLeft( aRect.Right() - nSizeX );
1262 else
1263 aRect.SetRight( aRect.Left() + nSizeX );
1264 }
1265 if (ePart == SC_SHADOW_HSTART)
1266 {
1267 if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::BottomLeft)
1268 aRect.AdjustRight( -nSizeX );
1269 else
1270 aRect.AdjustLeft(nSizeX );
1271 }
1272 if (ePart == SC_SHADOW_VSTART)
1273 {
1274 if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::TopRight)
1275 aRect.AdjustBottom( -nSizeY );
1276 else
1277 aRect.AdjustTop(nSizeY );
1278 }
1279
1280 //! merge rectangles?
1281 mpDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
1282 mpDev->DrawRect( aRect );
1283 }
1284 }
1285 }
1286
1287 nPosX += pRowInfo[0].pCellInfo[nArrX].nWidth * nLayoutSign;
1288 }
1289 }
1290 nPosY += nRowHeight;
1291 }
1292 }
1293
DrawClear()1294 void ScOutputData::DrawClear()
1295 {
1296 tools::Rectangle aRect;
1297 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1298 long nOneX = aOnePixel.Width();
1299 long nOneY = aOnePixel.Height();
1300
1301 // (called only for ScGridWindow)
1302 Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1303
1304 if (bMetaFile)
1305 nOneX = nOneY = 0;
1306
1307 mpDev->SetLineColor();
1308
1309 mpDev->SetFillColor( aBgColor );
1310
1311 long nPosY = nScrY;
1312 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1313 {
1314 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1315 long nRowHeight = pThisRowInfo->nHeight;
1316
1317 if ( pThisRowInfo->bChanged )
1318 {
1319 // scan for more rows which must be painted:
1320 SCSIZE nSkip = 0;
1321 while ( nArrY+nSkip+2<nArrCount && pRowInfo[nArrY+nSkip+1].bChanged )
1322 {
1323 ++nSkip;
1324 nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
1325 }
1326
1327 aRect = tools::Rectangle( Point( nScrX, nPosY ),
1328 Size( nScrW+1-nOneX, nRowHeight+1-nOneY) );
1329 mpDev->DrawRect( aRect );
1330
1331 nArrY += nSkip;
1332 }
1333 nPosY += nRowHeight;
1334 }
1335 }
1336
1337 // Lines
1338
lclGetSnappedX(const OutputDevice & rDev,long nPosX,bool bSnapPixel)1339 static long lclGetSnappedX( const OutputDevice& rDev, long nPosX, bool bSnapPixel )
1340 {
1341 return (bSnapPixel && nPosX) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( nPosX, 0 ) ) ).Width() : nPosX;
1342 }
1343
lclGetSnappedY(const OutputDevice & rDev,long nPosY,bool bSnapPixel)1344 static long lclGetSnappedY( const OutputDevice& rDev, long nPosY, bool bSnapPixel )
1345 {
1346 return (bSnapPixel && nPosY) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( 0, nPosY ) ) ).Height() : nPosY;
1347 }
1348
lclGetArrayColFromCellInfoX(sal_uInt16 nCellInfoX,sal_uInt16 nCellInfoFirstX,sal_uInt16 nCellInfoLastX,bool bRTL)1349 static size_t lclGetArrayColFromCellInfoX( sal_uInt16 nCellInfoX, sal_uInt16 nCellInfoFirstX, sal_uInt16 nCellInfoLastX, bool bRTL )
1350 {
1351 return static_cast< size_t >( bRTL ? (nCellInfoLastX + 2 - nCellInfoX) : (nCellInfoX - nCellInfoFirstX) );
1352 }
1353
DrawFrame(vcl::RenderContext & rRenderContext)1354 void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)
1355 {
1356 DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode();
1357
1358 Color aSingleColor;
1359 bool bUseSingleColor = false;
1360 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1361 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1362
1363 // if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
1364 // for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
1365 // that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
1366 // must be reset and the border colors handled here.
1367
1368 if ( ( nOldDrawMode & DrawModeFlags::WhiteFill ) && ( nOldDrawMode & DrawModeFlags::BlackLine ) )
1369 {
1370 rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::WhiteFill) );
1371 aSingleColor = COL_BLACK;
1372 bUseSingleColor = true;
1373 }
1374 else if ( ( nOldDrawMode & DrawModeFlags::SettingsFill ) && ( nOldDrawMode & DrawModeFlags::SettingsLine ) )
1375 {
1376 rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::SettingsFill) );
1377 aSingleColor = rStyleSettings.GetWindowTextColor(); // same as used in VCL for DrawModeFlags::SettingsLine
1378 bUseSingleColor = true;
1379 }
1380 else if ( bCellContrast )
1381 {
1382 aSingleColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
1383 bUseSingleColor = true;
1384 }
1385
1386 const Color* pForceColor = bUseSingleColor ? &aSingleColor : nullptr;
1387
1388 if (mrTabInfo.maArray.HasCellRotation())
1389 {
1390 DrawRotatedFrame(rRenderContext); // removes the lines that must not be painted here
1391 }
1392
1393 long nInitPosX = nScrX;
1394 if ( bLayoutRTL )
1395 {
1396 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
1397 long nOneX = aOnePixel.Width();
1398 nInitPosX += nMirrorW - nOneX;
1399 }
1400 long nLayoutSign = bLayoutRTL ? -1 : 1;
1401
1402 // *** set column and row sizes of the frame border array ***
1403
1404 svx::frame::Array& rArray = mrTabInfo.maArray;
1405 size_t nColCount = rArray.GetColCount();
1406 size_t nRowCount = rArray.GetRowCount();
1407
1408 // row heights
1409
1410 // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
1411 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
1412 long nOldPosY = nScrY - 1 - pRowInfo[ 0 ].nHeight;
1413 long nOldSnapY = lclGetSnappedY( rRenderContext, nOldPosY, bSnapPixel );
1414 rArray.SetYOffset( nOldSnapY );
1415 for( size_t nRow = 0; nRow < nRowCount; ++nRow )
1416 {
1417 long nNewPosY = nOldPosY + pRowInfo[ nRow ].nHeight;
1418 long nNewSnapY = lclGetSnappedY( rRenderContext, nNewPosY, bSnapPixel );
1419 rArray.SetRowHeight( nRow, nNewSnapY - nOldSnapY );
1420 nOldPosY = nNewPosY;
1421 nOldSnapY = nNewSnapY;
1422 }
1423
1424 // column widths
1425
1426 // column nX1 is not visible (dummy for borders from left) - subtract its width from initial position
1427 // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
1428 long nOldPosX = nInitPosX - nLayoutSign * (1 + pRowInfo[ 0 ].pCellInfo[ nX1 ].nWidth);
1429 long nOldSnapX = lclGetSnappedX( rRenderContext, nOldPosX, bSnapPixel );
1430 // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
1431 if( !bLayoutRTL )
1432 rArray.SetXOffset( nOldSnapX );
1433 for( sal_uInt16 nInfoIdx = nX1; nInfoIdx <= nX2 + 2; ++nInfoIdx )
1434 {
1435 size_t nCol = lclGetArrayColFromCellInfoX( nInfoIdx, nX1, nX2, bLayoutRTL );
1436 long nNewPosX = nOldPosX + pRowInfo[ 0 ].pCellInfo[ nInfoIdx ].nWidth * nLayoutSign;
1437 long nNewSnapX = lclGetSnappedX( rRenderContext, nNewPosX, bSnapPixel );
1438 rArray.SetColWidth( nCol, std::abs( nNewSnapX - nOldSnapX ) );
1439 nOldPosX = nNewPosX;
1440 nOldSnapX = nNewSnapX;
1441 }
1442 if( bLayoutRTL )
1443 rArray.SetXOffset( nOldSnapX );
1444
1445 // *** draw the array ***
1446
1447 size_t nFirstCol = 1;
1448 size_t nFirstRow = 1;
1449 size_t nLastCol = nColCount - 2;
1450 size_t nLastRow = nRowCount - 2;
1451
1452 if( mrTabInfo.mbPageMode )
1453 rArray.SetClipRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
1454
1455 // draw only rows with set RowInfo::bChanged flag
1456 size_t nRow1 = nFirstRow;
1457 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D());
1458 if (!pProcessor)
1459 return;
1460 drawinglayer::primitive2d::Primitive2DContainer aPrimitives;
1461 while( nRow1 <= nLastRow )
1462 {
1463 while( (nRow1 <= nLastRow) && !pRowInfo[ nRow1 ].bChanged ) ++nRow1;
1464 if( nRow1 <= nLastRow )
1465 {
1466 size_t nRow2 = nRow1;
1467 while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
1468 aPrimitives.append(
1469 rArray.CreateB2DPrimitiveRange(
1470 nFirstCol, nRow1, nLastCol, nRow2, pForceColor ));
1471 nRow1 = nRow2 + 1;
1472 }
1473 }
1474 pProcessor->process(aPrimitives);
1475 pProcessor.reset();
1476
1477 rRenderContext.SetDrawMode(nOldDrawMode);
1478 }
1479
DrawRotatedFrame(vcl::RenderContext & rRenderContext)1480 void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext)
1481 {
1482 //! save nRotMax
1483 SCCOL nRotMax = nX2;
1484 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
1485 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
1486 nRotMax = pRowInfo[nRotY].nRotMaxCol;
1487
1488 const ScPatternAttr* pPattern;
1489 const SfxItemSet* pCondSet;
1490
1491 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1492 bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1493
1494 long nInitPosX = nScrX;
1495 if ( bLayoutRTL )
1496 {
1497 Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
1498 long nOneX = aOnePixel.Width();
1499 nInitPosX += nMirrorW - nOneX;
1500 }
1501 long nLayoutSign = bLayoutRTL ? -1 : 1;
1502
1503 tools::Rectangle aClipRect( Point(nScrX, nScrY), Size(nScrW, nScrH) );
1504 if (bMetaFile)
1505 {
1506 rRenderContext.Push();
1507 rRenderContext.IntersectClipRegion( aClipRect );
1508 }
1509 else
1510 rRenderContext.SetClipRegion( vcl::Region( aClipRect ) );
1511
1512 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D( ));
1513 long nPosY = nScrY;
1514 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
1515 {
1516 // Rotated is also drawn one line above/below Changed if parts extend into the cell
1517
1518 RowInfo& rPrevRowInfo = pRowInfo[nArrY-1];
1519 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1520 RowInfo& rNextRowInfo = pRowInfo[nArrY+1];
1521
1522 long nRowHeight = rThisRowInfo.nHeight;
1523 if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
1524 ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
1525 ( nArrY+1<nArrCount && rNextRowInfo.bChanged ) ) )
1526 {
1527 SCROW nY = rThisRowInfo.nRowNo;
1528 long nPosX = 0;
1529 SCCOL nX;
1530 for (nX=0; nX<=nRotMax; nX++)
1531 {
1532 if (nX==nX1) nPosX = nInitPosX; // calculated individually for preceding positions
1533
1534 sal_uInt16 nArrX = nX + 1;
1535
1536 CellInfo* pInfo = &rThisRowInfo.pCellInfo[nArrX];
1537 long nColWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1538 if ( pInfo->nRotateDir > ScRotateDir::Standard &&
1539 !pInfo->bHOverlapped && !pInfo->bVOverlapped )
1540 {
1541 pPattern = pInfo->pPatternAttr;
1542 pCondSet = pInfo->pConditionSet;
1543 if (!pPattern)
1544 {
1545 pPattern = mpDoc->GetPattern( nX, nY, nTab );
1546 pInfo->pPatternAttr = pPattern;
1547 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
1548 pInfo->pConditionSet = pCondSet;
1549 }
1550
1551 //! LastPattern etc.
1552
1553 long nAttrRotate = pPattern->GetRotateVal( pCondSet );
1554 SvxRotateMode eRotMode =
1555 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
1556
1557 if (nAttrRotate)
1558 {
1559 if (nX < nX1) // compute negative position
1560 {
1561 nPosX = nInitPosX;
1562 SCCOL nCol = nX1;
1563 while (nCol > nX)
1564 {
1565 --nCol;
1566 nPosX -= nLayoutSign * static_cast<long>(pRowInfo[0].pCellInfo[nCol + 1].nWidth);
1567 }
1568 }
1569
1570 // start position minus 1 so rotated backgrounds suit the border
1571 // (border is on the grid)
1572
1573 long nTop = nPosY - 1;
1574 long nBottom = nPosY + nRowHeight - 1;
1575 long nTopLeft = nPosX - nLayoutSign;
1576 long nTopRight = nPosX + (nColWidth - 1) * nLayoutSign;
1577 long nBotLeft = nTopLeft;
1578 long nBotRight = nTopRight;
1579
1580 // inclusion of the sign here hasn't been decided yet
1581 // (if not, the extension of the non-rotated background must also be changed)
1582 double nRealOrient = nLayoutSign * nAttrRotate * F_PI18000; // 1/100th degrees
1583 double nCos = cos(nRealOrient);
1584 double nSin = sin(nRealOrient);
1585 //! restrict !!!
1586 long nSkew = static_cast<long>(nRowHeight * nCos / nSin);
1587
1588 switch (eRotMode)
1589 {
1590 case SVX_ROTATE_MODE_BOTTOM:
1591 nTopLeft += nSkew;
1592 nTopRight += nSkew;
1593 break;
1594 case SVX_ROTATE_MODE_CENTER:
1595 nSkew /= 2;
1596 nTopLeft += nSkew;
1597 nTopRight += nSkew;
1598 nBotLeft -= nSkew;
1599 nBotRight -= nSkew;
1600 break;
1601 case SVX_ROTATE_MODE_TOP:
1602 nBotLeft -= nSkew;
1603 nBotRight -= nSkew;
1604 break;
1605 default:
1606 {
1607 // added to avoid warnings
1608 }
1609 }
1610
1611 Point aPoints[4];
1612 aPoints[0] = Point(nTopLeft, nTop);
1613 aPoints[1] = Point(nTopRight, nTop);
1614 aPoints[2] = Point(nBotRight, nBottom);
1615 aPoints[3] = Point(nBotLeft, nBottom);
1616
1617 const SvxBrushItem* pBackground = pInfo->pBackground;
1618 if (!pBackground)
1619 pBackground = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
1620 if (bCellContrast)
1621 {
1622 // high contrast for cell borders and backgrounds -> empty background
1623 pBackground = ScGlobal::GetEmptyBrushItem();
1624 }
1625 if (!pInfo->mxColorScale)
1626 {
1627 const Color& rColor = pBackground->GetColor();
1628 if (rColor.GetTransparency() != 255)
1629 {
1630 // draw background only for the changed row itself
1631 // (background doesn't extend into other cells).
1632 // For the borders (rotated and normal), clipping should be
1633 // set if the row isn't changed, but at least the borders
1634 // don't cover the cell contents.
1635 if (rThisRowInfo.bChanged)
1636 {
1637 tools::Polygon aPoly(4, aPoints);
1638
1639 // for DrawPolygon, without Pen one pixel is left out
1640 // to the right and below...
1641 if (rColor.GetTransparency() == 0)
1642 rRenderContext.SetLineColor(rColor);
1643 else
1644 rRenderContext.SetLineColor();
1645 rRenderContext.SetFillColor(rColor);
1646 rRenderContext.DrawPolygon(aPoly);
1647 }
1648 }
1649 }
1650 else
1651 {
1652 tools::Polygon aPoly(4, aPoints);
1653 boost::optional<Color> const & pColor = pInfo->mxColorScale;
1654
1655 // for DrawPolygon, without Pen one pixel is left out
1656 // to the right and below...
1657 if (pColor->GetTransparency() == 0)
1658 rRenderContext.SetLineColor(*pColor);
1659 else
1660 rRenderContext.SetLineColor();
1661 rRenderContext.SetFillColor(*pColor);
1662 rRenderContext.DrawPolygon(aPoly);
1663
1664 }
1665 }
1666 }
1667 nPosX += nColWidth * nLayoutSign;
1668 }
1669 }
1670 nPosY += nRowHeight;
1671 }
1672
1673 pProcessor.reset();
1674
1675 if (bMetaFile)
1676 rRenderContext.Pop();
1677 else
1678 rRenderContext.SetClipRegion();
1679 }
1680
CreateProcessor2D()1681 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> ScOutputData::CreateProcessor2D( )
1682 {
1683 mpDoc->InitDrawLayer(mpDoc->GetDocumentShell());
1684 ScDrawLayer* pDrawLayer = mpDoc->GetDrawLayer();
1685 if (!pDrawLayer)
1686 return nullptr;
1687
1688 basegfx::B2DRange aViewRange;
1689 SdrPage *pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
1690 const drawinglayer::geometry::ViewInformation2D aNewViewInfos(
1691 basegfx::B2DHomMatrix( ),
1692 mpDev->GetViewTransformation(),
1693 aViewRange,
1694 GetXDrawPageForSdrPage( pDrawPage ),
1695 0.0,
1696 uno::Sequence< beans::PropertyValue >() );
1697
1698 return drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
1699 *mpDev, aNewViewInfos );
1700 }
1701
1702 // Printer
1703
GetChangedAreaRegion()1704 vcl::Region ScOutputData::GetChangedAreaRegion()
1705 {
1706 vcl::Region aRegion;
1707 tools::Rectangle aDrawingRect;
1708 bool bHad(false);
1709 long nPosY = nScrY;
1710 SCSIZE nArrY;
1711
1712 aDrawingRect.SetLeft( nScrX );
1713 aDrawingRect.SetRight( nScrX+nScrW-1 );
1714
1715 for(nArrY=1; nArrY+1<nArrCount; nArrY++)
1716 {
1717 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1718
1719 if(pThisRowInfo->bChanged)
1720 {
1721 if(!bHad)
1722 {
1723 aDrawingRect.SetTop( nPosY );
1724 bHad = true;
1725 }
1726
1727 aDrawingRect.SetBottom( nPosY + pRowInfo[nArrY].nHeight - 1 );
1728 }
1729 else if(bHad)
1730 {
1731 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1732 bHad = false;
1733 }
1734
1735 nPosY += pRowInfo[nArrY].nHeight;
1736 }
1737
1738 if(bHad)
1739 {
1740 aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1741 }
1742
1743 return aRegion;
1744 }
1745
SetChangedClip()1746 bool ScOutputData::SetChangedClip()
1747 {
1748 tools::PolyPolygon aPoly;
1749
1750 tools::Rectangle aDrawingRect;
1751 aDrawingRect.SetLeft( nScrX );
1752 aDrawingRect.SetRight( nScrX+nScrW-1 );
1753
1754 bool bHad = false;
1755 long nPosY = nScrY;
1756 SCSIZE nArrY;
1757 for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1758 {
1759 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1760
1761 if ( pThisRowInfo->bChanged )
1762 {
1763 if (!bHad)
1764 {
1765 aDrawingRect.SetTop( nPosY );
1766 bHad = true;
1767 }
1768 aDrawingRect.SetBottom( nPosY + pRowInfo[nArrY].nHeight - 1 );
1769 }
1770 else if (bHad)
1771 {
1772 aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1773 bHad = false;
1774 }
1775 nPosY += pRowInfo[nArrY].nHeight;
1776 }
1777
1778 if (bHad)
1779 aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1780
1781 bool bRet = (aPoly.Count() != 0);
1782 if (bRet)
1783 mpDev->SetClipRegion(vcl::Region(aPoly));
1784 return bRet;
1785 }
1786
FindChanged()1787 void ScOutputData::FindChanged()
1788 {
1789 SCCOL nX;
1790 SCSIZE nArrY;
1791
1792 bool bWasIdleEnabled = mpDoc->IsIdleEnabled();
1793 mpDoc->EnableIdle(false);
1794 for (nArrY=0; nArrY<nArrCount; nArrY++)
1795 pRowInfo[nArrY].bChanged = false;
1796
1797 SCCOL nCol1 = mpDoc->MaxCol(), nCol2 = 0;
1798 SCROW nRow1 = mpDoc->MaxRow(), nRow2 = 0;
1799 bool bAnyDirty = false;
1800 bool bAnyChanged = false;
1801
1802 for (nArrY=0; nArrY<nArrCount; nArrY++)
1803 {
1804 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1805 for (nX=nX1; nX<=nX2; nX++)
1806 {
1807 const ScRefCellValue& rCell = pThisRowInfo->pCellInfo[nX+1].maCell;
1808
1809 if (rCell.meType != CELLTYPE_FORMULA)
1810 continue;
1811
1812 ScFormulaCell* pFCell = rCell.mpFormula;
1813 if (pFCell->IsRunning())
1814 // still being interpreted. Skip it.
1815 continue;
1816
1817 bool bDirty = pFCell->GetDirty();
1818 bAnyChanged = bAnyChanged || pFCell->IsChanged();
1819
1820 if (bDirty)
1821 {
1822 if (!bAnyDirty)
1823 {
1824 ScProgress::CreateInterpretProgress(mpDoc);
1825 bAnyDirty = true;
1826 }
1827
1828 ScAddress& rPos(pFCell->aPos);
1829 nCol1 = std::min(rPos.Col(), nCol1);
1830 nCol2 = std::max(rPos.Col(), nCol2);
1831 nRow1 = std::min(rPos.Row(), nRow1);
1832 nRow2 = std::max(rPos.Row(), nRow2);
1833 }
1834 }
1835 }
1836
1837 if (bAnyDirty || bAnyChanged)
1838 {
1839 if (bAnyDirty)
1840 mpDoc->EnsureFormulaCellResults(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab), true);
1841
1842 for (nArrY=0; nArrY<nArrCount; nArrY++)
1843 {
1844 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1845 for (nX=nX1; nX<=nX2; nX++)
1846 {
1847 const ScRefCellValue& rCell = pThisRowInfo->pCellInfo[nX+1].maCell;
1848
1849 if (rCell.meType != CELLTYPE_FORMULA)
1850 continue;
1851
1852 ScFormulaCell* pFCell = rCell.mpFormula;
1853 if (pFCell->IsRunning())
1854 // still being interpreted. Skip it.
1855 continue;
1856
1857 if (!pFCell->IsChanged())
1858 // the result hasn't changed. Skip it.
1859 continue;
1860
1861 pThisRowInfo->bChanged = true;
1862 if ( pThisRowInfo->pCellInfo[nX+1].bMerged )
1863 {
1864 SCSIZE nOverY = nArrY + 1;
1865 while ( nOverY<nArrCount &&
1866 pRowInfo[nOverY].pCellInfo[nX+1].bVOverlapped )
1867 {
1868 pRowInfo[nOverY].bChanged = true;
1869 ++nOverY;
1870 }
1871 }
1872 }
1873 }
1874
1875 if (bAnyDirty)
1876 ScProgress::DeleteInterpretProgress();
1877 }
1878
1879 mpDoc->EnableIdle(bWasIdleEnabled);
1880 }
1881
FillReferenceMark(SCCOL nRefStartX,SCROW nRefStartY,SCCOL nRefEndX,SCROW nRefEndY,const Color & rColor)1882 ReferenceMark ScOutputData::FillReferenceMark( SCCOL nRefStartX, SCROW nRefStartY,
1883 SCCOL nRefEndX, SCROW nRefEndY, const Color& rColor)
1884 {
1885 ReferenceMark aResult;
1886
1887 PutInOrder( nRefStartX, nRefEndX );
1888 PutInOrder( nRefStartY, nRefEndY );
1889
1890 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
1891 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
1892
1893 if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
1894 nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
1895 {
1896 long nMinX = nScrX;
1897 long nMinY = nScrY;
1898 long nMaxX = nScrX + nScrW - 1;
1899 long nMaxY = nScrY + nScrH - 1;
1900 if ( bLayoutRTL )
1901 {
1902 long nTemp = nMinX;
1903 nMinX = nMaxX;
1904 nMaxX = nTemp;
1905 }
1906 long nLayoutSign = bLayoutRTL ? -1 : 1;
1907
1908 bool bTop = false;
1909 bool bBottom = false;
1910 bool bLeft = false;
1911 bool bRight = false;
1912
1913 long nPosY = nScrY;
1914 bool bNoStartY = ( nY1 < nRefStartY );
1915 bool bNoEndY = false;
1916 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
1917 {
1918 SCROW nY = pRowInfo[nArrY].nRowNo;
1919
1920 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
1921 {
1922 nMinY = nPosY;
1923 bTop = true;
1924 }
1925 if ( nY==nRefEndY )
1926 {
1927 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
1928 bBottom = true;
1929 }
1930 if ( nY>nRefEndY && bNoEndY )
1931 {
1932 nMaxY = nPosY-2;
1933 bBottom = true;
1934 }
1935 bNoStartY = ( nY < nRefStartY );
1936 bNoEndY = ( nY < nRefEndY );
1937 nPosY += pRowInfo[nArrY].nHeight;
1938 }
1939
1940 long nPosX = nScrX;
1941 if ( bLayoutRTL )
1942 nPosX += nMirrorW - 1; // always in pixels
1943
1944 for (SCCOL nX=nX1; nX<=nX2; nX++)
1945 {
1946 if ( nX==nRefStartX )
1947 {
1948 nMinX = nPosX;
1949 bLeft = true;
1950 }
1951 if ( nX==nRefEndX )
1952 {
1953 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 2 ) * nLayoutSign;
1954 bRight = true;
1955 }
1956 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
1957 }
1958
1959 if (bTop && bBottom && bLeft && bRight)
1960 {
1961 aResult = ReferenceMark( nMinX / mnPPTX * double( aZoomX ),
1962 nMinY / mnPPTY * double( aZoomY ),
1963 ( nMaxX - nMinX ) / mnPPTX * double( aZoomX ),
1964 ( nMaxY - nMinY ) / mnPPTY * double( aZoomY ),
1965 nTab,
1966 rColor );
1967 }
1968 }
1969
1970 return aResult;
1971 }
1972
DrawRefMark(SCCOL nRefStartX,SCROW nRefStartY,SCCOL nRefEndX,SCROW nRefEndY,const Color & rColor,bool bHandle)1973 void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
1974 SCCOL nRefEndX, SCROW nRefEndY,
1975 const Color& rColor, bool bHandle )
1976 {
1977 PutInOrder( nRefStartX, nRefEndX );
1978 PutInOrder( nRefStartY, nRefEndY );
1979
1980 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
1981 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
1982
1983 if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
1984 nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
1985 {
1986 long nMinX = nScrX;
1987 long nMinY = nScrY;
1988 long nMaxX = nScrX + nScrW - 1;
1989 long nMaxY = nScrY + nScrH - 1;
1990 if ( bLayoutRTL )
1991 {
1992 long nTemp = nMinX;
1993 nMinX = nMaxX;
1994 nMaxX = nTemp;
1995 }
1996 long nLayoutSign = bLayoutRTL ? -1 : 1;
1997
1998 bool bTop = false;
1999 bool bBottom = false;
2000 bool bLeft = false;
2001 bool bRight = false;
2002
2003 long nPosY = nScrY;
2004 bool bNoStartY = ( nY1 < nRefStartY );
2005 bool bNoEndY = false;
2006 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2007 {
2008 SCROW nY = pRowInfo[nArrY].nRowNo;
2009
2010 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2011 {
2012 nMinY = nPosY;
2013 bTop = true;
2014 }
2015 if ( nY==nRefEndY )
2016 {
2017 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
2018 bBottom = true;
2019 }
2020 if ( nY>nRefEndY && bNoEndY )
2021 {
2022 nMaxY = nPosY-2;
2023 bBottom = true;
2024 }
2025 bNoStartY = ( nY < nRefStartY );
2026 bNoEndY = ( nY < nRefEndY );
2027 nPosY += pRowInfo[nArrY].nHeight;
2028 }
2029
2030 long nPosX = nScrX;
2031 if ( bLayoutRTL )
2032 nPosX += nMirrorW - 1; // always in pixels
2033
2034 for (SCCOL nX=nX1; nX<=nX2; nX++)
2035 {
2036 if ( nX==nRefStartX )
2037 {
2038 nMinX = nPosX;
2039 bLeft = true;
2040 }
2041 if ( nX==nRefEndX )
2042 {
2043 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 2 ) * nLayoutSign;
2044 bRight = true;
2045 }
2046 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2047 }
2048
2049 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2050 nMaxY >= nMinY )
2051 {
2052 mpDev->SetLineColor( rColor );
2053 if (bTop && bBottom && bLeft && bRight && !comphelper::LibreOfficeKit::isActive() )
2054 {
2055 mpDev->SetFillColor();
2056 mpDev->DrawRect( tools::Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2057 }
2058 else if ( !comphelper::LibreOfficeKit::isActive() )
2059 {
2060 if (bTop)
2061 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMaxX, nMinY ) );
2062 if (bBottom)
2063 mpDev->DrawLine( Point( nMinX, nMaxY ), Point( nMaxX, nMaxY ) );
2064 if (bLeft)
2065 mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMinX, nMaxY ) );
2066 if (bRight)
2067 mpDev->DrawLine( Point( nMaxX, nMinY ), Point( nMaxX, nMaxY ) );
2068 }
2069 if ( bHandle && bRight && bBottom && !comphelper::LibreOfficeKit::isActive() )
2070 {
2071 mpDev->SetLineColor( rColor );
2072 mpDev->SetFillColor( rColor );
2073
2074 const sal_Int32 aRadius = 4;
2075
2076 sal_Int32 aRectMaxX1 = nMaxX - nLayoutSign * aRadius;
2077 sal_Int32 aRectMaxX2 = nMaxX + nLayoutSign;
2078 sal_Int32 aRectMinX1 = nMinX - nLayoutSign;
2079 sal_Int32 aRectMinX2 = nMinX + nLayoutSign * aRadius;
2080
2081 sal_Int32 aRectMaxY1 = nMaxY - aRadius;
2082 sal_Int32 aRectMaxY2 = nMaxY + 1;
2083 sal_Int32 aRectMinY1 = nMinY - 1;
2084 sal_Int32 aRectMinY2 = nMinY + aRadius;
2085
2086 // Draw corner rectangles
2087 tools::Rectangle aLowerRight( aRectMaxX1, aRectMaxY1, aRectMaxX2, aRectMaxY2 );
2088 tools::Rectangle aUpperLeft ( aRectMinX1, aRectMinY1, aRectMinX2, aRectMinY2 );
2089 tools::Rectangle aLowerLeft ( aRectMinX1, aRectMaxY1, aRectMinX2, aRectMaxY2 );
2090 tools::Rectangle aUpperRight( aRectMaxX1, aRectMinY1, aRectMaxX2, aRectMinY2 );
2091
2092 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerRight ) ), lclCornerRectTransparency );
2093 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperLeft ) ), lclCornerRectTransparency );
2094 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerLeft ) ), lclCornerRectTransparency );
2095 mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperRight ) ), lclCornerRectTransparency );
2096 }
2097 }
2098 }
2099 }
2100
DrawOneChange(SCCOL nRefStartX,SCROW nRefStartY,SCCOL nRefEndX,SCROW nRefEndY,const Color & rColor,sal_uInt16 nType)2101 void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
2102 SCCOL nRefEndX, SCROW nRefEndY,
2103 const Color& rColor, sal_uInt16 nType )
2104 {
2105 PutInOrder( nRefStartX, nRefEndX );
2106 PutInOrder( nRefStartY, nRefEndY );
2107
2108 if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2109 mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
2110
2111 if ( nRefStartX <= nVisX2 + 1 && nRefEndX >= nVisX1 &&
2112 nRefStartY <= nVisY2 + 1 && nRefEndY >= nVisY1 ) // +1 because it touches next cells left/top
2113 {
2114 long nMinX = nScrX;
2115 long nMinY = nScrY;
2116 long nMaxX = nScrX+nScrW-1;
2117 long nMaxY = nScrY+nScrH-1;
2118 if ( bLayoutRTL )
2119 {
2120 long nTemp = nMinX;
2121 nMinX = nMaxX;
2122 nMaxX = nTemp;
2123 }
2124 long nLayoutSign = bLayoutRTL ? -1 : 1;
2125
2126 bool bTop = false;
2127 bool bBottom = false;
2128 bool bLeft = false;
2129 bool bRight = false;
2130
2131 long nPosY = nScrY;
2132 bool bNoStartY = ( nY1 < nRefStartY );
2133 bool bNoEndY = false;
2134 for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
2135 {
2136 SCROW nY = pRowInfo[nArrY].nRowNo;
2137
2138 if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2139 {
2140 nMinY = nPosY - 1;
2141 bTop = true;
2142 }
2143 if ( nY==nRefEndY )
2144 {
2145 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
2146 bBottom = true;
2147 }
2148 if ( nY>nRefEndY && bNoEndY )
2149 {
2150 nMaxY = nPosY - 1;
2151 bBottom = true;
2152 }
2153 bNoStartY = ( nY < nRefStartY );
2154 bNoEndY = ( nY < nRefEndY );
2155 nPosY += pRowInfo[nArrY].nHeight;
2156 }
2157
2158 long nPosX = nScrX;
2159 if ( bLayoutRTL )
2160 nPosX += nMirrorW - 1; // always in pixels
2161
2162 for (SCCOL nX=nX1; nX<=nX2+1; nX++)
2163 {
2164 if ( nX==nRefStartX )
2165 {
2166 nMinX = nPosX - nLayoutSign;
2167 bLeft = true;
2168 }
2169 if ( nX==nRefEndX )
2170 {
2171 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 1 ) * nLayoutSign;
2172 bRight = true;
2173 }
2174 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2175 }
2176
2177 if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2178 nMaxY >= nMinY )
2179 {
2180 if ( nType == SC_CAT_DELETE_ROWS )
2181 bLeft = bRight = bBottom = false; //! thick lines???
2182 else if ( nType == SC_CAT_DELETE_COLS )
2183 bTop = bBottom = bRight = false; //! thick lines???
2184
2185 mpDev->SetLineColor( rColor );
2186 if (bTop && bBottom && bLeft && bRight)
2187 {
2188 mpDev->SetFillColor();
2189 mpDev->DrawRect( tools::Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2190 }
2191 else
2192 {
2193 if (bTop)
2194 {
2195 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2196 if ( nType == SC_CAT_DELETE_ROWS )
2197 mpDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
2198 }
2199 if (bBottom)
2200 mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2201 if (bLeft)
2202 {
2203 mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2204 if ( nType == SC_CAT_DELETE_COLS )
2205 mpDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
2206 }
2207 if (bRight)
2208 mpDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2209 }
2210 if ( bLeft && bTop )
2211 {
2212 mpDev->SetLineColor();
2213 mpDev->SetFillColor( rColor );
2214 mpDev->DrawRect( tools::Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
2215 }
2216 }
2217 }
2218 }
2219
DrawChangeTrack()2220 void ScOutputData::DrawChangeTrack()
2221 {
2222 ScChangeTrack* pTrack = mpDoc->GetChangeTrack();
2223 ScChangeViewSettings* pSettings = mpDoc->GetChangeViewSettings();
2224 if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
2225 return; // nothing there or hidden
2226
2227 ScActionColorChanger aColorChanger(*pTrack);
2228
2229 // clipping happens from the outside
2230 //! without clipping, only paint affected cells ??!??!?
2231
2232 SCCOL nEndX = nX2;
2233 SCROW nEndY = nY2;
2234 if ( nEndX < mpDoc->MaxCol() ) ++nEndX; // also from the next cell since the mark
2235 if ( nEndY < mpDoc->MaxRow() ) ++nEndY; // protrudes from the preceding cell
2236 ScRange aViewRange( nX1, nY1, nTab, nEndX, nEndY, nTab );
2237 const ScChangeAction* pAction = pTrack->GetFirst();
2238 while (pAction)
2239 {
2240 ScChangeActionType eActionType;
2241 if ( pAction->IsVisible() )
2242 {
2243 eActionType = pAction->GetType();
2244 const ScBigRange& rBig = pAction->GetBigRange();
2245 if ( rBig.aStart.Tab() == nTab )
2246 {
2247 ScRange aRange = rBig.MakeRange();
2248
2249 if ( eActionType == SC_CAT_DELETE_ROWS )
2250 aRange.aEnd.SetRow( aRange.aStart.Row() );
2251 else if ( eActionType == SC_CAT_DELETE_COLS )
2252 aRange.aEnd.SetCol( aRange.aStart.Col() );
2253
2254 if ( aRange.Intersects( aViewRange ) &&
2255 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2256 {
2257 aColorChanger.Update( *pAction );
2258 Color aColor( aColorChanger.GetColor() );
2259 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2260 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2261
2262 }
2263 }
2264 if ( eActionType == SC_CAT_MOVE &&
2265 static_cast<const ScChangeActionMove*>(pAction)->
2266 GetFromRange().aStart.Tab() == nTab )
2267 {
2268 ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
2269 GetFromRange().MakeRange();
2270 if ( aRange.Intersects( aViewRange ) &&
2271 ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2272 {
2273 aColorChanger.Update( *pAction );
2274 Color aColor( aColorChanger.GetColor() );
2275 DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2276 aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2277 }
2278 }
2279 }
2280
2281 pAction = pAction->GetNext();
2282 }
2283 }
2284
2285 //TODO: moggi Need to check if this can't be written simpler
DrawNoteMarks(vcl::RenderContext & rRenderContext)2286 void ScOutputData::DrawNoteMarks(vcl::RenderContext& rRenderContext)
2287 {
2288
2289 bool bFirst = true;
2290
2291 long nInitPosX = nScrX;
2292 if ( bLayoutRTL )
2293 nInitPosX += nMirrorW - 1; // always in pixels
2294 long nLayoutSign = bLayoutRTL ? -1 : 1;
2295
2296 long nPosY = nScrY;
2297 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2298 {
2299 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2300 if ( pThisRowInfo->bChanged )
2301 {
2302 long nPosX = nInitPosX;
2303 for (SCCOL nX=nX1; nX<=nX2; nX++)
2304 {
2305 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2306 bool bIsMerged = false;
2307
2308 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2309 {
2310 // find start of merged cell
2311 bIsMerged = true;
2312 SCROW nY = pRowInfo[nArrY].nRowNo;
2313 SCCOL nMergeX = nX;
2314 SCROW nMergeY = nY;
2315 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2316 // use origin's pCell for NotePtr test below
2317 }
2318
2319 if ( mpDoc->GetNote(nX, pRowInfo[nArrY].nRowNo, nTab) && ( bIsMerged ||
2320 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2321 {
2322 if (bFirst)
2323 {
2324 rRenderContext.SetLineColor(COL_WHITE);
2325
2326 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2327 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2328 rRenderContext.SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2329 else
2330 rRenderContext.SetFillColor(COL_LIGHTRED);
2331
2332 bFirst = false;
2333 }
2334
2335 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 4 ) * nLayoutSign;
2336 if ( bIsMerged || pInfo->bMerged )
2337 {
2338 // if merged, add widths of all cells
2339 SCCOL nNextX = nX + 1;
2340 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2341 {
2342 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2343 ++nNextX;
2344 }
2345 }
2346 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2347 rRenderContext.DrawRect( tools::Rectangle( nMarkX-5*nLayoutSign,nPosY,nMarkX+1*nLayoutSign,nPosY+6 ) );
2348 }
2349
2350 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2351 }
2352 }
2353 nPosY += pThisRowInfo->nHeight;
2354 }
2355 }
2356
AddPDFNotes()2357 void ScOutputData::AddPDFNotes()
2358 {
2359 vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >( mpDev->GetExtOutDevData() );
2360 if ( !pPDFData || !pPDFData->GetIsExportNotes() )
2361 return;
2362
2363 long nInitPosX = nScrX;
2364 if ( bLayoutRTL )
2365 {
2366 Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
2367 long nOneX = aOnePixel.Width();
2368 nInitPosX += nMirrorW - nOneX;
2369 }
2370 long nLayoutSign = bLayoutRTL ? -1 : 1;
2371
2372 long nPosY = nScrY;
2373 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2374 {
2375 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2376 if ( pThisRowInfo->bChanged )
2377 {
2378 long nPosX = nInitPosX;
2379 for (SCCOL nX=nX1; nX<=nX2; nX++)
2380 {
2381 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2382 bool bIsMerged = false;
2383 SCROW nY = pRowInfo[nArrY].nRowNo;
2384 SCCOL nMergeX = nX;
2385 SCROW nMergeY = nY;
2386
2387 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2388 {
2389 // find start of merged cell
2390 bIsMerged = true;
2391 mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2392 // use origin's pCell for NotePtr test below
2393 }
2394
2395 if ( mpDoc->GetNote(nMergeX, nMergeY, nTab) && ( bIsMerged ||
2396 ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2397 {
2398 long nNoteWidth = static_cast<long>( SC_CLIPMARK_SIZE * mnPPTX );
2399 long nNoteHeight = static_cast<long>( SC_CLIPMARK_SIZE * mnPPTY );
2400
2401 long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - nNoteWidth ) * nLayoutSign;
2402 if ( bIsMerged || pInfo->bMerged )
2403 {
2404 // if merged, add widths of all cells
2405 SCCOL nNextX = nX + 1;
2406 while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2407 {
2408 nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2409 ++nNextX;
2410 }
2411 }
2412 if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2413 {
2414 tools::Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
2415 const ScPostIt* pNote = mpDoc->GetNote(nMergeX, nMergeY, nTab);
2416
2417 // Note title is the cell address (as on printed note pages)
2418 ScAddress aAddress( nMergeX, nMergeY, nTab );
2419 OUString aTitle(aAddress.Format(ScRefFlags::VALID, mpDoc, mpDoc->GetAddressConvention()));
2420
2421 // Content has to be a simple string without line breaks
2422 OUString aContent = pNote->GetText();
2423 aContent = aContent.replaceAll("\n", " ");
2424
2425 vcl::PDFNote aNote;
2426 aNote.Title = aTitle;
2427 aNote.Contents = aContent;
2428 pPDFData->CreateNote( aNoteRect, aNote );
2429 }
2430 }
2431
2432 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2433 }
2434 }
2435 nPosY += pThisRowInfo->nHeight;
2436 }
2437 }
2438
DrawClipMarks()2439 void ScOutputData::DrawClipMarks()
2440 {
2441 if (!bAnyClipped)
2442 return;
2443
2444 Color aArrowFillCol( COL_LIGHTRED );
2445
2446 DrawModeFlags nOldDrawMode = mpDev->GetDrawMode();
2447 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2448 if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2449 {
2450 // use DrawMode to change the arrow's outline color
2451 mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::SettingsLine );
2452 // use text color also for the fill color
2453 aArrowFillCol = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
2454 }
2455
2456 long nInitPosX = nScrX;
2457 if ( bLayoutRTL )
2458 nInitPosX += nMirrorW - 1; // always in pixels
2459 long nLayoutSign = bLayoutRTL ? -1 : 1;
2460
2461 tools::Rectangle aCellRect;
2462 long nPosY = nScrY;
2463 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2464 {
2465 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2466 if ( pThisRowInfo->bChanged )
2467 {
2468 SCROW nY = pThisRowInfo->nRowNo;
2469 long nPosX = nInitPosX;
2470 for (SCCOL nX=nX1; nX<=nX2; nX++)
2471 {
2472 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2473 if (pInfo->nClipMark != ScClipMark::NONE)
2474 {
2475 if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2476 {
2477 // merge origin may be outside of visible area - use document functions
2478
2479 SCCOL nOverX = nX;
2480 SCROW nOverY = nY;
2481 long nStartPosX = nPosX;
2482 long nStartPosY = nPosY;
2483
2484 while ( nOverX > 0 && ( mpDoc->GetAttr(
2485 nOverX, nOverY, nTab, ATTR_MERGE_FLAG )->GetValue() & ScMF::Hor ) )
2486 {
2487 --nOverX;
2488 nStartPosX -= nLayoutSign * static_cast<long>( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2489 }
2490
2491 while ( nOverY > 0 && ( mpDoc->GetAttr(
2492 nOverX, nOverY, nTab, ATTR_MERGE_FLAG )->GetValue() & ScMF::Ver ) )
2493 {
2494 --nOverY;
2495 nStartPosY -= nLayoutSign * static_cast<long>( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2496 }
2497
2498 long nOutWidth = static_cast<long>( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
2499 long nOutHeight = static_cast<long>( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
2500
2501 const ScMergeAttr* pMerge = mpDoc->GetAttr( nOverX, nOverY, nTab, ATTR_MERGE );
2502 SCCOL nCountX = pMerge->GetColMerge();
2503 for (SCCOL i=1; i<nCountX; i++)
2504 nOutWidth += static_cast<long>( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2505 SCROW nCountY = pMerge->GetRowMerge();
2506 nOutHeight += static_cast<long>(mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY));
2507
2508 if ( bLayoutRTL )
2509 nStartPosX -= nOutWidth - 1;
2510 aCellRect = tools::Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2511 }
2512 else
2513 {
2514 long nOutWidth = pRowInfo[0].pCellInfo[nX+1].nWidth;
2515 long nOutHeight = pThisRowInfo->nHeight;
2516
2517 if ( pInfo->bMerged && pInfo->pPatternAttr )
2518 {
2519 SCCOL nOverX = nX;
2520 SCROW nOverY = nY;
2521 const ScMergeAttr* pMerge =
2522 &pInfo->pPatternAttr->GetItem(ATTR_MERGE);
2523 SCCOL nCountX = pMerge->GetColMerge();
2524 for (SCCOL i=1; i<nCountX; i++)
2525 nOutWidth += static_cast<long>( mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX );
2526 SCROW nCountY = pMerge->GetRowMerge();
2527 nOutHeight += static_cast<long>(mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY));
2528 }
2529
2530 long nStartPosX = nPosX;
2531 if ( bLayoutRTL )
2532 nStartPosX -= nOutWidth - 1;
2533 // #i80447# create aCellRect from two points in case nOutWidth is 0
2534 aCellRect = tools::Rectangle( Point( nStartPosX, nPosY ),
2535 Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
2536 }
2537
2538 aCellRect.AdjustBottom( -1 ); // don't paint over the cell grid
2539 if ( bLayoutRTL )
2540 aCellRect.AdjustLeft(1 );
2541 else
2542 aCellRect.AdjustRight( -1 );
2543
2544 long nMarkPixel = static_cast<long>( SC_CLIPMARK_SIZE * mnPPTX );
2545 Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
2546
2547 if ( pInfo->nClipMark & ( bLayoutRTL ? ScClipMark::Right : ScClipMark::Left ) )
2548 {
2549 // visually left
2550 tools::Rectangle aMarkRect = aCellRect;
2551 aMarkRect.SetRight( aCellRect.Left()+nMarkPixel-1 );
2552 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, true );
2553 }
2554 if ( pInfo->nClipMark & ( bLayoutRTL ? ScClipMark::Left : ScClipMark::Right ) )
2555 {
2556 // visually right
2557 tools::Rectangle aMarkRect = aCellRect;
2558 aMarkRect.SetLeft( aCellRect.Right()-nMarkPixel+1 );
2559 SvxFont::DrawArrow( *mpDev, aMarkRect, aMarkSize, aArrowFillCol, false );
2560 }
2561 }
2562 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2563 }
2564 }
2565 nPosY += pThisRowInfo->nHeight;
2566 }
2567
2568 mpDev->SetDrawMode(nOldDrawMode);
2569 }
2570
2571 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2572