Rebased ref, commits from common ancestor: commit 0717eb8008de753466baab6a97b57200282a4463 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Thu Mar 7 12:37:00 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Fri Mar 8 17:17:05 2019 +0100
MSForms: UITest for drop-down form field's propertis dialog Also changed the dialog's code a bit to work correctly with the UI test too. Change-Id: Idec85746f5ada979518d1fb0e09dc1c8e22ba7c1 diff --git a/sw/qa/uitest/writer_tests/data/drop_down_form_field.doc b/sw/qa/uitest/writer_tests/data/drop_down_form_field.doc new file mode 100644 index 000000000000..cf94a1fdada1 Binary files /dev/null and b/sw/qa/uitest/writer_tests/data/drop_down_form_field.doc differ diff --git a/sw/qa/uitest/writer_tests/data/drop_down_form_field.docx b/sw/qa/uitest/writer_tests/data/drop_down_form_field.docx new file mode 100644 index 000000000000..d039cd2b60d3 Binary files /dev/null and b/sw/qa/uitest/writer_tests/data/drop_down_form_field.docx differ diff --git a/sw/qa/uitest/writer_tests/data/drop_down_form_field.odt b/sw/qa/uitest/writer_tests/data/drop_down_form_field.odt new file mode 100644 index 000000000000..f27b1157418c Binary files /dev/null and b/sw/qa/uitest/writer_tests/data/drop_down_form_field.odt differ diff --git a/sw/qa/uitest/writer_tests/data/empty_drop_down_form_field.odt b/sw/qa/uitest/writer_tests/data/empty_drop_down_form_field.odt new file mode 100644 index 000000000000..bd85dc2a902d Binary files /dev/null and b/sw/qa/uitest/writer_tests/data/empty_drop_down_form_field.odt differ diff --git a/sw/qa/uitest/writer_tests5/DropDownFormFieldPropertiesDialog.py b/sw/qa/uitest/writer_tests5/DropDownFormFieldPropertiesDialog.py new file mode 100644 index 000000000000..5628e83992e1 --- /dev/null +++ b/sw/qa/uitest/writer_tests5/DropDownFormFieldPropertiesDialog.py @@ -0,0 +1,266 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# 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/. +# +from uitest.framework import UITestCase +from uitest.uihelper.common import get_state_as_dict +from libreoffice.uno.propertyvalue import mkPropertyValues +import org.libreoffice.unotest +import pathlib +import time + +def get_url_for_data_file(file_name): + return pathlib.Path(org.libreoffice.unotest.makeCopyFromTDOC(file_name)).as_uri() + +class dropDownFormFieldDialog(UITestCase): + + def test_add_new_items(self): + + # open a file with an empty form field + writer_doc = self.ui_test.load_file(get_url_for_data_file("empty_drop_down_form_field.odt")) + document = self.ui_test.get_component() + xWriterDoc = self.xUITest.getTopFocusWindow() + + # open the dialog (cursor is at the field) + self.ui_test.execute_dialog_through_command(".uno:ControlProperties") + xDialog = self.xUITest.getTopFocusWindow() + + itemEntry = xDialog.getChild("item_entry") + addButton = xDialog.getChild("add_button") + itemsList = xDialog.getChild("items_treeview") + + # initial state + self.assertEqual(get_state_as_dict(itemEntry)["Text"], "") + self.assertEqual(get_state_as_dict(addButton)["Enabled"], "false") + self.assertEqual(get_state_as_dict(itemsList)["Children"], "0") + + # add some new items + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"1000"})) + self.assertEqual(get_state_as_dict(addButton)["Enabled"], "true") + addButton.executeAction("CLICK", tuple()) + self.assertEqual(get_state_as_dict(addButton)["Enabled"], "false") + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"2000"})) + addButton.executeAction("CLICK", tuple()) + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"3000"})) + addButton.executeAction("CLICK", tuple()) + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"4000"})) + addButton.executeAction("CLICK", tuple()) + + # check whether the items are there in the list + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "2000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "4000") + + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + # check whether items are the same after reopening + self.ui_test.execute_dialog_through_command(".uno:ControlProperties") + xDialog = self.xUITest.getTopFocusWindow() + + itemsList = xDialog.getChild("items_treeview") + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "2000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "4000") + + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + self.ui_test.close_doc() + + def test_remove_items(self): + + # open a file with an empty form field + writer_doc = self.ui_test.load_file(get_url_for_data_file("empty_drop_down_form_field.odt")) + document = self.ui_test.get_component() + xWriterDoc = self.xUITest.getTopFocusWindow() + + # open the dialog (cursor is at the field) + self.ui_test.execute_dialog_through_command(".uno:ControlProperties") + xDialog = self.xUITest.getTopFocusWindow() + + itemEntry = xDialog.getChild("item_entry") + addButton = xDialog.getChild("add_button") + itemsList = xDialog.getChild("items_treeview") + removeButton = xDialog.getChild("remove_button") + + # initial state + self.assertEqual(get_state_as_dict(itemEntry)["Text"], "") + self.assertEqual(get_state_as_dict(addButton)["Enabled"], "false") + self.assertEqual(get_state_as_dict(itemsList)["Children"], "0") + self.assertEqual(get_state_as_dict(removeButton)["Enabled"], "false") + + # add some new items + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"1000"})) + self.assertEqual(get_state_as_dict(addButton)["Enabled"], "true") + addButton.executeAction("CLICK", tuple()) + self.assertEqual(get_state_as_dict(removeButton)["Enabled"], "true") + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"2000"})) + addButton.executeAction("CLICK", tuple()) + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"3000"})) + addButton.executeAction("CLICK", tuple()) + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"4000"})) + addButton.executeAction("CLICK", tuple()) + + # check whether the items are there in the list + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "2000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "4000") + + # select an item from the list and remove it + itemsList.getChild("1").executeAction("SELECT", tuple()); + removeButton.executeAction("CLICK", tuple()) + + # check whether the right item was removed + self.assertEqual(get_state_as_dict(itemsList)["Children"], "3") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "4000") + + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + # check whether items are the same after reopening + self.ui_test.execute_dialog_through_command(".uno:ControlProperties") + xDialog = self.xUITest.getTopFocusWindow() + + itemsList = xDialog.getChild("items_treeview") + removeButton = xDialog.getChild("remove_button") + self.assertEqual(get_state_as_dict(itemsList)["Children"], "3") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "4000") + + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + self.ui_test.close_doc() + + def test_move_items(self): + + # open a file with an empty form field + writer_doc = self.ui_test.load_file(get_url_for_data_file("empty_drop_down_form_field.odt")) + document = self.ui_test.get_component() + xWriterDoc = self.xUITest.getTopFocusWindow() + + # open the dialog (cursor is at the field) + self.ui_test.execute_dialog_through_command(".uno:ControlProperties") + xDialog = self.xUITest.getTopFocusWindow() + + itemEntry = xDialog.getChild("item_entry") + addButton = xDialog.getChild("add_button") + itemsList = xDialog.getChild("items_treeview") + upButton = xDialog.getChild("up_button") + downButton = xDialog.getChild("down_button") + + # initial state + self.assertEqual(get_state_as_dict(itemEntry)["Text"], "") + self.assertEqual(get_state_as_dict(addButton)["Enabled"], "false") + self.assertEqual(get_state_as_dict(itemsList)["Children"], "0") + self.assertEqual(get_state_as_dict(upButton)["Enabled"], "false") + self.assertEqual(get_state_as_dict(downButton)["Enabled"], "false") + + # add some new items + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"1000"})) + self.assertEqual(get_state_as_dict(addButton)["Enabled"], "true") + addButton.executeAction("CLICK", tuple()) + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"2000"})) + addButton.executeAction("CLICK", tuple()) + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"3000"})) + addButton.executeAction("CLICK", tuple()) + itemEntry.executeAction("TYPE", mkPropertyValues({"TEXT":"4000"})) + addButton.executeAction("CLICK", tuple()) + + # check whether the items are there in the list + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "2000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "4000") + + # select an item from the list and move it up + itemsList.getChild("1").executeAction("SELECT", tuple()) + self.assertEqual(get_state_as_dict(upButton)["Enabled"], "true") + self.assertEqual(get_state_as_dict(downButton)["Enabled"], "true") + upButton.executeAction("CLICK", tuple()) + self.assertEqual(get_state_as_dict(upButton)["Enabled"], "false") + self.assertEqual(get_state_as_dict(downButton)["Enabled"], "true") + + # check whether the item was correctly moved + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "2000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "4000") + + # move down the selected item + downButton.executeAction("CLICK", tuple()) + downButton.executeAction("CLICK", tuple()) + downButton.executeAction("CLICK", tuple()) + self.assertEqual(get_state_as_dict(upButton)["Enabled"], "true") + self.assertEqual(get_state_as_dict(downButton)["Enabled"], "false") + + # check whether the item was correctly moved + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "4000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "2000") + + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + # check whether items are the same after reopening + self.ui_test.execute_dialog_through_command(".uno:ControlProperties") + xDialog = self.xUITest.getTopFocusWindow() + + itemsList = xDialog.getChild("items_treeview") + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "4000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "2000") + + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + self.ui_test.close_doc() + + def test_drop_down_after_import(self): + + files = ["drop_down_form_field.odt", "drop_down_form_field.doc", "drop_down_form_field.docx"] + for file in files: + # open a file with a drop-down for field with items and selection + writer_doc = self.ui_test.load_file(get_url_for_data_file(file)) + document = self.ui_test.get_component() + xWriterDoc = self.xUITest.getTopFocusWindow() + + # open the dialog (cursor is at the field) + self.ui_test.execute_dialog_through_command(".uno:ControlProperties") + xDialog = self.xUITest.getTopFocusWindow() + + itemsList = xDialog.getChild("items_treeview") + + # check whether the items are there in the list + self.assertEqual(get_state_as_dict(itemsList)["Children"], "4") + self.assertEqual(get_state_as_dict(itemsList.getChild("0"))["Text"], "1000") + self.assertEqual(get_state_as_dict(itemsList.getChild("1"))["Text"], "2000") + self.assertEqual(get_state_as_dict(itemsList.getChild("2"))["Text"], "3000") + self.assertEqual(get_state_as_dict(itemsList.getChild("3"))["Text"], "4000") + + self.assertEqual(get_state_as_dict(itemsList)["SelectEntryText"], "3000") + + xOKBtn = xDialog.getChild("ok") + self.ui_test.close_dialog_through_button(xOKBtn) + + self.ui_test.close_doc() + +# vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/sw/source/ui/fldui/DropDownFormFieldDialog.cxx b/sw/source/ui/fldui/DropDownFormFieldDialog.cxx index 3b30aaf9131a..ccd9829ce5f2 100644 --- a/sw/source/ui/fldui/DropDownFormFieldDialog.cxx +++ b/sw/source/ui/fldui/DropDownFormFieldDialog.cxx @@ -28,7 +28,7 @@ DropDownFormFieldDialog::DropDownFormFieldDialog(weld::Window* pParent, , m_xListDownButton(m_xBuilder->weld_button("down_button")) { m_xListItemEntry->connect_key_press(LINK(this, DropDownFormFieldDialog, KeyPressedHdl)); - m_xListItemEntry->connect_key_release(LINK(this, DropDownFormFieldDialog, KeyReleasedHdl)); + m_xListItemEntry->connect_changed(LINK(this, DropDownFormFieldDialog, EntryChangedHdl)); m_xListItemsTreeView->set_size_request(m_xListItemEntry->get_preferred_size().Width(), m_xListItemEntry->get_preferred_size().Height() * 5); @@ -57,10 +57,9 @@ IMPL_LINK(DropDownFormFieldDialog, KeyPressedHdl, const KeyEvent&, rEvent, bool) return false; } -IMPL_LINK_NOARG(DropDownFormFieldDialog, KeyReleasedHdl, const KeyEvent&, bool) +IMPL_LINK_NOARG(DropDownFormFieldDialog, EntryChangedHdl, weld::Entry&, void) { UpdateButtons(); - return false; } IMPL_LINK(DropDownFormFieldDialog, ButtonPushedHdl, weld::Button&, rButton, void) diff --git a/sw/source/uibase/inc/DropDownFormFieldDialog.hxx b/sw/source/uibase/inc/DropDownFormFieldDialog.hxx index 3fbb59db0ebc..aee5c5232845 100644 --- a/sw/source/uibase/inc/DropDownFormFieldDialog.hxx +++ b/sw/source/uibase/inc/DropDownFormFieldDialog.hxx @@ -41,7 +41,7 @@ private: DECL_LINK(ListChangedHdl, weld::TreeView&, void); DECL_LINK(KeyPressedHdl, const KeyEvent&, bool); - DECL_LINK(KeyReleasedHdl, const KeyEvent&, bool); + DECL_LINK(EntryChangedHdl, weld::Entry&, void); DECL_LINK(ButtonPushedHdl, weld::Button&, void); void InitControls(); commit 7a75c1fb145f22d5272f5f5814262c9da200a38d Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Wed Mar 6 16:58:17 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Fri Mar 8 17:17:04 2019 +0100 MSForms: Test insertion of form fields and undo / redo of this insertion. Change-Id: I526faceab8eb1ce2f16d41ab1bed8cfb1bfcca24 diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx index dfd8d747f72f..697ec3533b59 100644 --- a/sw/qa/extras/uiwriter/uiwriter2.cxx +++ b/sw/qa/extras/uiwriter/uiwriter2.cxx @@ -30,6 +30,7 @@ #include <anchoredobject.hxx> #include <swtypes.hxx> #include <fmtornt.hxx> +#include <xmloff/odffields.hxx> namespace { @@ -89,6 +90,10 @@ public: CPPUNIT_TEST(testTdf52391); CPPUNIT_TEST(testTdf101873); CPPUNIT_TEST(testTableWidth); + CPPUNIT_TEST(testTextFormFieldInsertion); + CPPUNIT_TEST(testCheckboxFormFieldInsertion); + CPPUNIT_TEST(testDropDownFormFieldInsertion); + CPPUNIT_TEST(testMixedFormFieldInsertion); CPPUNIT_TEST_SUITE_END(); private: @@ -937,6 +942,150 @@ void SwUiWriterTest2::testTableWidth() getProperty<sal_Int16>(xTables->getByIndex(0), "RelativeWidth")); } +void SwUiWriterTest2::testTextFormFieldInsertion() +{ + load(DATA_DIRECTORY, "frame_size_export.docx"); + 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(pListEntries == pParameters->end()); + auto pResult = pParameters->find(ODF_FORMDROPDOWN_RESULT); + CPPUNIT_ASSERT(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 a3ed7b96abced43a41f859b345b3f19ba11a968a 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: Fri Mar 8 17:17:04 2019 +0100 MSForms: Add some extra comments for the new code 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 14a6ac2327df36b29bfd023a9f11df87966ee2bd Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Tue Mar 5 21:07:32 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Fri Mar 8 17:17:03 2019 +0100 MSForms: Test legacy form field import / export for the supported formats. Change-Id: Idbb80d097b21386e7d2673290a318d98b92125d5 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(); diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx index 2f248a996b7c..dfd8d747f72f 100644 --- a/sw/qa/extras/uiwriter/uiwriter2.cxx +++ b/sw/qa/extras/uiwriter/uiwriter2.cxx @@ -62,6 +62,10 @@ public: void testTdf52391(); void testTdf101873(); void testTableWidth(); + void testTextFormFieldInsertion(); + void testCheckboxFormFieldInsertion(); + void testDropDownFormFieldInsertion(); + void testMixedFormFieldInsertion(); CPPUNIT_TEST_SUITE(SwUiWriterTest2); CPPUNIT_TEST(testRedlineMoveInsertInDelete); commit f1faffac924ba2c022e5d7a0ea284826b6f890d9 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Tue Mar 5 19:40:08 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Fri Mar 8 17:17:02 2019 +0100 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 diff --git a/sw/source/core/crsr/DropDownFormFieldButton.cxx b/sw/source/core/crsr/DropDownFormFieldButton.cxx index d3a50b653dca..202622022fc1 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 09564999d321..3b30aaf9131a 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 34b08c2b4ece6bd3699cd9331e234ba0a293eb58 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: Fri Mar 8 17:17:02 2019 +0100 MSForms: Open Control Properties dialog by double click for drop-down field Change-Id: I66c0a7bad63d929ae346afe9d328d87dfa2c24ae diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 85d24b1d61c5..6ee65c5fdd7d 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -3364,6 +3364,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 fb95d4aa02a10688b9b6ceb4bd1f4899c754f5c3 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Mon Mar 4 20:52:38 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Fri Mar 8 17:17:01 2019 +0100 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. Change-Id: I5c7db138d14380899fee046c95a5afe14cfea213 diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index 4294c4f1e520..fff03ed1ffb5 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -598,7 +598,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 939838d3dfc2..1cd8d8cb1613 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 c8671f015e91..2093a2d8c14f 100644 --- a/sw/inc/strings.hrc +++ b/sw/inc/strings.hrc @@ -1328,6 +1328,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 66c61eef6dc5..d2fade9a1901 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..d3a50b653dca --- /dev/null +++ b/sw/source/core/crsr/DropDownFormFieldButton.cxx @@ -0,0 +1,247 @@ +/* -*- 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::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(); + Show(false); // Hide the button here and make it visible later, to make transparent background work with SAL_USE_VCLPLUGIN=gen + Invalidate(); +} + +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 = Color(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 4bb6d6780295..2e2a5417d0a0 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; @@ -481,11 +482,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) @@ -511,6 +514,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 af7a56200564..f04c7a06e1f8 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -2009,6 +2009,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 6014215f9e70..13b1926ee62f 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -54,6 +54,7 @@ #include <viscrs.hxx> #include <edimp.hxx> #include <tools/datetimeutils.hxx> +#include <view.hxx> using namespace ::sw::mark; @@ -372,6 +373,7 @@ namespace sw { namespace mark , m_vFieldmarks() , m_vAnnotationMarks() , m_pDoc(&rDoc) + , m_pLastActiveFieldmark(nullptr) { } ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM, @@ -956,6 +958,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)); } @@ -1031,6 +1036,7 @@ namespace sw { namespace mark void MarkManager::clearAllMarks() { + ClearFieldActivation(); m_vFieldmarks.clear(); m_vBookmarks.clear(); @@ -1117,10 +1123,61 @@ namespace sw { namespace mark SwPaM aPaM = SwPaM(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..abe159860d6f --- /dev/null +++ b/sw/source/core/inc/DropDownFormFieldButton.hxx @@ -0,0 +1,53 @@ +/* -*- 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; + + void CalcPosAndSize(const SwRect& rPortionPaintArea); + + virtual void MouseButtonUp(const MouseEvent& rMEvt) override; + DECL_DLLPRIVATE_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 71ad5c913d6c..11291f7b881a 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(xmlTextWriterPtr pWriter) const; // Annotation Marks @@ -125,6 +133,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 3bde575ab399..9f6c8af89f34 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 2697f3022639..fa56ada86eba 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 e2a482e870dc..2a52f9b539c7 100644 --- a/sw/source/core/text/porfld.cxx +++ b/sw/source/core/text/porfld.cxx @@ -43,6 +43,7 @@ #include <accessibilityoptions.hxx> #include <editeng/lrspitem.hxx> #include <unicode/ubidi.h> +#include <bookmrk.hxx> using namespace ::com::sun::star; @@ -1310,7 +1311,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 4434f1e8c577..069ab3798060 100644 --- a/sw/source/core/text/porfld.hxx +++ b/sw/source/core/text/porfld.hxx @@ -217,12 +217,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 22458d77b710..85d24b1d61c5 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -4627,12 +4627,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 65484c32e748..c70e84156b97 100644 --- a/sw/source/uibase/shells/textsh1.cxx +++ b/sw/source/uibase/shells/textsh1.cxx @@ -120,6 +120,8 @@ #include <numrule.hxx> #include <memory> #include <xmloff/odffields.hxx> +#include <swabstdlg.hxx> +#include <bookmrk.hxx> using namespace ::com::sun::star; using namespace com::sun::star::beans; @@ -1382,10 +1384,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 63febf29b44a..59fc540e0d35 100644 --- a/sw/source/uibase/uiview/view.cxx +++ b/sw/source/uibase/uiview/view.cxx @@ -1067,6 +1067,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 7d6aac2913d9..3ac2ebcadd3e 100644 --- a/sw/source/uibase/uiview/viewling.cxx +++ b/sw/source/uibase/uiview/viewling.cxx @@ -825,114 +825,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 4cd2cc499df4d4d03bb690c917a6faf90bb30713 Author: Tamás Zolnai <tamas.zol...@collabora.com> AuthorDate: Sat Mar 2 08:41:01 2019 +0100 Commit: Tamás Zolnai <tamas.zol...@collabora.com> CommitDate: Fri Mar 8 17:16:49 2019 +0100 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. Change-Id: I3103e6b1c36289b27b62ab9ca7dfeebc14901c8a 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 92bb4c67d786..4bb6d6780295 100644 --- a/sw/source/core/crsr/bookmrk.cxx +++ b/sw/source/core/crsr/bookmrk.cxx @@ -478,6 +478,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 e06908f3438a..6014215f9e70 100644 --- a/sw/source/core/doc/docbm.cxx +++ b/sw/source/core/doc/docbm.cxx @@ -338,6 +338,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 @@ -414,6 +416,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; @@ -462,6 +467,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: @@ -522,9 +528,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 ); @@ -934,6 +951,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() ) @@ -1077,6 +1095,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 = SwPaM(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 cbae235520e8..71ad5c913d6c 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(xmlTextWriterPtr pWriter) const; diff --git a/sw/source/core/inc/bookmrk.hxx b/sw/source/core/inc/bookmrk.hxx index 9bf1c9d7679c..3bde575ab399 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 95763c1b0a09..5c38402ba17c 100644 --- a/sw/source/core/inc/unobookmark.hxx +++ b/sw/source/core/inc/unobookmark.hxx @@ -68,6 +68,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 631373f98d99..2697f3022639 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 753263a2aa6f..0a53c27c4516 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()) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits