[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.2' - 7 commits - sw/inc sw/Library_sw.mk sw/qa sw/source

Tamás Zolnai (via logerrit) logerrit at kemper.freedesktop.org
Wed Jun 19 12:29:22 UTC 2019


 sw/Library_sw.mk                                                                |    1 
 sw/inc/fesh.hxx                                                                 |    3 
 sw/inc/strings.hrc                                                              |    2 
 sw/inc/swtypes.hxx                                                              |    3 
 sw/qa/extras/uiwriter/data/floating_table/small_floating_table.odt              |binary
 sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.doc        |binary
 sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.docx       |binary
 sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.odt        |binary
 sw/qa/extras/uiwriter/data/floating_table/unfloatable_small_floating_table.docx |binary
 sw/qa/extras/uiwriter/uiwriter2.cxx                                             |  165 +++++++++
 sw/source/core/frmedt/fefly1.cxx                                                |    3 
 sw/source/core/frmedt/feshview.cxx                                              |   11 
 sw/source/core/inc/flyfrm.hxx                                                   |   15 
 sw/source/core/inc/frame.hxx                                                    |    8 
 sw/source/core/inc/layfrm.hxx                                                   |    3 
 sw/source/core/inc/sortedobjs.hxx                                               |    3 
 sw/source/core/inc/txtfrm.hxx                                                   |    2 
 sw/source/core/layout/findfrm.cxx                                               |   13 
 sw/source/core/layout/fly.cxx                                                   |  107 ++++++
 sw/source/core/layout/paintfrm.cxx                                              |   12 
 sw/source/core/text/frmform.cxx                                                 |   12 
 sw/source/uibase/docvw/FloatingTableButton.cxx                                  |  177 ++++++++++
 sw/source/uibase/docvw/FrameControlsManager.cxx                                 |   43 ++
 sw/source/uibase/docvw/HeaderFooterWin.cxx                                      |   79 ++--
 sw/source/uibase/inc/FloatingTableButton.hxx                                    |   37 ++
 sw/source/uibase/inc/FrameControlsManager.hxx                                   |    1 
 sw/source/uibase/inc/HeaderFooterWin.hxx                                        |   10 
 27 files changed, 652 insertions(+), 58 deletions(-)

New commits:
commit 38a7a61aa85e2b3a6eda53422cfcd9bc2e2f590c
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Fri Jan 4 11:23:59 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Jun 19 14:28:17 2019 +0200

    Unfloat: Test layout change of unfloat operation
    
    Change-Id: I75298a392de6a10861ac96e1bc58a30173cd2dd2
    Reviewed-on: https://gerrit.libreoffice.org/65823
    Tested-by: Jenkins
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit dd0b559d6aac5bf09566af735bd00b28c00fb2e4)
    Reviewed-on: https://gerrit.libreoffice.org/65874
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index f45272a771c7..14d0bd77ac49 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -32,8 +32,7 @@
 #include <view.hxx>
 #include <sortedobjs.hxx>
 #include <anchoredobject.hxx>
-#include <FrameControlsManager.hxx>
-#include <FloatingTableButton.hxx>
+#include <swtypes.hxx>
 
 namespace
 {
@@ -65,6 +64,7 @@ public:
     void testUnfloatButtonSmallTable();
     void testUnfloatButton();
     void testUnfloatButtonReadOnlyMode();
+    void testUnfloating();
 
     CPPUNIT_TEST_SUITE(SwUiWriterTest2);
     CPPUNIT_TEST(testRedlineMoveInsertInDelete);
@@ -87,6 +87,7 @@ public:
     CPPUNIT_TEST(testUnfloatButtonSmallTable);
     CPPUNIT_TEST(testUnfloatButton);
     CPPUNIT_TEST(testUnfloatButtonReadOnlyMode);
+    CPPUNIT_TEST(testUnfloating);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -879,6 +880,53 @@ void SwUiWriterTest2::testUnfloatButtonReadOnlyMode()
     CPPUNIT_ASSERT(!pFlyFrame->IsShowUnfloatButton(pWrtShell));
 }
 
+void SwUiWriterTest2::testUnfloating()
+{
+    // Test what happens when pushing the unfloat button
+    load(FLOATING_TABLE_DATA_DIRECTORY, "unfloatable_floating_table.odt");
+    SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    CPPUNIT_ASSERT(pTextDoc);
+    SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    SwFlyFrame* pFlyFrame;
+
+    // Before unfloating we have only one page with a fly frame
+    {
+        CPPUNIT_ASSERT_EQUAL(SwFrameType::Page, pWrtShell->GetLayout()->GetLower()->GetType());
+        CPPUNIT_ASSERT(!pWrtShell->GetLayout()->GetLower()->GetNext());
+        CPPUNIT_ASSERT_EQUAL(SwFrameType::Txt,
+                             pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetType());
+        const SwSortedObjs* pAnchored
+            = pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs();
+        CPPUNIT_ASSERT(pAnchored);
+        CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pAnchored->size());
+        SwAnchoredObject* pAnchoredObj = (*pAnchored)[0];
+        pFlyFrame = dynamic_cast<SwFlyFrame*>(pAnchoredObj);
+        CPPUNIT_ASSERT(pFlyFrame);
+    }
+
+    // Select the floating table
+    SdrObject* pObj = pFlyFrame->GetFormat()->FindRealSdrObject();
+    CPPUNIT_ASSERT(pObj);
+    pWrtShell->SelectObj(Point(), 0, pObj);
+    CPPUNIT_ASSERT(pFlyFrame->IsShowUnfloatButton(pWrtShell));
+
+    // Push the unfloat button
+    pFlyFrame->ActiveUnfloatButton(pWrtShell);
+
+    // After unfloating we have two pages with one tablre frame on each page
+    CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetNext());
+    CPPUNIT_ASSERT_EQUAL(SwFrameType::Page,
+                         pWrtShell->GetLayout()->GetLower()->GetNext()->GetType());
+    CPPUNIT_ASSERT(!pWrtShell->GetLayout()->GetLower()->GetNext()->GetNext());
+    CPPUNIT_ASSERT_EQUAL(SwFrameType::Tab,
+                         pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetType());
+    CPPUNIT_ASSERT_EQUAL(
+        SwFrameType::Tab,
+        pWrtShell->GetLayout()->GetLower()->GetNext()->GetLower()->GetLower()->GetType());
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest2);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index 5ee5eb152b9b..218fbe4a98ec 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -274,6 +274,9 @@ public:
     void SelectionHasChanged(SwFEShell* pShell);
     bool IsShowUnfloatButton(SwWrtShell* pWrtSh) const;
 
+    // For testing only (see uiwriter)
+    void ActiveUnfloatButton(SwWrtShell* pWrtSh);
+
 private:
     void UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const;
     void PaintDecorators() const;
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index e087f23430ad..fa47b1799b76 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -1849,6 +1849,17 @@ bool SwFlyFrame::IsShowUnfloatButton(SwWrtShell* pWrtSh) const
     return nBodyHeight < nTableHeight + nFrameOffset;
 }
 
+void SwFlyFrame::ActiveUnfloatButton(SwWrtShell* pWrtSh)
+{
+    SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
+    SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
+    SwFrameControlPtr pControl = rMngr.GetControl(FloatingTable, this);
+    if (pControl.get() || pControl->GetWindow())
+    {
+        pControl->GetWindow()->MouseButtonDown(MouseEvent());
+    }
+}
+
 void SwFlyFrame::UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const
 {
     if (pWrtSh == nullptr)
commit ebea6821f35a746259d866114ee53d445530df31
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Wed Jan 2 18:06:37 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Jun 19 14:28:17 2019 +0200

    Unfloat: Disable undoing of unfloat operation
    
    I tested to use undo events for unfloat operations:
    moving a table outside of the text frame and removing the
    text frame, but sometimes it just crashed. So now we handle
    unfloating similar to the reverse operation (table is moved
    into a text frame(MakeFlyAndMove).
    
    Reviewed-on: https://gerrit.libreoffice.org/65822
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    Tested-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 9a115beac9a13ae320a9abf578be25bfbff1e02d)
    Reviewed-on: https://gerrit.libreoffice.org/65873
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Miklos Vajna <vmiklos at collabora.com>
    
    Change-Id: I4eaeda550ccc51252abd4abde6cee45c76a8483e

diff --git a/sw/source/uibase/docvw/FloatingTableButton.cxx b/sw/source/uibase/docvw/FloatingTableButton.cxx
index 905c647bb618..c2494945ba24 100644
--- a/sw/source/uibase/docvw/FloatingTableButton.cxx
+++ b/sw/source/uibase/docvw/FloatingTableButton.cxx
@@ -20,6 +20,8 @@
 #include <txtfrm.hxx>
 #include <ndindex.hxx>
 #include <swtable.hxx>
+#include <IDocumentState.hxx>
+#include <IDocumentUndoRedo.hxx>
 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
 #include <drawinglayer/attribute/fontattribute.hxx>
@@ -100,12 +102,23 @@ void FloatingTableButton::MouseButtonDown(const MouseEvent& /*rMEvt*/)
     if (pTableNode == nullptr)
         return;
 
+    SwDoc& rDoc = *pTextFrame->GetTextNodeFirst()->GetDoc();
+
+    // Move the table outside of the text frame
     SwNodeRange aRange(*pTableNode, 0, *pTableNode->EndOfSectionNode(), 1);
-    pTableNode->getIDocumentContentOperations().MoveNodeRange(aRange, aInsertPos,
-                                                              SwMoveFlags::DEFAULT);
+    rDoc.getIDocumentContentOperations().MoveNodeRange(aRange, aInsertPos, SwMoveFlags::DEFAULT);
 
     // Remove the floating table's frame
     SwFrame::DestroyFrame(pFlyFrame);
+
+    rDoc.getIDocumentState().SetModified();
+
+    // Undoing MoveNodeRange() is not working correctly in case of tables, it crashes some times
+    // So don't allow to undo after unfloating (similar to MakeFlyAndMove() method)
+    if (rDoc.GetIDocumentUndoRedo().DoesUndo())
+    {
+        rDoc.GetIDocumentUndoRedo().DelAllUndoObj();
+    }
 }
 
 void FloatingTableButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
commit 9ff9378e076c25d6f81e5f8aaa310b1d13823504
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Fri Jan 4 21:10:27 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Jun 19 14:28:17 2019 +0200

    Unfloat: Implement unfloating of a floating table
    
    Triggered by the unfloat button.
    
    Reviewed-on: https://gerrit.libreoffice.org/65821
    Tested-by: Jenkins
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit dcf70bb4188e019154d6201936bf1ee2e16149a3)
    
    Change-Id: I863f0ec481480343c184b0b5fa94b9ba1aa9276c
    Reviewed-on: https://gerrit.libreoffice.org/65872
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/sw/source/uibase/docvw/FloatingTableButton.cxx b/sw/source/uibase/docvw/FloatingTableButton.cxx
index 8f124f46f652..905c647bb618 100644
--- a/sw/source/uibase/docvw/FloatingTableButton.cxx
+++ b/sw/source/uibase/docvw/FloatingTableButton.cxx
@@ -14,6 +14,12 @@
 #include <strings.hrc>
 #include <vcl/metric.hxx>
 #include <viewopt.hxx>
+#include <frame.hxx>
+#include <flyfrm.hxx>
+#include <tabfrm.hxx>
+#include <txtfrm.hxx>
+#include <ndindex.hxx>
+#include <swtable.hxx>
 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
 #include <drawinglayer/attribute/fontattribute.hxx>
@@ -21,6 +27,7 @@
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
 #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
 #include <basegfx/vector/b2dvector.hxx>
+#include <DocumentContentOperationsManager.hxx>
 
 #define TEXT_PADDING 3
 #define BOX_DISTANCE 3
@@ -58,7 +65,47 @@ void FloatingTableButton::SetOffset(Point aBottomRightPixel)
 
 void FloatingTableButton::MouseButtonDown(const MouseEvent& /*rMEvt*/)
 {
-    // Move the table outside of the frame
+    assert(GetFrame()->IsFlyFrame());
+    // const_cast is needed because of bad design of ISwFrameControl and derived classes
+    SwFlyFrame* pFlyFrame = const_cast<SwFlyFrame*>(static_cast<const SwFlyFrame*>(GetFrame()));
+
+    // Find the table inside the text frame
+    SwTabFrame* pTableFrame = nullptr;
+    SwFrame* pLower = pFlyFrame->GetLower();
+    while (pLower)
+    {
+        if (pLower->IsTabFrame())
+        {
+            pTableFrame = static_cast<SwTabFrame*>(pLower);
+            break;
+        }
+        pLower = pLower->GetNext();
+    }
+
+    if (pTableFrame == nullptr)
+        return;
+
+    // Insert the table at the position of the text node which has the frame anchored to
+    SwFrame* pAnchoreFrame = pFlyFrame->AnchorFrame();
+    if (pAnchoreFrame == nullptr || !pAnchoreFrame->IsTextFrame())
+        return;
+
+    SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pAnchoreFrame);
+    if (pTextFrame->GetTextNodeFirst() == nullptr)
+        return;
+
+    SwNodeIndex aInsertPos((*pTextFrame->GetTextNodeFirst()));
+
+    SwTableNode* pTableNode = pTableFrame->GetTable()->GetTableNode();
+    if (pTableNode == nullptr)
+        return;
+
+    SwNodeRange aRange(*pTableNode, 0, *pTableNode->EndOfSectionNode(), 1);
+    pTableNode->getIDocumentContentOperations().MoveNodeRange(aRange, aInsertPos,
+                                                              SwMoveFlags::DEFAULT);
+
+    // Remove the floating table's frame
+    SwFrame::DestroyFrame(pFlyFrame);
 }
 
 void FloatingTableButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
@@ -114,4 +161,4 @@ bool FloatingTableButton::Contains(const Point& rDocPt) const
 
 void FloatingTableButton::SetReadonly(bool bReadonly) { ShowAll(!bReadonly); }
 
-/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
\ No newline at end of file
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
commit 67e31f715ff8bd6e5c09506c221bed099025e616
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Fri Jan 4 02:51:36 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Jun 19 14:28:17 2019 +0200

    Unfloat: Add some tests about the visibility of the unfloat button
    
    Reviewed-on: https://gerrit.libreoffice.org/65820
    Tested-by: Jenkins
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit 9c4a374baa4d18dec4066e547d76a40501b20d45)
    
    Change-Id: Id0bc6e5be5a55480233afeae44eccac24fa01434
    Reviewed-on: https://gerrit.libreoffice.org/65871
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/sw/qa/extras/uiwriter/data/floating_table/small_floating_table.odt b/sw/qa/extras/uiwriter/data/floating_table/small_floating_table.odt
new file mode 100644
index 000000000000..6b77569f2583
Binary files /dev/null and b/sw/qa/extras/uiwriter/data/floating_table/small_floating_table.odt differ
diff --git a/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.doc b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.doc
new file mode 100644
index 000000000000..e5247f1598c2
Binary files /dev/null and b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.doc differ
diff --git a/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.docx b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.docx
new file mode 100644
index 000000000000..cef1f7bf685d
Binary files /dev/null and b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.docx differ
diff --git a/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.odt b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.odt
new file mode 100644
index 000000000000..eb2534ba4c52
Binary files /dev/null and b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_floating_table.odt differ
diff --git a/sw/qa/extras/uiwriter/data/floating_table/unfloatable_small_floating_table.docx b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_small_floating_table.docx
new file mode 100644
index 000000000000..d51056af1177
Binary files /dev/null and b/sw/qa/extras/uiwriter/data/floating_table/unfloatable_small_floating_table.docx differ
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index d6410d60888b..f45272a771c7 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -26,11 +26,20 @@
 #include <fmtfsize.hxx>
 #include <fmtornt.hxx>
 #include <com/sun/star/style/BreakType.hpp>
+#include <flyfrms.hxx>
+#include <UndoManager.hxx>
+#include <edtwin.hxx>
+#include <view.hxx>
+#include <sortedobjs.hxx>
+#include <anchoredobject.hxx>
+#include <FrameControlsManager.hxx>
+#include <FloatingTableButton.hxx>
 
 namespace
 {
 char const DATA_DIRECTORY[] = "/sw/qa/extras/uiwriter/data2/";
-}
+char const FLOATING_TABLE_DATA_DIRECTORY[] = "/sw/qa/extras/uiwriter/data/floating_table/";
+} // namespace
 
 /// Second set of tests asserting the behavior of Writer user interface shells.
 class SwUiWriterTest2 : public SwModelTestBase
@@ -53,6 +62,9 @@ public:
     void testDocxAttributeTableExport();
     void testTdf125310();
     void testTdf125310b();
+    void testUnfloatButtonSmallTable();
+    void testUnfloatButton();
+    void testUnfloatButtonReadOnlyMode();
 
     CPPUNIT_TEST_SUITE(SwUiWriterTest2);
     CPPUNIT_TEST(testRedlineMoveInsertInDelete);
@@ -72,6 +84,9 @@ public:
     CPPUNIT_TEST(testDocxAttributeTableExport);
     CPPUNIT_TEST(testTdf125310);
     CPPUNIT_TEST(testTdf125310b);
+    CPPUNIT_TEST(testUnfloatButtonSmallTable);
+    CPPUNIT_TEST(testUnfloatButton);
+    CPPUNIT_TEST(testUnfloatButtonReadOnlyMode);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -764,6 +779,106 @@ void SwUiWriterTest2::testTdf125310b()
     CPPUNIT_ASSERT_EQUAL(1, getPages());
 }
 
+void SwUiWriterTest2::testUnfloatButtonSmallTable()
+{
+    // The floating table in the test document is too small, so we don't provide an unfloat button
+    load(FLOATING_TABLE_DATA_DIRECTORY, "small_floating_table.odt");
+    SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    CPPUNIT_ASSERT(pTextDoc);
+    SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    const SwSortedObjs* pAnchored
+        = pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs();
+    CPPUNIT_ASSERT(pAnchored);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pAnchored->size());
+    SwAnchoredObject* pAnchoredObj = (*pAnchored)[0];
+
+    SwFlyFrame* pFlyFrame = dynamic_cast<SwFlyFrame*>(pAnchoredObj);
+    CPPUNIT_ASSERT(pFlyFrame);
+    CPPUNIT_ASSERT(!pFlyFrame->IsShowUnfloatButton(pWrtShell));
+
+    SdrObject* pObj = pFlyFrame->GetFormat()->FindRealSdrObject();
+    CPPUNIT_ASSERT(pObj);
+    pWrtShell->SelectObj(Point(), 0, pObj);
+    CPPUNIT_ASSERT(!pFlyFrame->IsShowUnfloatButton(pWrtShell));
+}
+
+void SwUiWriterTest2::testUnfloatButton()
+{
+    // Different use cases where unfloat button should be visible
+    const std::vector<OUString> aTestFiles = {
+        "unfloatable_floating_table.odt", // Typical use case of multipage floating table
+        "unfloatable_floating_table.docx", // Need to test the DOCX import whether we detect the floating table correctly
+        "unfloatable_floating_table.doc", // Also the DOC import
+        "unfloatable_small_floating_table.docx" // Atypical use case, when the table is small, but because of it's position is it broken to two pages
+    };
+
+    for (const OUString& aTestFile : aTestFiles)
+    {
+        OString sTestFileName = OUStringToOString(aTestFile, RTL_TEXTENCODING_UTF8);
+        OString sFailureMessage = OString("Failure in the test file: ") + sTestFileName;
+
+        load(FLOATING_TABLE_DATA_DIRECTORY, sTestFileName.getStr());
+        SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+        CPPUNIT_ASSERT_MESSAGE(sFailureMessage.getStr(), pTextDoc);
+        SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+        CPPUNIT_ASSERT_MESSAGE(sFailureMessage.getStr(), pWrtShell);
+
+        const SwSortedObjs* pAnchored;
+        if (sTestFileName == "unfloatable_small_floating_table.docx")
+            pAnchored = pWrtShell->GetLayout()
+                            ->GetLower()
+                            ->GetLower()
+                            ->GetLower()
+                            ->GetNext()
+                            ->GetDrawObjs();
+        else
+            pAnchored = pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs();
+        CPPUNIT_ASSERT_MESSAGE(sFailureMessage.getStr(), pAnchored);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailureMessage.getStr(), static_cast<size_t>(1),
+                                     pAnchored->size());
+        SwAnchoredObject* pAnchoredObj = (*pAnchored)[0];
+
+        // The unfloat button is not visible until it gets selected
+        SwFlyFrame* pFlyFrame = dynamic_cast<SwFlyFrame*>(pAnchoredObj);
+        CPPUNIT_ASSERT_MESSAGE(sFailureMessage.getStr(), pFlyFrame);
+        CPPUNIT_ASSERT_MESSAGE(sFailureMessage.getStr(),
+                               !pFlyFrame->IsShowUnfloatButton(pWrtShell));
+
+        SdrObject* pObj = pFlyFrame->GetFormat()->FindRealSdrObject();
+        CPPUNIT_ASSERT_MESSAGE(sFailureMessage.getStr(), pObj);
+        pWrtShell->SelectObj(Point(), 0, pObj);
+        CPPUNIT_ASSERT_MESSAGE(sFailureMessage.getStr(), pFlyFrame->IsShowUnfloatButton(pWrtShell));
+    }
+}
+
+void SwUiWriterTest2::testUnfloatButtonReadOnlyMode()
+{
+    // In read only mode we don't show the unfloat button even if we have a multipage floating table
+    load(FLOATING_TABLE_DATA_DIRECTORY, "unfloatable_floating_table.odt");
+    SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    CPPUNIT_ASSERT(pTextDoc);
+    SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+    pWrtShell->SetReadonlyOption(true);
+
+    const SwSortedObjs* pAnchored
+        = pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs();
+    CPPUNIT_ASSERT(pAnchored);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pAnchored->size());
+    SwAnchoredObject* pAnchoredObj = (*pAnchored)[0];
+
+    SwFlyFrame* pFlyFrame = dynamic_cast<SwFlyFrame*>(pAnchoredObj);
+    CPPUNIT_ASSERT(pFlyFrame);
+    CPPUNIT_ASSERT(!pFlyFrame->IsShowUnfloatButton(pWrtShell));
+
+    SdrObject* pObj = pFlyFrame->GetFormat()->FindRealSdrObject();
+    CPPUNIT_ASSERT(pObj);
+    pWrtShell->SelectObj(Point(), 0, pObj);
+    CPPUNIT_ASSERT(!pFlyFrame->IsShowUnfloatButton(pWrtShell));
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest2);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index 6501ab592510..5ee5eb152b9b 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -24,6 +24,7 @@
 #include <vector>
 #include <frmfmt.hxx>
 #include <anchoredobject.hxx>
+#include <swdllapi.h>
 
 class SwFormatAnchor;
 class SwPageFrame;
@@ -58,7 +59,7 @@ bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove = true );
 
     #i26791# - inherit also from <SwAnchoredFlyFrame>
 */
-class SwFlyFrame : public SwLayoutFrame, public SwAnchoredObject
+class SW_DLLPUBLIC SwFlyFrame : public SwLayoutFrame, public SwAnchoredObject
 {
     // is allowed to lock, implemented in frmtool.cxx
     friend void AppendObj(SwFrame *const pFrame, SwPageFrame *const pPage, SwFrameFormat *const pFormat, const SwFormatAnchor & rAnch);
@@ -271,9 +272,9 @@ public:
     void InvalidateContentPos();
 
     void SelectionHasChanged(SwFEShell* pShell);
+    bool IsShowUnfloatButton(SwWrtShell* pWrtSh) const;
 
 private:
-    bool IsShowUnfloatButton(SwWrtShell* pWrtSh) const;
     void UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const;
     void PaintDecorators() const;
 };
diff --git a/sw/source/core/inc/layfrm.hxx b/sw/source/core/inc/layfrm.hxx
index 92fc189fba8a..8fd0e5f626aa 100644
--- a/sw/source/core/inc/layfrm.hxx
+++ b/sw/source/core/inc/layfrm.hxx
@@ -20,6 +20,7 @@
 #define INCLUDED_SW_SOURCE_CORE_INC_LAYFRM_HXX
 
 #include "frame.hxx"
+#include <swdllapi.h>
 
 class SwAnchoredObject;
 class SwContentFrame;
@@ -31,7 +32,7 @@ class SwBorderAttrs;
 class SwFormatFrameSize;
 class SwCellFrame;
 
-class SwLayoutFrame: public SwFrame
+class SW_DLLPUBLIC SwLayoutFrame: public SwFrame
 {
     // The SwFrame in disguise
     friend class SwFlowFrame;
diff --git a/sw/source/core/inc/sortedobjs.hxx b/sw/source/core/inc/sortedobjs.hxx
index 0fd6a9cb9d71..5e5dcc45712f 100644
--- a/sw/source/core/inc/sortedobjs.hxx
+++ b/sw/source/core/inc/sortedobjs.hxx
@@ -21,6 +21,7 @@
 
 #include <sal/types.h>
 #include <vector>
+#include <swdllapi.h>
 
 class SwAnchoredObject;
 
@@ -45,7 +46,7 @@ class SwAnchoredObject;
     If one of the sort criteria attributes of an anchored object changes,
     the sorting has to be updated - use method <Update(..)>
 */
-class SwSortedObjs
+class SW_DLLPUBLIC SwSortedObjs
 {
     private:
         std::vector< SwAnchoredObject* > maSortedObjLst;
commit 8dca18297479b334a153f3ad6b383d3f6157f0c6
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Wed Jan 2 17:57:22 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Jun 19 14:28:17 2019 +0200

    Unfloat: Handle unfloat button visibility
    
    We need to update the state of the button every time
    when the frame's layout changes or when the selection
    changes.
    Show the button if the text frame is selected and it's
    a floating table which would hang out of the actual page
    after unfloating.
    
    Reviewed-on: https://gerrit.libreoffice.org/65819
    Tested-by: Jenkins
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit 6e5c4001c7b5cab2b2cc6419072acbe5fa7cb04a)
    
    Change-Id: I6b64affb063f552921915a0735e80889e5fd8124
    Reviewed-on: https://gerrit.libreoffice.org/65870
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/sw/source/core/frmedt/fefly1.cxx b/sw/source/core/frmedt/fefly1.cxx
index d94ee5c8e6ad..65a19bc00487 100644
--- a/sw/source/core/frmedt/fefly1.cxx
+++ b/sw/source/core/frmedt/fefly1.cxx
@@ -266,6 +266,9 @@ void SwFEShell::SelectFlyFrame( SwFlyFrame& rFrame )
 
         pImpl->GetDrawView()->MarkObj( rFrame.GetVirtDrawObj(),
                                       pImpl->GetPageView() );
+
+        rFrame.SelectionHasChanged(this);
+
         KillPams();
         ClearMark();
         SelFlyGrabCursor();
diff --git a/sw/source/core/frmedt/feshview.cxx b/sw/source/core/frmedt/feshview.cxx
index 0d7a871c52c3..d3fa9b126e86 100644
--- a/sw/source/core/frmedt/feshview.cxx
+++ b/sw/source/core/frmedt/feshview.cxx
@@ -235,7 +235,11 @@ bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 nFlag, SdrObject *pObj )
             }
         }
         if ( bUnmark )
+        {
             pDView->UnmarkAll();
+            if (pOldSelFly)
+                pOldSelFly->SelectionHasChanged(this);
+        }
     }
     else
     {
@@ -275,6 +279,13 @@ bool SwFEShell::SelectObj( const Point& rPt, sal_uInt8 nFlag, SdrObject *pObj )
         }
     }
 
+    if ( rMrkList.GetMarkCount() == 1 )
+    {
+        SwFlyFrame *pSelFly = ::GetFlyFromMarked( &rMrkList, this );
+        if (pSelFly)
+            pSelFly->SelectionHasChanged(this);
+    }
+
     if (!(nFlag & SW_ALLOW_TEXTBOX))
     {
         // If the fly frame is a textbox of a shape, then select the shape instead.
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index c28dcd98b882..6501ab592510 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -37,6 +37,8 @@ namespace tools { class PolyPolygon; }
 class SwFlyDrawContact;
 class SwFormat;
 class SwViewShell;
+class SwFEShell;
+class SwWrtShell;
 
 
 /** search an anchor for paragraph bound frames starting from pOldAnch
@@ -267,6 +269,13 @@ public:
     Point& ContentPos() { return m_aContentPos; }
 
     void InvalidateContentPos();
+
+    void SelectionHasChanged(SwFEShell* pShell);
+
+private:
+    bool IsShowUnfloatButton(SwWrtShell* pWrtSh) const;
+    void UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const;
+    void PaintDecorators() const;
 };
 #endif
 
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index f81a62266a5e..e087f23430ad 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -68,6 +68,12 @@
 #include <basegfx/polygon/b2dpolygontools.hxx>
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
 
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <edtwin.hxx>
+#include <bodyfrm.hxx>
+#include <FrameControlsManager.hxx>
+
 using namespace ::com::sun::star;
 
 static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame );
@@ -279,6 +285,9 @@ void SwFlyFrame::DestroyImpl()
     FinitDrawObj();
 
     SwLayoutFrame::DestroyImpl();
+
+    SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(getRootFrame()->GetCurrShell());
+    UpdateUnfloatButton(pWrtSh, false);
 }
 
 SwFlyFrame::~SwFlyFrame()
@@ -1764,6 +1773,93 @@ void SwFlyFrame::InvalidateContentPos()
     Invalidate_();
 }
 
+void SwFlyFrame::SelectionHasChanged(SwFEShell* pShell)
+{
+    SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >(pShell);
+    if (pWrtSh == nullptr)
+        return;
+
+    UpdateUnfloatButton(pWrtSh, IsShowUnfloatButton(pWrtSh));
+}
+
+bool SwFlyFrame::IsShowUnfloatButton(SwWrtShell* pWrtSh) const
+{
+    if (pWrtSh == nullptr)
+        return false;
+
+    // In read only mode we don't allow unfloat operation
+    if (pWrtSh->GetViewOptions()->IsReadonly())
+        return false;
+
+    const SdrObject *pObj = GetFrameFormat().FindRealSdrObject();
+    if (pObj == nullptr)
+        return false;
+
+    // SwFlyFrame itself can mean images, ole objects, etc, but we interested in actual text frames
+    if (SwFEShell::GetObjCntType(*pObj) != OBJCNT_FLY)
+        return false;
+
+    // We show the button only for the selected text frame
+    SwDrawView *pView = pWrtSh->Imp()->GetDrawView();
+    if (pView == nullptr)
+        return false;
+
+    // Fly frame can be selected only alone
+    if (pView->GetMarkedObjectList().GetMarkCount() != 1)
+        return false;
+
+    if(!pView->IsObjMarked(pObj))
+        return false;
+
+    // A frame is a floating table if there is only one table (and maybe some whitespaces) inside it
+    int nTableCount = 0;
+    const SwFrame* pLower = GetLower();
+    const SwTabFrame* pTable = nullptr;
+    while (pLower)
+    {
+        if (pLower->IsTabFrame())
+        {
+            pTable = static_cast<const SwTabFrame*>(pLower);
+            ++nTableCount;
+            if (nTableCount > 1 || pTable == nullptr)
+                return false;
+        }
+
+        if (pLower->IsTextFrame())
+        {
+            const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(pLower);
+            if (!pTextFrame->GetText().trim().isEmpty())
+                return false;
+        }
+        pLower = pLower->GetNext();
+    }
+
+    if (nTableCount != 1 || pTable == nullptr)
+        return false;
+
+    // Show the unfold button only for multipage tables
+    const SwBodyFrame *pBody = GetAnchorFrame()->FindBodyFrame();
+    if (pBody == nullptr)
+        return false;
+
+    long nBodyHeight = pBody->getFrameArea().Height();
+    long nTableHeight = pTable->getFrameArea().Height();
+    long nFrameOffset = std::abs(GetAnchorFrame()->getFrameArea().Top() - pBody->getFrameArea().Top());
+
+    return nBodyHeight < nTableHeight + nFrameOffset;
+}
+
+void SwFlyFrame::UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const
+{
+    if (pWrtSh == nullptr)
+        return;
+
+    SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
+    SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
+    Point aBottomRightPixel = rEditWin.LogicToPixel( getFrameArea().BottomRight() );
+    rMngr.SetFloatingTableButton(this, bShow,  aBottomRightPixel);
+}
+
 SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst )
 {
     SwRectFnSet aRectFnSet(this);
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 0a9338f462b6..f116678d0b59 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -4094,12 +4094,24 @@ void SwFlyFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const&
     // have to paint frame borders added in heaven layer here...
     ProcessPrimitives(gProp.pBLines->GetBorderLines_Clear());
 
+    PaintDecorators();
+
     rRenderContext.Pop();
 
     if ( gProp.pSProgress && pNoText )
         SfxProgress::Reschedule();
 }
 
+void SwFlyFrame::PaintDecorators() const
+{
+    // Show the un-float button
+    SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >( gProp.pSGlobalShell );
+    if ( pWrtSh )
+    {
+        UpdateUnfloatButton(pWrtSh, IsShowUnfloatButton(pWrtSh));
+    }
+}
+
 void SwTabFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const& rRect, SwPrintData const*const) const
 {
     const SwViewOption* pViewOption = gProp.pSGlobalShell->GetViewOptions();
commit 5224950508e484adcfe03d7815cbc3f29eaa8de7
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Fri Jan 4 20:16:12 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Jun 19 14:28:17 2019 +0200

    Unfloat: Introduce Unfloat table button as a frame control
    
    Use the same button style and color what LO uses for header/footer
    button.
    Later it might be a good idea to have a separate configurable color
    for this button, but for now it's seems unneeded to introduce a
    new configure option for this.
    
    Reviewed-on: https://gerrit.libreoffice.org/65818
    Tested-by: Jenkins
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit 021c3a0ee1c95a1b0b8e7c72f9d8e81718862a62)
    
    Change-Id: Idf86aaa44e29846a2ee211a81fe5376b4335bb05
    Reviewed-on: https://gerrit.libreoffice.org/65869
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Miklos Vajna <vmiklos at collabora.com>

diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index f69c69adc337..2751a24a4b00 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -608,6 +608,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
     sw/source/uibase/docvw/AnnotationWin2 \
     sw/source/uibase/docvw/DashedLine \
     sw/source/uibase/docvw/FrameControlsManager \
+    sw/source/uibase/docvw/FloatingTableButton \
     sw/source/uibase/docvw/PageBreakWin \
     sw/source/uibase/docvw/OverlayRanges \
     sw/source/uibase/docvw/PostItMgr \
diff --git a/sw/inc/fesh.hxx b/sw/inc/fesh.hxx
index 5d45fa3e6621..e5e3275bcbec 100644
--- a/sw/inc/fesh.hxx
+++ b/sw/inc/fesh.hxx
@@ -227,8 +227,6 @@ private:
 
     SAL_DLLPRIVATE bool ImpEndCreate();
 
-    SAL_DLLPRIVATE static ObjCntType GetObjCntType( const SdrObject& rObj );
-
     /// Methods for copying of draw objects.
     SAL_DLLPRIVATE bool CopyDrawSel( SwFEShell* pDestShell, const Point& rSttPt,
                                 const Point& rInsPt, bool bIsMove,
@@ -311,6 +309,7 @@ public:
      * drag&drop of controls into header */
     bool IsSelContainsControl() const;
 
+    static ObjCntType GetObjCntType( const SdrObject& rObj );
     ObjCntType GetObjCntType( const Point &rPt, SdrObject *&rpObj ) const;
     ObjCntType GetObjCntTypeOfSelection() const;
 
diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc
index f0a07cd6e1b0..1b3153dab176 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -1204,6 +1204,8 @@
 #define STR_DELETE_FOOTER                       NC_("STR_DELETE_FOOTER", "Delete Footer...")
 #define STR_FORMAT_FOOTER                       NC_("STR_FORMAT_FOOTER", "Format Footer...")
 
+#define STR_UNFLOAT_TABLE                       NC_("STR_UNFLOAT_TABLE", "Un-float Table")
+
 #define STR_GRFILTER_OPENERROR                  NC_("STR_GRFILTER_OPENERROR", "Image file cannot be opened")
 #define STR_GRFILTER_IOERROR                    NC_("STR_GRFILTER_IOERROR", "Image file cannot be read")
 #define STR_GRFILTER_FORMATERROR                NC_("STR_GRFILTER_FORMATERROR", "Unknown image format")
diff --git a/sw/inc/swtypes.hxx b/sw/inc/swtypes.hxx
index a89413ccfa7d..41ce4e820e8f 100644
--- a/sw/inc/swtypes.hxx
+++ b/sw/inc/swtypes.hxx
@@ -248,7 +248,8 @@ enum FrameControlType
 {
     PageBreak,
     Header,
-    Footer
+    Footer,
+    FloatingTable
 };
 
 #endif
diff --git a/sw/source/uibase/docvw/FloatingTableButton.cxx b/sw/source/uibase/docvw/FloatingTableButton.cxx
new file mode 100644
index 000000000000..8f124f46f652
--- /dev/null
+++ b/sw/source/uibase/docvw/FloatingTableButton.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#include <FloatingTableButton.hxx>
+#include <HeaderFooterWin.hxx>
+
+#include <edtwin.hxx>
+#include <strings.hrc>
+#include <vcl/metric.hxx>
+#include <viewopt.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/attribute/fontattribute.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+
+#define TEXT_PADDING 3
+#define BOX_DISTANCE 3
+#define BUTTON_WIDTH 12
+
+FloatingTableButton::FloatingTableButton(SwEditWin* pEditWin, const SwFrame* pFrame)
+    : SwFrameMenuButtonBase(pEditWin, pFrame)
+    , m_sLabel(SwResId(STR_UNFLOAT_TABLE))
+{
+}
+
+FloatingTableButton::~FloatingTableButton() { disposeOnce(); }
+
+void FloatingTableButton::SetOffset(Point aBottomRightPixel)
+{
+    // Compute the text size and get the box position & size from it
+    tools::Rectangle aTextRect;
+    GetTextBoundRect(aTextRect, m_sLabel);
+    tools::Rectangle aTextPxRect = LogicToPixel(aTextRect);
+    FontMetric aFontMetric = GetFontMetric(GetFont());
+    Size aBoxSize(aTextPxRect.GetWidth() + BUTTON_WIDTH + TEXT_PADDING * 2,
+                  aFontMetric.GetLineHeight() + TEXT_PADDING * 2);
+
+    Point aBoxPos(aBottomRightPixel.X() - aBoxSize.Width() - BOX_DISTANCE,
+                  aBottomRightPixel.Y() - aBoxSize.Height());
+
+    if (AllSettings::GetLayoutRTL())
+    {
+        aBoxPos.setX(aBottomRightPixel.X() + BOX_DISTANCE);
+    }
+
+    // Set the position & Size of the window
+    SetPosSizePixel(aBoxPos, aBoxSize);
+}
+
+void FloatingTableButton::MouseButtonDown(const MouseEvent& /*rMEvt*/)
+{
+    // Move the table outside of the frame
+}
+
+void FloatingTableButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+    SetMapMode(MapMode(MapUnit::MapPixel));
+    drawinglayer::primitive2d::Primitive2DContainer aSeq;
+    const ::tools::Rectangle aRect(
+        ::tools::Rectangle(Point(0, 0), rRenderContext.PixelToLogic(GetSizePixel())));
+
+    // Create button
+    SwFrameButtonPainter::PaintButton(aSeq, aRect, false);
+
+    // Create the text primitive
+    basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
+    basegfx::B2DVector aFontSize;
+    drawinglayer::attribute::FontAttribute aFontAttr
+        = drawinglayer::primitive2d::getFontAttributeFromVclFont(
+            aFontSize, rRenderContext.GetFont(), false, false);
+
+    FontMetric aFontMetric = rRenderContext.GetFontMetric(rRenderContext.GetFont());
+    double nTextOffsetY = aFontMetric.GetAscent() + TEXT_PADDING;
+    double nTextOffsetX = std::abs(aRect.GetWidth() - rRenderContext.GetTextWidth(m_sLabel)) / 2.0;
+    Point aTextPos(nTextOffsetX, nTextOffsetY);
+
+    basegfx::B2DHomMatrix aTextMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
+        aFontSize.getX(), aFontSize.getY(), static_cast<double>(aTextPos.X()),
+        static_cast<double>(aTextPos.Y())));
+
+    aSeq.push_back(drawinglayer::primitive2d::Primitive2DReference(
+        new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+            aTextMatrix, m_sLabel, 0, m_sLabel.getLength(), std::vector<double>(), aFontAttr,
+            css::lang::Locale(), aLineColor)));
+
+    // Create the processor and process the primitives
+    const drawinglayer::geometry::ViewInformation2D aNewViewInfos;
+    std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(
+        drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(rRenderContext,
+                                                                         aNewViewInfos));
+
+    pProcessor->process(aSeq);
+}
+
+void FloatingTableButton::ShowAll(bool bShow) { Show(bShow); }
+
+bool FloatingTableButton::Contains(const Point& rDocPt) const
+{
+    ::tools::Rectangle aRect(GetPosPixel(), GetSizePixel());
+    if (aRect.IsInside(rDocPt))
+        return true;
+
+    return false;
+}
+
+void FloatingTableButton::SetReadonly(bool bReadonly) { ShowAll(!bReadonly); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
\ No newline at end of file
diff --git a/sw/source/uibase/docvw/FrameControlsManager.cxx b/sw/source/uibase/docvw/FrameControlsManager.cxx
index e0c09639d09b..6bad9e5dd3af 100644
--- a/sw/source/uibase/docvw/FrameControlsManager.cxx
+++ b/sw/source/uibase/docvw/FrameControlsManager.cxx
@@ -11,7 +11,9 @@
 #include <FrameControlsManager.hxx>
 #include <HeaderFooterWin.hxx>
 #include <PageBreakWin.hxx>
+#include <FloatingTableButton.hxx>
 #include <pagefrm.hxx>
+#include <flyfrm.hxx>
 #include <viewopt.hxx>
 #include <view.hxx>
 #include <wrtsh.hxx>
@@ -137,6 +139,39 @@ void SwFrameControlsManager::SetPageBreakControl( const SwPageFrame* pPageFrame
         pControl->ShowAll( true );
 }
 
+void SwFrameControlsManager::SetFloatingTableButton( const SwFlyFrame* pFlyFrame, bool bShow, Point aBottomRightPixel )
+{
+    if(pFlyFrame == nullptr)
+        return;
+
+    // Check if we already have the control
+    SwFrameControlPtr pControl;
+
+    SwFrameControlPtrMap& rControls = m_aControls[FloatingTable];
+
+    SwFrameControlPtrMap::iterator lb = rControls.lower_bound(pFlyFrame);
+    if (lb != rControls.end() && !(rControls.key_comp()(pFlyFrame, lb->first)))
+        pControl = lb->second;
+    else if (!bShow) // Do not create the control when it's not shown
+        return;
+    else
+    {
+        SwFrameControlPtr pNewControl( new SwFrameControl(
+                VclPtr<FloatingTableButton>::Create( m_pEditWin, pFlyFrame ).get() ) );
+        const SwViewOption* pViewOpt = m_pEditWin->GetView().GetWrtShell().GetViewOptions();
+        pNewControl->SetReadonly( pViewOpt->IsReadonly() );
+
+        rControls.insert(lb, make_pair(pFlyFrame, pNewControl));
+
+        pControl.swap( pNewControl );
+    }
+
+    FloatingTableButton* pButton = dynamic_cast<FloatingTableButton*>(pControl->GetWindow());
+    assert(pButton != nullptr);
+    pButton->SetOffset(aBottomRightPixel);
+    pControl->ShowAll( bShow );
+}
+
 SwFrameMenuButtonBase::SwFrameMenuButtonBase( SwEditWin* pEditWin, const SwFrame* pFrame ) :
     MenuButton( pEditWin, WB_DIALOGCONTROL ),
     m_pEditWin( pEditWin ),
@@ -146,7 +181,13 @@ SwFrameMenuButtonBase::SwFrameMenuButtonBase( SwEditWin* pEditWin, const SwFrame
 
 const SwPageFrame* SwFrameMenuButtonBase::GetPageFrame()
 {
-    return static_cast< const SwPageFrame * >( m_pFrame );
+    if (m_pFrame->IsPageFrame())
+        return static_cast<const SwPageFrame*>( m_pFrame );
+
+    if (m_pFrame->IsFlyFrame())
+        return static_cast<const SwFlyFrame*>(m_pFrame)->GetAnchorFrame()->FindPageFrame();
+
+    return m_pFrame->FindPageFrame();
 }
 
 void SwFrameMenuButtonBase::dispose()
diff --git a/sw/source/uibase/docvw/HeaderFooterWin.cxx b/sw/source/uibase/docvw/HeaderFooterWin.cxx
index 9e66daab2a24..411c1f3c87d2 100644
--- a/sw/source/uibase/docvw/HeaderFooterWin.cxx
+++ b/sw/source/uibase/docvw/HeaderFooterWin.cxx
@@ -80,7 +80,7 @@ namespace
         return basegfx::utils::hsl2rgb( aHslDark );
     }
 
-    B2DPolygon lcl_GetPolygon( const ::tools::Rectangle& rRect, bool bHeader )
+    B2DPolygon lcl_GetPolygon( const ::tools::Rectangle& rRect, bool bOnTop )
     {
         const double nRadius = 3;
         const double nKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
@@ -112,7 +112,7 @@ namespace
 
         aPolygon.append( B2DPoint( rRect.Right(), rRect.Top() ) );
 
-        if ( !bHeader )
+        if ( !bOnTop )
         {
             B2DRectangle aBRect( rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() );
             B2DHomMatrix aRotation = createRotateAroundPoint(
@@ -124,6 +124,42 @@ namespace
     }
 }
 
+void SwFrameButtonPainter::PaintButton(drawinglayer::primitive2d::Primitive2DContainer& rSeq,
+                                       const tools::Rectangle& rRect, bool bOnTop)
+{
+    rSeq.clear();
+    B2DPolygon aPolygon = lcl_GetPolygon(rRect, bOnTop);
+
+    // Colors
+    basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
+    basegfx::BColor aFillColor = lcl_GetFillColor(aLineColor);
+    basegfx::BColor aLighterColor = lcl_GetLighterGradientColor(aFillColor);
+
+    const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+    if (rSettings.GetHighContrastMode())
+    {
+        aFillColor = rSettings.GetDialogColor().getBColor();
+        aLineColor = rSettings.GetDialogTextColor().getBColor();
+
+        rSeq.push_back(drawinglayer::primitive2d::Primitive2DReference(
+                            new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), aFillColor)));
+    }
+    else
+    {
+        B2DRectangle aGradientRect(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom());
+        double nAngle = M_PI;
+        if (bOnTop)
+            nAngle = 0;
+        FillGradientAttribute aFillAttrs(drawinglayer::attribute::GradientStyle::Linear, 0.0, 0.0, 0.0, nAngle, aLighterColor, aFillColor, 10);
+        rSeq.push_back(drawinglayer::primitive2d::Primitive2DReference(
+                            new drawinglayer::primitive2d::FillGradientPrimitive2D(aGradientRect, aFillAttrs)));
+    }
+
+    // Create the border lines primitive
+    rSeq.push_back(drawinglayer::primitive2d::Primitive2DReference(
+                new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aPolygon, aLineColor)));
+}
+
 SwHeaderFooterWin::SwHeaderFooterWin( SwEditWin* pEditWin, const SwFrame *pFrame, bool bHeader ) :
     SwFrameMenuButtonBase( pEditWin, pFrame ),
     m_aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/swriter/ui/headerfootermenu.ui", ""),
