1
0
Fork 0
libreoffice/sw/source/ui/table/autoformatpreview.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

471 lines
16 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <editeng/adjustitem.hxx>
#include <editeng/boxitem.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/crossedoutitem.hxx>
#include <editeng/colritem.hxx>
#include <editeng/contouritem.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/shdditem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/wghtitem.hxx>
#include <vcl/settings.hxx>
#include <com/sun/star/i18n/BreakIterator.hpp>
#include <comphelper/processfactory.hxx>
#include <svtools/scriptedtext.hxx>
#include <svx/framelink.hxx>
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
#include <drawinglayer/processor2d/processor2dtools.hxx>
#include <strings.hrc>
#include <svtools/colorcfg.hxx>
#include <swmodule.hxx>
#include <autoformatpreview.hxx>
#define FRAME_OFFSET 4
AutoFormatPreview::AutoFormatPreview()
: maCurrentData(OUString())
, mbFitWidth(false)
, mbRTL(false)
, maStringJan(SwResId(STR_JAN))
, maStringFeb(SwResId(STR_FEB))
, maStringMar(SwResId(STR_MAR))
, maStringNorth(SwResId(STR_NORTH))
, maStringMid(SwResId(STR_MID))
, maStringSouth(SwResId(STR_SOUTH))
, maStringSum(SwResId(STR_SUM))
{
const uno::Reference<uno::XComponentContext>& xContext
= comphelper::getProcessComponentContext();
m_xBreak = i18n::BreakIterator::create(xContext);
mxNumFormat.reset(new SvNumberFormatter(xContext, LANGUAGE_SYSTEM));
Init();
}
void AutoFormatPreview::Resize()
{
Size aSize = GetOutputSizePixel();
maPreviousSize = Size(aSize.Width() - 6, aSize.Height() - 30);
mnLabelColumnWidth = (maPreviousSize.Width() - 4) / 4 - 12;
mnDataColumnWidth1 = (maPreviousSize.Width() - 4 - 2 * mnLabelColumnWidth) / 3;
mnDataColumnWidth2 = (maPreviousSize.Width() - 4 - 2 * mnLabelColumnWidth) / 4;
mnRowHeight = (maPreviousSize.Height() - 4) / 5;
NotifyChange(maCurrentData);
}
void AutoFormatPreview::DetectRTL(SwWrtShell const* pWrtShell)
{
if (!pWrtShell->IsCursorInTable()) // We haven't created the table yet
mbRTL = AllSettings::GetLayoutRTL();
else
mbRTL = pWrtShell->IsTableRightToLeft();
}
static void lcl_SetFontProperties(vcl::Font& rFont, const SvxFontItem& rFontItem,
const SvxWeightItem& rWeightItem,
const SvxPostureItem& rPostureItem)
{
rFont.SetFamily(rFontItem.GetFamily());
rFont.SetFamilyName(rFontItem.GetFamilyName());
rFont.SetStyleName(rFontItem.GetStyleName());
rFont.SetCharSet(rFontItem.GetCharSet());
rFont.SetPitch(rFontItem.GetPitch());
rFont.SetWeight(rWeightItem.GetValue());
rFont.SetItalic(rPostureItem.GetValue());
}
#define SETONALLFONTS(MethodName, Value) \
rFont.MethodName(Value); \
rCJKFont.MethodName(Value); \
rCTLFont.MethodName(Value);
void AutoFormatPreview::MakeFonts(vcl::RenderContext const& rRenderContext, sal_uInt8 nIndex,
vcl::Font& rFont, vcl::Font& rCJKFont, vcl::Font& rCTLFont)
{
const SwBoxAutoFormat& rBoxFormat = maCurrentData.GetBoxFormat(nIndex);
rFont = rCJKFont = rCTLFont = rRenderContext.GetFont();
Size aFontSize(rFont.GetFontSize().Width(), 10 * rRenderContext.GetDPIScaleFactor());
lcl_SetFontProperties(rFont, rBoxFormat.GetFont(), rBoxFormat.GetWeight(),
rBoxFormat.GetPosture());
lcl_SetFontProperties(rCJKFont, rBoxFormat.GetCJKFont(), rBoxFormat.GetCJKWeight(),
rBoxFormat.GetCJKPosture());
lcl_SetFontProperties(rCTLFont, rBoxFormat.GetCTLFont(), rBoxFormat.GetCTLWeight(),
rBoxFormat.GetCTLPosture());
SETONALLFONTS(SetUnderline, rBoxFormat.GetUnderline().GetValue());
SETONALLFONTS(SetOverline, rBoxFormat.GetOverline().GetValue());
SETONALLFONTS(SetStrikeout, rBoxFormat.GetCrossedOut().GetValue());
SETONALLFONTS(SetOutline, rBoxFormat.GetContour().GetValue());
SETONALLFONTS(SetShadow, rBoxFormat.GetShadowed().GetValue());
SETONALLFONTS(SetColor, rBoxFormat.GetColor().GetValue());
SETONALLFONTS(SetFontSize, aFontSize);
SETONALLFONTS(SetTransparent, true);
}
sal_uInt8 AutoFormatPreview::GetFormatIndex(size_t nCol, size_t nRow) const
{
static const sal_uInt8 pnFormatMap[]
= { 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 };
return pnFormatMap[maArray.GetCellIndex(nCol, nRow, mbRTL)];
}
void AutoFormatPreview::DrawString(vcl::RenderContext& rRenderContext, size_t nCol, size_t nRow)
{
// Output of the cell text:
sal_uLong nNum;
double nVal;
OUString cellString;
sal_uInt8 nIndex = static_cast<sal_uInt8>(maArray.GetCellIndex(nCol, nRow, mbRTL));
switch (nIndex)
{
case 1:
cellString = maStringJan;
break;
case 2:
cellString = maStringFeb;
break;
case 3:
cellString = maStringMar;
break;
case 5:
cellString = maStringNorth;
break;
case 10:
cellString = maStringMid;
break;
case 15:
cellString = maStringSouth;
break;
case 4:
case 20:
cellString = maStringSum;
break;
case 6:
case 8:
case 16:
case 18:
nVal = nIndex;
nNum = 5;
goto MAKENUMSTR;
case 17:
case 7:
nVal = nIndex;
nNum = 6;
goto MAKENUMSTR;
case 11:
case 12:
case 13:
nVal = nIndex;
nNum = 12 == nIndex ? 10 : 9;
goto MAKENUMSTR;
case 9:
nVal = 21;
nNum = 7;
goto MAKENUMSTR;
case 14:
nVal = 36;
nNum = 11;
goto MAKENUMSTR;
case 19:
nVal = 51;
nNum = 7;
goto MAKENUMSTR;
case 21:
nVal = 33;
nNum = 13;
goto MAKENUMSTR;
case 22:
nVal = 36;
nNum = 14;
goto MAKENUMSTR;
case 23:
nVal = 39;
nNum = 13;
goto MAKENUMSTR;
case 24:
nVal = 108;
nNum = 15;
goto MAKENUMSTR;
MAKENUMSTR:
if (maCurrentData.IsValueFormat())
{
OUString sFormat;
LanguageType eLng, eSys;
maCurrentData.GetBoxFormat(sal_uInt8(nNum)).GetValueFormat(sFormat, eLng, eSys);
SvNumFormatType nType;
bool bNew;
sal_Int32 nCheckPos;
sal_uInt32 nKey = mxNumFormat->GetIndexPuttingAndConverting(sFormat, eLng, eSys,
nType, bNew, nCheckPos);
const Color* pDummy;
mxNumFormat->GetOutputString(nVal, nKey, cellString, &pDummy);
}
else
cellString = OUString::number(sal_Int32(nVal));
break;
}
if (cellString.isEmpty())
return;
SvtScriptedTextHelper aScriptedText(rRenderContext);
Size aStrSize;
sal_uInt8 nFormatIndex = GetFormatIndex(nCol, nRow);
const basegfx::B2DRange aCellRange(maArray.GetCellRange(nCol, nRow));
const tools::Rectangle cellRect(basegfx::fround<tools::Long>(aCellRange.getMinX()),
basegfx::fround<tools::Long>(aCellRange.getMinY()),
basegfx::fround<tools::Long>(aCellRange.getMaxX()),
basegfx::fround<tools::Long>(aCellRange.getMaxY()));
Point aPos = cellRect.TopLeft();
tools::Long nRightX = 0;
Size theMaxStrSize(cellRect.GetWidth() - FRAME_OFFSET, cellRect.GetHeight() - FRAME_OFFSET);
if (maCurrentData.IsFont())
{
vcl::Font aFont, aCJKFont, aCTLFont;
MakeFonts(rRenderContext, nFormatIndex, aFont, aCJKFont, aCTLFont);
aScriptedText.SetFonts(&aFont, &aCJKFont, &aCTLFont);
}
else
aScriptedText.SetDefaultFont();
aScriptedText.SetText(cellString, m_xBreak);
aStrSize = aScriptedText.GetTextSize();
if (maCurrentData.IsFont() && theMaxStrSize.Height() < aStrSize.Height())
{
// If the string in this font does not
// fit into the cell, the standard font
// is taken again:
aScriptedText.SetDefaultFont();
aStrSize = aScriptedText.GetTextSize();
}
while (theMaxStrSize.Width() <= aStrSize.Width() && cellString.getLength() > 1)
{
cellString = cellString.copy(0, cellString.getLength() - 1);
aScriptedText.SetText(cellString, m_xBreak);
aStrSize = aScriptedText.GetTextSize();
}
nRightX = cellRect.GetWidth() - aStrSize.Width() - FRAME_OFFSET;
// vertical (always centering):
aPos.AdjustY((mnRowHeight - aStrSize.Height()) / 2);
// horizontal
if (mbRTL)
aPos.AdjustX(nRightX);
else if (maCurrentData.IsJustify())
{
const SvxAdjustItem& rAdj = maCurrentData.GetBoxFormat(nFormatIndex).GetAdjust();
switch (rAdj.GetAdjust())
{
case SvxAdjust::Left:
aPos.AdjustX(FRAME_OFFSET);
break;
case SvxAdjust::Right:
aPos.AdjustX(nRightX);
break;
default:
aPos.AdjustX((cellRect.GetWidth() - aStrSize.Width()) / 2);
break;
}
}
else
{
// Standard align:
if (nCol == 0 || nIndex == 4)
{
// Text-Label left or sum left aligned
aPos.AdjustX(FRAME_OFFSET);
}
else
{
// numbers/dates right aligned
aPos.AdjustX(nRightX);
}
}
aScriptedText.DrawText(aPos);
}
void AutoFormatPreview::DrawBackground(vcl::RenderContext& rRenderContext)
{
for (size_t nRow = 0; nRow < 5; ++nRow)
{
for (size_t nCol = 0; nCol < 5; ++nCol)
{
SvxBrushItem aBrushItem(
maCurrentData.GetBoxFormat(GetFormatIndex(nCol, nRow)).GetBackground());
rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
rRenderContext.SetLineColor();
rRenderContext.SetFillColor(aBrushItem.GetColor());
const basegfx::B2DRange aCellRange(maArray.GetCellRange(nCol, nRow));
rRenderContext.DrawRect(
tools::Rectangle(basegfx::fround<tools::Long>(aCellRange.getMinX()),
basegfx::fround<tools::Long>(aCellRange.getMinY()),
basegfx::fround<tools::Long>(aCellRange.getMaxX()),
basegfx::fround<tools::Long>(aCellRange.getMaxY())));
rRenderContext.Pop();
}
}
}
void AutoFormatPreview::PaintCells(vcl::RenderContext& rRenderContext)
{
// 1) background
if (maCurrentData.IsBackground())
DrawBackground(rRenderContext);
// 2) values
for (size_t nRow = 0; nRow < 5; ++nRow)
for (size_t nCol = 0; nCol < 5; ++nCol)
DrawString(rRenderContext, nCol, nRow);
// 3) border
if (!maCurrentData.IsFrame())
return;
const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(rRenderContext,
aNewViewInformation2D));
if (pProcessor2D)
{
pProcessor2D->process(maArray.CreateB2DPrimitiveArray());
pProcessor2D.reset();
}
}
void AutoFormatPreview::Init()
{
maArray.Initialize(5, 5);
mnLabelColumnWidth = 0;
mnDataColumnWidth1 = 0;
mnDataColumnWidth2 = 0;
mnRowHeight = 0;
CalcCellArray(false);
CalcLineMap();
}
void AutoFormatPreview::CalcCellArray(bool _bFitWidth)
{
maArray.SetAllColWidths(_bFitWidth ? mnDataColumnWidth2 : mnDataColumnWidth1);
maArray.SetColWidth(0, mnLabelColumnWidth);
maArray.SetColWidth(4, mnLabelColumnWidth);
maArray.SetAllRowHeights(mnRowHeight);
maPreviousSize.setWidth(maArray.GetWidth() + 4);
maPreviousSize.setHeight(maArray.GetHeight() + 4);
}
static void lclSetStyleFromBorder(svx::frame::Style& rStyle,
const ::editeng::SvxBorderLine* pBorder)
{
rStyle.Set(pBorder, 0.05, 5);
}
void AutoFormatPreview::CalcLineMap()
{
for (size_t nRow = 0; nRow < 5; ++nRow)
{
for (size_t nCol = 0; nCol < 5; ++nCol)
{
svx::frame::Style aStyle;
const SvxBoxItem& rItem
= maCurrentData.GetBoxFormat(GetFormatIndex(nCol, nRow)).GetBox();
lclSetStyleFromBorder(aStyle, rItem.GetLeft());
maArray.SetCellStyleLeft(nCol, nRow, aStyle);
lclSetStyleFromBorder(aStyle, rItem.GetRight());
maArray.SetCellStyleRight(nCol, nRow, aStyle);
lclSetStyleFromBorder(aStyle, rItem.GetTop());
maArray.SetCellStyleTop(nCol, nRow, aStyle);
lclSetStyleFromBorder(aStyle, rItem.GetBottom());
maArray.SetCellStyleBottom(nCol, nRow, aStyle);
// FIXME - uncomment to draw diagonal borders
// lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, true ).GetLine() );
// maArray.SetCellStyleTLBR( nCol, nRow, aStyle );
// lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, false ).GetLine() );
// maArray.SetCellStyleBLTR( nCol, nRow, aStyle );
}
}
}
void AutoFormatPreview::NotifyChange(const SwTableAutoFormat& rNewData)
{
maCurrentData = rNewData;
mbFitWidth = maCurrentData.IsJustify(); // true; //???
CalcCellArray(mbFitWidth);
CalcLineMap();
Invalidate();
}
void AutoFormatPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
rRenderContext.Push(vcl::PushFlags::ALL);
const Color& rWinColor
= SwModule::get()->GetColorConfig().GetColorValue(::svtools::DOCCOLOR).nColor;
rRenderContext.SetBackground(Wallpaper(rWinColor));
rRenderContext.Erase();
DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode();
if (rRenderContext.GetSettings().GetStyleSettings().GetHighContrastMode())
rRenderContext.SetDrawMode(DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill
| DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient);
Size theWndSize = rRenderContext.GetOutputSizePixel();
vcl::Font aFont(rRenderContext.GetFont());
aFont.SetTransparent(true);
rRenderContext.SetFont(aFont);
// Draw the Frame
Color oldColor = rRenderContext.GetLineColor();
rRenderContext.SetLineColor();
rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), theWndSize));
rRenderContext.SetLineColor(oldColor);
// Center the preview
maArray.SetXOffset(2 + (theWndSize.Width() - maPreviousSize.Width()) / 2);
maArray.SetYOffset(2 + (theWndSize.Height() - maPreviousSize.Height()) / 2);
// Draw cells on virtual device
PaintCells(rRenderContext);
rRenderContext.SetDrawMode(nOldDrawMode);
rRenderContext.Pop();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */