tdf#154545 sw Navigator: select & track nested bookmarks
After selecting a nested bookmark in the Navigator with
double click or Enter, the selected item changed to the
item of the main bookmark in the tree list. This jumping
was very annoying especially with multiple nested bookmarks
inside the same bookmark.
Navigator didn't track nested bookmarks, i.e. it always
showed the main bookmark instead of the actual nested one
under the text cursor.
Change-Id: Ic3f1e8321454d4ad892708e76c001da6eca30cf9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149915
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/uitest/navigator/tdf154521.py b/sw/qa/uitest/navigator/tdf154521.py
index 0dca5037..ac3c21d 100644
--- a/sw/qa/uitest/navigator/tdf154521.py
+++ b/sw/qa/uitest/navigator/tdf154521.py
@@ -38,12 +38,6 @@ class tdf154521(UITestCase):
global selectionChangedResult
with self.ui_test.create_doc_in_start_center("writer") as xDoc:
# type "foo", and create a bookmark on it
self.xUITest.executeCommand(".uno:Escape")
# click on the bookmark name in the Navigator
xWriterDoc = self.xUITest.getTopFocusWindow()
xWriterEdit = xWriterDoc.getChild("writer_edit")
@@ -54,6 +48,10 @@ class tdf154521(UITestCase):
xToolBar = xNavigatorPanel.getChild("content5")
xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "0"})) # 'root' button
# type "foo", and create a bookmark on it
self.xUITest.executeCommand(".uno:Escape")
xDoc.Text.insertString(xDoc.Text.getStart(), "foo", False)
self.xUITest.executeCommand(".uno:SelectAll")
diff --git a/sw/qa/uitest/navigator/tdf154545.py b/sw/qa/uitest/navigator/tdf154545.py
new file mode 100644
index 0000000..718f689
--- /dev/null
+++ b/sw/qa/uitest/navigator/tdf154545.py
@@ -0,0 +1,98 @@
# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
#
# 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/.
#
from uitest.framework import UITestCase
from libreoffice.uno.propertyvalue import mkPropertyValues
from uitest.uihelper.common import get_state_as_dict
import unohelper
class tdf154545(UITestCase):
def test_tdf154545(self):
global selectionChangedResult
with self.ui_test.create_doc_in_start_center("writer") as xDoc:
# click on the bookmark name in the Navigator
xWriterDoc = self.xUITest.getTopFocusWindow()
xWriterEdit = xWriterDoc.getChild("writer_edit")
self.xUITest.executeCommand(".uno:Sidebar")
xWriterEdit.executeAction("SIDEBAR", mkPropertyValues({"PANEL": "SwNavigatorPanel"}))
xNavigatorPanel = xWriterEdit.getChild("NavigatorPanel")
xToolBar = xNavigatorPanel.getChild("content5")
xToolBar.executeAction("CLICK", mkPropertyValues({"POS": "0"})) # 'root' button
# type "foo", and create a bookmark on it
xDoc.Text.insertString(xDoc.Text.getStart(), "foo", False)
self.xUITest.executeCommand(".uno:SelectAll")
with self.ui_test.execute_dialog_through_command(".uno:InsertBookmark", close_button="insert"):
pass
# check selected bookmark in Navigator
xWriterEdit.executeAction("FOCUS", tuple())
xContentTree = xNavigatorPanel.getChild("contenttree")
self.ui_test.wait_until_property_is_updated(xContentTree, "SelectEntryText", "Bookmark 1")
self.assertEqual(get_state_as_dict(xContentTree)["SelectEntryText"], "Bookmark 1")
self.assertEqual(get_state_as_dict(xContentTree)["SelectionCount"], "1")
self.xUITest.executeCommand(".uno:Escape")
# create a nested bookmark on the last "o"
cursor = xDoc.getCurrentController().getViewCursor()
cursor.goLeft(1, True)
with self.ui_test.execute_dialog_through_command(".uno:InsertBookmark", close_button="insert"):
pass
self.xUITest.executeCommand(".uno:Escape")
# check selected nested bookmark in Navigator
# This never occured: Navigator didn't track nested bookmarks
self.ui_test.wait_until_property_is_updated(xContentTree, "SelectEntryText", "Bookmark 2")
# This was Bookmark 1
self.assertEqual(get_state_as_dict(xContentTree)["SelectEntryText"], "Bookmark 2")
self.assertEqual(get_state_as_dict(xContentTree)["SelectionCount"], "1")
# Select nested bookmark in Navigator
xContentTree.executeAction("TYPE", mkPropertyValues({"KEYCODE": "RETURN"}))
# This jumped to Bookmark 1 after selection
self.ui_test.wait_until_property_is_updated(xContentTree, "SelectEntryText", "Bookmark 2")
# This was Bookmark 1
self.assertEqual(get_state_as_dict(xContentTree)["SelectEntryText"], "Bookmark 2")
self.assertEqual(get_state_as_dict(xContentTree)["SelectionCount"], "1")
# Try the same selection with Bookmark 1
xContentTree.executeAction("TYPE", mkPropertyValues({"KEYCODE": "UP"}))
self.ui_test.wait_until_property_is_updated(xContentTree, "SelectEntryText", "Bookmark 1")
self.assertEqual(get_state_as_dict(xContentTree)["SelectEntryText"], "Bookmark 1")
self.assertEqual(get_state_as_dict(xContentTree)["SelectionCount"], "1")
xContentTree.executeAction("TYPE", mkPropertyValues({"KEYCODE": "RETURN"}))
self.ui_test.wait_until_property_is_updated(xContentTree, "SelectEntryText", "Bookmark 1")
self.assertEqual(get_state_as_dict(xContentTree)["SelectEntryText"], "Bookmark 1")
self.assertEqual(get_state_as_dict(xContentTree)["SelectionCount"], "1")
# go to the previous item
xContentTree.executeAction("TYPE", mkPropertyValues({"KEYCODE": "UP"}))
self.ui_test.wait_until_property_is_updated(xContentTree, "SelectEntryText", "Bookmarks")
self.assertEqual(get_state_as_dict(xContentTree)["SelectEntryText"], "Bookmarks")
self.xUITest.executeCommand(".uno:Sidebar")
# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/uibase/inc/conttree.hxx b/sw/source/uibase/inc/conttree.hxx
index 587f1ce..5bcdc90 100644
--- a/sw/source/uibase/inc/conttree.hxx
+++ b/sw/source/uibase/inc/conttree.hxx
@@ -100,6 +100,7 @@ class SwContentTree final : public SfxListener
o3tl::enumarray<ContentTypeId,std::unique_ptr<SwContentType>> m_aHiddenContentArr;
OUString m_aContextStrings[CONTEXT_COUNT + 1];
OUString m_sInvisible;
OUString m_sSelectedItem; // last selected item (only bookmarks yet)
SwWrtShell* m_pHiddenShell; // dropped Doc
SwWrtShell* m_pActiveShell; // the active or a const. open view
diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx
index 806b207..9d9732a 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -3917,6 +3917,7 @@ void SwContentTree::UpdateTracking()
if (pCursor && ppBookmark != pMarkAccess->getBookmarksEnd() &&
!(m_bIsRoot && m_nRootType != ContentTypeId::BOOKMARK))
{
OUString sBookmarkName;
SwPosition* pCursorPoint = pCursor->GetPoint();
while (ppBookmark != pMarkAccess->getBookmarksEnd())
{
@@ -3924,13 +3925,32 @@ void SwContentTree::UpdateTracking()
*pCursorPoint >= (*ppBookmark)->GetMarkStart() &&
*pCursorPoint <= (*ppBookmark)->GetMarkEnd())
{
lcl_SelectByContentTypeAndName(this, *m_xTreeView,
SwResId(STR_CONTENT_TYPE_BOOKMARK),
(*ppBookmark)->GetName());
return;
sBookmarkName = (*ppBookmark)->GetName();
// keep previously selected bookmark instead
// of selecting a different bookmark inside of it
if (sBookmarkName == m_sSelectedItem)
break;
}
else if (!sBookmarkName.isEmpty() &&
*pCursorPoint < (*ppBookmark)->GetMarkStart())
{
// don't search a different bookmark inside the
// previous one, if the starting position of the next bookmarks
// is after the cursor position (assuming that the
// bookmark iterator jumps inside the same text by positions)
break;
}
++ppBookmark;
}
if (!sBookmarkName.isEmpty())
{
// select the bookmark
lcl_SelectByContentTypeAndName(this, *m_xTreeView,
SwResId(STR_CONTENT_TYPE_BOOKMARK),
sBookmarkName);
return;
}
}
}
// references
@@ -5342,6 +5362,7 @@ void SwContentTree::CopyOutlineSelections()
void SwContentTree::GotoContent(const SwContent* pCnt)
{
m_nLastGotoContentWasOutlinePos = SwOutlineNodes::npos;
m_sSelectedItem = "";
lcl_AssureStdModeAtShell(m_pActiveShell);
switch(m_nLastSelType = pCnt->GetParent()->GetType())
{
@@ -5376,6 +5397,7 @@ void SwContentTree::GotoContent(const SwContent* pCnt)
m_pActiveShell->StartAction();
m_pActiveShell->GotoMark(pCnt->GetName());
m_pActiveShell->EndAction();
m_sSelectedItem = pCnt->GetName();
}
break;
case ContentTypeId::REGION :