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