@@ -255,42 +291,13 @@ void SwHeaderFooterWin::Paint(vcl::RenderContext& rRenderContext, const ::tools:
 {
     // Use pixels for the rest of the drawing
     SetMapMode(MapMode(MapUnit::MapPixel));
-
+    drawinglayer::primitive2d::Primitive2DContainer aSeq;
     const ::tools::Rectangle aRect(::tools::Rectangle(Point(0, 0), rRenderContext.PixelToLogic(GetSizePixel())));
-    drawinglayer::primitive2d::Primitive2DContainer aSeq(3);
-
-    B2DPolygon aPolygon = lcl_GetPolygon(aRect, m_bIsHeader);
-
-    // Colors
-    basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
-    basegfx::BColor aFillColor = lcl_GetFillColor(aLineColor);
-    basegfx::BColor aLighterColor = lcl_GetLighterGradientColor(aFillColor);
 
-    const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
-    if (rSettings.GetHighContrastMode())
-    {
-        aFillColor = rSettings.GetDialogColor().getBColor();
-        aLineColor = rSettings.GetDialogTextColor().getBColor();
-
-        aSeq[0] = drawinglayer::primitive2d::Primitive2DReference(
-                    new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), aFillColor));
-    }
-    else
-    {
-        B2DRectangle aGradientRect(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
-        double nAngle = M_PI;
-        if (m_bIsHeader)
-            nAngle = 0;
-        FillGradientAttribute aFillAttrs(drawinglayer::attribute::GradientStyle::Linear, 0.0, 0.0, 0.0, nAngle, aLighterColor, aFillColor, 10);
-        aSeq[0] = drawinglayer::primitive2d::Primitive2DReference(
-                    new drawinglayer::primitive2d::FillGradientPrimitive2D(aGradientRect, aFillAttrs));
-    }
-
-    // Create the border lines primitive
-    aSeq[1] = drawinglayer::primitive2d::Primitive2DReference(
-                new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aPolygon, aLineColor));
+    SwFrameButtonPainter::PaintButton(aSeq, aRect, m_bIsHeader);
 
     // Create the text primitive
+    basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
     B2DVector aFontSize;
     FontAttribute aFontAttr = drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, rRenderContext.GetFont(), false, false);
 
@@ -302,10 +309,10 @@ void SwHeaderFooterWin::Paint(vcl::RenderContext& rRenderContext, const ::tools:
                                             aFontSize.getX(), aFontSize.getY(),
                                             double(aTextPos.X()), double(aTextPos.Y())));
 
-    aSeq[2] = drawinglayer::primitive2d::Primitive2DReference(
+    aSeq.push_back(drawinglayer::primitive2d::Primitive2DReference(
                     new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
                         aTextMatrix, m_sLabel, 0, m_sLabel.getLength(),
-                        std::vector<double>(), aFontAttr, css::lang::Locale(), aLineColor));
+                        std::vector<double>(), aFontAttr, css::lang::Locale(), aLineColor)));
 
     // Create the 'plus' or 'arrow' primitive
     B2DRectangle aSignArea(B2DPoint(aRect.Right() - BUTTON_WIDTH, 0.0),
diff --git a/sw/source/uibase/inc/FloatingTableButton.hxx b/sw/source/uibase/inc/FloatingTableButton.hxx
new file mode 100644
index 000000000000..b64ddfe07912
--- /dev/null
+++ b/sw/source/uibase/inc/FloatingTableButton.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#ifndef INCLUDED_SW_SOURCE_UIBASE_DOCVW_FLOATINGTABLEBUTTON_HXX
+#define INCLUDED_SW_SOURCE_UIBASE_DOCVW_FLOATINGTABLEBUTTON_HXX
+
+#include "FrameControl.hxx"
+#include <vcl/menubtn.hxx>
+
+class FloatingTableButton : public SwFrameMenuButtonBase
+{
+    OUString m_sLabel;
+
+public:
+    FloatingTableButton(SwEditWin* pEditWin, const SwFrame* pFrame);
+    virtual ~FloatingTableButton() override;
+
+    void SetOffset(Point aBottomRightPixel);
+
+    virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+    virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+
+    virtual void ShowAll(bool bShow) override;
+    virtual bool Contains(const Point& rDocPt) const override;
+
+    virtual void SetReadonly(bool bReadonly) override;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
\ No newline at end of file
diff --git a/sw/source/uibase/inc/FrameControlsManager.hxx b/sw/source/uibase/inc/FrameControlsManager.hxx
index df449922d755..096e61376b8c 100644
--- a/sw/source/uibase/inc/FrameControlsManager.hxx
+++ b/sw/source/uibase/inc/FrameControlsManager.hxx
@@ -47,6 +47,7 @@ class SwFrameControlsManager
         // Helper methods
         void SetHeaderFooterControl( const SwPageFrame* pPageFrame, FrameControlType eType, Point aOffset );
         void SetPageBreakControl( const SwPageFrame* pPageFrame );
+        void SetFloatingTableButton( const SwFlyFrame* pFlyFrame, bool bShow, Point aTopLeftPixel = Point() );
 };
 
 #endif
diff --git a/sw/source/uibase/inc/HeaderFooterWin.hxx b/sw/source/uibase/inc/HeaderFooterWin.hxx
index 47853074eec9..33a49c2d52e3 100644
--- a/sw/source/uibase/inc/HeaderFooterWin.hxx
+++ b/sw/source/uibase/inc/HeaderFooterWin.hxx
@@ -12,6 +12,16 @@
 #include "FrameControl.hxx"
 #include <vcl/builder.hxx>
 #include <vcl/menubtn.hxx>
+#include <vcl/timer.hxx>
+#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
+
+class SwFrameButtonPainter
+{
+public:
+
+    static void PaintButton(drawinglayer::primitive2d::Primitive2DContainer& rSeq,
+                            const tools::Rectangle& rRect, bool bOnTop);
+};
 
 /** Class for the header and footer separator control window.
 
commit 1efbc847abd8cfeb7335045340691a351dae6e3c
Author:     Tamás Zolnai <tamas.zolnai at collabora.com>
AuthorDate: Thu Jan 3 12:23:18 2019 +0100
Commit:     Tamás Zolnai <tamas.zolnai at collabora.com>
CommitDate: Wed Jun 19 14:28:17 2019 +0200

    Move FindBodyFrame from SwTextFrame to SwFrame
    
    So we can call it on other type of frames too.
    
    Reviewed-on: https://gerrit.libreoffice.org/65817
    Tested-by: Jenkins
    Reviewed-by: Tamás Zolnai <tamas.zolnai at collabora.com>
    (cherry picked from commit 484867ec5e716a1828a41b2535f7a1e10e8f3fe7)
    
    Reviewed-on: https://gerrit.libreoffice.org/65868
    Reviewed-by: Miklos Vajna <vmiklos at collabora.com>
    Tested-by: Miklos Vajna <vmiklos at collabora.com>
    (cherry picked from commit 641f8a1370d6b57fc35778a833b601de7fb14954)
    
    Change-Id: I74e80eb831ba1fc00abb8db1ffa3728758e68376

diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 920bd621fff4..0a9a1ea823c0 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -38,6 +38,7 @@
 class SwLayoutFrame;
 class SwRootFrame;
 class SwPageFrame;
+class SwBodyFrame;
 class SwFlyFrame;
 class SwSectionFrame;
 class SwFootnoteFrame;
@@ -661,6 +662,7 @@ public:
     SwFootnoteFrame       *ImplFindFootnoteFrame();
     SwFlyFrame            *ImplFindFlyFrame();
     SwSectionFrame        *ImplFindSctFrame();
+    const SwBodyFrame     *ImplFindBodyFrame() const;
     SwFrame               *FindFooterOrHeader();
     SwFrame               *GetLower();
     const SwFrame         *GetNext()  const { return mpNext; }
@@ -683,6 +685,7 @@ public:
     inline const SwFootnoteFrame  *FindFootnoteFrame() const;
     inline const SwFlyFrame  *FindFlyFrame() const;
     inline const SwSectionFrame *FindSctFrame() const;
+    inline const SwBodyFrame    *FindBodyFrame() const;
     inline const SwFrame     *FindNext() const;
     // #i27138# - add parameter <_bInSameFootnote>
     const SwContentFrame* FindNextCnt( const bool _bInSameFootnote = false ) const;
@@ -1085,6 +1088,11 @@ inline SwSectionFrame *SwFrame::FindSctFrame()
     return IsInSct() ? ImplFindSctFrame() : nullptr;
 }
 
+inline const SwBodyFrame *SwFrame::FindBodyFrame() const
+{
+    return IsInDocBody() ? ImplFindBodyFrame() : nullptr;
+}
+
 inline const SwTabFrame *SwFrame::FindTabFrame() const
 {
     return IsInTab() ? const_cast<SwFrame*>(this)->ImplFindTabFrame() : nullptr;
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index bf4c0ad8a316..86882201fbfd 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -591,8 +591,6 @@ public:
     /// Respect the Follows
     inline bool IsInside(TextFrameIndex nPos) const;
 
-    const SwBodyFrame   *FindBodyFrame()   const;
-
     /// DropCaps and selections
     bool GetDropRect( SwRect &rRect ) const
     { return HasPara() && GetDropRect_( rRect ); }
diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx
index a38f9f989529..5bdb1de12702 100644
--- a/sw/source/core/layout/findfrm.cxx
+++ b/sw/source/core/layout/findfrm.cxx
@@ -31,6 +31,7 @@
 #include <fmtftn.hxx>
 #include <fmtpdsc.hxx>
 #include <txtfrm.hxx>
+#include <bodyfrm.hxx>
 #include <calbck.hxx>
 #include <viewopt.hxx>
 #include <sal/log.hxx>
@@ -486,6 +487,18 @@ SwSectionFrame* SwFrame::ImplFindSctFrame()
     return static_cast<SwSectionFrame*>(pRet);
 }
 
+const SwBodyFrame* SwFrame::ImplFindBodyFrame() const
+{
+    const SwFrame *pRet = this;
+    while ( !pRet->IsBodyFrame() )
+    {
+        pRet = pRet->GetUpper();
+        if ( !pRet )
+            return nullptr;
+    }
+    return static_cast<const SwBodyFrame*>(pRet);
+}
+
 SwFootnoteFrame *SwFrame::ImplFindFootnoteFrame()
 {
     SwFrame *pRet = this;
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index dad1b9a47109..a513fde52629 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -172,18 +172,6 @@ bool SwTextFrame::GetDropRect_( SwRect &rRect ) const
     return false;
 }
 
-const SwBodyFrame *SwTextFrame::FindBodyFrame() const
-{
-    if ( IsInDocBody() )
-    {
-        const SwFrame *pFrame = GetUpper();
-        while( pFrame && !pFrame->IsBodyFrame() )
-            pFrame = pFrame->GetUpper();
-        return static_cast<const SwBodyFrame*>(pFrame);
-    }
-    return nullptr;
-}
-
 bool SwTextFrame::CalcFollow(TextFrameIndex const nTextOfst)
 {
     vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();


More information about the Libreoffice-commits mailing list