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 <editeng/adjustitem.hxx>
21 #include <editeng/boxitem.hxx>
22 #include <editeng/brushitem.hxx>
23 #include <editeng/crossedoutitem.hxx>
24 #include <editeng/colritem.hxx>
25 #include <editeng/contouritem.hxx>
26 #include <editeng/fontitem.hxx>
27 #include <editeng/postitem.hxx>
28 #include <editeng/shdditem.hxx>
29 #include <editeng/udlnitem.hxx>
30 #include <editeng/wghtitem.hxx>
31 #include <vcl/settings.hxx>
32 #include <com/sun/star/i18n/BreakIterator.hpp>
33 #include <comphelper/processfactory.hxx>
34 #include <svtools/scriptedtext.hxx>
35 #include <svx/framelink.hxx>
36 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
37 #include <drawinglayer/processor2d/processor2dtools.hxx>
38 #include <strings.hrc>
39 
40 #include <autoformatpreview.hxx>
41 
42 #define FRAME_OFFSET 4
43 
AutoFormatPreview()44 AutoFormatPreview::AutoFormatPreview()
45     : maCurrentData(OUString())
46     , mbFitWidth(false)
47     , mbRTL(false)
48     , maStringJan(SwResId(STR_JAN))
49     , maStringFeb(SwResId(STR_FEB))
50     , maStringMar(SwResId(STR_MAR))
51     , maStringNorth(SwResId(STR_NORTH))
52     , maStringMid(SwResId(STR_MID))
53     , maStringSouth(SwResId(STR_SOUTH))
54     , maStringSum(SwResId(STR_SUM))
55 {
56     uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
57     m_xBreak = i18n::BreakIterator::create(xContext);
58     mxNumFormat.reset(new SvNumberFormatter(xContext, LANGUAGE_SYSTEM));
59 
60     Init();
61 }
62 
Resize()63 void AutoFormatPreview::Resize()
64 {
65     Size aSize = GetOutputSizePixel();
66     maPreviousSize = Size(aSize.Width() - 6, aSize.Height() - 30);
67     mnLabelColumnWidth = (maPreviousSize.Width() - 4) / 4 - 12;
68     mnDataColumnWidth1 = (maPreviousSize.Width() - 4 - 2 * mnLabelColumnWidth) / 3;
69     mnDataColumnWidth2 = (maPreviousSize.Width() - 4 - 2 * mnLabelColumnWidth) / 4;
70     mnRowHeight = (maPreviousSize.Height() - 4) / 5;
71     NotifyChange(maCurrentData);
72 }
73 
DetectRTL(SwWrtShell const * pWrtShell)74 void AutoFormatPreview::DetectRTL(SwWrtShell const* pWrtShell)
75 {
76     if (!pWrtShell->IsCursorInTable()) // We haven't created the table yet
77         mbRTL = AllSettings::GetLayoutRTL();
78     else
79         mbRTL = pWrtShell->IsTableRightToLeft();
80 }
81 
lcl_SetFontProperties(vcl::Font & rFont,const SvxFontItem & rFontItem,const SvxWeightItem & rWeightItem,const SvxPostureItem & rPostureItem)82 static void lcl_SetFontProperties(vcl::Font& rFont, const SvxFontItem& rFontItem,
83                                   const SvxWeightItem& rWeightItem,
84                                   const SvxPostureItem& rPostureItem)
85 {
86     rFont.SetFamily(rFontItem.GetFamily());
87     rFont.SetFamilyName(rFontItem.GetFamilyName());
88     rFont.SetStyleName(rFontItem.GetStyleName());
89     rFont.SetCharSet(rFontItem.GetCharSet());
90     rFont.SetPitch(rFontItem.GetPitch());
91     rFont.SetWeight(rWeightItem.GetValue());
92     rFont.SetItalic(rPostureItem.GetValue());
93 }
94 
95 #define SETONALLFONTS(MethodName, Value)                                                           \
96     rFont.MethodName(Value);                                                                       \
97     rCJKFont.MethodName(Value);                                                                    \
98     rCTLFont.MethodName(Value);
99 
MakeFonts(vcl::RenderContext const & rRenderContext,sal_uInt8 nIndex,vcl::Font & rFont,vcl::Font & rCJKFont,vcl::Font & rCTLFont)100 void AutoFormatPreview::MakeFonts(vcl::RenderContext const& rRenderContext, sal_uInt8 nIndex,
101                                   vcl::Font& rFont, vcl::Font& rCJKFont, vcl::Font& rCTLFont)
102 {
103     const SwBoxAutoFormat& rBoxFormat = maCurrentData.GetBoxFormat(nIndex);
104 
105     rFont = rCJKFont = rCTLFont = rRenderContext.GetFont();
106     Size aFontSize(rFont.GetFontSize().Width(), 10 * rRenderContext.GetDPIScaleFactor());
107 
108     lcl_SetFontProperties(rFont, rBoxFormat.GetFont(), rBoxFormat.GetWeight(),
109                           rBoxFormat.GetPosture());
110     lcl_SetFontProperties(rCJKFont, rBoxFormat.GetCJKFont(), rBoxFormat.GetCJKWeight(),
111                           rBoxFormat.GetCJKPosture());
112     lcl_SetFontProperties(rCTLFont, rBoxFormat.GetCTLFont(), rBoxFormat.GetCTLWeight(),
113                           rBoxFormat.GetCTLPosture());
114 
115     SETONALLFONTS(SetUnderline, rBoxFormat.GetUnderline().GetValue());
116     SETONALLFONTS(SetOverline, rBoxFormat.GetOverline().GetValue());
117     SETONALLFONTS(SetStrikeout, rBoxFormat.GetCrossedOut().GetValue());
118     SETONALLFONTS(SetOutline, rBoxFormat.GetContour().GetValue());
119     SETONALLFONTS(SetShadow, rBoxFormat.GetShadowed().GetValue());
120     SETONALLFONTS(SetColor, rBoxFormat.GetColor().GetValue());
121     SETONALLFONTS(SetFontSize, aFontSize);
122     SETONALLFONTS(SetTransparent, true);
123 }
124 
GetFormatIndex(size_t nCol,size_t nRow) const125 sal_uInt8 AutoFormatPreview::GetFormatIndex(size_t nCol, size_t nRow) const
126 {
127     static const sal_uInt8 pnFormatMap[]
128         = { 0, 1, 2, 1, 3, 4, 5, 6, 5, 7, 8, 9, 10, 9, 11, 4, 5, 6, 5, 7, 12, 13, 14, 13, 15 };
129     return pnFormatMap[maArray.GetCellIndex(nCol, nRow, mbRTL)];
130 }
131 
DrawString(vcl::RenderContext & rRenderContext,size_t nCol,size_t nRow)132 void AutoFormatPreview::DrawString(vcl::RenderContext& rRenderContext, size_t nCol, size_t nRow)
133 {
134     // Output of the cell text:
135     sal_uLong nNum;
136     double nVal;
137     OUString cellString;
138     sal_uInt8 nIndex = static_cast<sal_uInt8>(maArray.GetCellIndex(nCol, nRow, mbRTL));
139 
140     switch (nIndex)
141     {
142         case 1:
143             cellString = maStringJan;
144             break;
145         case 2:
146             cellString = maStringFeb;
147             break;
148         case 3:
149             cellString = maStringMar;
150             break;
151         case 5:
152             cellString = maStringNorth;
153             break;
154         case 10:
155             cellString = maStringMid;
156             break;
157         case 15:
158             cellString = maStringSouth;
159             break;
160         case 4:
161         case 20:
162             cellString = maStringSum;
163             break;
164         case 6:
165         case 8:
166         case 16:
167         case 18:
168             nVal = nIndex;
169             nNum = 5;
170             goto MAKENUMSTR;
171         case 17:
172         case 7:
173             nVal = nIndex;
174             nNum = 6;
175             goto MAKENUMSTR;
176         case 11:
177         case 12:
178         case 13:
179             nVal = nIndex;
180             nNum = 12 == nIndex ? 10 : 9;
181             goto MAKENUMSTR;
182         case 9:
183             nVal = 21;
184             nNum = 7;
185             goto MAKENUMSTR;
186         case 14:
187             nVal = 36;
188             nNum = 11;
189             goto MAKENUMSTR;
190         case 19:
191             nVal = 51;
192             nNum = 7;
193             goto MAKENUMSTR;
194         case 21:
195             nVal = 33;
196             nNum = 13;
197             goto MAKENUMSTR;
198         case 22:
199             nVal = 36;
200             nNum = 14;
201             goto MAKENUMSTR;
202         case 23:
203             nVal = 39;
204             nNum = 13;
205             goto MAKENUMSTR;
206         case 24:
207             nVal = 108;
208             nNum = 15;
209             goto MAKENUMSTR;
210 
211         MAKENUMSTR:
212             if (maCurrentData.IsValueFormat())
213             {
214                 OUString sFormat;
215                 LanguageType eLng, eSys;
216                 maCurrentData.GetBoxFormat(sal_uInt8(nNum)).GetValueFormat(sFormat, eLng, eSys);
217 
218                 SvNumFormatType nType;
219                 bool bNew;
220                 sal_Int32 nCheckPos;
221                 sal_uInt32 nKey = mxNumFormat->GetIndexPuttingAndConverting(sFormat, eLng, eSys,
222                                                                             nType, bNew, nCheckPos);
223                 Color* pDummy;
224                 mxNumFormat->GetOutputString(nVal, nKey, cellString, &pDummy);
225             }
226             else
227                 cellString = OUString::number(sal_Int32(nVal));
228             break;
229     }
230 
231     if (cellString.isEmpty())
232         return;
233 
234     SvtScriptedTextHelper aScriptedText(rRenderContext);
235     Size aStrSize;
236     sal_uInt8 nFormatIndex = GetFormatIndex(nCol, nRow);
237     const basegfx::B2DRange aCellRange(maArray.GetCellRange(nCol, nRow, true));
238     const tools::Rectangle cellRect(
239         basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()),
240         basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY()));
241     Point aPos = cellRect.TopLeft();
242     long nRightX = 0;
243 
244     Size theMaxStrSize(cellRect.GetWidth() - FRAME_OFFSET, cellRect.GetHeight() - FRAME_OFFSET);
245     if (maCurrentData.IsFont())
246     {
247         vcl::Font aFont, aCJKFont, aCTLFont;
248         MakeFonts(rRenderContext, nFormatIndex, aFont, aCJKFont, aCTLFont);
249         aScriptedText.SetFonts(&aFont, &aCJKFont, &aCTLFont);
250     }
251     else
252         aScriptedText.SetDefaultFont();
253 
254     aScriptedText.SetText(cellString, m_xBreak);
255     aStrSize = aScriptedText.GetTextSize();
256 
257     if (maCurrentData.IsFont() && theMaxStrSize.Height() < aStrSize.Height())
258     {
259         // If the string in this font does not
260         // fit into the cell, the standard font
261         // is taken again:
262         aScriptedText.SetDefaultFont();
263         aStrSize = aScriptedText.GetTextSize();
264     }
265 
266     while (theMaxStrSize.Width() <= aStrSize.Width() && cellString.getLength() > 1)
267     {
268         cellString = cellString.copy(0, cellString.getLength() - 1);
269         aScriptedText.SetText(cellString, m_xBreak);
270         aStrSize = aScriptedText.GetTextSize();
271     }
272 
273     nRightX = cellRect.GetWidth() - aStrSize.Width() - FRAME_OFFSET;
274 
275     // vertical (always centering):
276     aPos.AdjustY((mnRowHeight - aStrSize.Height()) / 2);
277 
278     // horizontal
279     if (mbRTL)
280         aPos.AdjustX(nRightX);
281     else if (maCurrentData.IsJustify())
282     {
283         const SvxAdjustItem& rAdj = maCurrentData.GetBoxFormat(nFormatIndex).GetAdjust();
284         switch (rAdj.GetAdjust())
285         {
286             case SvxAdjust::Left:
287                 aPos.AdjustX(FRAME_OFFSET);
288                 break;
289             case SvxAdjust::Right:
290                 aPos.AdjustX(nRightX);
291                 break;
292             default:
293                 aPos.AdjustX((cellRect.GetWidth() - aStrSize.Width()) / 2);
294                 break;
295         }
296     }
297     else
298     {
299         // Standard align:
300         if (nCol == 0 || nIndex == 4)
301         {
302             // Text-Label left or sum left aligned
303             aPos.AdjustX(FRAME_OFFSET);
304         }
305         else
306         {
307             // numbers/dates right aligned
308             aPos.AdjustX(nRightX);
309         }
310     }
311 
312     aScriptedText.DrawText(aPos);
313 }
314 
DrawBackground(vcl::RenderContext & rRenderContext)315 void AutoFormatPreview::DrawBackground(vcl::RenderContext& rRenderContext)
316 {
317     for (size_t nRow = 0; nRow < 5; ++nRow)
318     {
319         for (size_t nCol = 0; nCol < 5; ++nCol)
320         {
321             SvxBrushItem aBrushItem(
322                 maCurrentData.GetBoxFormat(GetFormatIndex(nCol, nRow)).GetBackground());
323 
324             rRenderContext.Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
325             rRenderContext.SetLineColor();
326             rRenderContext.SetFillColor(aBrushItem.GetColor());
327             const basegfx::B2DRange aCellRange(maArray.GetCellRange(nCol, nRow, true));
328             rRenderContext.DrawRect(tools::Rectangle(
329                 basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()),
330                 basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY())));
331             rRenderContext.Pop();
332         }
333     }
334 }
335 
PaintCells(vcl::RenderContext & rRenderContext)336 void AutoFormatPreview::PaintCells(vcl::RenderContext& rRenderContext)
337 {
338     // 1) background
339     if (maCurrentData.IsBackground())
340         DrawBackground(rRenderContext);
341 
342     // 2) values
343     for (size_t nRow = 0; nRow < 5; ++nRow)
344         for (size_t nCol = 0; nCol < 5; ++nCol)
345             DrawString(rRenderContext, nCol, nRow);
346 
347     // 3) border
348     if (maCurrentData.IsFrame())
349     {
350         const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
351         std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
352             drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
353                 rRenderContext, aNewViewInformation2D));
354 
355         if (pProcessor2D)
356         {
357             pProcessor2D->process(maArray.CreateB2DPrimitiveArray());
358             pProcessor2D.reset();
359         }
360     }
361 }
362 
Init()363 void AutoFormatPreview::Init()
364 {
365     maArray.Initialize(5, 5);
366     mnLabelColumnWidth = 0;
367     mnDataColumnWidth1 = 0;
368     mnDataColumnWidth2 = 0;
369     mnRowHeight = 0;
370     CalcCellArray(false);
371     CalcLineMap();
372 }
373 
CalcCellArray(bool _bFitWidth)374 void AutoFormatPreview::CalcCellArray(bool _bFitWidth)
375 {
376     maArray.SetAllColWidths(_bFitWidth ? mnDataColumnWidth2 : mnDataColumnWidth1);
377     maArray.SetColWidth(0, mnLabelColumnWidth);
378     maArray.SetColWidth(4, mnLabelColumnWidth);
379 
380     maArray.SetAllRowHeights(mnRowHeight);
381 
382     maPreviousSize.setWidth(maArray.GetWidth() + 4);
383     maPreviousSize.setHeight(maArray.GetHeight() + 4);
384 }
385 
lclSetStyleFromBorder(svx::frame::Style & rStyle,const::editeng::SvxBorderLine * pBorder)386 static void lclSetStyleFromBorder(svx::frame::Style& rStyle,
387                                   const ::editeng::SvxBorderLine* pBorder)
388 {
389     rStyle.Set(pBorder, 0.05, 5);
390 }
391 
CalcLineMap()392 void AutoFormatPreview::CalcLineMap()
393 {
394     for (size_t nRow = 0; nRow < 5; ++nRow)
395     {
396         for (size_t nCol = 0; nCol < 5; ++nCol)
397         {
398             svx::frame::Style aStyle;
399 
400             const SvxBoxItem& rItem
401                 = maCurrentData.GetBoxFormat(GetFormatIndex(nCol, nRow)).GetBox();
402             lclSetStyleFromBorder(aStyle, rItem.GetLeft());
403             maArray.SetCellStyleLeft(nCol, nRow, aStyle);
404             lclSetStyleFromBorder(aStyle, rItem.GetRight());
405             maArray.SetCellStyleRight(nCol, nRow, aStyle);
406             lclSetStyleFromBorder(aStyle, rItem.GetTop());
407             maArray.SetCellStyleTop(nCol, nRow, aStyle);
408             lclSetStyleFromBorder(aStyle, rItem.GetBottom());
409             maArray.SetCellStyleBottom(nCol, nRow, aStyle);
410 
411             // FIXME - uncomment to draw diagonal borders
412             //            lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, true ).GetLine() );
413             //            maArray.SetCellStyleTLBR( nCol, nRow, aStyle );
414             //            lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, false ).GetLine() );
415             //            maArray.SetCellStyleBLTR( nCol, nRow, aStyle );
416         }
417     }
418 }
419 
NotifyChange(const SwTableAutoFormat & rNewData)420 void AutoFormatPreview::NotifyChange(const SwTableAutoFormat& rNewData)
421 {
422     maCurrentData = rNewData;
423     mbFitWidth = maCurrentData.IsJustify(); // true;  //???
424     CalcCellArray(mbFitWidth);
425     CalcLineMap();
426     Invalidate();
427 }
428 
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)429 void AutoFormatPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
430 {
431     rRenderContext.Push(PushFlags::ALL);
432 
433     DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode();
434     if (rRenderContext.GetSettings().GetStyleSettings().GetHighContrastMode())
435         rRenderContext.SetDrawMode(DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill
436                                    | DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient);
437 
438     Size theWndSize = rRenderContext.GetOutputSizePixel();
439 
440     vcl::Font aFont(rRenderContext.GetFont());
441     aFont.SetTransparent(true);
442 
443     rRenderContext.SetFont(aFont);
444     rRenderContext.SetLineColor();
445     const Color& rWinColor = rRenderContext.GetSettings().GetStyleSettings().GetWindowColor();
446     rRenderContext.SetBackground(Wallpaper(rWinColor));
447     rRenderContext.SetFillColor(rWinColor);
448 
449     // Draw the Frame
450     Color oldColor = rRenderContext.GetLineColor();
451     rRenderContext.SetLineColor();
452     rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), theWndSize));
453     rRenderContext.SetLineColor(oldColor);
454 
455     // Center the preview
456     maArray.SetXOffset(2 + (theWndSize.Width() - maPreviousSize.Width()) / 2);
457     maArray.SetYOffset(2 + (theWndSize.Height() - maPreviousSize.Height()) / 2);
458     // Draw cells on virtual device
459     PaintCells(rRenderContext);
460 
461     rRenderContext.SetDrawMode(nOldDrawMode);
462     rRenderContext.Pop();
463 }
464 
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
466