include/vcl/window.hxx | 2 sfx2/source/control/charwin.cxx | 1 shell/source/win32/spsupp/COMOpenDocuments.cxx | 36 +- sw/Library_sw.mk | 1 sw/inc/IDocumentMarkAccess.hxx | 8 sw/inc/crsrsh.hxx | 8 sw/inc/strings.hrc | 4 sw/inc/swundo.hxx | 4 sw/inc/view.hxx | 4 sw/qa/extras/globalfilter/data/checkbox_form_field.odt |binary sw/qa/extras/globalfilter/data/dropdown_form_field.odt |binary sw/qa/extras/globalfilter/data/text_form_field.odt |binary sw/qa/extras/globalfilter/globalfilter.cxx | 217 ++++++++++++++ sw/qa/extras/uiwriter/uiwriter2.cxx | 155 ++++++++++ sw/source/core/crsr/DropDownFormFieldButton.cxx | 256 +++++++++++++++++ sw/source/core/crsr/bookmrk.cxx | 74 ++++ sw/source/core/crsr/crsrsh.cxx | 2 sw/source/core/doc/docbm.cxx | 139 +++++++++ sw/source/core/inc/DropDownFormFieldButton.hxx | 54 +++ sw/source/core/inc/MarkManager.hxx | 13 sw/source/core/inc/UndoBookmark.hxx | 29 + sw/source/core/inc/bookmrk.hxx | 26 + sw/source/core/inc/rolbck.hxx | 33 ++ sw/source/core/inc/unobookmark.hxx | 2 sw/source/core/text/itrform2.cxx | 6 sw/source/core/text/porfld.cxx | 16 - sw/source/core/text/porfld.hxx | 8 sw/source/core/undo/rolbck.cxx | 90 +++++ sw/source/core/undo/unbkmk.cxx | 32 ++ sw/source/core/undo/undobj.cxx | 3 sw/source/core/unocore/unobkm.cxx | 23 + sw/source/ui/config/optcomp.cxx | 2 sw/source/ui/fldui/DropDownFormFieldDialog.cxx | 19 - sw/source/uibase/docvw/edtwin.cxx | 21 - sw/source/uibase/shells/textfld.cxx | 40 ++ sw/source/uibase/shells/textsh1.cxx | 12 sw/source/uibase/uiview/view.cxx | 3 sw/source/uibase/uiview/viewling.cxx | 110 ------- sw/uiconfig/swriter/ui/optcompatpage.ui | 2 writerfilter/source/dmapper/FormControlHelper.cxx | 17 - 40 files changed, 1308 insertions(+), 164 deletions(-)
New commits: commit bbfb5805d080c108c60b668a1315eb6472114635 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Mar 6 15:48:05 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Add some extra comments for the new code. Reviewed-on: https://gerrit.libreoffice.org/68965 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit d47f037a220636d70297bc098ed08e0bcb763aa9) Change-Id: I4b70eb2164032623a12f9e703c660eca1d6768ec diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx b/sw/qa/extras/globalfilter/globalfilter.cxx index 68a97df6c3bc..fd55bc0dc747 100644 --- a/sw/qa/extras/globalfilter/globalfilter.cxx +++ b/sw/qa/extras/globalfilter/globalfilter.cxx @@ -1225,7 +1225,7 @@ void Test::testDropDownFormField() CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(0), vListEntries.getLength()); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(-1), nSelection); } - else + else // The second one has list and also a selected item { CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(4), vListEntries.getLength()); CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(1), nSelection); diff --git a/sw/source/core/inc/UndoBookmark.hxx b/sw/source/core/inc/UndoBookmark.hxx index 7b9dd4fc68e5..3e2017d0721d 100644 --- a/sw/source/core/inc/UndoBookmark.hxx +++ b/sw/source/core/inc/UndoBookmark.hxx @@ -98,6 +98,7 @@ private: virtual void RedoImpl( ::sw::UndoRedoContext & ) override; }; +/// Handling undo / redo of checkbox and drop-down form field insertion class SwUndoInsNoTextFieldmark : public SwUndo { private: @@ -110,6 +111,7 @@ public: virtual void RedoImpl( ::sw::UndoRedoContext & ) override; }; +/// Handling undo / redo of text form field insertion class SwUndoInsTextFieldmark : public SwUndo { private: diff --git a/sw/source/core/inc/rolbck.hxx b/sw/source/core/inc/rolbck.hxx index 3fde226b7acf..2feec7e6d973 100644 --- a/sw/source/core/inc/rolbck.hxx +++ b/sw/source/core/inc/rolbck.hxx @@ -262,6 +262,8 @@ class SwHistoryBookmark : public SwHistoryHint std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndo; }; +/// History object containing all information used during undo / redo +/// of checkbox and drop-down form field insertion. class SwHistoryNoTextFieldmark : public SwHistoryHint { public: @@ -275,6 +277,8 @@ class SwHistoryNoTextFieldmark : public SwHistoryHint const sal_Int32 m_nContent; }; +/// History object containing all information used during undo / redo +/// of text form field insertion. class SwHistoryTextFieldmark : public SwHistoryHint { public: commit 2d95079d3c469eddeb88b997ccbef11c844fd582 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Jun 19 19:22:06 2019 +0200 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Test insertion of form fields and undo / redo of this insertion. Reviewed-on: https://gerrit.libreoffice.org/68966 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit 695f6746b555a7b74e84c466469c28030be99e73) Change-Id: I526faceab8eb1ce2f16d41ab1bed8cfb1bfcca24 Reviewed-on: https://gerrit.libreoffice.org/69199 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx index a88bc96b5c4d..122efa846efe 100644 --- a/sw/qa/extras/uiwriter/uiwriter2.cxx +++ b/sw/qa/extras/uiwriter/uiwriter2.cxx @@ -34,6 +34,9 @@ #include <anchoredobject.hxx> #include <swtypes.hxx> #include <vcl/scheduler.hxx> +#include <fmtornt.hxx> +#include <xmloff/odffields.hxx> +#include <com/sun/star/frame/DispatchHelper.hpp> namespace { @@ -66,6 +69,10 @@ public: void testUnfloatButton(); void testUnfloatButtonReadOnlyMode(); void testUnfloating(); + void testTextFormFieldInsertion(); + void testCheckboxFormFieldInsertion(); + void testDropDownFormFieldInsertion(); + void testMixedFormFieldInsertion(); CPPUNIT_TEST_SUITE(SwUiWriterTest2); CPPUNIT_TEST(testRedlineMoveInsertInDelete); @@ -89,6 +96,10 @@ public: CPPUNIT_TEST(testUnfloatButton); CPPUNIT_TEST(testUnfloatButtonReadOnlyMode); CPPUNIT_TEST(testUnfloating); + CPPUNIT_TEST(testTextFormFieldInsertion); + CPPUNIT_TEST(testCheckboxFormFieldInsertion); + CPPUNIT_TEST(testDropDownFormFieldInsertion); + CPPUNIT_TEST(testMixedFormFieldInsertion); CPPUNIT_TEST_SUITE_END(); private: @@ -949,6 +960,150 @@ void SwUiWriterTest2::testUnfloating() } } +void SwUiWriterTest2::testTextFormFieldInsertion() +{ + SwDoc* pDoc = createDoc(); + CPPUNIT_ASSERT(pDoc); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + CPPUNIT_ASSERT(pMarkAccess); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + + // Insert a text form field + lcl_dispatchCommand(mxComponent, ".uno:TextFormField", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + + // Check whether the fieldmark is created + auto aIter = pMarkAccess->getAllMarksBegin(); + CPPUNIT_ASSERT(aIter != pMarkAccess->getAllMarksEnd()); + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + CPPUNIT_ASSERT(pFieldmark); + CPPUNIT_ASSERT_EQUAL(OUString(ODF_FORMTEXT), pFieldmark->GetFieldname()); + + // The text form field has the placholder text in it + uno::Reference<text::XTextRange> xPara = getParagraph(1); + sal_Unicode vEnSpaces[5] = { 8194, 8194, 8194, 8194, 8194 }; + CPPUNIT_ASSERT_EQUAL(OUString(vEnSpaces, 5), xPara->getString()); + + // Undo insertion + lcl_dispatchCommand(mxComponent, ".uno:Undo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + xPara.set(getParagraph(1)); + CPPUNIT_ASSERT(xPara->getString().isEmpty()); + + // Redo insertion + lcl_dispatchCommand(mxComponent, ".uno:Redo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + xPara.set(getParagraph(1)); + CPPUNIT_ASSERT_EQUAL(OUString(vEnSpaces, 5), xPara->getString()); +} + +void SwUiWriterTest2::testCheckboxFormFieldInsertion() +{ + SwDoc* pDoc = createDoc(); + CPPUNIT_ASSERT(pDoc); + + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + CPPUNIT_ASSERT(pMarkAccess); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + + // Insert a checkbox form field + lcl_dispatchCommand(mxComponent, ".uno:CheckBoxFormField", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + + // Check whether the fieldmark is created + auto aIter = pMarkAccess->getAllMarksBegin(); + CPPUNIT_ASSERT(aIter != pMarkAccess->getAllMarksEnd()); + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + CPPUNIT_ASSERT(pFieldmark); + CPPUNIT_ASSERT_EQUAL(OUString(ODF_FORMCHECKBOX), pFieldmark->GetFieldname()); + // The checkbox is not checked by default + ::sw::mark::ICheckboxFieldmark* pCheckBox + = dynamic_cast<::sw::mark::ICheckboxFieldmark*>(pFieldmark); + CPPUNIT_ASSERT(pCheckBox); + CPPUNIT_ASSERT(!pCheckBox->IsChecked()); + + // Undo insertion + lcl_dispatchCommand(mxComponent, ".uno:Undo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + + // Redo insertion + lcl_dispatchCommand(mxComponent, ".uno:Redo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + aIter = pMarkAccess->getAllMarksBegin(); + CPPUNIT_ASSERT(aIter != pMarkAccess->getAllMarksEnd()); + pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + CPPUNIT_ASSERT(pFieldmark); + CPPUNIT_ASSERT_EQUAL(OUString(ODF_FORMCHECKBOX), pFieldmark->GetFieldname()); +} + +void SwUiWriterTest2::testDropDownFormFieldInsertion() +{ + SwDoc* pDoc = createDoc(); + CPPUNIT_ASSERT(pDoc); + + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + CPPUNIT_ASSERT(pMarkAccess); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + + // Insert a drop-down form field + lcl_dispatchCommand(mxComponent, ".uno:DropDownFormField", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + + // Check whether the fieldmark is created + auto aIter = pMarkAccess->getAllMarksBegin(); + CPPUNIT_ASSERT(aIter != pMarkAccess->getAllMarksEnd()); + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + CPPUNIT_ASSERT(pFieldmark); + CPPUNIT_ASSERT_EQUAL(OUString(ODF_FORMDROPDOWN), pFieldmark->GetFieldname()); + // Check drop down field's parameters. By default these params are not set + const sw::mark::IFieldmark::parameter_map_t* const pParameters = pFieldmark->GetParameters(); + auto pListEntries = pParameters->find(ODF_FORMDROPDOWN_LISTENTRY); + CPPUNIT_ASSERT(bool(pListEntries == pParameters->end())); + auto pResult = pParameters->find(ODF_FORMDROPDOWN_RESULT); + CPPUNIT_ASSERT(bool(pResult == pParameters->end())); + + // Undo insertion + lcl_dispatchCommand(mxComponent, ".uno:Undo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + + // Redo insertion + lcl_dispatchCommand(mxComponent, ".uno:Redo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount()); + aIter = pMarkAccess->getAllMarksBegin(); + CPPUNIT_ASSERT(aIter != pMarkAccess->getAllMarksEnd()); + pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + CPPUNIT_ASSERT(pFieldmark); + CPPUNIT_ASSERT_EQUAL(OUString(ODF_FORMDROPDOWN), pFieldmark->GetFieldname()); +} + +void SwUiWriterTest2::testMixedFormFieldInsertion() +{ + SwDoc* pDoc = createDoc(); + CPPUNIT_ASSERT(pDoc); + + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + CPPUNIT_ASSERT(pMarkAccess); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + + // Insert fields + lcl_dispatchCommand(mxComponent, ".uno:TextFormField", {}); + lcl_dispatchCommand(mxComponent, ".uno:CheckBoxFormField", {}); + lcl_dispatchCommand(mxComponent, ".uno:DropDownFormField", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pMarkAccess->getAllMarksCount()); + + // Undo insertion + lcl_dispatchCommand(mxComponent, ".uno:Undo", {}); + lcl_dispatchCommand(mxComponent, ".uno:Undo", {}); + lcl_dispatchCommand(mxComponent, ".uno:Undo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pMarkAccess->getAllMarksCount()); + + // Redo insertion + lcl_dispatchCommand(mxComponent, ".uno:Redo", {}); + lcl_dispatchCommand(mxComponent, ".uno:Redo", {}); + lcl_dispatchCommand(mxComponent, ".uno:Redo", {}); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), pMarkAccess->getAllMarksCount()); +} + CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest2); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 0c43160596ce978e085a8a94bfd9e6737f8db29f Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Jun 19 19:19:07 2019 +0200 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Test legacy form field import / export for the supported formats. Reviewed-on: https://gerrit.libreoffice.org/68964 Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> Tested-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit 2a378bad84c3125c032f0c11f1cbcff23e24c7cb) Change-Id: Idbb80d097b21386e7d2673290a318d98b92125d5 Reviewed-on: https://gerrit.libreoffice.org/69198 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/sw/qa/extras/globalfilter/data/checkbox_form_field.odt b/sw/qa/extras/globalfilter/data/checkbox_form_field.odt new file mode 100644 index 000000000000..14c931ed37da Binary files /dev/null and b/sw/qa/extras/globalfilter/data/checkbox_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/data/dropdown_form_field.odt b/sw/qa/extras/globalfilter/data/dropdown_form_field.odt new file mode 100644 index 000000000000..caaa66acda8f Binary files /dev/null and b/sw/qa/extras/globalfilter/data/dropdown_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/data/text_form_field.odt b/sw/qa/extras/globalfilter/data/text_form_field.odt new file mode 100644 index 000000000000..96af26f7708f Binary files /dev/null and b/sw/qa/extras/globalfilter/data/text_form_field.odt differ diff --git a/sw/qa/extras/globalfilter/globalfilter.cxx b/sw/qa/extras/globalfilter/globalfilter.cxx index f9a6a60df823..68a97df6c3bc 100644 --- a/sw/qa/extras/globalfilter/globalfilter.cxx +++ b/sw/qa/extras/globalfilter/globalfilter.cxx @@ -25,6 +25,10 @@ #include <ndindex.hxx> #include <pam.hxx> #include <unotools/fltrcfg.hxx> +#include <xmloff/odffields.hxx> +#include <IDocumentMarkAccess.hxx> +#include <IMark.hxx> +#include <bookmrk.hxx> class Test : public SwModelTestBase { @@ -45,6 +49,9 @@ public: #endif void testRedlineFlags(); void testBulletAsImage(); + void testTextFormField(); + void testCheckBoxFormField(); + void testDropDownFormField(); CPPUNIT_TEST_SUITE(Test); CPPUNIT_TEST(testEmbeddedGraphicRoundtrip); @@ -60,6 +67,9 @@ public: #endif CPPUNIT_TEST(testRedlineFlags); CPPUNIT_TEST(testBulletAsImage); + CPPUNIT_TEST(testTextFormField); + CPPUNIT_TEST(testCheckBoxFormField); + CPPUNIT_TEST(testDropDownFormField); CPPUNIT_TEST_SUITE_END(); }; @@ -1023,6 +1033,213 @@ void Test::testBulletAsImage() } } +void Test::testTextFormField() +{ + const OUString aFilterNames[] = { + "writer8", + "MS Word 97", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + if (mxComponent.is()) + mxComponent->dispose(); + mxComponent = loadFromDesktop(m_directories.getURLFromSrc("/sw/qa/extras/globalfilter/data/text_form_field.odt"), "com.sun.star.text.TextDocument"); + + const OString sFailedMessage = OString("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= rFilterName; + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + uno::Reference< lang::XComponent > xComponent(xStorable, uno::UNO_QUERY); + xComponent->dispose(); + mxComponent = loadFromDesktop(aTempFile.GetURL(), "com.sun.star.text.TextDocument"); + + // Check the document after round trip + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + // We have two text form fields + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(2), pMarkAccess->getAllMarksCount()); + + // Check whether all fieldmarks are text form fields + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(ODF_FORMTEXT), pFieldmark->GetFieldname()); + } + + // In the first paragraph we have an empty text form field with the placeholder spaces + const uno::Reference< text::XTextRange > xPara = getParagraph(1); + sal_Unicode vEnSpaces[5] = {8194, 8194, 8194, 8194, 8194}; + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(vEnSpaces, 5), xPara->getString()); + + // In the second paragraph we have a set text + const uno::Reference< text::XTextRange > xPara2 = getParagraph(2); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("xxxxx"), xPara2->getString()); + } +} + +void Test::testCheckBoxFormField() +{ + const OUString aFilterNames[] = { + "writer8", + "MS Word 97", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + if (mxComponent.is()) + mxComponent->dispose(); + mxComponent = loadFromDesktop(m_directories.getURLFromSrc("/sw/qa/extras/globalfilter/data/checkbox_form_field.odt"), "com.sun.star.text.TextDocument"); + + const OString sFailedMessage = OString("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= rFilterName; + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + uno::Reference< lang::XComponent > xComponent(xStorable, uno::UNO_QUERY); + xComponent->dispose(); + mxComponent = loadFromDesktop(aTempFile.GetURL(), "com.sun.star.text.TextDocument"); + + // Check the document after round trip + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + // We have two check box form fields + if(rFilterName == "Office Open XML Text") + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(4), pMarkAccess->getAllMarksCount()); + else + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(2), pMarkAccess->getAllMarksCount()); + + int nIndex = 0; + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + + if(rFilterName == "Office Open XML Text") // OOXML import also generates bookmarks + { + if(!pFieldmark) + continue; + } + + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(ODF_FORMCHECKBOX), pFieldmark->GetFieldname()); + ::sw::mark::ICheckboxFieldmark* pCheckBox = dynamic_cast< ::sw::mark::ICheckboxFieldmark* >(pFieldmark); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pCheckBox); + + // The first one is unchecked, the other one is checked + if(nIndex == 0) + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), !pCheckBox->IsChecked()); + else + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pCheckBox->IsChecked()); + ++nIndex; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(2), nIndex); + } +} + +void Test::testDropDownFormField() +{ + const OUString aFilterNames[] = { + "writer8", + "MS Word 97", + "Office Open XML Text", + }; + + for (const OUString& rFilterName : aFilterNames) + { + if (mxComponent.is()) + mxComponent->dispose(); + mxComponent = loadFromDesktop(m_directories.getURLFromSrc("/sw/qa/extras/globalfilter/data/dropdown_form_field.odt"), "com.sun.star.text.TextDocument"); + + const OString sFailedMessage = OString("Failed on filter: ") + rFilterName.toUtf8(); + + // Export the document and import again for a check + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= rFilterName; + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + xStorable->storeToURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + uno::Reference< lang::XComponent > xComponent(xStorable, uno::UNO_QUERY); + xComponent->dispose(); + mxComponent = loadFromDesktop(aTempFile.GetURL(), "com.sun.star.text.TextDocument"); + + // Check the document after round trip + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get()); + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pTextDoc); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(2), pMarkAccess->getAllMarksCount()); + + int nIndex = 0; + for(auto aIter = pMarkAccess->getAllMarksBegin(); aIter != pMarkAccess->getAllMarksEnd(); ++aIter) + { + ::sw::mark::IFieldmark* pFieldmark = dynamic_cast<::sw::mark::IFieldmark*>(aIter->get()); + + if(!pFieldmark) + continue; + + CPPUNIT_ASSERT_MESSAGE(sFailedMessage.getStr(), pFieldmark); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString(ODF_FORMDROPDOWN), pFieldmark->GetFieldname()); + + // Check drop down field's parameters. + const sw::mark::IFieldmark::parameter_map_t* const pParameters = pFieldmark->GetParameters(); + css::uno::Sequence<OUString> vListEntries; + sal_Int32 nSelection = -1; + auto pListEntries = pParameters->find(ODF_FORMDROPDOWN_LISTENTRY); + if (pListEntries != pParameters->end()) + { + pListEntries->second >>= vListEntries; + + if(vListEntries.getLength()) + { + auto pResult = pParameters->find(ODF_FORMDROPDOWN_RESULT); + if (pResult != pParameters->end()) + { + pResult->second >>= nSelection; + } + } + } + + // The first one is empty + if(nIndex == 0) + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(0), vListEntries.getLength()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(-1), nSelection); + } + else + { + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(4), vListEntries.getLength()); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), sal_Int32(1), nSelection); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("1000"), vListEntries[0]); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("2000"), vListEntries[1]); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("3000"), vListEntries[2]); + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), OUString("4000"), vListEntries[3]); + } + ++nIndex; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage.getStr(), int(2), nIndex); + } +} + CPPUNIT_TEST_SUITE_REGISTRATION(Test); CPPUNIT_PLUGIN_IMPLEMENT(); commit e69e2851105287a1529ed366a902428aad93db2a Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Sun Mar 10 09:45:56 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Fix handling of drop-down form field after DOC import In the properties dialog, code expected that the ODF_FORMDROPDOWN_RESULT is not set in case of an empty list. This caused a crash. The field popup window code expected that the list is not specified when it is empty, but DOC import code sets ODF_FORMDROPDOWN_LISTENTRY even if the list is empty. Change-Id: If4c86fc5a08cdc578150afaa42ad7e86bdba9150 Reviewed-on: https://gerrit.libreoffice.org/68963 Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> Tested-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit aa3b3ee8c2aad6af69f0710c7531ef2cf9fb1fc1) diff --git a/sw/source/core/crsr/DropDownFormFieldButton.cxx b/sw/source/core/crsr/DropDownFormFieldButton.cxx index a4614da8932e..bef4c873dace 100644 --- a/sw/source/core/crsr/DropDownFormFieldButton.cxx +++ b/sw/source/core/crsr/DropDownFormFieldButton.cxx @@ -53,14 +53,15 @@ SwFieldDialog::SwFieldDialog(SwEditWin* parent, sw::mark::IFieldmark* fieldBM, l OUString sListKey = ODF_FORMDROPDOWN_LISTENTRY; sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(sListKey); + css::uno::Sequence<OUString> vListEntries; if (pListEntries != pParameters->end()) { - css::uno::Sequence<OUString> vListEntries; pListEntries->second >>= vListEntries; for (OUString const& i : vListEntries) aListBox->InsertEntry(i); } - else + + if (vListEntries.getLength() == 0) { aListBox->InsertEntry(SwResId(STR_DROP_DOWN_EMPTY_LIST)); } diff --git a/sw/source/ui/fldui/DropDownFormFieldDialog.cxx b/sw/source/ui/fldui/DropDownFormFieldDialog.cxx index e52907fd6c74..dd187704aa7a 100644 --- a/sw/source/ui/fldui/DropDownFormFieldDialog.cxx +++ b/sw/source/ui/fldui/DropDownFormFieldDialog.cxx @@ -119,7 +119,8 @@ void DropDownFormFieldDialog::InitControls() { sal_Int32 nSelection = -1; pResult->second >>= nSelection; - m_xListItemsTreeView->select_text(vListEntries[nSelection]); + if (vListEntries.getLength() > nSelection) + m_xListItemsTreeView->select_text(vListEntries[nSelection]); } } } commit 324e54de0a00f90c2d868c714d69120a83d7765d Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Sat Mar 2 10:22:54 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Open Control Properties dialog by double click for drop-down field Change-Id: I66c0a7bad63d929ae346afe9d328d87dfa2c24ae Reviewed-on: https://gerrit.libreoffice.org/68962 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/69196 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 3d2e52058ce7..cb6b59b8736d 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -3348,6 +3348,21 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt) // table. rSh.SelTableBox(); } + + SwContentAtPos aContentAtPos(IsAttrAtPos::FormControl); + if( rSh.GetContentAtPos( aDocPos, aContentAtPos ) && + aContentAtPos.aFnd.pFieldmark != nullptr) + { + IFieldmark *pFieldBM = const_cast< IFieldmark* > ( aContentAtPos.aFnd.pFieldmark ); + if ( pFieldBM->GetFieldname( ) == ODF_FORMDROPDOWN ) + { + RstMBDownFlags(); + rSh.getIDocumentMarkAccess()->ClearFieldActivation(); + GetView().GetViewFrame()->GetBindings().Execute(SID_FM_CTL_PROPERTIES); + return; + } + } + g_bHoldSelection = true; return; } commit e87c8b4ce567492c71affdfdaf49426faa69d2a5 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Jun 19 19:13:37 2019 +0200 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Add a drop-down button for drop-down form field * Introduce a editing frame with a button for drop-down form field. ** The frame is mouse transparent. ** Pushing the button opens the popup window with the items of the field. * The button is visible when the cursor is inside the field. Reviewed-on: https://gerrit.libreoffice.org/68961 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit 10be5b6ce972dff517f3ceed41cab04d3e051f57) Change-Id: I5c7db138d14380899fee046c95a5afe14cfea213 diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index 6557c45434d1..9d2dbe51e0a4 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -628,7 +628,7 @@ protected: SAL_DLLPRIVATE void ImplInvalidate( const vcl::Region* rRegion, InvalidateFlags nFlags ); - SAL_DLLPRIVATE WindowHitTest ImplHitTest( const Point& rFramePos ); + virtual WindowHitTest ImplHitTest( const Point& rFramePos ); SAL_DLLPRIVATE void ImplSetMouseTransparent( bool bTransparent ); diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index 2751a24a4b00..b70451c18df9 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -150,6 +150,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\ sw/source/core/crsr/crsrsh \ sw/source/core/crsr/crstrvl \ sw/source/core/crsr/crstrvl1 \ + sw/source/core/crsr/DropDownFormFieldButton \ sw/source/core/crsr/findattr \ sw/source/core/crsr/findcoll \ sw/source/core/crsr/findfmt \ diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx index cbd523c012b1..d7111112612f 100644 --- a/sw/inc/IDocumentMarkAccess.hxx +++ b/sw/inc/IDocumentMarkAccess.hxx @@ -27,6 +27,7 @@ class SwPaM; struct SwPosition; class SwTextNode; +class SwCursorShell; namespace sw { namespace mark { class SaveBookmark; // FIXME: Ugly: SaveBookmark is a core-internal class, and should not be used in the interface @@ -258,6 +259,9 @@ class IDocumentMarkAccess virtual void deleteFieldmarkAt(const SwPosition& rPos) = 0; virtual ::sw::mark::IFieldmark* changeNonTextFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType) = 0; + virtual void NotifyCursorUpdate(const SwCursorShell& rCursorShell) = 0; + virtual void ClearFieldActivation() = 0; + // Annotation Marks virtual const_iterator_t getAnnotationMarksBegin() const = 0; virtual const_iterator_t getAnnotationMarksEnd() const = 0; diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc index da13d2fb16e6..b16f0051d182 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -1332,6 +1332,9 @@ #define STR_MENU_UP NC_("STR_MENU_UP", "~Upwards") #define STR_MENU_DOWN NC_("STR_MENU_DOWN", "Do~wnwards") + +#define STR_DROP_DOWN_EMPTY_LIST NC_("STR_DROP_DOWN_EMPTY_LIST", "No Item specified") + /*-------------------------------------------------------------------- Description: Classification strings --------------------------------------------------------------------*/ diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx index fe33f94e6dd9..94e2cc86e81e 100644 --- a/sw/inc/view.hxx +++ b/sw/inc/view.hxx @@ -208,7 +208,6 @@ class SW_DLLPUBLIC SwView: public SfxViewShell std::unique_ptr<SwPostItMgr> m_pPostItMgr; SelectionType m_nSelectionType; - VclPtr<FloatingWindow> m_pFieldPopup; sal_uInt16 m_nPageCnt; // current draw mode @@ -265,8 +264,6 @@ class SW_DLLPUBLIC SwView: public SfxViewShell DECL_DLLPRIVATE_LINK( TimeoutHdl, Timer*, void ); - DECL_DLLPRIVATE_LINK( FieldPopupModeEndHdl, FloatingWindow*, void ); - inline long GetXScroll() const; inline long GetYScroll() const; SAL_DLLPRIVATE Point AlignToPixel(const Point& rPt) const; @@ -423,7 +420,6 @@ public: void SpellError(LanguageType eLang); bool ExecSpellPopup( const Point& rPt ); - void ExecFieldPopup( const Point& rPt, sw::mark::IFieldmark *fieldBM ); void ExecSmartTagPopup( const Point& rPt ); DECL_LINK( OnlineSpellCallback, SpellCallbackInfo&, void ); diff --git a/sw/source/core/crsr/DropDownFormFieldButton.cxx b/sw/source/core/crsr/DropDownFormFieldButton.cxx new file mode 100644 index 000000000000..a4614da8932e --- /dev/null +++ b/sw/source/core/crsr/DropDownFormFieldButton.cxx @@ -0,0 +1,255 @@ +/* -*- 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 <DropDownFormFieldButton.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <edtwin.hxx> +#include <basegfx/color/bcolortools.hxx> +#include <viewopt.hxx> +#include <bookmrk.hxx> +#include <vcl/floatwin.hxx> +#include <vcl/event.hxx> +#include <vcl/lstbox.hxx> +#include <xmloff/odffields.hxx> +#include <IMark.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <strings.hrc> + +/** + * Popup dialog for drop-down form field showing the list items of the field. + * The user can select the item using this popup while filling in a form. + */ +class SwFieldDialog : public FloatingWindow +{ +private: + VclPtr<ListBox> aListBox; + sw::mark::IFieldmark* pFieldmark; + + DECL_LINK(MyListBoxHandler, ListBox&, void); + +public: + SwFieldDialog(SwEditWin* parent, sw::mark::IFieldmark* fieldBM, long nMinListWidth); + virtual ~SwFieldDialog() override; + virtual void dispose() override; +}; + +SwFieldDialog::SwFieldDialog(SwEditWin* parent, sw::mark::IFieldmark* fieldBM, long nMinListWidth) + : FloatingWindow(parent, WB_BORDER | WB_SYSTEMWINDOW) + , aListBox(VclPtr<ListBox>::Create(this)) + , pFieldmark(fieldBM) +{ + if (fieldBM != nullptr) + { + const sw::mark::IFieldmark::parameter_map_t* const pParameters = fieldBM->GetParameters(); + + OUString sListKey = ODF_FORMDROPDOWN_LISTENTRY; + sw::mark::IFieldmark::parameter_map_t::const_iterator pListEntries + = pParameters->find(sListKey); + if (pListEntries != pParameters->end()) + { + css::uno::Sequence<OUString> vListEntries; + pListEntries->second >>= vListEntries; + for (OUString const& i : vListEntries) + aListBox->InsertEntry(i); + } + else + { + aListBox->InsertEntry(SwResId(STR_DROP_DOWN_EMPTY_LIST)); + } + + // Select the current one + OUString sResultKey = ODF_FORMDROPDOWN_RESULT; + sw::mark::IFieldmark::parameter_map_t::const_iterator pResult + = pParameters->find(sResultKey); + if (pResult != pParameters->end()) + { + sal_Int32 nSelection = -1; + pResult->second >>= nSelection; + aListBox->SelectEntryPos(nSelection); + } + } + + Size lbSize(aListBox->GetOptimalSize()); + lbSize.AdjustWidth(50); + lbSize.AdjustHeight(20); + lbSize.setWidth(std::max(lbSize.Width(), nMinListWidth)); + aListBox->SetSizePixel(lbSize); + aListBox->SetSelectHdl(LINK(this, SwFieldDialog, MyListBoxHandler)); + aListBox->Show(); + + SetSizePixel(lbSize); +} + +SwFieldDialog::~SwFieldDialog() { disposeOnce(); } + +void SwFieldDialog::dispose() +{ + aListBox.disposeAndClear(); + FloatingWindow::dispose(); +} + +IMPL_LINK(SwFieldDialog, MyListBoxHandler, ListBox&, rBox, void) +{ + if (!rBox.IsTravelSelect()) + { + OUString sSelection = rBox.GetSelectedEntry(); + if (sSelection == SwResId(STR_DROP_DOWN_EMPTY_LIST)) + { + EndPopupMode(); + return; + } + + sal_Int32 nSelection = rBox.GetSelectedEntryPos(); + if (nSelection >= 0) + { + OUString sKey = ODF_FORMDROPDOWN_RESULT; + (*pFieldmark->GetParameters())[sKey] <<= nSelection; + pFieldmark->Invalidate(); + SwView& rView = static_cast<SwEditWin*>(GetParent())->GetView(); + rView.GetDocShell()->SetModified(); + } + + EndPopupMode(); + } +} + +DropDownFormFieldButton::DropDownFormFieldButton(SwEditWin* pEditWin, + sw::mark::DropDownFieldmark& rFieldmark) + : MenuButton(pEditWin, WB_DIALOGCONTROL) + , m_rFieldmark(rFieldmark) +{ + assert(GetParent()); + assert(dynamic_cast<SwEditWin*>(GetParent())); +} + +DropDownFormFieldButton::~DropDownFormFieldButton() { disposeOnce(); } + +void DropDownFormFieldButton::dispose() +{ + m_pFieldPopup.disposeAndClear(); + MenuButton::dispose(); +} + +void DropDownFormFieldButton::CalcPosAndSize(const SwRect& rPortionPaintArea) +{ + assert(GetParent()); + + Point aBoxPos = GetParent()->LogicToPixel(rPortionPaintArea.Pos()); + Size aBoxSize = GetParent()->LogicToPixel(rPortionPaintArea.SSize()); + + // First calculate the size of the frame around the field + int nPadding = aBoxSize.Height() / 4; + aBoxPos.AdjustX(-nPadding); + aBoxPos.AdjustY(-nPadding); + aBoxSize.AdjustWidth(2 * nPadding); + aBoxSize.AdjustHeight(2 * nPadding); + + m_aFieldFramePixel = tools::Rectangle(aBoxPos, aBoxSize); + + // Then extend the size with the button area + aBoxSize.AdjustWidth(GetParent()->LogicToPixel(rPortionPaintArea.SSize()).Height()); + + SetPosSizePixel(aBoxPos, aBoxSize); +} + +void DropDownFormFieldButton::MouseButtonUp(const MouseEvent&) +{ + assert(GetParent()); + + Point aPixPos = GetPosPixel(); + aPixPos.AdjustY(GetSizePixel().Height()); + + m_pFieldPopup = VclPtr<SwFieldDialog>::Create(static_cast<SwEditWin*>(GetParent()), + &m_rFieldmark, GetSizePixel().Width()); + m_pFieldPopup->SetPopupModeEndHdl(LINK(this, DropDownFormFieldButton, FieldPopupModeEndHdl)); + + tools::Rectangle aRect(GetParent()->OutputToScreenPixel(aPixPos), Size(0, 0)); + m_pFieldPopup->StartPopupMode(aRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus); + Invalidate(); +} + +IMPL_LINK_NOARG(DropDownFormFieldButton, FieldPopupModeEndHdl, FloatingWindow*, void) +{ + m_pFieldPopup.disposeAndClear(); + m_rFieldmark.Invalidate(); + // Hide the button here and make it visible later, to make transparent background work with SAL_USE_VCLPLUGIN=gen + Show(false); + Invalidate(); +} + +static basegfx::BColor lcl_GetFillColor(const basegfx::BColor& rLineColor, double aLuminance) +{ + basegfx::BColor aHslLine = basegfx::utils::rgb2hsl(rLineColor); + aHslLine.setZ(aLuminance); + return basegfx::utils::hsl2rgb(aHslLine); +} + +void DropDownFormFieldButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + SetMapMode(MapMode(MapUnit::MapPixel)); + + //const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); + Color aLineColor = COL_BLACK; + Color aFillColor + = Color(lcl_GetFillColor(aLineColor.getBColor(), (m_pFieldPopup ? 0.5 : 0.75))); + + // Draw the frame around the field + // GTK3 backend cuts down the frame's top and left border, to avoid that add a padding around the frame + int nPadding = 1; + Point aPos(nPadding, nPadding); + Size aSize(m_aFieldFramePixel.GetSize().Width() - nPadding, + m_aFieldFramePixel.GetSize().Height() - 2 * nPadding); + const tools::Rectangle aFrameRect(tools::Rectangle(aPos, aSize)); + rRenderContext.SetLineColor(aLineColor); + rRenderContext.SetFillColor(COL_TRANSPARENT); + rRenderContext.DrawRect(aFrameRect); + + // Draw the button next to the frame + Point aButtonPos(aFrameRect.TopLeft()); + aButtonPos.AdjustX(aFrameRect.GetSize().getWidth() - 1); + Size aButtonSize(aFrameRect.GetSize()); + aButtonSize.setWidth(GetSizePixel().getWidth() - aFrameRect.getWidth() - nPadding); + const tools::Rectangle aButtonRect(tools::Rectangle(aButtonPos, aButtonSize)); + + // Background & border + rRenderContext.SetLineColor(aLineColor); + rRenderContext.SetFillColor(aFillColor); + rRenderContext.DrawRect(aButtonRect); + + // the arrowhead + rRenderContext.SetLineColor(aLineColor); + rRenderContext.SetFillColor(aLineColor); + + Point aCenter(aButtonPos.X() + (aButtonSize.Width() / 2), + aButtonPos.Y() + (aButtonSize.Height() / 2)); + Size aArrowSize(aButtonSize.Width() / 4, aButtonSize.Height() / 10); + + tools::Polygon aPoly(3); + aPoly.SetPoint(Point(aCenter.X() - aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 0); + aPoly.SetPoint(Point(aCenter.X() + aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 1); + aPoly.SetPoint(Point(aCenter.X(), aCenter.Y() + aArrowSize.Height()), 2); + rRenderContext.DrawPolygon(aPoly); +} + +WindowHitTest DropDownFormFieldButton::ImplHitTest(const Point& rFramePos) +{ + // We need to check whether the position hits the button (the frame should be mouse transparent) + WindowHitTest aResult = MenuButton::ImplHitTest(rFramePos); + if (aResult != WindowHitTest::Inside) + return aResult; + else + { + return rFramePos.X() >= m_aFieldFramePixel.Right() ? WindowHitTest::Inside + : WindowHitTest::Transparent; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/core/crsr/bookmrk.cxx b/sw/source/core/crsr/bookmrk.cxx index 259168f49440..f3cd8ddf9d91 100644 --- a/sw/source/core/crsr/bookmrk.cxx +++ b/sw/source/core/crsr/bookmrk.cxx @@ -37,6 +37,7 @@ #include <comphelper/random.hxx> #include <comphelper/anytostring.hxx> #include <sal/log.hxx> +#include <edtwin.hxx> using namespace ::sw::mark; using namespace ::com::sun::star; @@ -482,11 +483,13 @@ namespace sw { namespace mark DropDownFieldmark::DropDownFieldmark(const SwPaM& rPaM) : Fieldmark(rPaM) + , m_pButton(nullptr) { } DropDownFieldmark::~DropDownFieldmark() { + m_pButton.disposeAndClear(); } void DropDownFieldmark::InitDoc(SwDoc* const io_pDoc, sw::mark::InsertMode const eMode) @@ -512,6 +515,44 @@ namespace sw { namespace mark lcl_RemoveFieldMarks(this, pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT); } + + void DropDownFieldmark::SetPortionPaintArea(const SwRect& rPortionPaintArea) + { + if(m_aPortionPaintArea == rPortionPaintArea && + m_pButton && m_pButton->IsVisible()) + return; + + m_aPortionPaintArea = rPortionPaintArea; + if(m_pButton) + { + m_pButton->Show(); + m_pButton->CalcPosAndSize(m_aPortionPaintArea); + m_pButton->Invalidate(); + } + } + + void DropDownFieldmark::ShowButton(SwEditWin* pEditWin) + { + if(pEditWin) + { + if(!m_pButton) + m_pButton = VclPtr<DropDownFormFieldButton>::Create(pEditWin, *this); + m_pButton->CalcPosAndSize(m_aPortionPaintArea); + m_pButton->Show(); + } + } + + void DropDownFieldmark::HideButton() + { + if(m_pButton) + m_pButton->Show(false); + } + + void DropDownFieldmark::RemoveButton() + { + if(m_pButton) + m_pButton.disposeAndClear(); + } }} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 607c6f42ca92..696eb41c73c8 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -2007,6 +2007,8 @@ void SwCursorShell::UpdateCursor( sal_uInt16 eFlags, bool bIdleEnd ) if( m_bSVCursorVis ) m_pVisibleCursor->Show(); // show again + + getIDocumentMarkAccess()->NotifyCursorUpdate(*this); } void SwCursorShell::RefreshBlockCursor() diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx index 222eeb846e8c..7068e81b5c91 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -55,6 +55,7 @@ #include <viscrs.hxx> #include <edimp.hxx> #include <tools/datetimeutils.hxx> +#include <view.hxx> using namespace ::sw::mark; @@ -373,6 +374,7 @@ namespace sw { namespace mark , m_vFieldmarks() , m_vAnnotationMarks() , m_pDoc(&rDoc) + , m_pLastActiveFieldmark(nullptr) { } ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM, @@ -960,6 +962,9 @@ namespace sw { namespace mark IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark); if ( ppFieldmark != m_vFieldmarks.end() ) { + if(m_pLastActiveFieldmark == ppFieldmark->get()) + ClearFieldActivation(); + m_vFieldmarks.erase(ppFieldmark); ret.reset(new LazyFieldmarkDeleter(*ppMark, m_pDoc)); } @@ -1036,6 +1041,7 @@ namespace sw { namespace mark void MarkManager::clearAllMarks() { + ClearFieldActivation(); m_vFieldmarks.clear(); m_vBookmarks.clear(); m_aMarkNamesSet.clear(); @@ -1123,10 +1129,61 @@ namespace sw { namespace mark SwPaM aPaM(pFieldmark->GetMarkPos()); // Remove the old fieldmark and create a new one with the new type - deleteFieldmarkAt(*aPaM.GetPoint()); - return makeNoTextFieldBookmark(aPaM, sName, rNewType); + if(aPaM.GetPoint()->nContent > 0) + { + --aPaM.GetPoint()->nContent; + SwPosition aNewPos (aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent); + deleteFieldmarkAt(aNewPos); + return makeNoTextFieldBookmark(aPaM, sName, rNewType); + } + return nullptr; + } + + void MarkManager::NotifyCursorUpdate(const SwCursorShell& rCursorShell) + { + SwView* pSwView = dynamic_cast<SwView *>(rCursorShell.GetSfxViewShell()); + if(!pSwView) + return; + + SwEditWin& rEditWin = pSwView->GetEditWin(); + SwPosition aPos(*rCursorShell.GetCursor()->GetPoint()); + IFieldmark* pFieldBM = getFieldmarkFor(aPos); + DropDownFieldmark* pNewActiveFieldmark = nullptr; + if ((!pFieldBM || pFieldBM->GetFieldname() != ODF_FORMDROPDOWN) + && aPos.nContent.GetIndex() > 0 ) + { + --aPos.nContent; + pFieldBM = getFieldmarkFor(aPos); + } + + if ( pFieldBM && pFieldBM->GetFieldname() == ODF_FORMDROPDOWN ) + { + if (m_pLastActiveFieldmark != pFieldBM) + { + DropDownFieldmark* pDropDownFm = dynamic_cast<DropDownFieldmark*>(pFieldBM); + pDropDownFm->ShowButton(&rEditWin); + pNewActiveFieldmark = pDropDownFm; + } + else + { + pNewActiveFieldmark = m_pLastActiveFieldmark; + } + } + + if(pNewActiveFieldmark != m_pLastActiveFieldmark) + { + ClearFieldActivation(); + m_pLastActiveFieldmark = pNewActiveFieldmark; + } } + void MarkManager::ClearFieldActivation() + { + if(m_pLastActiveFieldmark) + m_pLastActiveFieldmark->RemoveButton(); + + m_pLastActiveFieldmark = nullptr; + } IFieldmark* MarkManager::getDropDownFor(const SwPosition& rPos) const { diff --git a/sw/source/core/inc/DropDownFormFieldButton.hxx b/sw/source/core/inc/DropDownFormFieldButton.hxx new file mode 100644 index 000000000000..e8b9153cb1a6 --- /dev/null +++ b/sw/source/core/inc/DropDownFormFieldButton.hxx @@ -0,0 +1,54 @@ +/* -*- 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_CORE_TEXT_DROPDOWNFORMEFIELDBUTTO_HXX +#define INCLUDED_SW_SOURCE_CORE_TEXT_DROPDOWNFORMEFIELDBUTTO_HXX + +#include <vcl/menubtn.hxx> +#include <swrect.hxx> + +class SwFieldFormDropDownPortion; +class SwEditWin; +class FloatingWindow; +namespace sw +{ +namespace mark +{ +class DropDownFieldmark; +} +} + +/** + * This button is shown when the cursor is in a drop-down form field. + * The user can select an item of the field using this button while filling in a form. + */ +class DropDownFormFieldButton : public MenuButton +{ +public: + DropDownFormFieldButton(SwEditWin* pEditWin, sw::mark::DropDownFieldmark& rFieldMark); + virtual ~DropDownFormFieldButton() override; + virtual void dispose() override; + + void CalcPosAndSize(const SwRect& rPortionPaintArea); + + virtual void MouseButtonUp(const MouseEvent& rMEvt) override; + DECL_LINK(FieldPopupModeEndHdl, FloatingWindow*, void); + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual WindowHitTest ImplHitTest(const Point& rFramePos) override; + +private: + tools::Rectangle m_aFieldFramePixel; + sw::mark::DropDownFieldmark& m_rFieldmark; + VclPtr<FloatingWindow> m_pFieldPopup; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx index 4544bae57b85..6ca604a29976 100644 --- a/sw/source/core/inc/MarkManager.hxx +++ b/sw/source/core/inc/MarkManager.hxx @@ -24,11 +24,16 @@ #include <IDocumentMarkAccess.hxx> #include <unordered_set> #include <unordered_map> +#include <memory> + +class SwCursorShell; namespace sw { namespace mark { typedef std::unordered_map<OUString, sal_Int32> MarkBasenameMapUniqueOffset_t; + class DropDownFieldmark; + class MarkManager : virtual public IDocumentMarkAccess { @@ -88,6 +93,9 @@ namespace sw { virtual void deleteFieldmarkAt(const SwPosition& rPos) override; virtual ::sw::mark::IFieldmark* changeNonTextFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType) override; + virtual void NotifyCursorUpdate(const SwCursorShell& rCursorShell) override; + virtual void ClearFieldActivation() override; + void dumpAsXml(struct _xmlTextWriter* pWriter) const; // Annotation Marks @@ -126,6 +134,8 @@ namespace sw { container_t m_vAnnotationMarks; SwDoc * const m_pDoc; + + sw::mark::DropDownFieldmark* m_pLastActiveFieldmark; }; } // namespace mark } diff --git a/sw/source/core/inc/bookmrk.hxx b/sw/source/core/inc/bookmrk.hxx index 362f0aeb3156..142fbf7fe4a0 100644 --- a/sw/source/core/inc/bookmrk.hxx +++ b/sw/source/core/inc/bookmrk.hxx @@ -29,6 +29,8 @@ #include <osl/diagnose.h> #include <IMark.hxx> #include <swserv.hxx> +#include <swrect.hxx> +#include "DropDownFormFieldButton.hxx" namespace com { namespace sun { @@ -42,6 +44,7 @@ namespace com { struct SwPosition; // fwd Decl. wg. UI class SwDoc; +class SwEditWin; namespace sw { namespace mark { @@ -267,6 +270,17 @@ namespace sw { virtual ~DropDownFieldmark() override; virtual void InitDoc(SwDoc* const io_pDoc, sw::mark::InsertMode eMode) override; virtual void ReleaseDoc(SwDoc* const pDoc) override; + + // This method should be called only by the portion so we can now the portion's painting area + void SetPortionPaintArea(const SwRect& rPortionPaintArea); + + void ShowButton(SwEditWin* pEditWin); + void HideButton(); + void RemoveButton(); + + private: + SwRect m_aPortionPaintArea; + VclPtr<DropDownFormFieldButton> m_pButton; }; } } diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index a864f281c70d..44acc4e194b5 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -908,7 +908,7 @@ SwTextPortion *SwTextFormatter::WhichTextPor( SwTextFormatInfo &rInf ) const } else if (pBM->GetFieldname( ) == ODF_FORMDROPDOWN) { - pPor = new SwFieldFormDropDownPortion(sw::mark::ExpandFieldmark(pBM)); + pPor = new SwFieldFormDropDownPortion(pBM, sw::mark::ExpandFieldmark(pBM)); } /* we need to check for ODF_FORMTEXT for scenario having FormFields inside FORMTEXT. * Otherwise file will crash on open. diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx index bb563e63875a..b03d28942e3d 100644 --- a/sw/source/core/text/porfld.cxx +++ b/sw/source/core/text/porfld.cxx @@ -44,6 +44,7 @@ #include <accessibilityoptions.hxx> #include <editeng/lrspitem.hxx> #include <unicode/ubidi.h> +#include <bookmrk.hxx> using namespace ::com::sun::star; @@ -1311,7 +1312,20 @@ sal_uInt16 SwCombinedPortion::GetViewWidth( const SwTextSizeInfo &rInf ) const SwFieldPortion *SwFieldFormDropDownPortion::Clone(const OUString &rExpand) const { - return new SwFieldFormDropDownPortion(rExpand); + return new SwFieldFormDropDownPortion(m_pFieldMark, rExpand); +} + +void SwFieldFormDropDownPortion::Paint( const SwTextPaintInfo &rInf ) const +{ + SwFieldPortion::Paint( rInf ); + + ::sw::mark::DropDownFieldmark* pDropDownField = dynamic_cast< ::sw::mark::DropDownFieldmark* >(m_pFieldMark); + if(pDropDownField) + { + SwRect aPaintArea; + rInf.CalcRect( *this, &aPaintArea ); + pDropDownField->SetPortionPaintArea(aPaintArea); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx index 1490d9399c60..2d1498d9b3ac 100644 --- a/sw/source/core/text/porfld.hxx +++ b/sw/source/core/text/porfld.hxx @@ -218,12 +218,18 @@ namespace sw { namespace mark { class SwFieldFormDropDownPortion : public SwFieldPortion { public: - explicit SwFieldFormDropDownPortion(const OUString &rExpand) + explicit SwFieldFormDropDownPortion(sw::mark::IFieldmark *pFieldMark, const OUString &rExpand) : SwFieldPortion(rExpand) + , m_pFieldMark(pFieldMark) { } // Field cloner for SplitGlue virtual SwFieldPortion *Clone( const OUString &rExpand ) const override; + + virtual void Paint( const SwTextPaintInfo &rInf ) const override; + +private: + sw::mark::IFieldmark* m_pFieldMark; }; #endif diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 0f4a669bcf05..3d2e52058ce7 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -4613,12 +4613,6 @@ void SwEditWin::MouseButtonUp(const MouseEvent& rMEvt) rCheckboxFm.SetChecked(!rCheckboxFm.IsChecked()); rCheckboxFm.Invalidate(); rSh.InvalidateWindows( m_rView.GetVisArea() ); - } else if ( fieldBM->GetFieldname() == ODF_FORMDROPDOWN ) { - m_rView.ExecFieldPopup( aDocPt, fieldBM ); - fieldBM->Invalidate(); - rSh.InvalidateWindows( m_rView.GetVisArea() ); - } else { - // unknown type.. } } } diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx index bef8fe50dfb1..b95e5b9fcc76 100644 --- a/sw/source/uibase/shells/textsh1.cxx +++ b/sw/source/uibase/shells/textsh1.cxx @@ -121,6 +121,7 @@ #include <memory> #include <xmloff/odffields.hxx> #include <swabstdlg.hxx> +#include <bookmrk.hxx> using namespace ::com::sun::star; using namespace com::sun::star::beans; @@ -1354,10 +1355,14 @@ void SwTextShell::Execute(SfxRequest &rReq) { SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateDropDownFormFieldDialog(rWrtSh.GetView().GetFrameWeld(), pFieldBM)); - pDlg->Execute(); - pFieldBM->Invalidate(); - rWrtSh.InvalidateWindows( rWrtSh.GetView().GetVisArea() ); - rWrtSh.UpdateCursor(); // cursor position might be invalid + if (pDlg->Execute() == RET_OK) + { + pFieldBM->Invalidate(); + rWrtSh.InvalidateWindows( rWrtSh.GetView().GetVisArea() ); + rWrtSh.UpdateCursor(); // cursor position might be invalid + // Hide the button here and make it visible later, to make transparent background work with SAL_USE_VCLPLUGIN=gen + dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldBM)->HideButton(); + } } else { diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx index c3a6711e6d50..039977ff6827 100644 --- a/sw/source/uibase/uiview/view.cxx +++ b/sw/source/uibase/uiview/view.cxx @@ -1065,6 +1065,9 @@ SwView::~SwView() SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", ""); SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_GRAPHIC_VIEW_SELECTION, "selection", "EMPTY"); + // Need to remove activated field's button before disposing EditWin. + GetWrtShell().getIDocumentMarkAccess()->ClearFieldActivation(); + GetViewFrame()->GetWindow().RemoveChildEventListener( LINK( this, SwView, WindowChildEventListener ) ); m_pPostItMgr.reset(); diff --git a/sw/source/uibase/uiview/viewling.cxx b/sw/source/uibase/uiview/viewling.cxx index c29c1637ab87..6aed16bc533f 100644 --- a/sw/source/uibase/uiview/viewling.cxx +++ b/sw/source/uibase/uiview/viewling.cxx @@ -822,114 +822,4 @@ void SwView::ExecSmartTagPopup( const Point& rPt ) m_pWrtShell->LockView( bOldViewLock ); } -class SwFieldDialog : public FloatingWindow -{ -private: - VclPtr<ListBox> aListBox; - IFieldmark *pFieldmark; - - DECL_LINK( MyListBoxHandler, ListBox&, void ); - -public: - SwFieldDialog( SwEditWin* parent, IFieldmark *fieldBM ); - virtual ~SwFieldDialog() override; - virtual void dispose() override; -}; - -SwFieldDialog::SwFieldDialog( SwEditWin* parent, IFieldmark *fieldBM ) : - FloatingWindow( parent, WB_BORDER | WB_SYSTEMWINDOW ), - aListBox(VclPtr<ListBox>::Create(this)), - pFieldmark( fieldBM ) -{ - if ( fieldBM != nullptr ) - { - const IFieldmark::parameter_map_t* const pParameters = fieldBM->GetParameters(); - - OUString sListKey = ODF_FORMDROPDOWN_LISTENTRY; - IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find( sListKey ); - if(pListEntries != pParameters->end()) - { - Sequence< OUString > vListEntries; - pListEntries->second >>= vListEntries; - for( OUString const & i : vListEntries) - aListBox->InsertEntry(i); - } - - // Select the current one - OUString sResultKey = ODF_FORMDROPDOWN_RESULT; - IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find( sResultKey ); - if ( pResult != pParameters->end() ) - { - sal_Int32 nSelection = -1; - pResult->second >>= nSelection; - aListBox->SelectEntryPos( nSelection ); - } - } - - Size lbSize(aListBox->GetOptimalSize()); - lbSize.AdjustWidth(50 ); - lbSize.AdjustHeight(20 ); - aListBox->SetSizePixel(lbSize); - aListBox->SetSelectHdl( LINK( this, SwFieldDialog, MyListBoxHandler ) ); - aListBox->Show(); - - SetSizePixel( lbSize ); -} - -SwFieldDialog::~SwFieldDialog() -{ - disposeOnce(); -} - -void SwFieldDialog::dispose() -{ - aListBox.disposeAndClear(); - FloatingWindow::dispose(); -} - -IMPL_LINK( SwFieldDialog, MyListBoxHandler, ListBox&, rBox, void ) -{ - if ( !rBox.IsTravelSelect() ) - { - sal_Int32 selection = rBox.GetSelectedEntryPos(); - if ( selection >= 0 ) - { - OUString sKey = ODF_FORMDROPDOWN_RESULT; - (*pFieldmark->GetParameters())[ sKey ] <<= selection; - pFieldmark->Invalidate(); - SwView& rView = static_cast<SwEditWin*>( GetParent() )->GetView(); - rView.GetDocShell()->SetModified(); - } - - EndPopupMode(); - } -} - -IMPL_LINK_NOARG(SwView, FieldPopupModeEndHdl, FloatingWindow*, void) -{ - m_pFieldPopup.disposeAndClear(); -} - -void SwView::ExecFieldPopup( const Point& rPt, IFieldmark *fieldBM ) -{ - // Don't show popup if there is no list item - auto pListEntries = fieldBM->GetParameters()->find( ODF_FORMDROPDOWN_LISTENTRY ); - Sequence< OUString > vListEntries; - if(pListEntries != fieldBM->GetParameters()->end()) - { - pListEntries->second >>= vListEntries; - } - - if(vListEntries.getLength() == 0) - return; - - const Point aPixPos = GetEditWin().LogicToPixel( rPt ); - - m_pFieldPopup = VclPtr<SwFieldDialog>::Create( m_pEditWin, fieldBM ); - m_pFieldPopup->SetPopupModeEndHdl( LINK( this, SwView, FieldPopupModeEndHdl ) ); - - tools::Rectangle aRect( m_pEditWin->OutputToScreenPixel( aPixPos ), Size( 0, 0 ) ); - m_pFieldPopup->StartPopupMode( aRect, FloatWinPopupFlags::Down|FloatWinPopupFlags::GrabFocus ); -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit c34f0b2d0695d69196e90820e479ce541c5973f5 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Jun 19 16:39:27 2019 +0200 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Introduce a new IFieldMark for drop-down form field * It was weird anyway that a drop-down form field was represented as an CheckboxFieldmark. * It will be useful for later commits, to have a separate field type for drop-down field. * Needed to fix-up the API a bit because it was designed to specify the field type after initialization. I solved it in a way to not break the API behavior. Hopefully it's not very slow. Reviewed-on: https://gerrit.libreoffice.org/68960 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit f66a83c95c21b4311918a64bb85016857b49f4d4) Change-Id: I3103e6b1c36289b27b62ab9ca7dfeebc14901c8a Reviewed-on: https://gerrit.libreoffice.org/69194 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx index 823326e2b8ac..cbd523c012b1 100644 --- a/sw/inc/IDocumentMarkAccess.hxx +++ b/sw/inc/IDocumentMarkAccess.hxx @@ -47,6 +47,7 @@ class IDocumentMarkAccess ANNOTATIONMARK, TEXT_FIELDMARK, CHECKBOX_FIELDMARK, + DROPDOWN_FIELDMARK, NAVIGATOR_REMINDER }; @@ -255,6 +256,7 @@ class IDocumentMarkAccess virtual std::vector< ::sw::mark::IFieldmark* > getDropDownsFor(const SwPaM &rPaM) const=0; virtual void deleteFieldmarkAt(const SwPosition& rPos) = 0; + virtual ::sw::mark::IFieldmark* changeNonTextFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType) = 0; // Annotation Marks virtual const_iterator_t getAnnotationMarksBegin() const = 0; diff --git a/sw/source/core/crsr/bookmrk.cxx b/sw/source/core/crsr/bookmrk.cxx index 1fa3e307aca5..259168f49440 100644 --- a/sw/source/core/crsr/bookmrk.cxx +++ b/sw/source/core/crsr/bookmrk.cxx @@ -479,6 +479,39 @@ namespace sw { namespace mark pResult->second >>= bResult; return bResult; } + + DropDownFieldmark::DropDownFieldmark(const SwPaM& rPaM) + : Fieldmark(rPaM) + { + } + + DropDownFieldmark::~DropDownFieldmark() + { + } + + void DropDownFieldmark::InitDoc(SwDoc* const io_pDoc, sw::mark::InsertMode const eMode) + { + if (eMode == sw::mark::InsertMode::New) + { + lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT); + + // For some reason the end mark is moved from 1 by the Insert: + // we don't want this for checkboxes + SwPosition aNewEndPos = GetMarkEnd(); + aNewEndPos.nContent--; + SetMarkEndPos( aNewEndPos ); + } + else + { + lcl_AssertFieldMarksSet(this, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT); + } + } + + void DropDownFieldmark::ReleaseDoc(SwDoc* const pDoc) + { + lcl_RemoveFieldMarks(this, pDoc, + CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FORMELEMENT); + } }} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx index 97b29bdb21c6..222eeb846e8c 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -339,6 +339,8 @@ IDocumentMarkAccess::MarkType IDocumentMarkAccess::GetType(const IMark& rBkmk) return MarkType::TEXT_FIELDMARK; else if(*pMarkTypeInfo == typeid(CheckboxFieldmark)) return MarkType::CHECKBOX_FIELDMARK; + else if(*pMarkTypeInfo == typeid(DropDownFieldmark)) + return MarkType::DROPDOWN_FIELDMARK; else if(*pMarkTypeInfo == typeid(NavigatorReminder)) return MarkType::NAVIGATOR_REMINDER; else @@ -415,6 +417,9 @@ namespace sw { namespace mark case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK: pMark = std::shared_ptr<IMark>(new CheckboxFieldmark(rPaM)); break; + case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK: + pMark = std::shared_ptr<IMark>(new DropDownFieldmark(rPaM)); + break; case IDocumentMarkAccess::MarkType::NAVIGATOR_REMINDER: pMark = std::shared_ptr<IMark>(new NavigatorReminder(rPaM)); break; @@ -464,6 +469,7 @@ namespace sw { namespace mark break; case IDocumentMarkAccess::MarkType::TEXT_FIELDMARK: case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK: + case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK: lcl_InsertMarkSorted(m_vFieldmarks, pMark); break; case IDocumentMarkAccess::MarkType::ANNOTATIONMARK: @@ -524,9 +530,20 @@ namespace sw { namespace mark bool bEnableSetModified = m_pDoc->getIDocumentState().IsEnableSetModified(); m_pDoc->getIDocumentState().SetEnableSetModified(false); - sw::mark::IMark* pMark = makeMark( rPaM, rName, - IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK, - sw::mark::InsertMode::New); + sw::mark::IMark* pMark = nullptr; + if(rType == ODF_FORMCHECKBOX) + { + pMark = makeMark( rPaM, rName, + IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK, + sw::mark::InsertMode::New); + } + else if(rType == ODF_FORMDROPDOWN) + { + pMark = makeMark( rPaM, rName, + IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK, + sw::mark::InsertMode::New); + } + sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark ); if (pFieldMark) pFieldMark->SetFieldname( rType ); @@ -938,6 +955,7 @@ namespace sw { namespace mark case IDocumentMarkAccess::MarkType::TEXT_FIELDMARK: case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK: + case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK: { IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark); if ( ppFieldmark != m_vFieldmarks.end() ) @@ -1083,6 +1101,32 @@ namespace sw { namespace mark deleteMark(lcl_FindMark(m_vAllMarks, *pFieldmark)); } + ::sw::mark::IFieldmark* MarkManager::changeNonTextFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType) + { + bool bActualChange = false; + if(rNewType == ODF_FORMDROPDOWN) + { + if (dynamic_cast<::sw::mark::CheckboxFieldmark*>(pFieldmark)) + bActualChange = true; + } + else if(rNewType == ODF_FORMCHECKBOX) + { + if (dynamic_cast<::sw::mark::DropDownFieldmark*>(pFieldmark)) + bActualChange = true; + } + + if (!bActualChange) + return nullptr; + + // Store attributes needed to create the new fieldmark + OUString sName = pFieldmark->GetName(); + SwPaM aPaM(pFieldmark->GetMarkPos()); + + // Remove the old fieldmark and create a new one with the new type + deleteFieldmarkAt(*aPaM.GetPoint()); + return makeNoTextFieldBookmark(aPaM, sName, rNewType); + } + IFieldmark* MarkManager::getDropDownFor(const SwPosition& rPos) const { diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx index 7a3612bb6131..4544bae57b85 100644 --- a/sw/source/core/inc/MarkManager.hxx +++ b/sw/source/core/inc/MarkManager.hxx @@ -86,6 +86,7 @@ namespace sw { virtual std::vector< ::sw::mark::IFieldmark* > getDropDownsFor(const SwPaM &rPaM) const override; virtual void deleteFieldmarkAt(const SwPosition& rPos) override; + virtual ::sw::mark::IFieldmark* changeNonTextFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType) override; void dumpAsXml(struct _xmlTextWriter* pWriter) const; diff --git a/sw/source/core/inc/bookmrk.hxx b/sw/source/core/inc/bookmrk.hxx index d5f0495ef09e..362f0aeb3156 100644 --- a/sw/source/core/inc/bookmrk.hxx +++ b/sw/source/core/inc/bookmrk.hxx @@ -245,6 +245,7 @@ namespace sw { virtual void ReleaseDoc(SwDoc* const pDoc) override; }; + /// Fieldmark representing a checkbox form field. class CheckboxFieldmark : virtual public ICheckboxFieldmark , public Fieldmark @@ -256,6 +257,17 @@ namespace sw { bool IsChecked() const override; void SetChecked(bool checked) override; }; + + /// Fieldmark representing a drop-down form field. + class DropDownFieldmark + : public Fieldmark + { + public: + DropDownFieldmark(const SwPaM& rPaM); + virtual ~DropDownFieldmark() override; + virtual void InitDoc(SwDoc* const io_pDoc, sw::mark::InsertMode eMode) override; + virtual void ReleaseDoc(SwDoc* const pDoc) override; + }; } } #endif diff --git a/sw/source/core/inc/unobookmark.hxx b/sw/source/core/inc/unobookmark.hxx index 39a9e973502f..a11f42c4d855 100644 --- a/sw/source/core/inc/unobookmark.hxx +++ b/sw/source/core/inc/unobookmark.hxx @@ -67,6 +67,8 @@ protected: const ::sw::mark::IMark* GetBookmark() const; + IDocumentMarkAccess* GetIDocumentMarkAccess(); + void registerInMark( SwXBookmark& rXMark, ::sw::mark::IMark* const pMarkBase ); virtual ~SwXBookmark() override; diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 3517812be531..a864f281c70d 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -917,10 +917,6 @@ SwTextPortion *SwTextFormatter::WhichTextPor( SwTextFormatInfo &rInf ) const { pPor = new SwFieldMarkPortion(); } - else - { - assert( false ); // unknown type... - } } } if( !pPor ) diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx index a66247f33fe1..abd18ac53499 100644 --- a/sw/source/core/unocore/unobkm.cxx +++ b/sw/source/core/unocore/unobkm.cxx @@ -134,6 +134,11 @@ const ::sw::mark::IMark* SwXBookmark::GetBookmark() const return m_pImpl->m_pRegisteredBookmark; } +IDocumentMarkAccess* SwXBookmark::GetIDocumentMarkAccess() +{ + return m_pImpl->m_pDoc->getIDocumentMarkAccess(); +} + SwXBookmark::SwXBookmark(SwDoc *const pDoc) : m_pImpl( new SwXBookmark::Impl(pDoc) ) { @@ -620,7 +625,21 @@ void SwXFieldmark::setFieldType(const OUString & fieldType) dynamic_cast<const IFieldmark*>(GetBookmark())); if(!pBkm) throw uno::RuntimeException(); - pBkm->SetFieldname(fieldType); + if(fieldType != getFieldType()) + { + if(fieldType == ODF_FORMDROPDOWN || fieldType == ODF_FORMCHECKBOX) + { + ::sw::mark::IFieldmark* pNewFieldmark = GetIDocumentMarkAccess()->changeNonTextFieldmarkType(pBkm, fieldType); + if (pNewFieldmark) + { + registerInMark(*this, pNewFieldmark); + return; + } + } + + // We did not generate a new fieldmark, so set the type ID + pBkm->SetFieldname(fieldType); + } } uno::Reference<container::XNameContainer> SwXFieldmark::getParameters() @@ -654,6 +673,8 @@ SwXFieldmark::CreateXFieldmark(SwDoc & rDoc, ::sw::mark::IMark *const pMark, pXBkmk = new SwXFieldmark(false, &rDoc); else if (dynamic_cast< ::sw::mark::CheckboxFieldmark* >(pMark)) pXBkmk = new SwXFieldmark(true, &rDoc); + else if (dynamic_cast< ::sw::mark::DropDownFieldmark* >(pMark)) + pXBkmk = new SwXFieldmark(true, &rDoc); else pXBkmk = new SwXFieldmark(isReplacementObject, &rDoc); diff --git a/writerfilter/source/dmapper/FormControlHelper.cxx b/writerfilter/source/dmapper/FormControlHelper.cxx index 3088a4a27361..98e7bb0ba319 100644 --- a/writerfilter/source/dmapper/FormControlHelper.cxx +++ b/writerfilter/source/dmapper/FormControlHelper.cxx @@ -202,6 +202,20 @@ bool FormControlHelper::createCheckbox(uno::Reference<text::XTextRange> const& x void FormControlHelper::processField(uno::Reference<text::XFormField> const& xFormField) { + // Set field type first before adding parameters. + if (m_pImpl->m_eFieldId == FIELD_FORMTEXT ) + { + xFormField->setFieldType(ODF_FORMTEXT); + } + else if (m_pImpl->m_eFieldId == FIELD_FORMCHECKBOX ) + { + xFormField->setFieldType(ODF_FORMCHECKBOX); + } + else if (m_pImpl->m_eFieldId == FIELD_FORMDROPDOWN ) + { + xFormField->setFieldType(ODF_FORMDROPDOWN); + } + uno::Reference<container::XNameContainer> xNameCont = xFormField->getParameters(); uno::Reference<container::XNamed> xNamed( xFormField, uno::UNO_QUERY ); if ( m_pFFData && xNamed.is() && xNameCont.is() ) @@ -223,7 +237,6 @@ void FormControlHelper::processField(uno::Reference<text::XFormField> const& xFo if (m_pImpl->m_eFieldId == FIELD_FORMTEXT ) { - xFormField->setFieldType(ODF_FORMTEXT); sTmp = m_pFFData->getName(); try { @@ -255,7 +268,6 @@ void FormControlHelper::processField(uno::Reference<text::XFormField> const& xFo } else if (m_pImpl->m_eFieldId == FIELD_FORMCHECKBOX ) { - xFormField->setFieldType(ODF_FORMCHECKBOX); uno::Reference<beans::XPropertySet> xPropSet(xFormField, uno::UNO_QUERY); uno::Any aAny; aAny <<= m_pFFData->getCheckboxChecked(); @@ -264,7 +276,6 @@ void FormControlHelper::processField(uno::Reference<text::XFormField> const& xFo } else if (m_pImpl->m_eFieldId == FIELD_FORMDROPDOWN ) { - xFormField->setFieldType(ODF_FORMDROPDOWN); const FFDataHandler::DropDownEntries_t& rEntries = m_pFFData->getDropDownEntries(); if (!rEntries.empty()) { commit 356959529c4891093c435c40ddc93b57b625d40a Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Feb 20 12:45:44 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:35 2019 +0200 MSForms: Update cursor position after the drop down form field was changed Change-Id: I0e9e8a0e9212cdf539caa163f9071bc2f21e4c9f Reviewed-on: https://gerrit.libreoffice.org/68959 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit 499501e8cf1d511eb95a7b72b755c2dc69985719) Reviewed-on: https://gerrit.libreoffice.org/69193 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx index a5c8e1acc4d2..c76be980179d 100644 --- a/sw/inc/crsrsh.hxx +++ b/sw/inc/crsrsh.hxx @@ -162,6 +162,10 @@ public: READONLY = (1 << 3) ///< make visible in spite of Readonly }; + SAL_DLLPRIVATE void UpdateCursor( + sal_uInt16 eFlags = SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE, + bool bIdleEnd = false ); + private: SwRect m_aCharRect; ///< Char-SRectangle on which the cursor is located @@ -232,10 +236,6 @@ private: SwFrame* m_oldColFrame; - SAL_DLLPRIVATE void UpdateCursor( - sal_uInt16 eFlags = SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE, - bool bIdleEnd = false ); - SAL_DLLPRIVATE void MoveCursorToNum(); SAL_DLLPRIVATE void ParkPams( SwPaM* pDelRg, SwShellCursor** ppDelRing ); diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx index ae9db9357140..bef8fe50dfb1 100644 --- a/sw/source/uibase/shells/textsh1.cxx +++ b/sw/source/uibase/shells/textsh1.cxx @@ -1357,6 +1357,7 @@ void SwTextShell::Execute(SfxRequest &rReq) pDlg->Execute(); pFieldBM->Invalidate(); rWrtSh.InvalidateWindows( rWrtSh.GetView().GetVisArea() ); + rWrtSh.UpdateCursor(); // cursor position might be invalid } else { commit c6f4b7397e55d061daaa9cb024151f33a9ec755a Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Thu Feb 21 13:39:27 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:34 2019 +0200 MSForms: Disable legacy field menu slots if the cursor is inside a text field Insertion of fields inside fields is not an allowed operation. Change-Id: Icfdbc1add9c828227201b70cd545a83b6dcbc3e6 Reviewed-on: https://gerrit.libreoffice.org/68957 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit c138047c75dcd0d6c572a58870edf2a7761ae35e) Reviewed-on: https://gerrit.libreoffice.org/69192 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/sw/source/uibase/shells/textfld.cxx b/sw/source/uibase/shells/textfld.cxx index 55d19a48eee8..6b1915e095b3 100644 --- a/sw/source/uibase/shells/textfld.cxx +++ b/sw/source/uibase/shells/textfld.cxx @@ -924,6 +924,12 @@ void SwTextShell::StateField( SfxItemSet &rSet ) case FN_INSERT_FLD_TITLE: case FN_INSERT_FLD_TOPIC: case FN_INSERT_DBFIELD: + if ( rSh.CursorInsideInputField() ) + { + rSet.DisableItem(nWhich); + } + break; + case FN_INSERT_TEXT_FORMFIELD: case FN_INSERT_CHECKBOX_FORMFIELD: case FN_INSERT_DROPDOWN_FORMFIELD: @@ -931,6 +937,24 @@ void SwTextShell::StateField( SfxItemSet &rSet ) { rSet.DisableItem(nWhich); } + else + { + // Check whether we are in a text form field + SwPosition aCursorPos(*rSh.GetCursor()->GetPoint()); + sw::mark::IFieldmark* pFieldBM = GetShell().getIDocumentMarkAccess()->getFieldmarkFor(aCursorPos); + if ((!pFieldBM || pFieldBM->GetFieldname() != ODF_FORMTEXT) + && aCursorPos.nContent.GetIndex() > 0) + { + SwPosition aPos(aCursorPos); + --aPos.nContent; + pFieldBM = GetShell().getIDocumentMarkAccess()->getFieldmarkFor(aPos); + } + if (pFieldBM && pFieldBM->GetFieldname() == ODF_FORMTEXT && + (aCursorPos > pFieldBM->GetMarkStart() && aCursorPos < pFieldBM->GetMarkEnd() )) + { + rSet.DisableItem(nWhich); + } + } break; } commit a138e5a5910d782068cf9bb76dab48f873be18cf Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Thu Feb 21 13:40:14 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:34 2019 +0200 Fix typo Change-Id: I2b09bf30c3769f6b987409cabf24735647d3c31d Reviewed-on: https://gerrit.libreoffice.org/68958 Reviewed-by: Julien Nabet <serval2...@yahoo.fr> Tested-by: Jenkins (cherry picked from commit ba296f8e413f0cb1cd4095a342495b511df2aea4) Reviewed-on: https://gerrit.libreoffice.org/69191 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> diff --git a/sw/source/ui/config/optcomp.cxx b/sw/source/ui/config/optcomp.cxx index 524e8642276b..1a74d382a7ca 100644 --- a/sw/source/ui/config/optcomp.cxx +++ b/sw/source/ui/config/optcomp.cxx @@ -60,7 +60,7 @@ SwCompatibilityOptPage::SwCompatibilityOptPage(vcl::Window* pParent, const SfxIt get(m_pFormattingLB, "format"); get(m_pGlobalOptionsLB, "globaloptions"); get(m_pOptionsLB, "options"); - get(m_pGlobalOptionsCLB, "globaloptioncheckboxs"); + get(m_pGlobalOptionsCLB, "globaloptioncheckbox"); get(m_pDefaultPB, "default"); for ( int i = (static_cast<int>(SvtCompatibilityEntry::Index::Module) + 1); i < static_cast<int>(SvtCompatibilityEntry::Index::INVALID); ++i ) diff --git a/sw/uiconfig/swriter/ui/optcompatpage.ui b/sw/uiconfig/swriter/ui/optcompatpage.ui index 8f4a5342c75d..3965324f43bb 100644 --- a/sw/uiconfig/swriter/ui/optcompatpage.ui +++ b/sw/uiconfig/swriter/ui/optcompatpage.ui @@ -140,7 +140,7 @@ <property name="can_focus">False</property> <property name="row_spacing">5</property> <child> - <object class="svxcorelo-SvxCheckListBox" id="globaloptioncheckboxs:border"> + <object class="svxcorelo-SvxCheckListBox" id="globaloptioncheckbox:border"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="hexpand">True</property> commit e87a61e4147140972716a653c8bfe10968031ef2 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Jun 19 16:07:23 2019 +0200 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Wed Jun 19 22:21:34 2019 +0200 MSForms: Implement undo / redo for insertion of legacy form fields Need to handle undo / redo explicitely for form fields, because there is no a general working undo / redo mechanism for fieldmarks. During the insertion of the fieldmark, text insertion also happens which generates an interfering undo action, so we need to disable undoing temporary. Also need to invalidta SID_UNDO slot to make the undo toolbar item updated after we insert a form field. Reviewed-on: https://gerrit.libreoffice.org/68956 Tested-by: Jenkins Reviewed-by: Tamás Zolnai <tamas.zol...@collabora.com> (cherry picked from commit 55d6be75732d1bb0067bba9496c74ef30be9a3ec) Change-Id: I358c2704cb30212a38f8a998888a36f72fa404e5 diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx index 3fb7090e5067..823326e2b8ac 100644 --- a/sw/inc/IDocumentMarkAccess.hxx +++ b/sw/inc/IDocumentMarkAccess.hxx @@ -254,6 +254,8 @@ class IDocumentMarkAccess virtual ::sw::mark::IFieldmark* getDropDownFor(const SwPosition& pos) const=0; virtual std::vector< ::sw::mark::IFieldmark* > getDropDownsFor(const SwPaM &rPaM) const=0; + virtual void deleteFieldmarkAt(const SwPosition& rPos) = 0; + // Annotation Marks virtual const_iterator_t getAnnotationMarksBegin() const = 0; virtual const_iterator_t getAnnotationMarksEnd() const = 0; diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc index 1b3153dab176..da13d2fb16e6 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -539,6 +539,7 @@ #define STR_UNDO_TBLSTYLE_DELETE NC_("STR_UNDO_TBLSTYLE_DELETE", "Delete table style: $1") #define STR_UNDO_TBLSTYLE_UPDATE NC_("STR_UNDO_TBLSTYLE_UPDATE", "Update table style: $1") #define STR_UNDO_TABLE_DELETE NC_("STR_UNDO_TABLE_DELETE", "Delete table") +#define STR_UNDO_INSERT_FORM_FIELD NC_("STR_UNDO_INSERT_FORM_FIELD", "Insert form field") #define STR_ACCESS_DOC_NAME NC_("STR_ACCESS_DOC_NAME", "Document view") #define STR_ACCESS_DOC_DESC NC_("STR_ACCESS_DOC_DESC", "Document view") diff --git a/sw/inc/swundo.hxx b/sw/inc/swundo.hxx index c393554f0614..90fa6c51d055 100644 --- a/sw/inc/swundo.hxx +++ b/sw/inc/swundo.hxx @@ -162,7 +162,9 @@ enum class SwUndoId UI_DELETE_PAGE_BREAK, // 131 UI_TEXT_CORRECTION, // 132 UI_TABLE_DELETE, // 133 - CONFLICT // 134 + CONFLICT, // 134 + + INSERT_FORM_FIELD // 135 }; OUString GetUndoComment(SwUndoId eId); diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx index f48e3c626cc2..97b29bdb21c6 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -492,6 +492,10 @@ namespace sw { namespace mark const OUString& rName, const OUString& rType ) { + // Disable undo, because we handle it using SwUndoInsTextFieldmark + bool bUndoIsEnabled = m_pDoc->GetIDocumentUndoRedo().DoesUndo(); + m_pDoc->GetIDocumentUndoRedo().DoUndo(false); + sw::mark::IMark* pMark = makeMark( rPaM, rName, IDocumentMarkAccess::MarkType::TEXT_FIELDMARK, sw::mark::InsertMode::New); @@ -499,6 +503,12 @@ namespace sw { namespace mark if (pFieldMark) pFieldMark->SetFieldname( rType ); + if (bUndoIsEnabled) + { + m_pDoc->GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled); + m_pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsTextFieldmark>(*pFieldMark)); + } + return pFieldMark; } @@ -507,6 +517,10 @@ namespace sw { namespace mark const OUString& rName, const OUString& rType) { + // Disable undo, because we handle it using SwUndoInsNoTextFieldmark + bool bUndoIsEnabled = m_pDoc->GetIDocumentUndoRedo().DoesUndo(); + m_pDoc->GetIDocumentUndoRedo().DoUndo(false); + bool bEnableSetModified = m_pDoc->getIDocumentState().IsEnableSetModified(); m_pDoc->getIDocumentState().SetEnableSetModified(false); @@ -517,6 +531,12 @@ namespace sw { namespace mark if (pFieldMark) pFieldMark->SetFieldname( rType ); + if (bUndoIsEnabled) + { + m_pDoc->GetIDocumentUndoRedo().DoUndo(bUndoIsEnabled); + m_pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsNoTextFieldmark>(*pFieldMark)); + } + m_pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified); m_pDoc->getIDocumentState().SetModified(); @@ -1052,6 +1072,18 @@ namespace sw { namespace mark return dynamic_cast<IFieldmark*>(pFieldmark->get()); } + void MarkManager::deleteFieldmarkAt(const SwPosition& rPos) + { + const_iterator_t pFieldmark = find_if( + m_vFieldmarks.begin(), + m_vFieldmarks.end(), + [&rPos] (pMark_t const& rpMark) { return rpMark->IsCoveringPosition(rPos); } ); + if(pFieldmark == m_vFieldmarks.end()) return; + + deleteMark(lcl_FindMark(m_vAllMarks, *pFieldmark)); + } + + IFieldmark* MarkManager::getDropDownFor(const SwPosition& rPos) const { IFieldmark *pMark = getFieldmarkFor(rPos); diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx index a12657ef2469..7a3612bb6131 100644 --- a/sw/source/core/inc/MarkManager.hxx +++ b/sw/source/core/inc/MarkManager.hxx @@ -85,6 +85,8 @@ namespace sw { virtual ::sw::mark::IFieldmark* getDropDownFor(const SwPosition &rPos) const override; virtual std::vector< ::sw::mark::IFieldmark* > getDropDownsFor(const SwPaM &rPaM) const override; + virtual void deleteFieldmarkAt(const SwPosition& rPos) override; + void dumpAsXml(struct _xmlTextWriter* pWriter) const; // Annotation Marks diff --git a/sw/source/core/inc/UndoBookmark.hxx b/sw/source/core/inc/UndoBookmark.hxx index eb32662c92d8..7b9dd4fc68e5 100644 --- a/sw/source/core/inc/UndoBookmark.hxx +++ b/sw/source/core/inc/UndoBookmark.hxx @@ -24,10 +24,13 @@ #include <undobj.hxx> class SwHistoryBookmark; +class SwHistoryNoTextFieldmark; +class SwHistoryTextFieldmark; namespace sw { namespace mark { class IMark; + class IFieldmark; } } @@ -95,6 +98,30 @@ private: virtual void RedoImpl( ::sw::UndoRedoContext & ) override; }; +class SwUndoInsNoTextFieldmark : public SwUndo +{ +private: + const std::unique_ptr<SwHistoryNoTextFieldmark> m_pHistoryNoTextFieldmark; + +public: + SwUndoInsNoTextFieldmark(const ::sw::mark::IFieldmark& rFieldmark); + + virtual void UndoImpl( ::sw::UndoRedoContext & ) override; + virtual void RedoImpl( ::sw::UndoRedoContext & ) override; +}; + +class SwUndoInsTextFieldmark : public SwUndo +{ +private: + const std::unique_ptr<SwHistoryTextFieldmark> m_pHistoryTextFieldmark; + +public: + SwUndoInsTextFieldmark(const ::sw::mark::IFieldmark& rFieldmark); + + virtual void UndoImpl( ::sw::UndoRedoContext & ) override; + virtual void RedoImpl( ::sw::UndoRedoContext & ) override; +}; + #endif // INCLUDED_SW_SOURCE_CORE_INC_UNDOBOOKMARK_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/inc/rolbck.hxx b/sw/source/core/inc/rolbck.hxx index 945ed1948388..3fde226b7acf 100644 --- a/sw/source/core/inc/rolbck.hxx +++ b/sw/source/core/inc/rolbck.hxx @@ -72,6 +72,8 @@ enum HISTORY_HINT { HSTRY_CHGFLYANCHOR, HSTRY_CHGFLYCHAIN, HSTRY_CHGCHARFMT, + HSTRY_NOTEXTFIELDMARK, + HSTRY_TEXTFIELDMARK, }; class SwHistoryHint @@ -260,6 +262,33 @@ class SwHistoryBookmark : public SwHistoryHint std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndo; }; +class SwHistoryNoTextFieldmark : public SwHistoryHint +{ + public: + SwHistoryNoTextFieldmark(const ::sw::mark::IFieldmark& rFieldMark); + virtual void SetInDoc(SwDoc* pDoc, bool) override; + void ResetInDoc(SwDoc* pDoc); + + private: + const OUString m_sType; + const sal_uLong m_nNode; + const sal_Int32 m_nContent; +}; + +class SwHistoryTextFieldmark : public SwHistoryHint +{ + public: + SwHistoryTextFieldmark(const ::sw::mark::IFieldmark& rFieldMark); + virtual void SetInDoc(SwDoc* pDoc, bool) override; + void ResetInDoc(SwDoc* pDoc); + + private: + const OUString m_sName; + const OUString m_sType; + const sal_uLong m_nNode; + const sal_Int32 m_nContent; +}; + class SwHistorySetAttrSet : public SwHistoryHint { SfxItemSet m_OldSet; diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx index b8048539f459..495ce724032d 100644 --- a/sw/source/core/undo/rolbck.cxx +++ b/sw/source/core/undo/rolbck.cxx @@ -674,6 +674,96 @@ bool SwHistoryBookmark::IsEqualBookmark(const ::sw::mark::IMark& rBkmk) && m_aName == rBkmk.GetName(); } +SwHistoryNoTextFieldmark::SwHistoryNoTextFieldmark(const ::sw::mark::IFieldmark& rFieldMark) + : SwHistoryHint(HSTRY_NOTEXTFIELDMARK) + , m_sType(rFieldMark.GetFieldname()) + , m_nNode(rFieldMark.GetMarkPos().nNode.GetIndex()) + , m_nContent(rFieldMark.GetMarkPos().nContent.GetIndex()) +{ +} + +void SwHistoryNoTextFieldmark::SetInDoc(SwDoc* pDoc, bool) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + std::unique_ptr<SwPaM> pPam; + + const SwContentNode* pContentNd = rNds[m_nNode]->GetContentNode(); + if(pContentNd) + pPam.reset(new SwPaM(*pContentNd, m_nContent)); + + if (pPam) + { + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + pMarkAccess->makeNoTextFieldBookmark(*pPam, OUString(), m_sType); + } +} + +void SwHistoryNoTextFieldmark::ResetInDoc(SwDoc* pDoc) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + std::unique_ptr<SwPaM> pPam; + + const SwContentNode* pContentNd = rNds[m_nNode]->GetContentNode(); + if(pContentNd) + pPam.reset(new SwPaM(*pContentNd, m_nContent-1)); + + if (pPam) + { + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + pMarkAccess->deleteFieldmarkAt(*pPam->GetPoint()); + } +} + +SwHistoryTextFieldmark::SwHistoryTextFieldmark(const ::sw::mark::IFieldmark& rFieldMark) + : SwHistoryHint(HSTRY_TEXTFIELDMARK) + , m_sName(rFieldMark.GetName()) + , m_sType(rFieldMark.GetFieldname()) + , m_nNode(rFieldMark.GetMarkPos().nNode.GetIndex()) + , m_nContent(rFieldMark.GetMarkPos().nContent.GetIndex()) +{ +} + +void SwHistoryTextFieldmark::SetInDoc(SwDoc* pDoc, bool) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + std::unique_ptr<SwPaM> pPam; + + const SwContentNode* pContentNd = rNds[m_nNode]->GetContentNode(); + if(pContentNd) + pPam.reset(new SwPaM(*pContentNd, m_nContent)); + + if (pPam) + { + IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess(); + SwPaM aFieldPam(pPam->GetPoint()->nNode, pPam->GetPoint()->nContent.GetIndex(), + pPam->GetPoint()->nNode, pPam->GetPoint()->nContent.GetIndex() + 5); + pMarksAccess->makeFieldBookmark(aFieldPam, m_sName, m_sType); + } +} + +void SwHistoryTextFieldmark::ResetInDoc(SwDoc* pDoc) +{ + ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); + + SwNodes& rNds = pDoc->GetNodes(); + std::unique_ptr<SwPaM> pPam; + + const SwContentNode* pContentNd = rNds[m_nNode]->GetContentNode(); + if(pContentNd) + pPam.reset(new SwPaM(*pContentNd, m_nContent)); + + if (pPam) + { + IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess(); + pMarkAccess->deleteFieldmarkAt(*pPam->GetPoint()); + } +} SwHistorySetAttrSet::SwHistorySetAttrSet( const SfxItemSet& rSet, sal_uLong nNodePos, const std::set<sal_uInt16> &rSetArr ) diff --git a/sw/source/core/undo/unbkmk.cxx b/sw/source/core/undo/unbkmk.cxx index fc465aad21b2..c4d77b6e2f71 100644 --- a/sw/source/core/undo/unbkmk.cxx +++ b/sw/source/core/undo/unbkmk.cxx @@ -148,4 +148,36 @@ void SwUndoRenameBookmark::RedoImpl(::sw::UndoRedoContext & rContext) Rename(rContext, m_sOldName, m_sNewName); } +SwUndoInsNoTextFieldmark::SwUndoInsNoTextFieldmark(const ::sw::mark::IFieldmark& rFieldmark) + : SwUndo(SwUndoId::INSERT, rFieldmark.GetMarkPos().GetDoc()) + , m_pHistoryNoTextFieldmark(new SwHistoryNoTextFieldmark(rFieldmark)) +{ +} + +void SwUndoInsNoTextFieldmark::UndoImpl(::sw::UndoRedoContext & rContext) +{ + m_pHistoryNoTextFieldmark->ResetInDoc(&rContext.GetDoc()); +} + +void SwUndoInsNoTextFieldmark::RedoImpl(::sw::UndoRedoContext & rContext) +{ + m_pHistoryNoTextFieldmark->SetInDoc(&rContext.GetDoc(), false); +} + +SwUndoInsTextFieldmark::SwUndoInsTextFieldmark(const ::sw::mark::IFieldmark& rFieldmark) + : SwUndo(SwUndoId::INSERT, rFieldmark.GetMarkPos().GetDoc()) + , m_pHistoryTextFieldmark(new SwHistoryTextFieldmark(rFieldmark)) +{ +} + +void SwUndoInsTextFieldmark::UndoImpl(::sw::UndoRedoContext & rContext) +{ + m_pHistoryTextFieldmark->ResetInDoc(&rContext.GetDoc()); +} + +void SwUndoInsTextFieldmark::RedoImpl(::sw::UndoRedoContext & rContext) +{ + m_pHistoryTextFieldmark->SetInDoc(&rContext.GetDoc(), false); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx index 63a8bd949bcc..844a29be2073 100644 --- a/sw/source/core/undo/undobj.cxx +++ b/sw/source/core/undo/undobj.cxx @@ -642,6 +642,9 @@ OUString GetUndoComment(SwUndoId eId) case SwUndoId::PARA_SIGN_ADD: pId = STR_PARAGRAPH_SIGN_UNDO; break; + case SwUndoId::INSERT_FORM_FIELD: + pId = STR_UNDO_INSERT_FORM_FIELD; + break; }; assert(pId); diff --git a/sw/source/uibase/shells/textfld.cxx b/sw/source/uibase/shells/textfld.cxx index 095d89bc1182..55d19a48eee8 100644 --- a/sw/source/uibase/shells/textfld.cxx +++ b/sw/source/uibase/shells/textfld.cxx @@ -74,6 +74,7 @@ #include <MarkManager.hxx> #include <xmloff/odffields.hxx> #include <IDocumentContentOperations.hxx> +#include <IDocumentUndoRedo.hxx> using namespace nsSwDocInfoSubType; @@ -722,6 +723,8 @@ FIELD_INSERT: case FN_INSERT_TEXT_FORMFIELD: { + rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr); + SwPaM* pCursorPos = rSh.GetCursor(); if(pCursorPos) { @@ -736,26 +739,39 @@ FIELD_INSERT: ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits