[Libreoffice-commits] core.git: Branch 'distro/nisz/libreoffice-7-1' - svx/source sw/inc sw/qa sw/source
Attila Bakos (NISZ) (via logerrit)
logerrit at kemper.freedesktop.org
Thu Aug 19 13:54:57 UTC 2021
svx/source/svdraw/svdpage.cxx | 5 -
sw/inc/textboxhelper.hxx | 4
sw/qa/extras/ooxmlexport/data/testTextBoxZOrder.docx |binary
sw/qa/extras/ooxmlexport/ooxmlexport16.cxx | 31 +++++++
sw/source/core/doc/textboxhelper.cxx | 70 ++++++++++++++--
sw/source/core/frmedt/feshview.cxx | 82 +++++++++++++++++++
6 files changed, 185 insertions(+), 7 deletions(-)
New commits:
commit 09aba686b452e3fa2d7ad3e06ebebba83aa0dfe7
Author: Attila Bakos (NISZ) <bakos.attilakaroly at nisz.hu>
AuthorDate: Fri May 7 10:18:01 2021 +0200
Commit: Gabor Kelemen <kelemen.gabor2 at nisz.hu>
CommitDate: Thu Aug 19 15:54:19 2021 +0200
tdf#138141 sw: fix textbox z-order
Textboxes are implemented as loosely connected
shape-text frame pairs. Missing synchronization
of their z-orders resulted e.g invisible or
only partially visible textbox content using
Arrange options with textboxes (see in local menu
or on Drawing Object Properties toolbar).
Note: because it's not possible to send frames
to the background, Arrange->To Background hasn't
supported, so likely it's worth to remove that
option later from local menu of textboxes.
Change-Id: I1aa50903ba55dd5b9e72ef203c4e30218bee68fb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115227
Tested-by: László Németh <nemeth at numbertext.org>
Reviewed-by: László Németh <nemeth at numbertext.org>
(cherry picked from commit 0e6d963fbca16f98a3dbb6ef2fee3736a89d055b)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120713
Tested-by: Gabor Kelemen <kelemen.gabor2 at nisz.hu>
Reviewed-by: Gabor Kelemen <kelemen.gabor2 at nisz.hu>
diff --git a/svx/source/svdraw/svdpage.cxx b/svx/source/svdraw/svdpage.cxx
index c1f8980f4236..be6907184c08 100644
--- a/svx/source/svdraw/svdpage.cxx
+++ b/svx/source/svdraw/svdpage.cxx
@@ -757,7 +757,10 @@ size_t SdrObjList::GetObjCount() const
SdrObject* SdrObjList::GetObj(size_t nNum) const
{
- return maList[nNum];
+ if (nNum < maList.size())
+ return maList[nNum];
+
+ return nullptr;
}
diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 90e173046133..6bfd8ddfad00 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -123,6 +123,10 @@ public:
/// Returns true if the given shape has a valid textframe.
static bool isTextBoxShapeHasValidTextFrame(css::uno::Reference<css::drawing::XShape> xShape);
+ // Returns true on success. Synchronize z-order of the text frame of the given textbox
+ // by setting it one level higher than the z-order of the shape of the textbox.
+ static bool DoTextBoxZOrderCorrection(SwFrameFormat* pShape);
+
/**
* If we have an associated TextFrame, then return that.
*
diff --git a/sw/qa/extras/ooxmlexport/data/testTextBoxZOrder.docx b/sw/qa/extras/ooxmlexport/data/testTextBoxZOrder.docx
new file mode 100644
index 000000000000..c6dd0b8f30c8
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/testTextBoxZOrder.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index f0664b1f002d..7e890145210d 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -18,6 +18,7 @@
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
#include <com/sun/star/packages/zip/ZipFileAccess.hpp>
#include <comphelper/configuration.hxx>
#include <editeng/escapementitem.hxx>
@@ -160,6 +161,36 @@ DECLARE_OOXMLEXPORT_TEST(testTdf133473_shadowSize, "tdf133473.docx")
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(200000), nSize1);
}
+DECLARE_OOXMLEXPORT_TEST(testTextBoxZOrder, "testTextBoxZOrder.docx")
+{
+ // Is load successful?
+ CPPUNIT_ASSERT(mxComponent);
+ // Collect the z-order values of the textboxes
+ std::vector<sal_uInt64> ShapeZorders;
+ std::vector<sal_uInt64> FrameZorders;
+ for (int i = 1; i < 4; i++)
+ {
+ uno::Reference<drawing::XShape> xShape(getShape(i));
+ CPPUNIT_ASSERT(xShape);
+ uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xShapeProperties);
+ uno::Reference<text::XTextFrame> xFrame = SwTextBoxHelper::getUnoTextFrame(xShape);
+ CPPUNIT_ASSERT(xFrame.is());
+ uno::Reference<beans::XPropertySet> const xFrameProperties(xFrame, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xFrameProperties);
+ ShapeZorders.push_back(xShapeProperties->getPropertyValue("ZOrder").get<sal_uInt64>());
+ FrameZorders.push_back(xFrameProperties->getPropertyValue("ZOrder").get<sal_uInt64>());
+ }
+ // Check the z-order values.
+ for (int i = 1; i < 3; i++)
+ {
+ CPPUNIT_ASSERT_GREATER(ShapeZorders[i - 1], ShapeZorders[i]);
+ CPPUNIT_ASSERT_GREATER(FrameZorders[i - 1], FrameZorders[i]);
+ CPPUNIT_ASSERT_GREATER(ShapeZorders[i - 1], FrameZorders[i - 1]);
+ }
+ // Without the fix it failed, because the z-order was wrong.
+}
+
DECLARE_OOXMLEXPORT_TEST(testTdf141550, "tdf141550.docx")
{
uno::Reference<drawing::XShape> xShape(getShape(1));
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 88138f6aee10..e5ade0b38125 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -39,6 +39,9 @@
#include <sal/log.hxx>
#include <tools/UnitConversion.hxx>
#include <svx/swframetypes.hxx>
+#include <drawdoc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <DocumentDrawModelManager.hxx>
#include <com/sun/star/document/XActionLockable.hpp>
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
@@ -136,6 +139,7 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, bool bCopyText)
pShape->SetFormatAttr(aSet);
}
+ DoTextBoxZOrderCorrection(pShape);
// Also initialize the properties, which are not constant, but inherited from the shape's ones.
uno::Reference<drawing::XShape> xShape(pShape->FindRealSdrObject()->getUnoShape(),
uno::UNO_QUERY);
@@ -960,6 +964,8 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const&
if (aTextBoxSet.Count())
pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);
+
+ DoTextBoxZOrderCorrection(&rShape);
}
SwFrameFormat* SwTextBoxHelper::getShapeFormat(uno::Reference<drawing::XShape> xShape)
@@ -1019,6 +1025,7 @@ bool SwTextBoxHelper::setWrapThrough(SwFrameFormat* pShape)
{
if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
{
+ ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
if (auto xFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat))
try
{
@@ -1070,6 +1077,7 @@ bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape)
{
try
{
+ ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
uno::Reference<beans::XPropertySet> const xPropertySet(
SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat),
uno::UNO_QUERY);
@@ -1136,7 +1144,7 @@ bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape)
}
}
- return doTextBoxPositioning(pShape);
+ return doTextBoxPositioning(pShape) && DoTextBoxZOrderCorrection(pShape);
}
}
return false;
@@ -1155,6 +1163,7 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape)
{
if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
{
+ ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
{
tools::Rectangle aRect(getTextRectangle(pShape, false));
@@ -1224,19 +1233,68 @@ std::optional<bool> SwTextBoxHelper::isAnchorTypeDifferent(SwFrameFormat* pShape
bool SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(SwFrameFormat* pShape)
{
- OUString sErrMsg;
if (pShape && pShape->Which() == RES_DRAWFRMFMT)
if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
if (pFormat && pFormat->Which() == RES_FLYFRMFMT)
return true;
else
- sErrMsg = "Shape do not have valid textframe!";
+ SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: "
+ "Shape does not have valid textframe!");
else
- sErrMsg = "Shape do not have associated frame!";
+ SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: "
+ "Shape does not have associated frame!");
else
- sErrMsg = "Not valid shape!";
+ SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: Not valid shape!");
+ return false;
+}
+
+bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape)
+{
+ if (isTextBoxShapeHasValidTextFrame(pShape))
+ {
+ if (SdrObject* pShpObj = pShape->FindRealSdrObject())
+ {
+ if (SdrObject* pFrmObj
+ = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT)->FindRealSdrObject())
+ {
+ // Get the draw model from the doc
+ SwDrawModel* pDrawModel
+ = pShape->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
+ if (pDrawModel)
+ {
+ // Not really sure this will work all page, but it seems it will.
+ auto pPage = pDrawModel->GetPage(0);
+ // Recalc all Zorders
+ pPage->RecalcObjOrdNums();
+ // If the shape is behind the frame, is good, but if there are some objects
+ // between of them that is wrong so put the frame exactly one level higher
+ // than the shape.
+ if (pFrmObj->GetOrdNum() > pShpObj->GetOrdNum())
+ pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pShpObj->GetOrdNum() + 1);
+ else
+ // Else, if the frame is behind the shape, bring to the front of it.
+ while (pFrmObj->GetOrdNum() <= pShpObj->GetOrdNum())
+ {
+ pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pFrmObj->GetOrdNum() + 1);
+ // If there is any problem with the indexes, do not run over the infinity
+ if (pPage->GetObjCount() == pFrmObj->GetOrdNum())
+ break;
+ }
+ pPage->RecalcObjOrdNums();
+ return true; // Success
+ }
+ SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
+ "No Valid Draw model for SdrObject for the shape!");
+ }
+ SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
+ "No Valid SdrObject for the frame!");
+ }
+ SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
+ "No Valid SdrObject for the shape!");
+ }
+ SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
+ "No Valid TextFrame!");
- SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: " << sErrMsg);
return false;
}
diff --git a/sw/source/core/frmedt/feshview.cxx b/sw/source/core/frmedt/feshview.cxx
index 439d99e9e2d7..9d907ea24fc7 100644
--- a/sw/source/core/frmedt/feshview.cxx
+++ b/sw/source/core/frmedt/feshview.cxx
@@ -1055,6 +1055,55 @@ void SwFEShell::SelectionToTop( bool bTop )
else
Imp()->GetDrawView()->MovMarkedToTop();
::lcl_NotifyNeighbours( &rMrkList );
+
+ // Does the selection contain a textbox?
+ for (size_t i = 0; i < rMrkList.GetMarkCount(); i++)
+ if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
+ // Get the textbox-shape
+ if (auto pFormat = FindFrameFormat(pObj))
+ {
+ // If it has not textframe skip...
+ if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat))
+ continue;
+ // If it has a textframe so it is a textbox, get its page
+ if (auto pDrwModel
+ = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
+ // Not really understood why everything is on page 0...
+ // but it is easier to handle sdrobjects, thats true
+ if (auto pPage = pDrwModel->GetPage(0))
+ {
+ // nShift: it means how many layers the pObj have to be shifted up,
+ // in order not to interfere with other shapes and textboxes.
+ // Situations:
+ // - The next shape has textframe: This shape have to shifted with
+ // two layers.
+ // - The next shape has not got textframe: This shape have to be
+ // shifted only one layer up.
+ // - The next shape is null:
+ // - This shape is already at heaven: Only the textframe have
+ // to be adjusted.
+ sal_uInt32 nShift = 0;
+ // Get the one level higher object (note: can be nullptr!)
+ const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() + 1, pObj->GetOrdNum() + 1);
+ // If there is a higher object (not null)...
+ if (pNextObj)
+ {
+ // One level shift is neccessary
+ nShift++;
+ // If this object is a textbox, two level increasing needed
+ // (one for the shape and one for the frame)
+ if (auto pNextFormat = FindFrameFormat(pNextObj))
+ if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT)
+ || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
+ nShift++;
+ }
+ // Set the new z-order.
+ pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() + nShift);
+ }
+ // The shape is on the right level, correct the layer of the frame
+ SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat);
+ }
+
GetDoc()->getIDocumentState().SetModified();
EndAllAction();
}
@@ -1075,6 +1124,36 @@ void SwFEShell::SelectionToBottom( bool bBottom )
else
Imp()->GetDrawView()->MovMarkedToBtm();
::lcl_NotifyNeighbours( &rMrkList );
+
+ // If the selection has textbox
+ for(size_t i = 0; i < rMrkList.GetMarkCount(); i++)
+ if (auto pObj = rMrkList.GetMark(i)->GetMarkedSdrObj())
+ // Get the shape of the textbox
+ if (auto pFormat = FindFrameFormat(pObj))
+ {
+ // If the shape has not textframes skip.
+ if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat))
+ continue;
+ // If has, move the shape to correct level with...
+ if (auto pDrwModel
+ = pFormat->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel())
+ if (auto pPage = pDrwModel->GetPage(0))
+ {
+ const auto pNextObj = pPage->SetObjectOrdNum(pObj->GetOrdNum() - 1, pObj->GetOrdNum() - 1);
+ // If there is a lower object (not null)...
+ if (pNextObj)
+ {
+ // If the lower has no textframe, just do nothing, else move by one lower
+ if (auto pNextFormat = FindFrameFormat(pNextObj))
+ if (SwTextBoxHelper::isTextBox(pNextFormat, RES_DRAWFRMFMT)
+ || SwTextBoxHelper::isTextBox(pNextFormat, RES_FLYFRMFMT))
+ pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() - 1);
+ }
+ }
+ // And set correct layer for the selected textbox.
+ SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat);
+ }
+
GetDoc()->getIDocumentState().SetModified();
EndAllAction();
}
@@ -1138,6 +1217,9 @@ void SwFEShell::ChangeOpaque( SdrLayerID nLayerId )
SvxOpaqueItem aOpa( pFormat->GetOpaque() );
aOpa.SetValue( nLayerId == rIDDMA.GetHellId() );
pFormat->SetFormatAttr( aOpa );
+ // If pObj has textframe, put its textframe to the right level
+ if (auto pTextBx = FindFrameFormat(pObj))
+ SwTextBoxHelper::DoTextBoxZOrderCorrection(pTextBx);
}
}
}
More information about the Libreoffice-commits
mailing list