1612 lines
53 KiB
C++
1612 lines
53 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-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/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <string_view>
|
|
|
|
#include <svx/svditer.hxx>
|
|
#include <svx/svdobj.hxx>
|
|
#include <svx/svdview.hxx>
|
|
#include <sfx2/linkmgr.hxx>
|
|
#include <sfx2/docfile.hxx>
|
|
#include <sfx2/viewfrm.hxx>
|
|
#include <vcl/commandevent.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <tools/urlobj.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <unotools/charclass.hxx>
|
|
|
|
#include <content.hxx>
|
|
#include <navipi.hxx>
|
|
#include <global.hxx>
|
|
#include <docsh.hxx>
|
|
#include <docfunc.hxx>
|
|
#include <scmod.hxx>
|
|
#include <rangenam.hxx>
|
|
#include <dbdata.hxx>
|
|
#include <drwlayer.hxx>
|
|
#include <transobj.hxx>
|
|
#include <drwtrans.hxx>
|
|
#include <lnktrans.hxx>
|
|
#include <strings.hrc>
|
|
#include <scresid.hxx>
|
|
#include <bitmaps.hlst>
|
|
#include <arealink.hxx>
|
|
#include <navicfg.hxx>
|
|
#include <navsett.hxx>
|
|
#include <postit.hxx>
|
|
#include <tabvwsh.hxx>
|
|
#include <drawview.hxx>
|
|
#include <clipparam.hxx>
|
|
#include <markdata.hxx>
|
|
|
|
using namespace com::sun::star;
|
|
|
|
// order of the categories in navigator -------------------------------------
|
|
|
|
const ScContentId pTypeList[int(ScContentId::LAST) + 1] =
|
|
{
|
|
ScContentId::ROOT, // ROOT (0) has to be at the front
|
|
ScContentId::TABLE,
|
|
ScContentId::RANGENAME,
|
|
ScContentId::DBAREA,
|
|
ScContentId::AREALINK,
|
|
ScContentId::GRAPHIC,
|
|
ScContentId::OLEOBJECT,
|
|
ScContentId::NOTE,
|
|
ScContentId::DRAWING
|
|
};
|
|
|
|
constexpr OUString aContentBmps[]=
|
|
{
|
|
RID_BMP_CONTENT_TABLE,
|
|
RID_BMP_CONTENT_RANGENAME,
|
|
RID_BMP_CONTENT_DBAREA,
|
|
RID_BMP_CONTENT_GRAPHIC,
|
|
RID_BMP_CONTENT_OLEOBJECT,
|
|
RID_BMP_CONTENT_NOTE,
|
|
RID_BMP_CONTENT_AREALINK,
|
|
RID_BMP_CONTENT_DRAWING
|
|
};
|
|
|
|
ScDocShell* ScContentTree::GetManualOrCurrent()
|
|
{
|
|
ScDocShell* pSh = nullptr;
|
|
if ( !aManualDoc.isEmpty() )
|
|
{
|
|
SfxObjectShell* pObjSh = SfxObjectShell::GetFirst( checkSfxObjectShell<ScDocShell> );
|
|
while ( pObjSh && !pSh )
|
|
{
|
|
if ( pObjSh->GetTitle() == aManualDoc )
|
|
pSh = dynamic_cast<ScDocShell*>( pObjSh );
|
|
pObjSh = SfxObjectShell::GetNext( *pObjSh, checkSfxObjectShell<ScDocShell> );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// only current when manual isn't set
|
|
// (so it's detected when the documents don't exists any longer)
|
|
|
|
SfxViewShell* pViewSh = SfxViewShell::Current();
|
|
if ( pViewSh )
|
|
{
|
|
SfxObjectShell* pObjSh = pViewSh->GetViewFrame().GetObjectShell();
|
|
pSh = dynamic_cast<ScDocShell*>( pObjSh );
|
|
}
|
|
}
|
|
|
|
return pSh;
|
|
}
|
|
|
|
// ScContentTree
|
|
|
|
ScContentTree::ScContentTree(std::unique_ptr<weld::TreeView> xTreeView, ScNavigatorDlg* pNavigatorDlg)
|
|
: m_xTreeView(std::move(xTreeView))
|
|
, m_xScratchIter(m_xTreeView->make_iterator())
|
|
, m_xTransferObj(new ScLinkTransferObj)
|
|
, pParentWindow(pNavigatorDlg)
|
|
, nRootType(ScContentId::ROOT)
|
|
, bIsInNavigatorDlg(false)
|
|
, m_bFreeze(false)
|
|
, m_nAsyncMouseReleaseId(nullptr)
|
|
{
|
|
for (sal_uInt16 i = 0; i <= int(ScContentId::LAST); ++i)
|
|
pPosList[pTypeList[i]] = i; // inverse for searching
|
|
|
|
m_aRootNodes[ScContentId::ROOT] = nullptr;
|
|
for (sal_uInt16 i = 1; i < int(ScContentId::LAST); ++i)
|
|
InitRoot(static_cast<ScContentId>(i));
|
|
|
|
m_xTreeView->connect_row_activated(LINK(this, ScContentTree, ContentDoubleClickHdl));
|
|
m_xTreeView->connect_mouse_release(LINK(this, ScContentTree, MouseReleaseHdl));
|
|
m_xTreeView->connect_key_press(LINK(this, ScContentTree, KeyInputHdl));
|
|
m_xTreeView->connect_popup_menu(LINK(this, ScContentTree, CommandHdl));
|
|
m_xTreeView->connect_query_tooltip(LINK(this, ScContentTree, QueryTooltipHdl));
|
|
|
|
rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
|
|
m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
|
|
|
|
m_xTreeView->connect_drag_begin(LINK(this, ScContentTree, DragBeginHdl));
|
|
|
|
m_xTreeView->set_selection_mode( SelectionMode::Single );
|
|
|
|
m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
|
|
m_xTreeView->get_text_height() * 13);
|
|
}
|
|
|
|
ScContentTree::~ScContentTree()
|
|
{
|
|
if (m_nAsyncMouseReleaseId)
|
|
{
|
|
Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
|
|
m_nAsyncMouseReleaseId = nullptr;
|
|
}
|
|
}
|
|
|
|
const TranslateId SCSTR_CONTENT_ARY[] =
|
|
{
|
|
SCSTR_CONTENT_ROOT,
|
|
SCSTR_CONTENT_TABLE,
|
|
SCSTR_CONTENT_RANGENAME,
|
|
SCSTR_CONTENT_DBAREA,
|
|
SCSTR_CONTENT_GRAPHIC,
|
|
SCSTR_CONTENT_OLEOBJECT,
|
|
SCSTR_CONTENT_NOTE,
|
|
SCSTR_CONTENT_AREALINK,
|
|
SCSTR_CONTENT_DRAWING
|
|
};
|
|
|
|
void ScContentTree::InitRoot( ScContentId nType )
|
|
{
|
|
if ( nType == ScContentId::ROOT )
|
|
return;
|
|
|
|
if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
|
|
{
|
|
m_aRootNodes[nType] = nullptr;
|
|
return;
|
|
}
|
|
|
|
auto const & aImage = aContentBmps[static_cast<int>(nType) - 1];
|
|
|
|
OUString aName;
|
|
if(comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
//In case of LOK we may have many different ScContentTrees in different languages.
|
|
//At creation time, we store what language we use, and then use it later too.
|
|
//It does not work in the constructor, that is why it is here.
|
|
if (!m_pResLocaleForLOK)
|
|
{
|
|
m_pResLocaleForLOK = std::make_unique<std::locale>(ScModule::get()->GetResLocale());
|
|
}
|
|
aName = Translate::get(SCSTR_CONTENT_ARY[static_cast<int>(nType)], *m_pResLocaleForLOK);
|
|
}
|
|
else
|
|
{
|
|
aName = ScResId(SCSTR_CONTENT_ARY[static_cast<int>(nType)]);
|
|
}
|
|
// back to the correct position:
|
|
sal_uInt16 nPos = nRootType != ScContentId::ROOT ? 0 : pPosList[nType]-1;
|
|
m_aRootNodes[nType] = m_xTreeView->make_iterator();
|
|
m_xTreeView->insert(nullptr, nPos, &aName, nullptr, nullptr, nullptr, false, m_aRootNodes[nType].get());
|
|
m_xTreeView->set_image(*m_aRootNodes[nType], aImage);
|
|
}
|
|
|
|
void ScContentTree::ClearAll()
|
|
{
|
|
//There are one method in Control::SetUpdateMode(), and one override method SvTreeListBox::SetUpdateMode(). Here although
|
|
//SvTreeListBox::SetUpdateMode() is called in refresh method, it only call SvTreeListBox::SetUpdateMode(), not Control::SetUpdateMode().
|
|
//In m_xTreeView->clear(), Broadcast( LISTACTION_CLEARED ) will be called and finally, it will be trapped into the event yield() loop. And
|
|
//the InitRoot() method won't be called. Then if a user click or press key to update the navigator tree, crash happens.
|
|
//So the solution is to disable the UpdateMode of Control, then call Clear(), then recover the update mode
|
|
bool bWasFrozen = m_bFreeze;
|
|
if (!bWasFrozen)
|
|
freeze();
|
|
m_xTreeView->clear();
|
|
if (!bWasFrozen)
|
|
thaw();
|
|
for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
|
|
InitRoot(static_cast<ScContentId>(i));
|
|
}
|
|
|
|
void ScContentTree::ClearType(ScContentId nType)
|
|
{
|
|
if (nType == ScContentId::ROOT)
|
|
ClearAll();
|
|
else
|
|
{
|
|
weld::TreeIter* pParent = m_aRootNodes[nType].get();
|
|
if (!pParent || m_xTreeView->iter_has_child(*pParent)) // not if no children existing
|
|
{
|
|
if (pParent)
|
|
m_xTreeView->remove(*pParent); // with all children
|
|
InitRoot( nType ); // if needed insert anew
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScContentTree::InsertContent( ScContentId nType, const OUString& rValue )
|
|
{
|
|
weld::TreeIter* pParent = m_aRootNodes[nType].get();
|
|
if (pParent)
|
|
{
|
|
m_xTreeView->insert(pParent, -1, &rValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
|
|
m_xTreeView->set_sensitive(*m_xScratchIter, true);
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL("InsertContent without parent");
|
|
}
|
|
}
|
|
|
|
void ScContentTree::GetEntryIndexes(ScContentId& rnRootIndex, sal_uLong& rnChildIndex, const weld::TreeIter* pEntry) const
|
|
{
|
|
rnRootIndex = ScContentId::ROOT;
|
|
rnChildIndex = SC_CONTENT_NOCHILD;
|
|
|
|
if( !pEntry )
|
|
return;
|
|
|
|
std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(pEntry));
|
|
if (!m_xTreeView->iter_parent(*xParent))
|
|
xParent.reset();
|
|
bool bFound = false;
|
|
for( int i = 1; !bFound && (i <= int(ScContentId::LAST)); ++i )
|
|
{
|
|
ScContentId nRoot = static_cast<ScContentId>(i);
|
|
if (!m_aRootNodes[nRoot])
|
|
continue;
|
|
if (m_xTreeView->iter_compare(*pEntry, *m_aRootNodes[nRoot]) == 0)
|
|
{
|
|
rnRootIndex = nRoot;
|
|
rnChildIndex = ~0UL;
|
|
bFound = true;
|
|
}
|
|
else if (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[nRoot]) == 0)
|
|
{
|
|
rnRootIndex = nRoot;
|
|
|
|
// search the entry in all child entries of the parent
|
|
sal_uLong nEntry = 0;
|
|
std::unique_ptr<weld::TreeIter> xIterEntry(m_xTreeView->make_iterator(xParent.get()));
|
|
bool bIterEntry = m_xTreeView->iter_children(*xIterEntry);
|
|
while (!bFound && bIterEntry)
|
|
{
|
|
if (m_xTreeView->iter_compare(*pEntry, *xIterEntry) == 0)
|
|
{
|
|
rnChildIndex = nEntry;
|
|
bFound = true; // exit the while loop
|
|
}
|
|
bIterEntry = m_xTreeView->iter_next_sibling(*xIterEntry);
|
|
++nEntry;
|
|
}
|
|
|
|
bFound = true; // exit the for loop
|
|
}
|
|
}
|
|
}
|
|
|
|
sal_uLong ScContentTree::GetChildIndex(const weld::TreeIter* pEntry) const
|
|
{
|
|
ScContentId nRoot;
|
|
sal_uLong nChild;
|
|
GetEntryIndexes(nRoot, nChild, pEntry);
|
|
return nChild;
|
|
}
|
|
|
|
static OUString lcl_GetDBAreaRange( const ScDocument* pDoc, const OUString& rDBName )
|
|
{
|
|
OUString aRet;
|
|
if (pDoc)
|
|
{
|
|
ScDBCollection* pDbNames = pDoc->GetDBCollection();
|
|
const ScDBData* pData = pDbNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
|
|
if (pData)
|
|
{
|
|
ScRange aRange;
|
|
pData->GetArea(aRange);
|
|
aRet = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS_3D);
|
|
}
|
|
}
|
|
return aRet;
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ScContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
|
|
{
|
|
ScContentId nType;
|
|
sal_uLong nChild;
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_cursor(xEntry.get()))
|
|
xEntry.reset();
|
|
GetEntryIndexes(nType, nChild, xEntry.get());
|
|
|
|
if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
|
|
{
|
|
OUString aText(m_xTreeView->get_text(*xEntry));
|
|
|
|
if ( !aManualDoc.isEmpty() )
|
|
pParentWindow->SetCurrentDoc( aManualDoc );
|
|
|
|
switch( nType )
|
|
{
|
|
case ScContentId::TABLE:
|
|
{
|
|
// tdf#133159 store current config before changing sheet
|
|
// plausible that this should be done for all cases, but this
|
|
// is the known case that needs it
|
|
StoreNavigatorSettings();
|
|
pParentWindow->SetCurrentTableStr( aText );
|
|
}
|
|
break;
|
|
|
|
case ScContentId::RANGENAME:
|
|
pParentWindow->SetCurrentCellStr( aText );
|
|
break;
|
|
|
|
case ScContentId::DBAREA:
|
|
{
|
|
// If the same names of area and DB exists, then
|
|
// SID_CURRENTCELL takes the area name.
|
|
// Therefore for DB areas access them directly via address.
|
|
|
|
OUString aRangeStr = lcl_GetDBAreaRange( GetSourceDocument(), aText );
|
|
if (!aRangeStr.isEmpty())
|
|
pParentWindow->SetCurrentCellStr( aRangeStr );
|
|
}
|
|
break;
|
|
|
|
case ScContentId::OLEOBJECT:
|
|
case ScContentId::GRAPHIC:
|
|
case ScContentId::DRAWING:
|
|
pParentWindow->SetCurrentObject( aText );
|
|
break;
|
|
|
|
case ScContentId::NOTE:
|
|
{
|
|
ScAddress aPos = GetNotePos( nChild );
|
|
pParentWindow->SetCurrentTable( aPos.Tab() );
|
|
pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
|
|
// Check whether the comment is currently visible and toggle its visibility
|
|
ScDocument* pSrcDoc = GetSourceDocument();
|
|
if (ScPostIt* pNote = pSrcDoc ? pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()) : nullptr)
|
|
{
|
|
bool bVisible = pNote->IsCaptionShown();
|
|
// Effectivelly set the visibility of the comment
|
|
GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, !bVisible);
|
|
// Put the note in edit mode
|
|
ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
|
|
pScTabViewShell->EditNote();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ScContentId::AREALINK:
|
|
{
|
|
const ScAreaLink* pLink = GetLink(nChild);
|
|
ScDocument* pSrcDoc = GetSourceDocument();
|
|
if (pLink && pSrcDoc)
|
|
{
|
|
const ScRange& aRange = pLink->GetDestArea();
|
|
OUString aRangeStr(aRange.Format(*pSrcDoc, ScRefFlags::RANGE_ABS_3D, pSrcDoc->GetAddressConvention()));
|
|
pParentWindow->SetCurrentCellStr( aRangeStr );
|
|
}
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
ScNavigatorDlg::ReleaseFocus(); // set focus into document
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ScContentTree::LaunchAsyncStoreNavigatorSettings()
|
|
{
|
|
if (!m_nAsyncMouseReleaseId)
|
|
m_nAsyncMouseReleaseId = Application::PostUserEvent(LINK(this, ScContentTree, AsyncStoreNavigatorSettings));
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ScContentTree, MouseReleaseHdl, const MouseEvent&, bool)
|
|
{
|
|
LaunchAsyncStoreNavigatorSettings();
|
|
return false;
|
|
}
|
|
|
|
IMPL_LINK_NOARG(ScContentTree, AsyncStoreNavigatorSettings, void*, void)
|
|
{
|
|
m_nAsyncMouseReleaseId = nullptr;
|
|
StoreNavigatorSettings();
|
|
}
|
|
|
|
IMPL_LINK(ScContentTree, KeyInputHdl, const KeyEvent&, rKEvt, bool)
|
|
{
|
|
bool bUsed = false;
|
|
|
|
const vcl::KeyCode aCode = rKEvt.GetKeyCode();
|
|
if (aCode.GetCode() == KEY_RETURN)
|
|
{
|
|
switch (aCode.GetModifier())
|
|
{
|
|
case KEY_MOD1:
|
|
ToggleRoot(); // toggle root mode (as in Writer)
|
|
bUsed = true;
|
|
break;
|
|
case 0:
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_cursor(xEntry.get()))
|
|
xEntry.reset();
|
|
if (xEntry)
|
|
{
|
|
ScContentId nType;
|
|
sal_uLong nChild;
|
|
GetEntryIndexes(nType, nChild, xEntry.get());
|
|
|
|
if (nType != ScContentId::ROOT && nChild == SC_CONTENT_NOCHILD)
|
|
{
|
|
if (m_xTreeView->get_row_expanded(*xEntry))
|
|
m_xTreeView->collapse_row(*xEntry);
|
|
else
|
|
m_xTreeView->expand_row(*xEntry);
|
|
}
|
|
else
|
|
ContentDoubleClickHdl(*m_xTreeView); // select content as if double clicked
|
|
}
|
|
|
|
bUsed = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
//Make KEY_SPACE has same function as DoubleClick, and realize
|
|
//multi-selection.
|
|
if ( bIsInNavigatorDlg )
|
|
{
|
|
if(aCode.GetCode() == KEY_SPACE )
|
|
{
|
|
bUsed = true;
|
|
ScContentId nType;
|
|
sal_uLong nChild;
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_cursor(xEntry.get()))
|
|
xEntry.reset();
|
|
GetEntryIndexes(nType, nChild, xEntry.get());
|
|
|
|
if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
|
|
{
|
|
OUString aText(m_xTreeView->get_text(*xEntry));
|
|
if (!aManualDoc.isEmpty())
|
|
pParentWindow->SetCurrentDoc( aManualDoc );
|
|
switch (nType)
|
|
{
|
|
case ScContentId::OLEOBJECT:
|
|
case ScContentId::GRAPHIC:
|
|
case ScContentId::DRAWING:
|
|
{
|
|
ScDrawView* pScDrawView = nullptr;
|
|
ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
|
|
if (pScTabViewShell)
|
|
pScDrawView = pScTabViewShell->GetViewData().GetScDrawView();
|
|
if (pScDrawView)
|
|
{
|
|
pScDrawView->SelectCurrentViewObject(aText);
|
|
bool bHasMakredObject = false;
|
|
weld::TreeIter* pParent = m_aRootNodes[nType].get();
|
|
std::unique_ptr<weld::TreeIter> xBeginEntry(m_xTreeView->make_iterator(pParent));
|
|
bool bBeginEntry = false;
|
|
if (pParent)
|
|
bBeginEntry = m_xTreeView->iter_children(*xBeginEntry);
|
|
while (bBeginEntry)
|
|
{
|
|
OUString aTempText(m_xTreeView->get_text(*xBeginEntry));
|
|
if( pScDrawView->GetObjectIsMarked( pScDrawView->GetObjectByName( aTempText ) ) )
|
|
{
|
|
bHasMakredObject = true;
|
|
break;
|
|
}
|
|
bBeginEntry = m_xTreeView->iter_next(*xBeginEntry);
|
|
}
|
|
if (!bHasMakredObject && pScTabViewShell)
|
|
pScTabViewShell->SetDrawShell(false);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bUsed)
|
|
{
|
|
if (aCode.GetCode() == KEY_F5)
|
|
StoreNavigatorSettings();
|
|
else
|
|
LaunchAsyncStoreNavigatorSettings();
|
|
}
|
|
|
|
return bUsed;
|
|
}
|
|
|
|
IMPL_LINK(ScContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)
|
|
{
|
|
bool bDone = false;
|
|
|
|
ScContentId nType;
|
|
sal_uLong nChild;
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_cursor(xEntry.get()))
|
|
xEntry.reset();
|
|
GetEntryIndexes(nType, nChild, xEntry.get());
|
|
|
|
switch ( rCEvt.GetCommand() )
|
|
{
|
|
case CommandEventId::ContextMenu:
|
|
{
|
|
// drag-and-drop mode
|
|
std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), u"modules/scalc/ui/dropmenu.ui"_ustr));
|
|
std::unique_ptr<weld::Menu> xPop(xBuilder->weld_menu(u"contextmenu"_ustr));
|
|
std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu(u"dragmodesubmenu"_ustr));
|
|
|
|
switch (pParentWindow->GetDropMode())
|
|
{
|
|
case 0:
|
|
xDropMenu->set_active(u"hyperlink"_ustr, true);
|
|
break;
|
|
case 1:
|
|
xDropMenu->set_active(u"link"_ustr, true);
|
|
break;
|
|
case 2:
|
|
xDropMenu->set_active(u"copy"_ustr, true);
|
|
break;
|
|
}
|
|
|
|
// displayed document
|
|
std::unique_ptr<weld::Menu> xDocMenu(xBuilder->weld_menu(u"displaymenu"_ustr));
|
|
sal_uInt16 i=0;
|
|
OUString sActive;
|
|
OUString sId;
|
|
// loaded documents
|
|
ScDocShell* pCurrentSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
|
|
SfxObjectShell* pSh = SfxObjectShell::GetFirst();
|
|
while ( pSh )
|
|
{
|
|
if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
|
|
{
|
|
OUString aName = pSh->GetTitle();
|
|
OUString aEntry = aName;
|
|
if ( pSh == pCurrentSh )
|
|
aEntry += pParentWindow->aStrActive;
|
|
else
|
|
aEntry += pParentWindow->aStrNotActive;
|
|
++i;
|
|
sId = "document" + OUString::number(i);
|
|
xDocMenu->append_radio(sId, aEntry);
|
|
if (aName == aManualDoc)
|
|
sActive = sId;
|
|
}
|
|
pSh = SfxObjectShell::GetNext( *pSh );
|
|
}
|
|
// "active window"
|
|
++i;
|
|
sId = "document" + OUString::number(i);
|
|
xDocMenu->append_radio(sId, pParentWindow->aStrActiveWin);
|
|
if (aManualDoc.isEmpty())
|
|
sActive = sId;
|
|
xDocMenu->set_active(sActive, true);
|
|
|
|
// Edit/Delete Comments are only visible for comments
|
|
if (nType != ScContentId::NOTE)
|
|
{
|
|
xPop->set_visible(u"edit"_ustr, false);
|
|
xPop->set_visible(u"delete"_ustr, false);
|
|
}
|
|
|
|
OUString sIdent = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
|
|
if (sIdent == "hyperlink")
|
|
pParentWindow->SetDropMode(0);
|
|
else if (sIdent == "link")
|
|
pParentWindow->SetDropMode(1);
|
|
else if (sIdent == "copy")
|
|
pParentWindow->SetDropMode(2);
|
|
else if (sIdent.startsWith("document"))
|
|
{
|
|
OUString aName = xDocMenu->get_label(sIdent);
|
|
SelectDoc(aName);
|
|
}
|
|
else if (sIdent == "edit")
|
|
{
|
|
ScAddress aPos = GetNotePos( nChild );
|
|
pParentWindow->SetCurrentTable( aPos.Tab() );
|
|
pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
|
|
ScDocument* pSrcDoc = GetSourceDocument();
|
|
if (pSrcDoc->GetNote(aPos.Col(), aPos.Row(), aPos.Tab()))
|
|
{
|
|
// Make the note visible and put it in edit mode
|
|
GetManualOrCurrent()->GetDocFunc().ShowNote(aPos, true);
|
|
ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
|
|
pScTabViewShell->EditNote();
|
|
bDone = true;
|
|
}
|
|
}
|
|
else if (sIdent == "delete")
|
|
{
|
|
ScAddress aPos = GetNotePos(nChild);
|
|
pParentWindow->SetCurrentTable(aPos.Tab());
|
|
pParentWindow->SetCurrentCell(aPos.Col(), aPos.Row());
|
|
ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
|
|
pScTabViewShell->DeleteContents(InsertDeleteFlags::NOTE);
|
|
}
|
|
}
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
return bDone;
|
|
}
|
|
|
|
IMPL_LINK(ScContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
|
|
{
|
|
OUString aHelpText;
|
|
|
|
std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
|
|
if (!m_xTreeView->iter_parent(*xParent))
|
|
xParent.reset();
|
|
|
|
if (!xParent) // Top-Level ?
|
|
{
|
|
aHelpText = OUString::number(m_xTreeView->iter_n_children(rEntry)) +
|
|
" " + m_xTreeView->get_text(rEntry);
|
|
}
|
|
else if (m_aRootNodes[ScContentId::NOTE] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::NOTE]) == 0)
|
|
{
|
|
aHelpText = m_xTreeView->get_text(rEntry); // notes as help text
|
|
}
|
|
else if (m_aRootNodes[ScContentId::AREALINK] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::AREALINK]) == 0)
|
|
{
|
|
auto nIndex = GetChildIndex(&rEntry);
|
|
if (nIndex != SC_CONTENT_NOCHILD)
|
|
{
|
|
const ScAreaLink* pLink = GetLink(nIndex);
|
|
if (pLink)
|
|
{
|
|
aHelpText = pLink->GetFile(); // source file as help text
|
|
}
|
|
}
|
|
}
|
|
|
|
return aHelpText;
|
|
}
|
|
|
|
ScDocument* ScContentTree::GetSourceDocument()
|
|
{
|
|
ScDocShell* pSh = GetManualOrCurrent();
|
|
if (pSh)
|
|
return &pSh->GetDocument();
|
|
return nullptr;
|
|
}
|
|
|
|
void ScContentTree::Refresh( ScContentId nType )
|
|
{
|
|
// if nothing has changed the cancel right away (against flicker)
|
|
if ( nType == ScContentId::NOTE )
|
|
if (!NoteStringsChanged())
|
|
return;
|
|
if ( nType == ScContentId::GRAPHIC )
|
|
if (!DrawNamesChanged(ScContentId::GRAPHIC))
|
|
return;
|
|
if ( nType == ScContentId::OLEOBJECT )
|
|
if (!DrawNamesChanged(ScContentId::OLEOBJECT))
|
|
return;
|
|
if ( nType == ScContentId::DRAWING )
|
|
if (!DrawNamesChanged(ScContentId::DRAWING))
|
|
return;
|
|
|
|
freeze();
|
|
|
|
ClearType( nType );
|
|
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::TABLE )
|
|
GetTableNames();
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::RANGENAME )
|
|
GetAreaNames();
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::DBAREA )
|
|
GetDbNames();
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::GRAPHIC )
|
|
GetGraphicNames();
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::OLEOBJECT )
|
|
GetOleNames();
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::DRAWING )
|
|
GetDrawingNames();
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::NOTE )
|
|
GetNoteStrings();
|
|
if ( nType == ScContentId::ROOT || nType == ScContentId::AREALINK )
|
|
GetLinkNames();
|
|
|
|
thaw();
|
|
|
|
ApplyNavigatorSettings();
|
|
}
|
|
|
|
void ScContentTree::GetTableNames()
|
|
{
|
|
if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::TABLE ) // hidden ?
|
|
return;
|
|
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
OUString aName;
|
|
SCTAB nCount = pDoc->GetTableCount();
|
|
for ( SCTAB i=0; i<nCount; i++ )
|
|
{
|
|
pDoc->GetName( i, aName );
|
|
InsertContent( ScContentId::TABLE, aName );
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
OUString createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
|
|
{
|
|
return OUString::Concat(rName) + " (" + rTableName + ")";
|
|
}
|
|
}
|
|
|
|
void ScContentTree::GetAreaNames()
|
|
{
|
|
if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::RANGENAME ) // hidden ?
|
|
return;
|
|
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
ScRange aDummy;
|
|
std::set<OUString> aSet;
|
|
ScRangeName* pRangeNames = pDoc->GetRangeName();
|
|
for (const auto& rEntry : *pRangeNames)
|
|
{
|
|
if (rEntry.second->IsValidReference(aDummy))
|
|
aSet.insert(rEntry.second->GetName());
|
|
}
|
|
for (SCTAB i = 0; i < pDoc->GetTableCount(); ++i)
|
|
{
|
|
ScRangeName* pLocalRangeName = pDoc->GetRangeName(i);
|
|
if (pLocalRangeName && !pLocalRangeName->empty())
|
|
{
|
|
OUString aTableName;
|
|
pDoc->GetName(i, aTableName);
|
|
for (const auto& rEntry : *pLocalRangeName)
|
|
{
|
|
if (rEntry.second->IsValidReference(aDummy))
|
|
aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const auto& rItem : aSet)
|
|
{
|
|
InsertContent(ScContentId::RANGENAME, rItem);
|
|
}
|
|
}
|
|
|
|
void ScContentTree::GetDbNames()
|
|
{
|
|
if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::DBAREA ) // hidden ?
|
|
return;
|
|
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
ScDBCollection* pDbNames = pDoc->GetDBCollection();
|
|
const ScDBCollection::NamedDBs& rDBs = pDbNames->getNamedDBs();
|
|
for (const auto& rxDB : rDBs)
|
|
{
|
|
const OUString& aStrName = rxDB->GetName();
|
|
InsertContent(ScContentId::DBAREA, aStrName);
|
|
}
|
|
}
|
|
|
|
bool ScContentTree::IsPartOfType( ScContentId nContentType, SdrObjKind nObjIdentifier )
|
|
{
|
|
bool bRet = false;
|
|
switch ( nContentType )
|
|
{
|
|
case ScContentId::GRAPHIC:
|
|
bRet = ( nObjIdentifier == SdrObjKind::Graphic );
|
|
break;
|
|
case ScContentId::OLEOBJECT:
|
|
bRet = ( nObjIdentifier == SdrObjKind::OLE2 );
|
|
break;
|
|
case ScContentId::DRAWING:
|
|
bRet = ( nObjIdentifier != SdrObjKind::Graphic && nObjIdentifier != SdrObjKind::OLE2 ); // everything else
|
|
break;
|
|
default:
|
|
OSL_FAIL("unknown content type");
|
|
}
|
|
return bRet;
|
|
}
|
|
|
|
constexpr int MAX_TREE_NODES = 1000;
|
|
|
|
void ScContentTree::GetDrawNames( ScContentId nType )
|
|
{
|
|
if (!bIsInNavigatorDlg)
|
|
return;
|
|
|
|
if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
|
|
return;
|
|
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
|
|
if (!pDrawLayer)
|
|
return;
|
|
|
|
ScDocShell* pShell = pDoc->GetDocumentShell();
|
|
if (!pShell)
|
|
return;
|
|
|
|
// iterate in flat mode for groups
|
|
SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
|
|
|
|
std::vector<OUString> aNames;
|
|
SCTAB nTabCount = pDoc->GetTableCount();
|
|
for (SCTAB nTab=0; nTab<nTabCount; nTab++)
|
|
{
|
|
SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
|
|
OSL_ENSURE(pPage,"Page ?");
|
|
if (!pPage)
|
|
continue;
|
|
SdrObjListIter aIter(pPage, eIter);
|
|
SdrObject* pObject = aIter.Next();
|
|
while (pObject)
|
|
{
|
|
if (IsPartOfType(nType, pObject->GetObjIdentifier()))
|
|
{
|
|
OUString aName = ScDrawLayer::GetVisibleName(pObject);
|
|
if (!aName.isEmpty())
|
|
aNames.push_back(aName);
|
|
if (aNames.size() > MAX_TREE_NODES)
|
|
{
|
|
SAL_WARN("sc", "too many tree nodes, ignoring the rest");
|
|
break;
|
|
}
|
|
}
|
|
pObject = aIter.Next();
|
|
}
|
|
}
|
|
|
|
weld::TreeIter* pParent = m_aRootNodes[nType].get();
|
|
assert(pParent && "InsertContent without parent");
|
|
// insert all of these in one go under pParent
|
|
m_xTreeView->bulk_insert_for_each(aNames.size(), [this, &aNames](weld::TreeIter& rIter, int nIndex) {
|
|
m_xTreeView->set_text(rIter, aNames[nIndex], 0);
|
|
m_xTreeView->set_sensitive(rIter, true);
|
|
}, pParent);
|
|
}
|
|
|
|
void ScContentTree::GetGraphicNames()
|
|
{
|
|
GetDrawNames( ScContentId::GRAPHIC );
|
|
}
|
|
|
|
void ScContentTree::GetOleNames()
|
|
{
|
|
GetDrawNames( ScContentId::OLEOBJECT );
|
|
}
|
|
|
|
void ScContentTree::GetDrawingNames()
|
|
{
|
|
GetDrawNames( ScContentId::DRAWING );
|
|
}
|
|
|
|
void ScContentTree::GetLinkNames()
|
|
{
|
|
if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::AREALINK ) // hidden ?
|
|
return;
|
|
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
|
|
assert(pLinkManager && "no LinkManager on document?");
|
|
const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
|
|
sal_uInt16 nCount = rLinks.size();
|
|
for (sal_uInt16 i=0; i<nCount; i++)
|
|
{
|
|
::sfx2::SvBaseLink* pBase = rLinks[i].get();
|
|
if (auto pScAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
|
|
InsertContent( ScContentId::AREALINK, pScAreaLink->GetSource() );
|
|
|
|
// insert in list the names of source areas
|
|
}
|
|
}
|
|
|
|
const ScAreaLink* ScContentTree::GetLink( sal_uLong nIndex )
|
|
{
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return nullptr;
|
|
|
|
sal_uLong nFound = 0;
|
|
sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
|
|
assert(pLinkManager && "no LinkManager on document?");
|
|
const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
|
|
sal_uInt16 nCount = rLinks.size();
|
|
for (sal_uInt16 i=0; i<nCount; i++)
|
|
{
|
|
::sfx2::SvBaseLink* pBase = rLinks[i].get();
|
|
if (auto pAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
|
|
{
|
|
if (nFound == nIndex)
|
|
return pAreaLink;
|
|
++nFound;
|
|
}
|
|
}
|
|
|
|
OSL_FAIL("link not found");
|
|
return nullptr;
|
|
}
|
|
|
|
static OUString lcl_NoteString( const ScPostIt& rNote )
|
|
{
|
|
return rNote.GetText().replace('\n', ' ');
|
|
}
|
|
|
|
void ScContentTree::GetNoteStrings()
|
|
{
|
|
if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::NOTE ) // hidden ?
|
|
return;
|
|
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return;
|
|
|
|
// loop over cell notes
|
|
std::vector<sc::NoteEntry> aEntries;
|
|
pDoc->GetAllNoteEntries(aEntries);
|
|
weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
|
|
for (const auto& rEntry : aEntries)
|
|
{
|
|
OUString aValue = lcl_NoteString(*rEntry.mpNote);
|
|
m_xTreeView->insert(pParent, -1, &aValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
|
|
m_xTreeView->set_sensitive(*m_xScratchIter, true);
|
|
}
|
|
}
|
|
|
|
ScAddress ScContentTree::GetNotePos( sal_uLong nIndex )
|
|
{
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return ScAddress();
|
|
|
|
return pDoc->GetNotePosition(nIndex);
|
|
}
|
|
|
|
bool ScContentTree::NoteStringsChanged()
|
|
{
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return false;
|
|
|
|
weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
|
|
if (!pParent)
|
|
return false;
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
|
|
bool bEntry = m_xTreeView->iter_children(*xEntry);
|
|
|
|
std::vector<sc::NoteEntry> aEntries;
|
|
pDoc->GetAllNoteEntries(aEntries);
|
|
for (const auto& rEntry : aEntries)
|
|
{
|
|
const ScPostIt* pNote = rEntry.mpNote;
|
|
if (!bEntry)
|
|
return true;
|
|
|
|
if (lcl_NoteString(*pNote) != m_xTreeView->get_text(*xEntry))
|
|
return true;
|
|
|
|
bEntry = m_xTreeView->iter_next_sibling(*xEntry);
|
|
}
|
|
|
|
return bEntry;
|
|
}
|
|
|
|
bool ScContentTree::DrawNamesChanged( ScContentId nType )
|
|
{
|
|
ScDocument* pDoc = GetSourceDocument();
|
|
if (!pDoc)
|
|
return false;
|
|
|
|
weld::TreeIter* pParent = m_aRootNodes[nType].get();
|
|
if (!pParent)
|
|
return false;
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
|
|
bool bEntry = m_xTreeView->iter_children(*xEntry);
|
|
|
|
// iterate in flat mode for groups
|
|
SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
|
|
|
|
bool bEqual = true;
|
|
ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
|
|
ScDocShell* pShell = pDoc->GetDocumentShell();
|
|
if (pDrawLayer && pShell)
|
|
{
|
|
SCTAB nTabCount = pDoc->GetTableCount();
|
|
for (SCTAB nTab=0; nTab<nTabCount && bEqual; nTab++)
|
|
{
|
|
SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
|
|
OSL_ENSURE(pPage,"Page ?");
|
|
if (pPage)
|
|
{
|
|
SdrObjListIter aIter( pPage, eIter );
|
|
SdrObject* pObject = aIter.Next();
|
|
while (pObject && bEqual)
|
|
{
|
|
if ( IsPartOfType( nType, pObject->GetObjIdentifier() ) )
|
|
{
|
|
if ( !bEntry )
|
|
bEqual = false;
|
|
else
|
|
{
|
|
if (ScDrawLayer::GetVisibleName(pObject) != m_xTreeView->get_text(*xEntry))
|
|
bEqual = false;
|
|
|
|
bEntry = m_xTreeView->iter_next_sibling(*xEntry);
|
|
}
|
|
}
|
|
pObject = aIter.Next();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bEntry )
|
|
bEqual = false; // anything else
|
|
|
|
return !bEqual;
|
|
}
|
|
|
|
static bool lcl_GetRange( const ScDocument& rDoc, ScContentId nType, const OUString& rName, ScRange& rRange )
|
|
{
|
|
bool bFound = false;
|
|
|
|
if ( nType == ScContentId::RANGENAME )
|
|
{
|
|
ScRangeName* pList = rDoc.GetRangeName();
|
|
if (pList)
|
|
{
|
|
const ScRangeData* p = pList->findByUpperName(ScGlobal::getCharClass().uppercase(rName));
|
|
if (p && p->IsValidReference(rRange))
|
|
bFound = true;
|
|
}
|
|
}
|
|
else if ( nType == ScContentId::DBAREA )
|
|
{
|
|
ScDBCollection* pList = rDoc.GetDBCollection();
|
|
if (pList)
|
|
{
|
|
const ScDBData* p = pList->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rName));
|
|
if (p)
|
|
{
|
|
SCTAB nTab;
|
|
SCCOL nCol1, nCol2;
|
|
SCROW nRow1, nRow2;
|
|
p->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
|
|
rRange = ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
|
|
bFound = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bFound;
|
|
}
|
|
|
|
static bool lcl_DoDragObject( ScDocShell* pSrcShell, std::u16string_view rName, ScContentId nType, weld::TreeView& rTreeView )
|
|
{
|
|
bool bDisallow = true;
|
|
|
|
ScDocument& rSrcDoc = pSrcShell->GetDocument();
|
|
ScDrawLayer* pModel = rSrcDoc.GetDrawLayer();
|
|
if (pModel)
|
|
{
|
|
bool bOle = ( nType == ScContentId::OLEOBJECT );
|
|
bool bGraf = ( nType == ScContentId::GRAPHIC );
|
|
SdrObjKind nDrawId = bOle ? SdrObjKind::OLE2 : ( bGraf ? SdrObjKind::Graphic : SdrObjKind::Group );
|
|
SCTAB nTab = 0;
|
|
SdrObject* pObject = pModel->GetNamedObject( rName, nDrawId, nTab );
|
|
if (pObject)
|
|
{
|
|
SdrView aEditView(*pModel);
|
|
aEditView.ShowSdrPage(aEditView.GetModel().GetPage(nTab));
|
|
SdrPageView* pPV = aEditView.GetSdrPageView();
|
|
aEditView.MarkObj(pObject, pPV);
|
|
|
|
// tdf125520 this is a D&D-start potentially with an OLE object. If
|
|
// so, we need to do similar as e.g. in ScDrawView::BeginDrag so that
|
|
// the temporary SdrModel for transfer does have a GetPersist() so
|
|
// that the EmbeddedObjectContainer gets copied. We need no CheckOle
|
|
// here, test is simpler.
|
|
ScDocShellRef aDragShellRef;
|
|
if(SdrObjKind::OLE2 == pObject->GetObjIdentifier())
|
|
{
|
|
aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
|
|
aDragShellRef->DoInitNew();
|
|
}
|
|
|
|
ScDrawLayer::SetGlobalDrawPersist(aDragShellRef.get());
|
|
std::unique_ptr<SdrModel> pDragModel(aEditView.CreateMarkedObjModel());
|
|
ScDrawLayer::SetGlobalDrawPersist(nullptr);
|
|
|
|
TransferableObjectDescriptor aObjDesc;
|
|
pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
|
|
aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
|
|
// maSize is set in ScDrawTransferObj ctor
|
|
|
|
rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pDragModel), pSrcShell, std::move(aObjDesc) );
|
|
|
|
pTransferObj->SetDragSourceObj( *pObject, nTab );
|
|
pTransferObj->SetDragSourceFlags(ScDragSrc::Navigator);
|
|
|
|
ScModule::get()->SetDragObject(nullptr, pTransferObj.get());
|
|
|
|
rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
|
|
rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
|
|
|
|
bDisallow = false;
|
|
}
|
|
}
|
|
|
|
return bDisallow;
|
|
}
|
|
|
|
static bool lcl_DoDragCells( ScDocShell* pSrcShell, const ScRange& rRange, ScDragSrc nFlags, weld::TreeView& rTreeView )
|
|
{
|
|
bool bDisallow = true;
|
|
|
|
ScDocument& rSrcDoc = pSrcShell->GetDocument();
|
|
ScMarkData aMark(rSrcDoc.GetSheetLimits());
|
|
aMark.SelectTable( rRange.aStart.Tab(), true );
|
|
aMark.SetMarkArea( rRange );
|
|
|
|
if ( !rSrcDoc.HasSelectedBlockMatrixFragment( rRange.aStart.Col(), rRange.aStart.Row(),
|
|
rRange.aEnd.Col(), rRange.aEnd.Row(),
|
|
aMark ) )
|
|
{
|
|
ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
|
|
ScClipParam aClipParam(rRange, false);
|
|
rSrcDoc.CopyToClip(aClipParam, pClipDoc.get(), &aMark, false, false);
|
|
// pClipDoc->ExtendMerge( rRange, sal_True );
|
|
|
|
TransferableObjectDescriptor aObjDesc;
|
|
pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
|
|
aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
|
|
// maSize is set in ScTransferObj ctor
|
|
|
|
rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), std::move(aObjDesc) );
|
|
|
|
pTransferObj->SetDragSource( pSrcShell, aMark );
|
|
pTransferObj->SetDragSourceFlags( nFlags );
|
|
|
|
ScModule::get()->SetDragObject(pTransferObj.get(), nullptr); // for internal D&D
|
|
|
|
rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
|
|
rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
|
|
|
|
bDisallow = false;
|
|
}
|
|
|
|
return bDisallow;
|
|
}
|
|
|
|
IMPL_LINK(ScContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
|
|
{
|
|
rUnsetDragIcon = true;
|
|
|
|
StoreNavigatorSettings();
|
|
|
|
bool bDisallow = true;
|
|
|
|
ScModule* pScMod = ScModule::get();
|
|
|
|
ScContentId nType;
|
|
sal_uLong nChild;
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_cursor(xEntry.get()))
|
|
xEntry.reset();
|
|
|
|
GetEntryIndexes(nType, nChild, xEntry.get());
|
|
|
|
if( xEntry &&
|
|
(nChild != SC_CONTENT_NOCHILD) &&
|
|
(nType != ScContentId::ROOT) &&
|
|
(nType != ScContentId::NOTE) &&
|
|
(nType != ScContentId::AREALINK) )
|
|
{
|
|
OUString aText(m_xTreeView->get_text(*xEntry));
|
|
|
|
ScDocument* pLocalDoc = nullptr; // for URL drop
|
|
OUString aDocName;
|
|
ScDocShell* pDocSh = GetManualOrCurrent();
|
|
if (pDocSh)
|
|
{
|
|
if (pDocSh->HasName())
|
|
aDocName = pDocSh->GetMedium()->GetName();
|
|
else
|
|
pLocalDoc = &pDocSh->GetDocument(); // drop only in this document
|
|
}
|
|
|
|
bool bDoLinkTrans = false; // use ScLinkTransferObj
|
|
OUString aLinkURL; // for ScLinkTransferObj
|
|
OUString aLinkText;
|
|
|
|
sal_uInt16 nDropMode = pParentWindow->GetDropMode();
|
|
switch ( nDropMode )
|
|
{
|
|
case SC_DROPMODE_URL:
|
|
{
|
|
OUString aUrl = aDocName + "#" + aText;
|
|
|
|
pScMod->SetDragJump( pLocalDoc, aUrl, aText );
|
|
|
|
if (!aDocName.isEmpty())
|
|
{
|
|
// provide URL to outside only if the document has a name
|
|
// (without name, only internal D&D via SetDragJump)
|
|
|
|
aLinkURL = aUrl;
|
|
aLinkText = aText;
|
|
}
|
|
bDoLinkTrans = true;
|
|
}
|
|
break;
|
|
case SC_DROPMODE_LINK:
|
|
{
|
|
if ( !aDocName.isEmpty() ) // link only to named documents
|
|
{
|
|
// for internal D&D, set flag to insert a link
|
|
|
|
switch ( nType )
|
|
{
|
|
case ScContentId::TABLE:
|
|
pScMod->SetDragLink( aDocName, aText, OUString() );
|
|
bDoLinkTrans = true;
|
|
break;
|
|
case ScContentId::RANGENAME:
|
|
case ScContentId::DBAREA:
|
|
pScMod->SetDragLink( aDocName, OUString(), aText );
|
|
bDoLinkTrans = true;
|
|
break;
|
|
|
|
// other types cannot be linked
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SC_DROPMODE_COPY:
|
|
{
|
|
ScDocShell* pSrcShell = GetManualOrCurrent();
|
|
if ( pSrcShell )
|
|
{
|
|
ScDocument& rSrcDoc = pSrcShell->GetDocument();
|
|
if ( nType == ScContentId::RANGENAME || nType == ScContentId::DBAREA )
|
|
{
|
|
ScRange aRange;
|
|
if ( lcl_GetRange( rSrcDoc, nType, aText, aRange ) )
|
|
{
|
|
bDisallow = lcl_DoDragCells( pSrcShell, aRange, ScDragSrc::Navigator, *m_xTreeView );
|
|
}
|
|
}
|
|
else if ( nType == ScContentId::TABLE )
|
|
{
|
|
SCTAB nTab;
|
|
if ( rSrcDoc.GetTable( aText, nTab ) )
|
|
{
|
|
ScRange aRange(0, 0, nTab, rSrcDoc.MaxCol(), rSrcDoc.MaxRow(), nTab);
|
|
bDisallow = lcl_DoDragCells( pSrcShell, aRange, (ScDragSrc::Navigator | ScDragSrc::Table), *m_xTreeView );
|
|
}
|
|
}
|
|
else if ( nType == ScContentId::GRAPHIC || nType == ScContentId::OLEOBJECT ||
|
|
nType == ScContentId::DRAWING )
|
|
{
|
|
bDisallow = lcl_DoDragObject( pSrcShell, aText, nType, *m_xTreeView );
|
|
|
|
// during ExecuteDrag the navigator can be deleted
|
|
// -> don't access member anymore !!!
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (bDoLinkTrans)
|
|
{
|
|
if (!aLinkURL.isEmpty())
|
|
m_xTransferObj->SetLinkURL(aLinkURL, aLinkText);
|
|
|
|
rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
|
|
m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
|
|
|
|
bDisallow = false;
|
|
}
|
|
}
|
|
|
|
return bDisallow;
|
|
}
|
|
|
|
void ScContentTree::SetRootType( ScContentId nNew )
|
|
{
|
|
if ( nNew != nRootType )
|
|
{
|
|
nRootType = nNew;
|
|
Refresh();
|
|
|
|
ScNavipiCfg& rCfg = ScModule::get()->GetNavipiCfg();
|
|
rCfg.SetRootType( nRootType );
|
|
}
|
|
}
|
|
|
|
void ScContentTree::ToggleRoot() // after selection
|
|
{
|
|
ScContentId nNew = ScContentId::ROOT;
|
|
if ( nRootType == ScContentId::ROOT )
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
|
|
if (m_xTreeView->get_cursor(xEntry.get()))
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get()));
|
|
if (!m_xTreeView->iter_parent(*xParent))
|
|
xParent.reset();
|
|
|
|
for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
|
|
{
|
|
if (!m_aRootNodes[static_cast<ScContentId>(i)])
|
|
continue;
|
|
if ((m_xTreeView->iter_compare(*xEntry, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0) ||
|
|
(xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0))
|
|
{
|
|
nNew = static_cast<ScContentId>(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
SetRootType( nNew );
|
|
}
|
|
|
|
void ScContentTree::ResetManualDoc()
|
|
{
|
|
aManualDoc.clear();
|
|
|
|
ActiveDocChanged();
|
|
}
|
|
|
|
bool ScContentTree::ActiveDocChanged()
|
|
{
|
|
bool bRefreshed = false;
|
|
|
|
if (aManualDoc.isEmpty())
|
|
{
|
|
Refresh(); // content only if automatic
|
|
bRefreshed = true;
|
|
}
|
|
|
|
// if flag active Listbox must be updated
|
|
|
|
OUString aCurrent;
|
|
|
|
ScDocShell* pSh = GetManualOrCurrent();
|
|
if (pSh)
|
|
aCurrent = pSh->GetTitle();
|
|
else
|
|
{
|
|
// document is no longer available
|
|
|
|
aManualDoc.clear(); // again automatically
|
|
Refresh();
|
|
bRefreshed = true;
|
|
pSh = GetManualOrCurrent(); // should be active now
|
|
if (pSh)
|
|
aCurrent = pSh->GetTitle();
|
|
}
|
|
|
|
pParentWindow->GetDocNames( &aCurrent ); // select
|
|
|
|
return bRefreshed;
|
|
}
|
|
|
|
void ScContentTree::SetManualDoc(const OUString& rName)
|
|
{
|
|
aManualDoc = rName;
|
|
Refresh();
|
|
pParentWindow->GetDocNames( &aManualDoc ); // select
|
|
}
|
|
|
|
void ScContentTree::SelectDoc(const OUString& rName) // rName like shown in Menu/Listbox
|
|
{
|
|
if ( rName == pParentWindow->aStrActiveWin )
|
|
{
|
|
ResetManualDoc();
|
|
return;
|
|
}
|
|
|
|
// omit "active" or "inactive"
|
|
|
|
OUString aRealName = rName;
|
|
sal_Int32 nLen = rName.getLength();
|
|
sal_Int32 nActiveStart = nLen - pParentWindow->aStrActive.getLength();
|
|
if ( rName.subView( nActiveStart ) == pParentWindow->aStrActive )
|
|
aRealName = rName.copy( 0, nActiveStart );
|
|
sal_Int32 nNotActiveStart = nLen - pParentWindow->aStrNotActive.getLength();
|
|
if ( rName.subView( nNotActiveStart ) == pParentWindow->aStrNotActive )
|
|
aRealName = rName.copy( 0, nNotActiveStart );
|
|
|
|
bool bLoaded = false;
|
|
|
|
// Is it a normally loaded document?
|
|
|
|
SfxObjectShell* pSh = SfxObjectShell::GetFirst();
|
|
while ( pSh && !bLoaded )
|
|
{
|
|
if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
|
|
if ( pSh->GetTitle() == aRealName )
|
|
bLoaded = true;
|
|
pSh = SfxObjectShell::GetNext( *pSh );
|
|
}
|
|
|
|
if (bLoaded)
|
|
{
|
|
SetManualDoc(aRealName);
|
|
}
|
|
else
|
|
{
|
|
OSL_FAIL("SelectDoc: not found");
|
|
}
|
|
}
|
|
|
|
void ScContentTree::SelectEntryByName(const ScContentId nRoot, std::u16string_view rName)
|
|
{
|
|
weld::TreeIter* pParent = m_aRootNodes[nRoot].get();
|
|
|
|
if (!pParent || !m_xTreeView->iter_has_child(*pParent))
|
|
return;
|
|
|
|
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
|
|
bool bEntry = m_xTreeView->iter_children(*xEntry);
|
|
|
|
while (bEntry)
|
|
{
|
|
if (m_xTreeView->get_text(*xEntry) == rName)
|
|
{
|
|
m_xTreeView->select(*xEntry);
|
|
m_xTreeView->set_cursor(*xEntry);
|
|
|
|
// Scroll to the selected item
|
|
m_xTreeView->scroll_to_row(*xEntry);
|
|
|
|
StoreNavigatorSettings();
|
|
|
|
return;
|
|
}
|
|
bEntry = m_xTreeView->iter_next(*xEntry);
|
|
}
|
|
}
|
|
|
|
void ScContentTree::ApplyNavigatorSettings()
|
|
{
|
|
const ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
|
|
if( !pSettings )
|
|
return;
|
|
|
|
ScContentId nRootSel = pSettings->GetRootSelected();
|
|
auto nChildSel = pSettings->GetChildSelected();
|
|
|
|
// tdf#133079 ensure Sheet root is selected if nothing
|
|
// else would be
|
|
if (nRootSel == ScContentId::ROOT)
|
|
{
|
|
nRootSel = ScContentId::TABLE;
|
|
nChildSel = SC_CONTENT_NOCHILD;
|
|
}
|
|
|
|
for( int i = 1; i <= int(ScContentId::LAST); ++i )
|
|
{
|
|
ScContentId nEntry = static_cast<ScContentId>(i);
|
|
if( m_aRootNodes[ nEntry ] )
|
|
{
|
|
// gray or ungray
|
|
if (!m_xTreeView->iter_has_child(*m_aRootNodes[nEntry]))
|
|
m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], false);
|
|
else
|
|
m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], true);
|
|
|
|
// expand
|
|
bool bExp = pSettings->IsExpanded( nEntry );
|
|
if (bExp != m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]))
|
|
{
|
|
if( bExp )
|
|
m_xTreeView->expand_row(*m_aRootNodes[nEntry]);
|
|
else
|
|
m_xTreeView->collapse_row(*m_aRootNodes[nEntry]);
|
|
}
|
|
|
|
// select
|
|
if( nRootSel == nEntry )
|
|
{
|
|
std::unique_ptr<weld::TreeIter> xEntry;
|
|
if (bExp && (nChildSel != SC_CONTENT_NOCHILD))
|
|
{
|
|
xEntry = m_xTreeView->make_iterator(m_aRootNodes[nEntry].get());
|
|
if (!m_xTreeView->iter_children(*xEntry) || !m_xTreeView->iter_nth_sibling(*xEntry, nChildSel))
|
|
xEntry.reset();
|
|
}
|
|
m_xTreeView->select(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
|
|
m_xTreeView->set_cursor(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScContentTree::StoreNavigatorSettings()
|
|
{
|
|
if (m_nAsyncMouseReleaseId)
|
|
{
|
|
Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
|
|
m_nAsyncMouseReleaseId = nullptr;
|
|
}
|
|
|
|
ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
|
|
if( !pSettings )
|
|
return;
|
|
|
|
for( int i = 1; i <= int(ScContentId::LAST); ++i )
|
|
{
|
|
ScContentId nEntry = static_cast<ScContentId>(i);
|
|
bool bExp = m_aRootNodes[nEntry] && m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]);
|
|
pSettings->SetExpanded( nEntry, bExp );
|
|
}
|
|
|
|
std::unique_ptr<weld::TreeIter> xCurEntry(m_xTreeView->make_iterator());
|
|
if (!m_xTreeView->get_cursor(xCurEntry.get()))
|
|
xCurEntry.reset();
|
|
|
|
ScContentId nRoot;
|
|
sal_uLong nChild;
|
|
GetEntryIndexes(nRoot, nChild, xCurEntry.get());
|
|
|
|
pSettings->SetRootSelected( nRoot );
|
|
pSettings->SetChildSelected( nChild );
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|