summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAttila Bakos (NISZ) <bakos.attilakaroly@nisz.hu>2021-02-22 14:28:59 +0100
committerXisco Fauli <xiscofauli@libreoffice.org>2021-03-02 12:14:28 +0100
commit6edeb6a8209a990e83f07c02753d606226f59be7 (patch)
tree7fe435fb78a6db03782b3ab75280433bc65e7f57
parente941720d5c3e6a555c2405d5f8d9de6c37150e27 (diff)
tdf#140158 tdf#138598 tdf#140598 sw: fix sync of AS_CHAR textboxes
Textboxes anchored "As Character" fell apart, when typing before some characters or inserting a page break. By fixing that, the tdf#138598 bug also have fixed which was a regression from commit b6850bbe95418ecfde404be1696548f18d200c9b (tdf#106153 sw compatibility: fix textboxes exceeding the page). In addition, tdf140598 is also fixed, which was a regression from commit c96c386c5db45dc4d5e358915caad7474e373068 (tdf#136516 add positioning to SwTextBoxHelper::syncProperty()). Change-Id: Ifeadd8b2055ce52a019d651369ca41185de7bbe3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111338 Tested-by: László Németh <nemeth@numbertext.org> Reviewed-by: László Németh <nemeth@numbertext.org> Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111796 Tested-by: Jenkins
-rw-r--r--sw/inc/textboxhelper.hxx5
-rwxr-xr-xsw/qa/extras/uiwriter/data3/AsCharTxBxTest.docxbin0 -> 19888 bytes
-rw-r--r--sw/qa/extras/uiwriter/uiwriter3.cxx52
-rw-r--r--sw/source/core/doc/textboxhelper.cxx137
-rw-r--r--sw/source/core/text/porfly.cxx32
5 files changed, 204 insertions, 22 deletions
diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 45d8a6c56f5d..2043b1ffcfb3 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -16,6 +16,8 @@
#include <com/sun/star/uno/Any.h>
#include <com/sun/star/uno/Type.h>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <svx/swframetypes.hxx>
#include "swdllapi.h"
@@ -71,6 +73,9 @@ public:
static void getProperty(SwFrameFormat const* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
css::uno::Any& rValue);
+ /// There are two types of enum of anchor type, so this function maps this.
+ static css::text::TextContentAnchorType mapAnchorType(const RndStdIds& rAnchorID);
+
/// Similar to syncProperty(), but used by the internal API (e.g. for UI purposes).
static void syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& rSet);
diff --git a/sw/qa/extras/uiwriter/data3/AsCharTxBxTest.docx b/sw/qa/extras/uiwriter/data3/AsCharTxBxTest.docx
new file mode 100755
index 000000000000..7603b80d2c2d
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data3/AsCharTxBxTest.docx
Binary files differ
diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx b/sw/qa/extras/uiwriter/uiwriter3.cxx
index e568e695000a..018a96a78ee6 100644
--- a/sw/qa/extras/uiwriter/uiwriter3.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter3.cxx
@@ -725,6 +725,58 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf134253)
CPPUNIT_ASSERT_EQUAL(6, getPages());
}
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, TestAsCharTextBox)
+{
+ // Releated tickets:
+ // tdf#138598 Replace vertical alignment of As_char textboxes in footer
+ // tdf#140158 Remove horizontal positioning of As_char textboxes, because
+ // the anchor moving does the same for it.
+
+ load(DATA_DIRECTORY, "AsCharTxBxTest.docx");
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+
+ // Add 3x tab to the doc
+ pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
+ pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
+ pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
+ Scheduler::ProcessEventsToIdle();
+
+ auto pExportDump = parseLayoutDump();
+ CPPUNIT_ASSERT(pExportDump);
+
+ // Check if the texbox fallen apart due to the tabs
+ const double nLeftSideOfShape1
+ = getXPath(pExportDump, "/root/page/body/txt/anchored/SwAnchoredDrawObject/bounds", "left")
+ .toDouble();
+ const double nLeftSideOfTxBx1
+ = getXPath(pExportDump, "/root/page/body/txt/anchored/fly/infos/bounds", "left").toDouble();
+
+ CPPUNIT_ASSERT(nLeftSideOfShape1 < nLeftSideOfTxBx1);
+
+ // Another test is for the tdf#138598: Check footer textbox
+ const double nLeftSideOfShape2
+ = getXPath(pExportDump, "/root/page[2]/footer/txt/anchored/SwAnchoredDrawObject/bounds",
+ "left")
+ .toDouble();
+ const double nLeftSideOfTxBx2
+ = getXPath(pExportDump, "/root/page[2]/footer/txt/anchored/fly/infos/bounds", "left")
+ .toDouble();
+
+ CPPUNIT_ASSERT(nLeftSideOfShape2 < nLeftSideOfTxBx2);
+
+ const double nTopSideOfShape2
+ = getXPath(pExportDump, "/root/page[2]/footer/txt/anchored/SwAnchoredDrawObject/bounds",
+ "top")
+ .toDouble();
+ const double nTopSideOfTxBx2
+ = getXPath(pExportDump, "/root/page[2]/footer/txt/anchored/fly/infos/bounds", "top")
+ .toDouble();
+
+ CPPUNIT_ASSERT(nTopSideOfShape2 < nTopSideOfTxBx2);
+ // Without the fix in place the two texboxes has been fallen apart, and asserts will broken.
+}
+
CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf76636)
{
load(DATA_DIRECTORY, "tdf76636.doc");
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 4d44d1c35ff8..5257d448bd55 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -33,6 +33,7 @@
#include <editeng/memberids.h>
#include <svx/svdoashp.hxx>
#include <svx/svdpage.hxx>
+#include <svx/swframetypes.hxx>
#include <svl/itemiter.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <sal/log.hxx>
@@ -686,10 +687,39 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_u
if (aValue.get<text::TextContentAnchorType>()
== text::TextContentAnchorType::TextContentAnchorType_AS_CHARACTER)
{
- xPropertySet->setPropertyValue(
- UNO_NAME_ANCHOR_TYPE,
- uno::makeAny(
- text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER));
+ if (const auto aPos = pShape->GetAnchor().GetContentAnchor())
+ {
+ xPropertySet->setPropertyValue(
+ UNO_NAME_ANCHOR_TYPE,
+ uno::makeAny(text::TextContentAnchorType::
+ TextContentAnchorType_AT_CHARACTER));
+ xPropertySet->setPropertyValue(
+ UNO_NAME_HORI_ORIENT_RELATION,
+ uno::makeAny(text::RelOrientation::CHAR));
+
+ auto pAnch = pFormat->GetAnchor();
+ pAnch.SetAnchor(pShape->GetAnchor().GetContentAnchor());
+ tools::Rectangle aRect(getTextRectangle(pShape, false));
+
+ SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient());
+ aNewHOri.SetPos(aRect.getX());
+
+ SwFormatVertOrient aNewVOri(pFormat->GetVertOrient());
+ aNewVOri.SetPos(aRect.getY());
+
+ pFormat->SetFormatAttr(pAnch);
+ // tdf#140598: Do not apply wrong rectangle position.
+ if (aRect.TopLeft() != Point(0, 0))
+ {
+ pFormat->SetFormatAttr(aNewHOri);
+ pFormat->SetFormatAttr(aNewVOri);
+ }
+ else
+ SAL_WARN("sw.core",
+ "SwTextBoxHelper::syncProperty: Repositioning failed!");
+ }
+
+ return;
}
else // Otherwise copy the anchor type of the shape
{
@@ -699,11 +729,55 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_u
if (aValue.get<text::TextContentAnchorType>()
== text::TextContentAnchorType::TextContentAnchorType_AT_PAGE)
{
- xPropertySet->setPropertyValue(
- UNO_NAME_ANCHOR_PAGE_NO,
- uno::makeAny(pShape->GetAnchor().GetPageNum()));
+ if (pShape->GetAnchor().GetPageNum())
+ xPropertySet->setPropertyValue(
+ UNO_NAME_ANCHOR_PAGE_NO,
+ uno::makeAny(pShape->GetAnchor().GetPageNum()));
+ else
+ {
+ SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Invalid Page Num!");
+ return;
+ }
}
+ // At-Content Anchors have to be synced:
+ if (aValue.get<text::TextContentAnchorType>()
+ == text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH
+ || aValue.get<text::TextContentAnchorType>()
+ == text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER)
+ {
+ // If the shape has content...
+ if (auto aPos = pShape->GetAnchor().GetContentAnchor())
+ {
+ SwFormatAnchor aAnch(pFormat->GetAnchor());
+ // ...set it for the textframe too.
+ aAnch.SetAnchor(aPos);
+ pFormat->SetFormatAttr(aAnch);
+ }
+ else
+ SAL_WARN("sw.core",
+ "SwTextBoxHelper::syncProperty: Anchor without content!");
+ }
+ // And the repositioning:
+ if (pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
+ {
+ tools::Rectangle aRect(getTextRectangle(pShape, false));
+
+ // tdf#140598: Do not apply wrong rectangle position.
+ if (aRect.TopLeft() != Point(0, 0))
+ {
+ SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient());
+ aNewHOri.SetPos(aNewHOri.GetPos() + aRect.getX());
+ SwFormatVertOrient aNewVOri(pShape->GetVertOrient());
+ aNewVOri.SetPos(aNewVOri.GetPos() + aRect.getY());
+
+ pFormat->SetFormatAttr(aNewHOri);
+ pFormat->SetFormatAttr(aNewVOri);
+ }
+ else
+ SAL_WARN("sw.core",
+ "SwTextBoxHelper::syncProperty: Repositioning failed!");
+ }
return;
}
break;
@@ -834,12 +908,41 @@ void SwTextBoxHelper::restoreLinks(std::set<ZSortFly>& rOld, std::vector<SwFrame
}
}
+text::TextContentAnchorType SwTextBoxHelper::mapAnchorType(const RndStdIds& rAnchorID)
+{
+ text::TextContentAnchorType aAnchorType;
+ switch (rAnchorID)
+ {
+ case RndStdIds::FLY_AS_CHAR:
+ aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AS_CHARACTER;
+ break;
+ case RndStdIds::FLY_AT_CHAR:
+ aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER;
+ break;
+ case RndStdIds::FLY_AT_PARA:
+ aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH;
+ break;
+ case RndStdIds::FLY_AT_PAGE:
+ aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PAGE;
+ break;
+ case RndStdIds::FLY_AT_FLY:
+ aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_FRAME;
+ break;
+ default:
+ aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH;
+ SAL_WARN("sw.core", "SwTextBoxHelper::mapAnchorType: Unknown AnchorType!");
+ break;
+ }
+ return aAnchorType;
+}
+
void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& rSet)
{
SwFrameFormat* pFormat = getOtherTextBoxFormat(&rShape, RES_DRAWFRMFMT);
if (!pFormat)
return;
+ const bool bInlineAnchored = rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR;
SfxItemSet aTextBoxSet(pFormat->GetDoc()->GetAttrPool(), aFrameFormatSetRange);
SfxItemIter aIter(rSet);
@@ -861,6 +964,13 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const&
{
case RES_VERT_ORIENT:
{
+ // The new position can be with anchor changing so sync it!
+ const text::TextContentAnchorType aNewAnchorType
+ = mapAnchorType(rShape.GetAnchor().GetAnchorId());
+ syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType));
+ if (bInlineAnchored)
+ return;
+
auto& rOrient = static_cast<const SwFormatVertOrient&>(*pItem);
SwFormatVertOrient aOrient(rOrient);
@@ -885,6 +995,8 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const&
case RES_HORI_ORIENT:
{
auto& rOrient = static_cast<const SwFormatHoriOrient&>(*pItem);
+ if (bInlineAnchored)
+ return;
SwFormatHoriOrient aOrient(rOrient);
tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
@@ -910,11 +1022,14 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const&
tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
if (!aRect.IsEmpty())
{
- aVertOrient.SetPos(aVertOrient.GetPos() + aRect.getY());
- aTextBoxSet.Put(aVertOrient);
+ if (!bInlineAnchored)
+ {
+ aVertOrient.SetPos(aVertOrient.GetPos() + aRect.getY());
+ aHoriOrient.SetPos(aHoriOrient.GetPos() + aRect.getX());
- aHoriOrient.SetPos(aHoriOrient.GetPos() + aRect.getX());
- aTextBoxSet.Put(aHoriOrient);
+ aTextBoxSet.Put(aVertOrient);
+ aTextBoxSet.Put(aHoriOrient);
+ }
aSize.SetWidth(aRect.getWidth());
aSize.SetHeight(aRect.getHeight());
diff --git a/sw/source/core/text/porfly.cxx b/sw/source/core/text/porfly.cxx
index 24961c08b68d..cafa70c48227 100644
--- a/sw/source/core/text/porfly.cxx
+++ b/sw/source/core/text/porfly.cxx
@@ -352,20 +352,30 @@ void SwFlyCntPortion::SetBase( const SwTextFrame& rFrame, const Point &rBase,
// is relative to the print area of the anchor text frame.
tools::Rectangle aTextRectangle = SwTextBoxHelper::getTextRectangle(pShape);
- SwFormatHoriOrient aHori(pTextBox->GetHoriOrient());
- aHori.SetHoriOrient(css::text::HoriOrientation::NONE);
- sal_Int32 nLeft = aTextRectangle.getX() - rFrame.getFrameArea().Left()
- - rFrame.getFramePrintArea().Left();
- aHori.SetPos(nLeft);
-
+ const auto aPos(pShape->GetAnchor().GetContentAnchor());
SwFormatVertOrient aVert(pTextBox->GetVertOrient());
- aVert.SetVertOrient(css::text::VertOrientation::NONE);
- sal_Int32 const nTop = aTextRectangle.getY() - rFrame.getFrameArea().Top()
- - rFrame.getFramePrintArea().Top();
- aVert.SetPos(nTop);
+
+ // tdf#138598 Replace vertical alignment of As_char textboxes in footer
+ // tdf#140158 Remove horizontal positioning of As_char textboxes, because
+ // the anchor moving does the same for it.
+ if (!aPos->nNode.GetNode().FindFooterStartNode())
+ {
+ aVert.SetVertOrient(css::text::VertOrientation::NONE);
+ sal_Int32 const nTop = aTextRectangle.getY() - rFrame.getFrameArea().Top()
+ - rFrame.getFramePrintArea().Top();
+ aVert.SetPos(nTop);
+ }
+ else
+ {
+ aVert.SetVertOrient(css::text::VertOrientation::NONE);
+ aVert.SetPos(SwTextBoxHelper::getTextRectangle(pShape, false).getY());
+ }
+
+ SwFormatAnchor aNewTxBxAnchor(pTextBox->GetAnchor());
+ aNewTxBxAnchor.SetAnchor(aPos);
pTextBox->LockModify();
- pTextBox->SetFormatAttr(aHori);
+ pTextBox->SetFormatAttr(aNewTxBxAnchor);
pTextBox->SetFormatAttr(aVert);
pTextBox->UnlockModify();
}