tdf#95378 Writer Navigator document content tracking
This patch adds document content tracking for tables, frames, images, OLE objects and drawing objects. Change-Id: I99af15d2da9f4f97d8702b5a9cad4fc21b676166 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101253 Tested-by: Jenkins Reviewed-by: Jim Raykowski <raykowj@gmail.com>
This commit is contained in:
@@ -1882,11 +1882,8 @@ IMPL_LINK_NOARG(SwContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
|
|||||||
SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64());
|
SwContent* pCnt = reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xEntry).toInt64());
|
||||||
assert(pCnt && "no UserData");
|
assert(pCnt && "no UserData");
|
||||||
GotoContent(pCnt);
|
GotoContent(pCnt);
|
||||||
const ContentTypeId nActType = pCnt->GetParent()->GetType();
|
|
||||||
if (nActType == ContentTypeId::FRAME)
|
|
||||||
m_pActiveShell->EnterStdMode();
|
|
||||||
// fdo#36308 don't expand outlines on double-click
|
// fdo#36308 don't expand outlines on double-click
|
||||||
bConsumed = nActType == ContentTypeId::OUTLINE;
|
bConsumed = pCnt->GetParent()->GetType() == ContentTypeId::OUTLINE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3087,6 +3084,42 @@ void SwContentTree::HideTree()
|
|||||||
m_xTreeView->hide();
|
m_xTreeView->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void lcl_SelectByContentTypeAndName(SwContentTree* pThis, weld::TreeView& rContentTree,
|
||||||
|
const OUString& rContentTypeName, const OUString& rName)
|
||||||
|
{
|
||||||
|
if (!rName.isEmpty())
|
||||||
|
{
|
||||||
|
// find content type entry
|
||||||
|
std::unique_ptr<weld::TreeIter> xIter(rContentTree.make_iterator());
|
||||||
|
bool bFoundEntry = rContentTree.get_iter_first(*xIter);
|
||||||
|
while (bFoundEntry && rContentTypeName != rContentTree.get_text(*xIter))
|
||||||
|
bFoundEntry = rContentTree.iter_next_sibling(*xIter);
|
||||||
|
// find content type content entry and select it
|
||||||
|
if (bFoundEntry)
|
||||||
|
{
|
||||||
|
rContentTree.expand_row(*xIter); // assure content type entry is expanded
|
||||||
|
while (rContentTree.iter_next(*xIter) && lcl_IsContent(*xIter, rContentTree))
|
||||||
|
{
|
||||||
|
if (rName == rContentTree.get_text(*xIter))
|
||||||
|
{
|
||||||
|
// get first selected for comparison
|
||||||
|
std::unique_ptr<weld::TreeIter> xFirstSelected(rContentTree.make_iterator());
|
||||||
|
if (!rContentTree.get_selected(xFirstSelected.get()))
|
||||||
|
xFirstSelected.reset();
|
||||||
|
if (rContentTree.count_selected_rows() != 1 ||
|
||||||
|
rContentTree.iter_compare(*xIter, *xFirstSelected) != 0)
|
||||||
|
{
|
||||||
|
// unselect all entries and make passed entry visible and selected
|
||||||
|
rContentTree.set_cursor(*xIter);
|
||||||
|
pThis->Select();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** No idle with focus or while dragging */
|
/** No idle with focus or while dragging */
|
||||||
IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void)
|
IMPL_LINK_NOARG(SwContentTree, TimerUpdate, Timer *, void)
|
||||||
{
|
{
|
||||||
@@ -3136,72 +3169,131 @@ void SwContentTree::UpdateTracking()
|
|||||||
if (State::HIDDEN == m_eState)
|
if (State::HIDDEN == m_eState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// track document outline position at cursor
|
// m_bIgnoreViewChange is set on delete
|
||||||
if (m_nOutlineTracking == 3) // no outline tracking
|
if (m_bIgnoreViewChange)
|
||||||
|
{
|
||||||
|
m_bIgnoreViewChange = false;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL); // find out where the cursor is
|
// drawing
|
||||||
if (nActPos == SwOutlineNodes::npos)
|
if ((m_pActiveShell->GetSelectionType() & (SelectionType::DrawObject |
|
||||||
return;
|
SelectionType::DrawObjectEditMode)) &&
|
||||||
|
!(m_bIsRoot && m_nRootType != ContentTypeId::DRAWOBJECT))
|
||||||
// only track if selection is already an outline
|
{
|
||||||
std::unique_ptr<weld::TreeIter> xFirstSelected(m_xTreeView->make_iterator());
|
SdrView* pSdrView = m_pActiveShell->GetDrawView();
|
||||||
if (!m_xTreeView->get_selected(xFirstSelected.get()))
|
if(pSdrView && 1 == pSdrView->GetMarkedObjectCount())
|
||||||
xFirstSelected.reset();
|
|
||||||
if (xFirstSelected && lcl_IsContent(*xFirstSelected, *m_xTreeView) &&
|
|
||||||
reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xFirstSelected).toInt64())->GetParent()->GetType() != ContentTypeId::OUTLINE)
|
|
||||||
return;
|
|
||||||
if (xFirstSelected && lcl_IsContentType(*xFirstSelected, *m_xTreeView) &&
|
|
||||||
reinterpret_cast<SwContentType*>(m_xTreeView->get_id(*xFirstSelected).toInt64())->GetType() != ContentTypeId::OUTLINE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int nSelectedRows = m_xTreeView->count_selected_rows();
|
|
||||||
|
|
||||||
// find the outline in the tree and select it
|
|
||||||
m_xTreeView->all_foreach([this, nSelectedRows, nActPos, &xFirstSelected](weld::TreeIter& rEntry){
|
|
||||||
bool bRet = false;
|
|
||||||
|
|
||||||
if (lcl_IsContent(rEntry, *m_xTreeView) &&
|
|
||||||
reinterpret_cast<SwContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetParent()->GetType() == ContentTypeId::OUTLINE)
|
|
||||||
{
|
{
|
||||||
// might have been scrolled out of view by the user so leave it that way
|
SdrObject* pSelected = pSdrView->GetMarkedObjectByIndex(0);
|
||||||
if (reinterpret_cast<SwOutlineContent*>(m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos() == nActPos)
|
OUString aName(pSelected->GetName());
|
||||||
|
lcl_SelectByContentTypeAndName(this, *m_xTreeView,
|
||||||
|
SwResId(STR_CONTENT_TYPE_DRAWOBJECT), aName);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// graphic, frame, and ole
|
||||||
|
OUString aContentTypeName;
|
||||||
|
if (m_pActiveShell->GetSelectionType() == SelectionType::Graphic &&
|
||||||
|
!(m_bIsRoot && m_nRootType != ContentTypeId::GRAPHIC))
|
||||||
|
aContentTypeName = SwResId(STR_CONTENT_TYPE_GRAPHIC);
|
||||||
|
else if (m_pActiveShell->GetSelectionType() == SelectionType::Frame &&
|
||||||
|
!(m_bIsRoot && m_nRootType != ContentTypeId::FRAME))
|
||||||
|
aContentTypeName = SwResId(STR_CONTENT_TYPE_FRAME);
|
||||||
|
else if (m_pActiveShell->GetSelectionType() == SelectionType::Ole &&
|
||||||
|
!(m_bIsRoot && m_nRootType != ContentTypeId::OLE))
|
||||||
|
aContentTypeName = SwResId(STR_CONTENT_TYPE_OLE);
|
||||||
|
if (!aContentTypeName.isEmpty())
|
||||||
|
{
|
||||||
|
OUString aName(m_pActiveShell->GetFlyName());
|
||||||
|
lcl_SelectByContentTypeAndName(this, *m_xTreeView, aContentTypeName, aName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// table
|
||||||
|
if (m_pActiveShell->IsCursorInTable() &&
|
||||||
|
!(m_bIsRoot && m_nRootType != ContentTypeId::TABLE))
|
||||||
|
{
|
||||||
|
if(m_pActiveShell->GetTableFormat())
|
||||||
|
{
|
||||||
|
OUString aName = m_pActiveShell->GetTableFormat()->GetName();
|
||||||
|
lcl_SelectByContentTypeAndName(this, *m_xTreeView, SwResId(STR_CONTENT_TYPE_TABLE),
|
||||||
|
aName);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// outline
|
||||||
|
// find out where the cursor is
|
||||||
|
const SwOutlineNodes::size_type nActPos = GetWrtShell()->GetOutlinePos(MAXLEVEL);
|
||||||
|
if (!((m_bIsRoot && m_nRootType != ContentTypeId::OUTLINE) ||
|
||||||
|
m_nOutlineTracking == 3 || nActPos == SwOutlineNodes::npos))
|
||||||
|
{
|
||||||
|
// assure outline content type is expanded
|
||||||
|
// this assumes outline content type is first in treeview
|
||||||
|
std::unique_ptr<weld::TreeIter> xFirstEntry(m_xTreeView->make_iterator());
|
||||||
|
m_xTreeView->get_iter_first(*xFirstEntry);
|
||||||
|
m_xTreeView->expand_row(*xFirstEntry);
|
||||||
|
|
||||||
|
m_xTreeView->all_foreach([this, nActPos](weld::TreeIter& rEntry){
|
||||||
|
bool bRet = false;
|
||||||
|
if (lcl_IsContent(rEntry, *m_xTreeView) && reinterpret_cast<SwContent*>(
|
||||||
|
m_xTreeView->get_id(rEntry).toInt64())->GetParent()->GetType() ==
|
||||||
|
ContentTypeId::OUTLINE)
|
||||||
{
|
{
|
||||||
// only select if not already selected or tree has multiple entries selected
|
if (reinterpret_cast<SwOutlineContent*>(
|
||||||
if (nSelectedRows != 1 || m_xTreeView->iter_compare(rEntry, *xFirstSelected) != 0)
|
m_xTreeView->get_id(rEntry).toInt64())->GetOutlinePos() == nActPos)
|
||||||
{
|
{
|
||||||
if (m_nOutlineTracking == 2) // focused outline tracking
|
std::unique_ptr<weld::TreeIter> xFirstSelected(
|
||||||
|
m_xTreeView->make_iterator());
|
||||||
|
if (!m_xTreeView->get_selected(xFirstSelected.get()))
|
||||||
|
xFirstSelected.reset();
|
||||||
|
// only select if not already selected or tree has multiple entries selected
|
||||||
|
if (m_xTreeView->count_selected_rows() != 1 ||
|
||||||
|
m_xTreeView->iter_compare(rEntry, *xFirstSelected) != 0)
|
||||||
{
|
{
|
||||||
// collapse to children of root node
|
if (m_nOutlineTracking == 2) // focused outline tracking
|
||||||
std::unique_ptr<weld::TreeIter> xChildEntry(m_xTreeView->make_iterator());
|
|
||||||
if (m_xTreeView->get_iter_first(*xChildEntry) && m_xTreeView->iter_children(*xChildEntry))
|
|
||||||
{
|
{
|
||||||
do
|
// collapse to children of root node
|
||||||
|
std::unique_ptr<weld::TreeIter> xChildEntry(
|
||||||
|
m_xTreeView->make_iterator());
|
||||||
|
if (m_xTreeView->get_iter_first(*xChildEntry) &&
|
||||||
|
m_xTreeView->iter_children(*xChildEntry))
|
||||||
{
|
{
|
||||||
if (reinterpret_cast<SwContent*>(m_xTreeView->get_id(*xChildEntry).toInt64())->GetParent()->GetType() == ContentTypeId::OUTLINE)
|
do
|
||||||
m_xTreeView->collapse_row(*xChildEntry);
|
{
|
||||||
else
|
if (reinterpret_cast<SwContent*>(
|
||||||
break;
|
m_xTreeView->get_id(*xChildEntry).toInt64())->
|
||||||
|
GetParent()->GetType() == ContentTypeId::OUTLINE)
|
||||||
|
m_xTreeView->collapse_row(*xChildEntry);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (m_xTreeView->iter_next(*xChildEntry));
|
||||||
}
|
}
|
||||||
while (m_xTreeView->iter_next(*xChildEntry));
|
|
||||||
}
|
}
|
||||||
|
// unselect all entries, make pEntry visible, and select
|
||||||
|
m_xTreeView->set_cursor(rEntry);
|
||||||
|
Select();
|
||||||
}
|
}
|
||||||
m_xTreeView->set_cursor(rEntry); // unselect all entries, make pEntry visible, and select
|
bRet = true;
|
||||||
Select();
|
|
||||||
}
|
}
|
||||||
bRet = true;
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
{
|
||||||
{
|
// use of this break assumes outline content type is first in tree
|
||||||
// use of this break assumes outline content type is first in tree
|
if (lcl_IsContentType(rEntry, *m_xTreeView) &&
|
||||||
if (lcl_IsContentType(rEntry, *m_xTreeView) &&
|
reinterpret_cast<SwContentType*>(
|
||||||
reinterpret_cast<SwContentType*>(m_xTreeView->get_id(rEntry).toInt64())->GetType() != ContentTypeId::OUTLINE)
|
m_xTreeView->get_id(rEntry).toInt64())->GetType() !=
|
||||||
bRet = true;
|
ContentTypeId::OUTLINE)
|
||||||
}
|
bRet = true;
|
||||||
|
}
|
||||||
return bRet;
|
return bRet;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// clear treeview selections
|
||||||
|
m_xTreeView->unselect_all();
|
||||||
|
Select();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwContentTree::SelectOutlinesWithSelection()
|
void SwContentTree::SelectOutlinesWithSelection()
|
||||||
@@ -3940,6 +4032,9 @@ void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode)
|
|||||||
const ContentTypeId nType = pCnt->GetParent()->GetType();
|
const ContentTypeId nType = pCnt->GetParent()->GetType();
|
||||||
sal_uInt16 nSlot = 0;
|
sal_uInt16 nSlot = 0;
|
||||||
|
|
||||||
|
if(EditEntryMode::DELETE == nMode)
|
||||||
|
m_bIgnoreViewChange = true;
|
||||||
|
|
||||||
uno::Reference< container::XNameAccess > xNameAccess, xSecond, xThird;
|
uno::Reference< container::XNameAccess > xNameAccess, xSecond, xThird;
|
||||||
switch(nType)
|
switch(nType)
|
||||||
{
|
{
|
||||||
@@ -4134,7 +4229,7 @@ void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode)
|
|||||||
}
|
}
|
||||||
if(nSlot)
|
if(nSlot)
|
||||||
m_pActiveShell->GetView().GetViewFrame()->
|
m_pActiveShell->GetView().GetViewFrame()->
|
||||||
GetDispatcher()->Execute(nSlot, SfxCallMode::ASYNCHRON);
|
GetDispatcher()->Execute(nSlot, SfxCallMode::SYNCHRON);
|
||||||
else if(xNameAccess.is())
|
else if(xNameAccess.is())
|
||||||
{
|
{
|
||||||
uno::Any aObj = xNameAccess->getByName(pCnt->GetName());
|
uno::Any aObj = xNameAccess->getByName(pCnt->GetName());
|
||||||
|
Reference in New Issue
Block a user