summaryrefslogtreecommitdiffstats
path: root/svx/source/svdraw/svdotxat.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/svdraw/svdotxat.cxx')
-rw-r--r--svx/source/svdraw/svdotxat.cxx455
1 files changed, 455 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdotxat.cxx b/svx/source/svdraw/svdotxat.cxx
new file mode 100644
index 000000000..315e57e7c
--- /dev/null
+++ b/svx/source/svdraw/svdotxat.cxx
@@ -0,0 +1,455 @@
+/* -*- 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 <comphelper/string.hxx>
+#include <svl/style.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdorect.hxx>
+#include <svx/svdocapt.hxx>
+#include <editeng/editdata.hxx>
+#include <svx/sdtfchim.hxx>
+
+
+#include <editeng/outlobj.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/editobj.hxx>
+
+namespace {
+// The style family which is appended to the style names is padded to this many characters.
+const short PADDING_LENGTH_FOR_STYLE_FAMILY = 5;
+// this character will be used to pad the style families when they are appended to the style names
+const char PADDING_CHARACTER_FOR_STYLE_FAMILY = ' ';
+}
+
+bool SdrTextObj::AdjustTextFrameWidthAndHeight( tools::Rectangle& rR, bool bHgt, bool bWdt ) const
+{
+ if (!bTextFrame)
+ // Not a text frame. Bail out.
+ return false;
+
+ if (rR.IsEmpty())
+ // Empty rectangle.
+ return false;
+
+ bool bFitToSize = IsFitToSize();
+ if (bFitToSize)
+ return false;
+
+ bool bWdtGrow = bWdt && IsAutoGrowWidth();
+ bool bHgtGrow = bHgt && IsAutoGrowHeight();
+ if (!bWdtGrow && !bHgtGrow)
+ // Not supposed to auto-adjust width or height.
+ return false;
+
+ SdrTextAniKind eAniKind = GetTextAniKind();
+ SdrTextAniDirection eAniDir = GetTextAniDirection();
+
+ bool bScroll = eAniKind == SdrTextAniKind::Scroll || eAniKind == SdrTextAniKind::Alternate || eAniKind == SdrTextAniKind::Slide;
+ bool bHScroll = bScroll && (eAniDir == SdrTextAniDirection::Left || eAniDir == SdrTextAniDirection::Right);
+ bool bVScroll = bScroll && (eAniDir == SdrTextAniDirection::Up || eAniDir == SdrTextAniDirection::Down);
+
+ tools::Rectangle aOldRect = rR;
+ long nHgt = 0, nMinHgt = 0, nMaxHgt = 0;
+ long nWdt = 0, nMinWdt = 0, nMaxWdt = 0;
+
+ Size aNewSize = rR.GetSize();
+ aNewSize.AdjustWidth( -1 ); aNewSize.AdjustHeight( -1 );
+
+ Size aMaxSiz(100000, 100000);
+ Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
+
+ if (aTmpSiz.Width())
+ aMaxSiz.setWidth( aTmpSiz.Width() );
+ if (aTmpSiz.Height())
+ aMaxSiz.setHeight( aTmpSiz.Height() );
+
+ if (bWdtGrow)
+ {
+ nMinWdt = GetMinTextFrameWidth();
+ nMaxWdt = GetMaxTextFrameWidth();
+ if (nMaxWdt == 0 || nMaxWdt > aMaxSiz.Width())
+ nMaxWdt = aMaxSiz.Width();
+ if (nMinWdt <= 0)
+ nMinWdt = 1;
+
+ aNewSize.setWidth( nMaxWdt );
+ }
+
+ if (bHgtGrow)
+ {
+ nMinHgt = GetMinTextFrameHeight();
+ nMaxHgt = GetMaxTextFrameHeight();
+ if (nMaxHgt == 0 || nMaxHgt > aMaxSiz.Height())
+ nMaxHgt = aMaxSiz.Height();
+ if (nMinHgt <= 0)
+ nMinHgt = 1;
+
+ aNewSize.setHeight( nMaxHgt );
+ }
+
+ long nHDist = GetTextLeftDistance() + GetTextRightDistance();
+ long nVDist = GetTextUpperDistance() + GetTextLowerDistance();
+ aNewSize.AdjustWidth( -nHDist );
+ aNewSize.AdjustHeight( -nVDist );
+
+ if (aNewSize.Width() < 2)
+ aNewSize.setWidth( 2 );
+ if (aNewSize.Height() < 2)
+ aNewSize.setHeight( 2 );
+
+ if (!IsInEditMode())
+ {
+ if (bHScroll)
+ aNewSize.setWidth( 0x0FFFFFFF ); // don't break ticker text
+ if (bVScroll)
+ aNewSize.setHeight( 0x0FFFFFFF );
+ }
+
+ if (pEdtOutl)
+ {
+ pEdtOutl->SetMaxAutoPaperSize(aNewSize);
+ if (bWdtGrow)
+ {
+ Size aSiz2(pEdtOutl->CalcTextSize());
+ nWdt = aSiz2.Width() + 1; // a little tolerance
+ if (bHgtGrow)
+ nHgt = aSiz2.Height() + 1; // a little tolerance
+ }
+ else
+ {
+ nHgt = pEdtOutl->GetTextHeight() + 1; // a little tolerance
+ }
+ }
+ else
+ {
+ Outliner& rOutliner = ImpGetDrawOutliner();
+ rOutliner.SetPaperSize(aNewSize);
+ rOutliner.SetUpdateMode(true);
+ // TODO: add the optimization with bPortionInfoChecked etc. here
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if (pOutlinerParaObject)
+ {
+ rOutliner.SetText(*pOutlinerParaObject);
+ rOutliner.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT).GetValue());
+ }
+
+ if (bWdtGrow)
+ {
+ Size aSiz2(rOutliner.CalcTextSize());
+ nWdt = aSiz2.Width() + 1; // a little tolerance
+ if (bHgtGrow)
+ nHgt = aSiz2.Height() + 1; // a little tolerance
+ }
+ else
+ {
+ nHgt = rOutliner.GetTextHeight() + 1; // a little tolerance
+ }
+ rOutliner.Clear();
+ }
+
+ if (nWdt < nMinWdt)
+ nWdt = nMinWdt;
+ if (nWdt > nMaxWdt)
+ nWdt = nMaxWdt;
+ nWdt += nHDist;
+ if (nWdt < 1)
+ nWdt = 1; // nHDist may be negative
+ if (nHgt < nMinHgt)
+ nHgt = nMinHgt;
+ if (nHgt > nMaxHgt)
+ nHgt = nMaxHgt;
+ nHgt += nVDist;
+ if (nHgt < 1)
+ nHgt = 1; // nVDist may be negative
+ long nWdtGrow = nWdt - (rR.Right() - rR.Left());
+ long nHgtGrow = nHgt - (rR.Bottom() - rR.Top());
+
+ if (nWdtGrow == 0)
+ bWdtGrow = false;
+ if (nHgtGrow == 0)
+ bHgtGrow = false;
+
+ if (!bWdtGrow && !bHgtGrow)
+ return false;
+
+ if (bWdtGrow)
+ {
+ SdrTextHorzAdjust eHAdj = GetTextHorizontalAdjust();
+
+ if (eHAdj == SDRTEXTHORZADJUST_LEFT)
+ rR.AdjustRight(nWdtGrow );
+ else if (eHAdj == SDRTEXTHORZADJUST_RIGHT)
+ rR.AdjustLeft( -nWdtGrow );
+ else
+ {
+ long nWdtGrow2 = nWdtGrow / 2;
+ rR.AdjustLeft( -nWdtGrow2 );
+ rR.SetRight( rR.Left() + nWdt );
+ }
+ }
+
+ if (bHgtGrow)
+ {
+ SdrTextVertAdjust eVAdj = GetTextVerticalAdjust();
+
+ if (eVAdj == SDRTEXTVERTADJUST_TOP)
+ rR.AdjustBottom(nHgtGrow );
+ else if (eVAdj == SDRTEXTVERTADJUST_BOTTOM)
+ rR.AdjustTop( -nHgtGrow );
+ else
+ {
+ long nHgtGrow2 = nHgtGrow / 2;
+ rR.AdjustTop( -nHgtGrow2 );
+ rR.SetBottom( rR.Top() + nHgt );
+ }
+ }
+
+ if (aGeo.nRotationAngle)
+ {
+ // Object is rotated.
+ Point aD1(rR.TopLeft());
+ aD1 -= aOldRect.TopLeft();
+ Point aD2(aD1);
+ RotatePoint(aD2, Point(), aGeo.nSin, aGeo.nCos);
+ aD2 -= aD1;
+ rR.Move(aD2.X(), aD2.Y());
+ }
+
+ return true;
+}
+
+bool SdrTextObj::NbcAdjustTextFrameWidthAndHeight(bool bHgt, bool bWdt)
+{
+ bool bRet = AdjustTextFrameWidthAndHeight(maRect,bHgt,bWdt);
+ if (bRet)
+ {
+ SetRectsDirty();
+ if (dynamic_cast<const SdrRectObj *>(this) != nullptr) { // this is a hack
+ static_cast<SdrRectObj*>(this)->SetXPolyDirty();
+ }
+ if (dynamic_cast<const SdrCaptionObj *>(this) != nullptr) { // this is a hack
+ static_cast<SdrCaptionObj*>(this)->ImpRecalcTail();
+ }
+ }
+ return bRet;
+}
+
+bool SdrTextObj::AdjustTextFrameWidthAndHeight()
+{
+ tools::Rectangle aNewRect(maRect);
+ bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
+ if (bRet) {
+ tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
+ maRect = aNewRect;
+ SetRectsDirty();
+ if (dynamic_cast<const SdrRectObj *>(this) != nullptr) { // this is a hack
+ static_cast<SdrRectObj*>(this)->SetXPolyDirty();
+ }
+ bool bScPostIt = false;
+ if (auto pCaptionObj = dynamic_cast<SdrCaptionObj *>(this)) { // this is a hack
+ pCaptionObj->ImpRecalcTail();
+ // tdf#114956, tdf#138549 use GetSpecialTextBoxShadow to recognize
+ // that this SdrCaption is for a ScPostit
+ bScPostIt = pCaptionObj->GetSpecialTextBoxShadow();
+ }
+
+ // to not slow down EditView visualization on Overlay (see
+ // TextEditOverlayObject) it is necessary to suppress the
+ // Invalidates for the deep repaint when the size of the
+ // TextFrame changed (AdjustTextFrameWidthAndHeight returned
+ // true). The ObjectChanges are valid, invalidate will be
+ // done on EndTextEdit anyways
+ const bool bSuppressChangeWhenEditOnOverlay(
+ IsInEditMode() &&
+ GetTextEditOutliner() &&
+ GetTextEditOutliner()->hasEditViewCallbacks());
+
+ if (!bSuppressChangeWhenEditOnOverlay || bScPostIt)
+ {
+ SetChanged();
+ BroadcastObjectChange();
+ }
+
+ SendUserCall(SdrUserCallType::Resize,aBoundRect0);
+ }
+ return bRet;
+}
+
+void SdrTextObj::ImpSetTextStyleSheetListeners()
+{
+ SfxStyleSheetBasePool* pStylePool(getSdrModelFromSdrObject().GetStyleSheetPool());
+ if (pStylePool!=nullptr)
+ {
+ std::vector<OUString> aStyleNames;
+ OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
+ if (pOutlinerParaObject!=nullptr)
+ {
+ // First, we collect all stylesheets contained in the ParaObject in
+ // the container aStyles. The Family is always appended to the name
+ // of the stylesheet.
+ const EditTextObject& rTextObj=pOutlinerParaObject->GetTextObject();
+ OUString aStyleName;
+ SfxStyleFamily eStyleFam;
+ sal_Int32 nParaCnt=rTextObj.GetParagraphCount();
+
+
+ for(sal_Int32 nParaNum(0); nParaNum < nParaCnt; nParaNum++)
+ {
+ rTextObj.GetStyleSheet(nParaNum, aStyleName, eStyleFam);
+
+ if (!aStyleName.isEmpty())
+ {
+ AppendFamilyToStyleName(aStyleName, eStyleFam);
+
+ bool bFnd(false);
+ sal_uInt32 nNum(aStyleNames.size());
+
+ while(!bFnd && nNum > 0)
+ {
+ // we don't want duplicate stylesheets
+ nNum--;
+ bFnd = aStyleName == aStyleNames[nNum];
+ }
+
+ if(!bFnd)
+ {
+ aStyleNames.push_back(aStyleName);
+ }
+ }
+ }
+ }
+
+ // now convert the strings in the vector from names to StyleSheet*
+ o3tl::sorted_vector<SfxStyleSheet*> aStyleSheets;
+ while (!aStyleNames.empty()) {
+ OUString aName = aStyleNames.back();
+ aStyleNames.pop_back();
+
+ SfxStyleFamily eFam = ReadFamilyFromStyleName(aName);
+ SfxStyleSheetBase* pStyleBase = pStylePool->Find(aName,eFam);
+ SfxStyleSheet* pStyle = dynamic_cast<SfxStyleSheet*>( pStyleBase );
+ if (pStyle!=nullptr && pStyle!=GetStyleSheet()) {
+ aStyleSheets.insert(pStyle);
+ }
+ }
+ // now remove all superfluous stylesheets
+ sal_uInt16 nNum=GetBroadcasterCount();
+ while (nNum>0) {
+ nNum--;
+ SfxBroadcaster* pBroadcast=GetBroadcasterJOE(nNum);
+ SfxStyleSheet* pStyle=dynamic_cast<SfxStyleSheet*>( pBroadcast );
+ if (pStyle!=nullptr && pStyle!=GetStyleSheet()) { // special case for stylesheet of the object
+ if (aStyleSheets.find(pStyle)==aStyleSheets.end()) {
+ EndListening(*pStyle);
+ }
+ }
+ }
+ // and finally, merge all stylesheets that are contained in aStyles with previous broadcasters
+ for(SfxStyleSheet* pStyle : aStyleSheets) {
+ // let StartListening see for itself if there's already a listener registered
+ StartListening(*pStyle, DuplicateHandling::Prevent);
+ }
+ }
+}
+
+/** iterates over the paragraphs of a given SdrObject and removes all
+ hard set character attributes with the which ids contained in the
+ given vector
+*/
+void SdrTextObj::RemoveOutlinerCharacterAttribs( const std::vector<sal_uInt16>& rCharWhichIds )
+{
+ sal_Int32 nText = getTextCount();
+
+ while( --nText >= 0 )
+ {
+ SdrText* pText = getText( nText );
+ OutlinerParaObject* pOutlinerParaObject = pText ? pText->GetOutlinerParaObject() : nullptr;
+
+ if(pOutlinerParaObject)
+ {
+ Outliner* pOutliner = nullptr;
+
+ if( pEdtOutl || (pText == getActiveText()) )
+ pOutliner = pEdtOutl;
+
+ if(!pOutliner)
+ {
+ pOutliner = &ImpGetDrawOutliner();
+ pOutliner->SetText(*pOutlinerParaObject);
+ }
+
+ ESelection aSelAll( 0, 0, EE_PARA_ALL, EE_TEXTPOS_ALL );
+ for( const auto& rWhichId : rCharWhichIds )
+ {
+ pOutliner->RemoveAttribs( aSelAll, false, rWhichId );
+ }
+
+ if(!pEdtOutl || (pText != getActiveText()) )
+ {
+ const sal_Int32 nParaCount = pOutliner->GetParagraphCount();
+ std::unique_ptr<OutlinerParaObject> pTemp = pOutliner->CreateParaObject(0, nParaCount);
+ pOutliner->Clear();
+ NbcSetOutlinerParaObjectForText(std::move(pTemp), pText);
+ }
+ }
+ }
+}
+
+bool SdrTextObj::HasText() const
+{
+ if( pEdtOutl )
+ return HasTextImpl(pEdtOutl);
+
+ OutlinerParaObject* pOPO = GetOutlinerParaObject();
+
+ bool bHasText = false;
+ if( pOPO )
+ {
+ const EditTextObject& rETO = pOPO->GetTextObject();
+ sal_Int32 nParaCount = rETO.GetParagraphCount();
+
+ if( nParaCount > 0 )
+ bHasText = (nParaCount > 1) || (!rETO.GetText( 0 ).isEmpty());
+ }
+
+ return bHasText;
+}
+
+void SdrTextObj::AppendFamilyToStyleName(OUString& styleName, SfxStyleFamily family)
+{
+ OUStringBuffer aFam;
+ aFam.append(static_cast<sal_Int32>(family));
+ comphelper::string::padToLength(aFam, PADDING_LENGTH_FOR_STYLE_FAMILY , PADDING_CHARACTER_FOR_STYLE_FAMILY);
+
+ styleName += "|" + aFam.makeStringAndClear();
+}
+
+SfxStyleFamily SdrTextObj::ReadFamilyFromStyleName(const OUString& styleName)
+{
+ OUString familyString = styleName.copy(styleName.getLength() - PADDING_LENGTH_FOR_STYLE_FAMILY);
+ familyString = comphelper::string::stripEnd(familyString, PADDING_CHARACTER_FOR_STYLE_FAMILY);
+ sal_uInt16 nFam = static_cast<sal_uInt16>(familyString.toInt32());
+ assert(nFam != 0);
+ return static_cast<SfxStyleFamily>(nFam);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */