Bug Summary

File:home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx
Warning:line 1549, column 21
Forming reference to null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name content.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SC_DLLIMPLEMENTATION -D SC_INFO_OSVERSION="LINUX" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/clew/source/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sc/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23
24#include <svx/svditer.hxx>
25#include <svx/svdobj.hxx>
26#include <svx/svdview.hxx>
27#include <sfx2/linkmgr.hxx>
28#include <sfx2/docfile.hxx>
29#include <sfx2/viewfrm.hxx>
30#include <vcl/commandevent.hxx>
31#include <vcl/help.hxx>
32#include <vcl/svapp.hxx>
33#include <tools/urlobj.hxx>
34#include <sal/log.hxx>
35#include <unotools/charclass.hxx>
36
37#include <content.hxx>
38#include <navipi.hxx>
39#include <global.hxx>
40#include <docsh.hxx>
41#include <scmod.hxx>
42#include <rangenam.hxx>
43#include <dbdata.hxx>
44#include <tablink.hxx>
45#include <drwlayer.hxx>
46#include <transobj.hxx>
47#include <drwtrans.hxx>
48#include <lnktrans.hxx>
49#include <strings.hrc>
50#include <scresid.hxx>
51#include <bitmaps.hlst>
52#include <arealink.hxx>
53#include <navicfg.hxx>
54#include <navsett.hxx>
55#include <postit.hxx>
56#include <tabvwsh.hxx>
57#include <drawview.hxx>
58#include <clipparam.hxx>
59#include <markdata.hxx>
60
61using namespace com::sun::star;
62
63// order of the categories in navigator -------------------------------------
64
65const ScContentId pTypeList[int(ScContentId::LAST) + 1] =
66{
67 ScContentId::ROOT, // ROOT (0) has to be at the front
68 ScContentId::TABLE,
69 ScContentId::RANGENAME,
70 ScContentId::DBAREA,
71 ScContentId::AREALINK,
72 ScContentId::GRAPHIC,
73 ScContentId::OLEOBJECT,
74 ScContentId::NOTE,
75 ScContentId::DRAWING
76};
77
78const std::u16string_view aContentBmps[]=
79{
80 u"" RID_BMP_CONTENT_TABLE"sc/res/nc01.png",
81 u"" RID_BMP_CONTENT_RANGENAME"sc/res/nc02.png",
82 u"" RID_BMP_CONTENT_DBAREA"sc/res/nc03.png",
83 u"" RID_BMP_CONTENT_GRAPHIC"sc/res/nc04.png",
84 u"" RID_BMP_CONTENT_OLEOBJECT"sc/res/nc05.png",
85 u"" RID_BMP_CONTENT_NOTE"sc/res/nc06.png",
86 u"" RID_BMP_CONTENT_AREALINK"sc/res/nc07.png",
87 u"" RID_BMP_CONTENT_DRAWING"sc/res/nc08.png"
88};
89
90ScDocShell* ScContentTree::GetManualOrCurrent()
91{
92 ScDocShell* pSh = nullptr;
93 if ( !aManualDoc.isEmpty() )
94 {
95 SfxObjectShell* pObjSh = SfxObjectShell::GetFirst( checkSfxObjectShell<ScDocShell> );
96 while ( pObjSh && !pSh )
97 {
98 if ( pObjSh->GetTitle() == aManualDoc )
99 pSh = dynamic_cast<ScDocShell*>( pObjSh );
100 pObjSh = SfxObjectShell::GetNext( *pObjSh, checkSfxObjectShell<ScDocShell> );
101 }
102 }
103 else
104 {
105 // only current when manual isn't set
106 // (so it's detected when the documents don't exists any longer)
107
108 SfxViewShell* pViewSh = SfxViewShell::Current();
109 if ( pViewSh )
110 {
111 SfxObjectShell* pObjSh = pViewSh->GetViewFrame()->GetObjectShell();
112 pSh = dynamic_cast<ScDocShell*>( pObjSh );
113 }
114 }
115
116 return pSh;
117}
118
119// ScContentTree
120
121ScContentTree::ScContentTree(std::unique_ptr<weld::TreeView> xTreeView, ScNavigatorDlg* pNavigatorDlg)
122 : m_xTreeView(std::move(xTreeView))
123 , m_xScratchIter(m_xTreeView->make_iterator())
124 , m_xTransferObj(new ScLinkTransferObj)
125 , pParentWindow(pNavigatorDlg)
126 , nRootType(ScContentId::ROOT)
127 , bHiddenDoc(false)
128 , pHiddenDocument(nullptr)
129 , bisInNavigatoeDlg(false)
130 , m_bFreeze(false)
131 , m_nAsyncMouseReleaseId(nullptr)
132{
133 for (sal_uInt16 i = 0; i <= int(ScContentId::LAST); ++i)
134 pPosList[pTypeList[i]] = i; // inverse for searching
135
136 m_aRootNodes[ScContentId::ROOT] = nullptr;
137 for (sal_uInt16 i = 1; i < int(ScContentId::LAST); ++i)
138 InitRoot(static_cast<ScContentId>(i));
139
140 m_xTreeView->connect_row_activated(LINK(this, ScContentTree, ContentDoubleClickHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScContentTree
*>(this), &ScContentTree::LinkStubContentDoubleClickHdl
)
);
141 m_xTreeView->connect_mouse_release(LINK(this, ScContentTree, MouseReleaseHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScContentTree
*>(this), &ScContentTree::LinkStubMouseReleaseHdl)
);
142 m_xTreeView->connect_key_press(LINK(this, ScContentTree, KeyInputHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScContentTree
*>(this), &ScContentTree::LinkStubKeyInputHdl)
);
143 m_xTreeView->connect_popup_menu(LINK(this, ScContentTree, CommandHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScContentTree
*>(this), &ScContentTree::LinkStubCommandHdl)
);
144 m_xTreeView->connect_query_tooltip(LINK(this, ScContentTree, QueryTooltipHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScContentTree
*>(this), &ScContentTree::LinkStubQueryTooltipHdl)
);
145
146 rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj.get());
147 m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE | DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK);
148
149 m_xTreeView->connect_drag_begin(LINK(this, ScContentTree, DragBeginHdl)::tools::detail::makeLink( ::tools::detail::castTo<ScContentTree
*>(this), &ScContentTree::LinkStubDragBeginHdl)
);
150}
151
152ScContentTree::~ScContentTree()
153{
154 if (m_nAsyncMouseReleaseId)
155 {
156 Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
157 m_nAsyncMouseReleaseId = nullptr;
158 }
159 pParentWindow.clear();
160}
161
162static const char* SCSTR_CONTENT_ARY[] =
163{
164 SCSTR_CONTENT_ROOTreinterpret_cast<char const *>("SCSTR_CONTENT_ROOT" "\004"
u8"Contents")
,
165 SCSTR_CONTENT_TABLEreinterpret_cast<char const *>("SCSTR_CONTENT_TABLE" "\004"
u8"Sheets")
,
166 SCSTR_CONTENT_RANGENAMEreinterpret_cast<char const *>("SCSTR_CONTENT_RANGENAME"
"\004" u8"Range names")
,
167 SCSTR_CONTENT_DBAREAreinterpret_cast<char const *>("SCSTR_CONTENT_DBAREA" "\004"
u8"Database ranges")
,
168 SCSTR_CONTENT_GRAPHICreinterpret_cast<char const *>("SCSTR_CONTENT_GRAPHIC" "\004"
u8"Images")
,
169 SCSTR_CONTENT_OLEOBJECTreinterpret_cast<char const *>("SCSTR_CONTENT_OLEOBJECT"
"\004" u8"OLE objects")
,
170 SCSTR_CONTENT_NOTEreinterpret_cast<char const *>("SCSTR_CONTENT_NOTE" "\004"
u8"Comments")
,
171 SCSTR_CONTENT_AREALINKreinterpret_cast<char const *>("SCSTR_CONTENT_AREALINK"
"\004" u8"Linked areas")
,
172 SCSTR_CONTENT_DRAWINGreinterpret_cast<char const *>("SCSTR_CONTENT_DRAWING" "\004"
u8"Drawing objects")
173};
174
175void ScContentTree::InitRoot( ScContentId nType )
176{
177 if ( nType == ScContentId::ROOT )
178 return;
179
180 if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
181 {
182 m_aRootNodes[nType] = nullptr;
183 return;
184 }
185
186 auto const aImage(aContentBmps[static_cast<int>(nType) - 1]);
187 OUString aName(ScResId(SCSTR_CONTENT_ARY[static_cast<int>(nType)]));
188 // back to the correct position:
189 sal_uInt16 nPos = nRootType != ScContentId::ROOT ? 0 : pPosList[nType]-1;
190 m_aRootNodes[nType] = m_xTreeView->make_iterator();
191 m_xTreeView->insert(nullptr, nPos, &aName, nullptr, nullptr, nullptr, false, m_aRootNodes[nType].get());
192 m_xTreeView->set_image(*m_aRootNodes[nType], aImage);
193}
194
195void ScContentTree::ClearAll()
196{
197 //There are one method in Control::SetUpdateMode(), and one override method SvTreeListBox::SetUpdateMode(). Here although
198 //SvTreeListBox::SetUpdateMode() is called in refresh method, it only call SvTreeListBox::SetUpdateMode(), not Control::SetUpdateMode().
199 //In m_xTreeView->clear(), Broadcast( LISTACTION_CLEARED ) will be called and finally, it will be trapped into the event yield() loop. And
200 //the InitRoot() method won't be called. Then if a user click or press key to update the navigator tree, crash happens.
201 //So the solution is to disable the UpdateMode of Control, then call Clear(), then recover the update mode
202 bool bWasFrozen = m_bFreeze;
203 if (!bWasFrozen)
204 freeze();
205 m_xTreeView->clear();
206 if (!bWasFrozen)
207 thaw();
208 for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
209 InitRoot(static_cast<ScContentId>(i));
210}
211
212void ScContentTree::ClearType(ScContentId nType)
213{
214 if (nType == ScContentId::ROOT)
215 ClearAll();
216 else
217 {
218 weld::TreeIter* pParent = m_aRootNodes[nType].get();
219 if (!pParent || m_xTreeView->iter_has_child(*pParent)) // not if no children existing
220 {
221 if (pParent)
222 m_xTreeView->remove(*pParent); // with all children
223 InitRoot( nType ); // if needed insert anew
224 }
225 }
226}
227
228void ScContentTree::InsertContent( ScContentId nType, const OUString& rValue )
229{
230 weld::TreeIter* pParent = m_aRootNodes[nType].get();
231 if (pParent)
232 {
233 m_xTreeView->insert(pParent, -1, &rValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
234 m_xTreeView->set_sensitive(*m_xScratchIter, true);
235 }
236 else
237 {
238 OSL_FAIL("InsertContent without parent")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "238" ": "), "%s", "InsertContent without parent"); } } while
(false)
;
239 }
240}
241
242void ScContentTree::GetEntryIndexes(ScContentId& rnRootIndex, sal_uLong& rnChildIndex, const weld::TreeIter* pEntry) const
243{
244 rnRootIndex = ScContentId::ROOT;
245 rnChildIndex = SC_CONTENT_NOCHILD;
246
247 if( !pEntry )
248 return;
249
250 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(pEntry));
251 if (!m_xTreeView->iter_parent(*xParent))
252 xParent.reset();
253 bool bFound = false;
254 for( int i = 1; !bFound && (i <= int(ScContentId::LAST)); ++i )
255 {
256 ScContentId nRoot = static_cast<ScContentId>(i);
257 if (!m_aRootNodes[nRoot])
258 continue;
259 if (m_xTreeView->iter_compare(*pEntry, *m_aRootNodes[nRoot]) == 0)
260 {
261 rnRootIndex = nRoot;
262 rnChildIndex = ~0UL;
263 bFound = true;
264 }
265 else if (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[nRoot]) == 0)
266 {
267 rnRootIndex = nRoot;
268
269 // search the entry in all child entries of the parent
270 sal_uLong nEntry = 0;
271 std::unique_ptr<weld::TreeIter> xIterEntry(m_xTreeView->make_iterator(xParent.get()));
272 bool bIterEntry = m_xTreeView->iter_children(*xIterEntry);
273 while (!bFound && bIterEntry)
274 {
275 if (m_xTreeView->iter_compare(*pEntry, *xIterEntry) == 0)
276 {
277 rnChildIndex = nEntry;
278 bFound = true; // exit the while loop
279 }
280 bIterEntry = m_xTreeView->iter_next_sibling(*xIterEntry);
281 ++nEntry;
282 }
283
284 bFound = true; // exit the for loop
285 }
286 }
287}
288
289sal_uLong ScContentTree::GetChildIndex(const weld::TreeIter* pEntry) const
290{
291 ScContentId nRoot;
292 sal_uLong nChild;
293 GetEntryIndexes(nRoot, nChild, pEntry);
294 return nChild;
295}
296
297static OUString lcl_GetDBAreaRange( const ScDocument* pDoc, const OUString& rDBName )
298{
299 OUString aRet;
300 if (pDoc)
301 {
302 ScDBCollection* pDbNames = pDoc->GetDBCollection();
303 const ScDBData* pData = pDbNames->getNamedDBs().findByUpperName(ScGlobal::getCharClassPtr()->uppercase(rDBName));
304 if (pData)
305 {
306 ScRange aRange;
307 pData->GetArea(aRange);
308 aRet = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS_3D);
309 }
310 }
311 return aRet;
312}
313
314IMPL_LINK_NOARG(ScContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)bool ScContentTree::LinkStubContentDoubleClickHdl(void * instance
, weld::TreeView& data) { return static_cast<ScContentTree
*>(instance)->ContentDoubleClickHdl(data); } bool ScContentTree
::ContentDoubleClickHdl(__attribute__ ((unused)) weld::TreeView
&)
315{
316 ScContentId nType;
317 sal_uLong nChild;
318 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
319 if (!m_xTreeView->get_cursor(xEntry.get()))
320 xEntry.reset();
321 GetEntryIndexes(nType, nChild, xEntry.get());
322
323 if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
324 {
325 if ( bHiddenDoc )
326 return false; //! later...
327
328 OUString aText(m_xTreeView->get_text(*xEntry));
329
330 if ( !aManualDoc.isEmpty() )
331 pParentWindow->SetCurrentDoc( aManualDoc );
332
333 switch( nType )
334 {
335 case ScContentId::TABLE:
336 pParentWindow->SetCurrentTableStr( aText );
337 break;
338
339 case ScContentId::RANGENAME:
340 pParentWindow->SetCurrentCellStr( aText );
341 break;
342
343 case ScContentId::DBAREA:
344 {
345 // If the same names of area and DB exists, then
346 // SID_CURRENTCELL takes the area name.
347 // Therefore for DB areas access them directly via address.
348
349 OUString aRangeStr = lcl_GetDBAreaRange( GetSourceDocument(), aText );
350 if (!aRangeStr.isEmpty())
351 pParentWindow->SetCurrentCellStr( aRangeStr );
352 }
353 break;
354
355 case ScContentId::OLEOBJECT:
356 case ScContentId::GRAPHIC:
357 case ScContentId::DRAWING:
358 pParentWindow->SetCurrentObject( aText );
359 break;
360
361 case ScContentId::NOTE:
362 {
363 ScAddress aPos = GetNotePos( nChild );
364 pParentWindow->SetCurrentTable( aPos.Tab() );
365 pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
366 }
367 break;
368
369 case ScContentId::AREALINK:
370 {
371 const ScAreaLink* pLink = GetLink(nChild);
372 ScDocument* pSrcDoc = GetSourceDocument();
373 if (pLink && pSrcDoc)
374 {
375 const ScRange& aRange = pLink->GetDestArea();
376 OUString aRangeStr(aRange.Format(*pSrcDoc, ScRefFlags::RANGE_ABS_3D, pSrcDoc->GetAddressConvention()));
377 pParentWindow->SetCurrentCellStr( aRangeStr );
378 }
379 }
380 break;
381 default: break;
382 }
383
384 ScNavigatorDlg::ReleaseFocus(); // set focus into document
385 }
386
387 return false;
388}
389
390void ScContentTree::LaunchAsyncStoreNavigatorSettings()
391{
392 if (!m_nAsyncMouseReleaseId)
393 m_nAsyncMouseReleaseId = Application::PostUserEvent(LINK(this, ScContentTree, AsyncStoreNavigatorSettings)::tools::detail::makeLink( ::tools::detail::castTo<ScContentTree
*>(this), &ScContentTree::LinkStubAsyncStoreNavigatorSettings
)
);
394}
395
396IMPL_LINK_NOARG(ScContentTree, MouseReleaseHdl, const MouseEvent&, bool)bool ScContentTree::LinkStubMouseReleaseHdl(void * instance, const
MouseEvent& data) { return static_cast<ScContentTree *
>(instance)->MouseReleaseHdl(data); } bool ScContentTree
::MouseReleaseHdl(__attribute__ ((unused)) const MouseEvent&
)
397{
398 LaunchAsyncStoreNavigatorSettings();
399 return false;
400}
401
402IMPL_LINK_NOARG(ScContentTree, AsyncStoreNavigatorSettings, void*, void)void ScContentTree::LinkStubAsyncStoreNavigatorSettings(void *
instance, void* data) { return static_cast<ScContentTree *
>(instance)->AsyncStoreNavigatorSettings(data); } void ScContentTree
::AsyncStoreNavigatorSettings(__attribute__ ((unused)) void*)
403{
404 m_nAsyncMouseReleaseId = nullptr;
405 StoreNavigatorSettings();
406}
407
408IMPL_LINK(ScContentTree, KeyInputHdl, const KeyEvent&, rKEvt, bool)bool ScContentTree::LinkStubKeyInputHdl(void * instance, const
KeyEvent& data) { return static_cast<ScContentTree *>
(instance)->KeyInputHdl(data); } bool ScContentTree::KeyInputHdl
(const KeyEvent& rKEvt)
409{
410 bool bUsed = false;
411
412 const vcl::KeyCode aCode = rKEvt.GetKeyCode();
413 if (aCode.GetCode() == KEY_RETURN)
414 {
415 switch (aCode.GetModifier())
416 {
417 case KEY_MOD1:
418 ToggleRoot(); // toggle root mode (as in Writer)
419 bUsed = true;
420 break;
421 case 0:
422 {
423 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
424 if (!m_xTreeView->get_cursor(xEntry.get()))
425 xEntry.reset();
426 if (xEntry)
427 {
428 ScContentId nType;
429 sal_uLong nChild;
430 GetEntryIndexes(nType, nChild, xEntry.get());
431
432 if (nType != ScContentId::ROOT && nChild == SC_CONTENT_NOCHILD)
433 {
434 if (m_xTreeView->get_row_expanded(*xEntry))
435 m_xTreeView->collapse_row(*xEntry);
436 else
437 m_xTreeView->expand_row(*xEntry);
438 }
439 else
440 ContentDoubleClickHdl(*m_xTreeView); // select content as if double clicked
441 }
442
443 bUsed = true;
444 }
445 break;
446 }
447 }
448 //Make KEY_SPACE has same function as DoubleClick
449 if ( bisInNavigatoeDlg )
450 {
451 if(aCode.GetCode() == KEY_SPACE )
452 {
453 bUsed = true;
454 ScContentId nType;
455 sal_uLong nChild;
456 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
457 if (!m_xTreeView->get_cursor(xEntry.get()))
458 xEntry.reset();
459 GetEntryIndexes(nType, nChild, xEntry.get());
460
461 if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
462 {
463 if ( bHiddenDoc )
464 return true; //! later...
465 OUString aText(m_xTreeView->get_text(*xEntry));
466 sKeyString = aText;
467 if (!aManualDoc.isEmpty())
468 pParentWindow->SetCurrentDoc( aManualDoc );
469 switch (nType)
470 {
471 case ScContentId::OLEOBJECT:
472 case ScContentId::GRAPHIC:
473 case ScContentId::DRAWING:
474 {
475 ScDrawView* pScDrawView = nullptr;
476 ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
477 if (pScTabViewShell)
478 pScDrawView = pScTabViewShell->GetViewData().GetScDrawView();
479 if (pScDrawView)
480 {
481 pScDrawView->SelectCurrentViewObject(aText);
482 bool bHasMakredObject = false;
483 weld::TreeIter* pParent = m_aRootNodes[nType].get();
484 std::unique_ptr<weld::TreeIter> xBeginEntry(m_xTreeView->make_iterator(pParent));
485 bool bBeginEntry = false;
486 if (pParent)
487 bBeginEntry = m_xTreeView->iter_children(*xBeginEntry);
488 while (bBeginEntry)
489 {
490 OUString aTempText(m_xTreeView->get_text(*xBeginEntry));
491 if( pScDrawView->GetObjectIsMarked( pScDrawView->GetObjectByName( aTempText ) ) )
492 {
493 bHasMakredObject = true;
494 break;
495 }
496 bBeginEntry = m_xTreeView->iter_next(*xBeginEntry);
497 }
498 if (!bHasMakredObject && pScTabViewShell)
499 pScTabViewShell->SetDrawShell(false);
500 ObjectFresh(nType, xEntry.get());
501 }
502 break;
503 }
504 default:
505 break;
506 }
507 }
508 }
509 }
510
511 if (!bUsed)
512 {
513 if (aCode.GetCode() == KEY_F5)
514 StoreNavigatorSettings();
515 else
516 LaunchAsyncStoreNavigatorSettings();
517 }
518
519 return bUsed;
520}
521
522IMPL_LINK(ScContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)bool ScContentTree::LinkStubCommandHdl(void * instance, const
CommandEvent& data) { return static_cast<ScContentTree
*>(instance)->CommandHdl(data); } bool ScContentTree::
CommandHdl(const CommandEvent& rCEvt)
523{
524 bool bDone = false;
525
526 switch ( rCEvt.GetCommand() )
527 {
528 case CommandEventId::ContextMenu:
529 {
530 // drag-and-drop mode
531 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/scalc/ui/dropmenu.ui"));
532 std::unique_ptr<weld::Menu> xPop(xBuilder->weld_menu("contextmenu"));
533 std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu("dragmodesubmenu"));
534
535 switch (pParentWindow->GetDropMode())
536 {
537 case 0:
538 xDropMenu->set_active("hyperlink", true);
539 break;
540 case 1:
541 xDropMenu->set_active("link", true);
542 break;
543 case 2:
544 xDropMenu->set_active("copy", true);
545 break;
546 }
547
548 // displayed document
549 std::unique_ptr<weld::Menu> xDocMenu(xBuilder->weld_menu("displaymenu"));
550//TODO aDocMenu->SetMenuFlags( aDocMenu->GetMenuFlags() | MenuFlags::NoAutoMnemonics );
551 sal_uInt16 i=0;
552 OUString sActive;
553 OUString sId;
554 // loaded documents
555 ScDocShell* pCurrentSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
556 SfxObjectShell* pSh = SfxObjectShell::GetFirst();
557 while ( pSh )
558 {
559 if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
560 {
561 OUString aName = pSh->GetTitle();
562 OUString aEntry = aName;
563 if ( pSh == pCurrentSh )
564 aEntry += pParentWindow->aStrActive;
565 else
566 aEntry += pParentWindow->aStrNotActive;
567 ++i;
568 sId = "document" + OUString::number(i);
569 xDocMenu->append_radio(sId, aEntry);
570 if ( !bHiddenDoc && aName == aManualDoc )
571 sActive = sId;
572 }
573 pSh = SfxObjectShell::GetNext( *pSh );
574 }
575 // "active window"
576 ++i;
577 sId = "document" + OUString::number(i);
578 xDocMenu->append_radio(sId, pParentWindow->aStrActiveWin);
579 if (!bHiddenDoc && aManualDoc.isEmpty())
580 sActive = sId;
581 // hidden document
582 if ( !aHiddenTitle.isEmpty() )
583 {
584 OUString aEntry = aHiddenTitle + pParentWindow->aStrHidden;
585 ++i;
586 sId = "document" + OUString::number(i);
587 xDocMenu->append_radio(sId, aEntry);
588 if (bHiddenDoc)
589 sActive = sId;
590 }
591 xDocMenu->set_active(sActive.toUtf8(), true);
592
593 OString sIdent = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
594 if (sIdent == "hyperlink")
595 pParentWindow->SetDropMode(0);
596 else if (sIdent == "link")
597 pParentWindow->SetDropMode(1);
598 else if (sIdent == "copy")
599 pParentWindow->SetDropMode(2);
600 else if (sIdent.startsWith("document"))
601 {
602 OUString aName = xDocMenu->get_label(sIdent);
603 SelectDoc(aName);
604 }
605 }
606 break;
607 default: break;
608 }
609
610 return bDone;
611}
612
613IMPL_LINK(ScContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)OUString ScContentTree::LinkStubQueryTooltipHdl(void * instance
, const weld::TreeIter& data) { return static_cast<ScContentTree
*>(instance)->QueryTooltipHdl(data); } OUString ScContentTree
::QueryTooltipHdl(const weld::TreeIter& rEntry)
614{
615 OUString aHelpText;
616
617 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
618 if (!m_xTreeView->iter_parent(*xParent))
619 xParent.reset();
620
621 if (!xParent) // Top-Level ?
622 {
623 aHelpText = OUString::number(m_xTreeView->iter_n_children(rEntry)) +
624 " " + m_xTreeView->get_text(rEntry);
625 }
626 else if (m_aRootNodes[ScContentId::NOTE] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::NOTE]) == 0)
627 {
628 aHelpText = m_xTreeView->get_text(rEntry); // notes as help text
629 }
630 else if (m_aRootNodes[ScContentId::AREALINK] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::AREALINK]) == 0)
631 {
632 auto nIndex = GetChildIndex(&rEntry);
633 if (nIndex != SC_CONTENT_NOCHILD)
634 {
635 const ScAreaLink* pLink = GetLink(nIndex);
636 if (pLink)
637 {
638 aHelpText = pLink->GetFile(); // source file as help text
639 }
640 }
641 }
642
643 return aHelpText;
644}
645
646ScDocument* ScContentTree::GetSourceDocument()
647{
648 if (bHiddenDoc)
649 return pHiddenDocument;
650 else
651 {
652 ScDocShell* pSh = GetManualOrCurrent();
653 if (pSh)
654 return &pSh->GetDocument();
655
656 }
657 return nullptr;
658}
659
660//Move along and draw "*" sign .
661void ScContentTree::ObjectFresh(ScContentId nType, const weld::TreeIter* pEntry)
662{
663 if (bHiddenDoc && !pHiddenDocument)
664 return; // other document displayed
665
666 if (!(nType == ScContentId::GRAPHIC || nType == ScContentId::OLEOBJECT || nType == ScContentId::DRAWING))
667 return;
668
669 auto nOldChildren = m_aRootNodes[nType] ? m_xTreeView->iter_n_children(*m_aRootNodes[nType]) : 0;
670 auto nOldPos = m_xTreeView->vadjustment_get_value();
671
672 freeze();
673 ClearType( nType );
674 GetDrawNames( nType/*, nId*/ );
675 thaw();
676
677 auto nNewChildren = m_aRootNodes[nType] ? m_xTreeView->iter_n_children(*m_aRootNodes[nType]) : 0;
678 bool bRestorePos = nOldChildren == nNewChildren;
679
680 if (!pEntry)
681 ApplyNavigatorSettings(bRestorePos, nOldPos);
682 if (!pEntry)
683 return;
684
685 weld::TreeIter* pParent = m_aRootNodes[nType].get();
686 std::unique_ptr<weld::TreeIter> xOldEntry;
687 std::unique_ptr<weld::TreeIter> xBeginEntry(m_xTreeView->make_iterator(pParent));
688 bool bBeginEntry = false;
689 if( pParent )
690 bBeginEntry = m_xTreeView->iter_children(*xBeginEntry);
691 while (bBeginEntry)
692 {
693 OUString aTempText(m_xTreeView->get_text(*xBeginEntry));
694 if (aTempText == sKeyString)
695 {
696 xOldEntry = m_xTreeView->make_iterator(xBeginEntry.get());
697 break;
698 }
699 bBeginEntry = m_xTreeView->iter_next(*xBeginEntry);
700 }
701 if (xOldEntry)
702 {
703 m_xTreeView->expand_row(*pParent);
704 m_xTreeView->select(*xOldEntry);
705 m_xTreeView->set_cursor(*xOldEntry);
706 StoreNavigatorSettings();
707 }
708}
709
710void ScContentTree::Refresh( ScContentId nType )
711{
712 if ( bHiddenDoc && !pHiddenDocument )
713 return; // other document displayed
714
715 // if nothing has changed the cancel right away (against flicker)
716
717 if ( nType == ScContentId::NOTE )
718 if (!NoteStringsChanged())
719 return;
720 if ( nType == ScContentId::GRAPHIC )
721 if (!DrawNamesChanged(ScContentId::GRAPHIC))
722 return;
723 if ( nType == ScContentId::OLEOBJECT )
724 if (!DrawNamesChanged(ScContentId::OLEOBJECT))
725 return;
726 if ( nType == ScContentId::DRAWING )
727 if (!DrawNamesChanged(ScContentId::DRAWING))
728 return;
729
730 freeze();
731
732 ClearType( nType );
733
734 if ( nType == ScContentId::ROOT || nType == ScContentId::TABLE )
735 GetTableNames();
736 if ( nType == ScContentId::ROOT || nType == ScContentId::RANGENAME )
737 GetAreaNames();
738 if ( nType == ScContentId::ROOT || nType == ScContentId::DBAREA )
739 GetDbNames();
740 if ( nType == ScContentId::ROOT || nType == ScContentId::GRAPHIC )
741 GetGraphicNames();
742 if ( nType == ScContentId::ROOT || nType == ScContentId::OLEOBJECT )
743 GetOleNames();
744 if ( nType == ScContentId::ROOT || nType == ScContentId::DRAWING )
745 GetDrawingNames();
746 if ( nType == ScContentId::ROOT || nType == ScContentId::NOTE )
747 GetNoteStrings();
748 if ( nType == ScContentId::ROOT || nType == ScContentId::AREALINK )
749 GetLinkNames();
750
751 thaw();
752
753 ApplyNavigatorSettings();
754}
755
756void ScContentTree::GetTableNames()
757{
758 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::TABLE ) // hidden ?
759 return;
760
761 ScDocument* pDoc = GetSourceDocument();
762 if (!pDoc)
763 return;
764
765 OUString aName;
766 SCTAB nCount = pDoc->GetTableCount();
767 for ( SCTAB i=0; i<nCount; i++ )
768 {
769 pDoc->GetName( i, aName );
770 InsertContent( ScContentId::TABLE, aName );
771 }
772}
773
774namespace {
775
776OUString createLocalRangeName(const OUString& rName, const OUString& rTableName)
777{
778 return rName + " (" + rTableName + ")";
779}
780}
781
782void ScContentTree::GetAreaNames()
783{
784 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::RANGENAME ) // hidden ?
785 return;
786
787 ScDocument* pDoc = GetSourceDocument();
788 if (!pDoc)
789 return;
790
791 ScRange aDummy;
792 std::set<OUString> aSet;
793 ScRangeName* pRangeNames = pDoc->GetRangeName();
794 for (const auto& rEntry : *pRangeNames)
795 {
796 if (rEntry.second->IsValidReference(aDummy))
797 aSet.insert(rEntry.second->GetName());
798 }
799 for (SCTAB i = 0; i < pDoc->GetTableCount(); ++i)
800 {
801 ScRangeName* pLocalRangeName = pDoc->GetRangeName(i);
802 if (pLocalRangeName && !pLocalRangeName->empty())
803 {
804 OUString aTableName;
805 pDoc->GetName(i, aTableName);
806 for (const auto& rEntry : *pLocalRangeName)
807 {
808 if (rEntry.second->IsValidReference(aDummy))
809 aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
810 }
811 }
812 }
813
814 for (const auto& rItem : aSet)
815 {
816 InsertContent(ScContentId::RANGENAME, rItem);
817 }
818}
819
820void ScContentTree::GetDbNames()
821{
822 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::DBAREA ) // hidden ?
823 return;
824
825 ScDocument* pDoc = GetSourceDocument();
826 if (!pDoc)
827 return;
828
829 ScDBCollection* pDbNames = pDoc->GetDBCollection();
830 const ScDBCollection::NamedDBs& rDBs = pDbNames->getNamedDBs();
831 for (const auto& rxDB : rDBs)
832 {
833 const OUString& aStrName = rxDB->GetName();
834 InsertContent(ScContentId::DBAREA, aStrName);
835 }
836}
837
838bool ScContentTree::IsPartOfType( ScContentId nContentType, sal_uInt16 nObjIdentifier )
839{
840 bool bRet = false;
841 switch ( nContentType )
842 {
843 case ScContentId::GRAPHIC:
844 bRet = ( nObjIdentifier == OBJ_GRAF );
845 break;
846 case ScContentId::OLEOBJECT:
847 bRet = ( nObjIdentifier == OBJ_OLE2 );
848 break;
849 case ScContentId::DRAWING:
850 bRet = ( nObjIdentifier != OBJ_GRAF && nObjIdentifier != OBJ_OLE2 ); // everything else
851 break;
852 default:
853 OSL_FAIL("unknown content type")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "853" ": "), "%s", "unknown content type"); } } while (false
)
;
854 }
855 return bRet;
856}
857
858void ScContentTree::GetDrawNames( ScContentId nType )
859{
860 if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
861 return;
862
863 ScDocument* pDoc = GetSourceDocument();
864 if (!pDoc)
865 return;
866
867 // iterate in flat mode for groups
868 SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
869
870 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
871 SfxObjectShell* pShell = pDoc->GetDocumentShell();
872 if (!(pDrawLayer && pShell))
873 return;
874
875 SCTAB nTabCount = pDoc->GetTableCount();
876 for (SCTAB nTab=0; nTab<nTabCount; nTab++)
877 {
878 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
879 OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "879" ": "), "%s", "Page ?"); } } while (false)
;
880 if (pPage)
881 {
882 SdrObjListIter aIter( pPage, eIter );
883 SdrObject* pObject = aIter.Next();
884 while (pObject)
885 {
886 if ( IsPartOfType( nType, pObject->GetObjIdentifier() ) )
887 {
888 OUString aName = ScDrawLayer::GetVisibleName( pObject );
889 if (!aName.isEmpty())
890 {
891 if( bisInNavigatoeDlg )
892 {
893 weld::TreeIter* pParent = m_aRootNodes[nType].get();
894 if (pParent)
895 {
896 m_xTreeView->insert(pParent, -1, &aName, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
897 m_xTreeView->set_sensitive(*m_xScratchIter, true);
898 }//end if parent
899 else
900 SAL_WARN("sc", "InsertContent without parent")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "sc")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "InsertContent without parent") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "900" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "InsertContent without parent"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "InsertContent without parent"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "900" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "InsertContent without parent") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "900" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "InsertContent without parent"), 0); }
else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "InsertContent without parent"; ::sal::detail::log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("sc"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "900" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
901 }
902 }
903
904 }
905
906 pObject = aIter.Next();
907 }
908 }
909 }
910}
911
912void ScContentTree::GetGraphicNames()
913{
914 GetDrawNames( ScContentId::GRAPHIC );
915}
916
917void ScContentTree::GetOleNames()
918{
919 GetDrawNames( ScContentId::OLEOBJECT );
920}
921
922void ScContentTree::GetDrawingNames()
923{
924 GetDrawNames( ScContentId::DRAWING );
925}
926
927void ScContentTree::GetLinkNames()
928{
929 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::AREALINK ) // hidden ?
930 return;
931
932 ScDocument* pDoc = GetSourceDocument();
933 if (!pDoc)
934 return;
935
936 sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
937 OSL_ENSURE(pLinkManager, "no LinkManager on document?")do { if (true && (!(pLinkManager))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "937" ": "), "%s", "no LinkManager on document?"); } } while
(false)
;
938 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
939 sal_uInt16 nCount = rLinks.size();
940 for (sal_uInt16 i=0; i<nCount; i++)
941 {
942 ::sfx2::SvBaseLink* pBase = rLinks[i].get();
943 if (dynamic_cast<const ScAreaLink*>( pBase) != nullptr)
944 InsertContent( ScContentId::AREALINK, static_cast<ScAreaLink*>(pBase)->GetSource() );
945
946 // insert in list the names of source areas
947 }
948}
949
950const ScAreaLink* ScContentTree::GetLink( sal_uLong nIndex )
951{
952 ScDocument* pDoc = GetSourceDocument();
953 if (!pDoc)
954 return nullptr;
955
956 sal_uLong nFound = 0;
957 sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
958 OSL_ENSURE(pLinkManager, "no LinkManager on document?")do { if (true && (!(pLinkManager))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "958" ": "), "%s", "no LinkManager on document?"); } } while
(false)
;
959 const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
960 sal_uInt16 nCount = rLinks.size();
961 for (sal_uInt16 i=0; i<nCount; i++)
962 {
963 ::sfx2::SvBaseLink* pBase = rLinks[i].get();
964 if (auto pAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
965 {
966 if (nFound == nIndex)
967 return pAreaLink;
968 ++nFound;
969 }
970 }
971
972 OSL_FAIL("link not found")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "972" ": "), "%s", "link not found"); } } while (false)
;
973 return nullptr;
974}
975
976static OUString lcl_NoteString( const ScPostIt& rNote )
977{
978 OUString aText = rNote.GetText();
979 sal_Int32 nAt;
980 while ( (nAt = aText.indexOf( '\n' )) != -1 )
981 aText = aText.replaceAt( nAt, 1, " " );
982 return aText;
983}
984
985void ScContentTree::GetNoteStrings()
986{
987 if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::NOTE ) // hidden ?
988 return;
989
990 ScDocument* pDoc = GetSourceDocument();
991 if (!pDoc)
992 return;
993
994 // loop over cell notes
995 std::vector<sc::NoteEntry> aEntries;
996 pDoc->GetAllNoteEntries(aEntries);
997 for (const auto& rEntry : aEntries)
998 InsertContent(ScContentId::NOTE, lcl_NoteString(*rEntry.mpNote));
999}
1000
1001ScAddress ScContentTree::GetNotePos( sal_uLong nIndex )
1002{
1003 ScDocument* pDoc = GetSourceDocument();
1004 if (!pDoc)
1005 return ScAddress();
1006
1007 return pDoc->GetNotePosition(nIndex);
1008}
1009
1010bool ScContentTree::NoteStringsChanged()
1011{
1012 ScDocument* pDoc = GetSourceDocument();
1013 if (!pDoc)
1014 return false;
1015
1016 weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
1017 if (!pParent)
1018 return false;
1019
1020 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
1021 bool bEntry = m_xTreeView->iter_children(*xEntry);
1022
1023 std::vector<sc::NoteEntry> aEntries;
1024 pDoc->GetAllNoteEntries(aEntries);
1025 for (const auto& rEntry : aEntries)
1026 {
1027 const ScPostIt* pNote = rEntry.mpNote;
1028 if (!bEntry)
1029 return true;
1030
1031 if (lcl_NoteString(*pNote) != m_xTreeView->get_text(*xEntry))
1032 return true;
1033
1034 bEntry = m_xTreeView->iter_next_sibling(*xEntry);
1035 }
1036
1037 return bEntry;
1038}
1039
1040bool ScContentTree::DrawNamesChanged( ScContentId nType )
1041{
1042 ScDocument* pDoc = GetSourceDocument();
1043 if (!pDoc)
1044 return false;
1045
1046 weld::TreeIter* pParent = m_aRootNodes[nType].get();
1047 if (!pParent)
1048 return false;
1049
1050 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
1051 bool bEntry = m_xTreeView->iter_children(*xEntry);
1052
1053 // iterate in flat mode for groups
1054 SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
1055
1056 bool bEqual = true;
1057 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
1058 SfxObjectShell* pShell = pDoc->GetDocumentShell();
1059 if (pDrawLayer && pShell)
1060 {
1061 SCTAB nTabCount = pDoc->GetTableCount();
1062 for (SCTAB nTab=0; nTab<nTabCount && bEqual; nTab++)
1063 {
1064 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
1065 OSL_ENSURE(pPage,"Page ?")do { if (true && (!(pPage))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "1065" ": "), "%s", "Page ?"); } } while (false)
;
1066 if (pPage)
1067 {
1068 SdrObjListIter aIter( pPage, eIter );
1069 SdrObject* pObject = aIter.Next();
1070 while (pObject && bEqual)
1071 {
1072 if ( IsPartOfType( nType, pObject->GetObjIdentifier() ) )
1073 {
1074 if ( !bEntry )
1075 bEqual = false;
1076 else
1077 {
1078 if (ScDrawLayer::GetVisibleName(pObject) != m_xTreeView->get_text(*xEntry))
1079 bEqual = false;
1080
1081 bEntry = m_xTreeView->iter_next_sibling(*xEntry);
1082 }
1083 }
1084 pObject = aIter.Next();
1085 }
1086 }
1087 }
1088 }
1089
1090 if ( bEntry )
1091 bEqual = false; // anything else
1092
1093 return !bEqual;
1094}
1095
1096static bool lcl_GetRange( const ScDocument& rDoc, ScContentId nType, const OUString& rName, ScRange& rRange )
1097{
1098 bool bFound = false;
1099
1100 if ( nType == ScContentId::RANGENAME )
1101 {
1102 ScRangeName* pList = rDoc.GetRangeName();
1103 if (pList)
1104 {
1105 const ScRangeData* p = pList->findByUpperName(ScGlobal::getCharClassPtr()->uppercase(rName));
1106 if (p && p->IsValidReference(rRange))
1107 bFound = true;
1108 }
1109 }
1110 else if ( nType == ScContentId::DBAREA )
1111 {
1112 ScDBCollection* pList = rDoc.GetDBCollection();
1113 if (pList)
1114 {
1115 const ScDBData* p = pList->getNamedDBs().findByUpperName(ScGlobal::getCharClassPtr()->uppercase(rName));
1116 if (p)
1117 {
1118 SCTAB nTab;
1119 SCCOL nCol1, nCol2;
1120 SCROW nRow1, nRow2;
1121 p->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
1122 rRange = ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1123 bFound = true;
1124 }
1125 }
1126 }
1127
1128 return bFound;
1129}
1130
1131static bool lcl_DoDragObject( ScDocShell* pSrcShell, const OUString& rName, ScContentId nType, weld::TreeView& rTreeView )
1132{
1133 bool bDisallow = true;
1134
1135 ScDocument& rSrcDoc = pSrcShell->GetDocument();
1136 ScDrawLayer* pModel = rSrcDoc.GetDrawLayer();
1137 if (pModel)
1138 {
1139 bool bOle = ( nType == ScContentId::OLEOBJECT );
1140 bool bGraf = ( nType == ScContentId::GRAPHIC );
1141 sal_uInt16 nDrawId = sal::static_int_cast<sal_uInt16>( bOle ? OBJ_OLE2 : ( bGraf ? OBJ_GRAF : OBJ_GRUP ) );
1142 SCTAB nTab = 0;
1143 SdrObject* pObject = pModel->GetNamedObject( rName, nDrawId, nTab );
1144 if (pObject)
1145 {
1146 SdrView aEditView(*pModel);
1147 aEditView.ShowSdrPage(aEditView.GetModel()->GetPage(nTab));
1148 SdrPageView* pPV = aEditView.GetSdrPageView();
1149 aEditView.MarkObj(pObject, pPV);
1150
1151 // tdf125520 this is a D&D-start potentially with an OLE object. If
1152 // so, we need to do similar as e.g. in ScDrawView::BeginDrag so that
1153 // the temporary SdrModel for transfer does have a GetPersist() so
1154 // that the EmbeddedObjectContainer gets copied. We need no CheckOle
1155 // here, test is simpler.
1156 ScDocShellRef aDragShellRef;
1157 if(OBJ_OLE2 == pObject->GetObjIdentifier())
1158 {
1159 aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
1160 aDragShellRef->DoInitNew();
1161 }
1162
1163 ScDrawLayer::SetGlobalDrawPersist(aDragShellRef.get());
1164 std::unique_ptr<SdrModel> pDragModel(aEditView.CreateMarkedObjModel());
1165 ScDrawLayer::SetGlobalDrawPersist(nullptr);
1166
1167 TransferableObjectDescriptor aObjDesc;
1168 pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
1169 aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
1170 // maSize is set in ScDrawTransferObj ctor
1171
1172 rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pDragModel), pSrcShell, aObjDesc );
1173
1174 pTransferObj->SetDragSourceObj( *pObject, nTab );
1175 pTransferObj->SetDragSourceFlags(ScDragSrc::Navigator);
1176
1177 SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->SetDragObject( nullptr, pTransferObj.get() );
1178
1179 rtl::Reference<TransferDataContainer> xHelper(pTransferObj.get());
1180 rTreeView.enable_drag_source(xHelper, DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE | DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK);
1181
1182 bDisallow = false;
1183 }
1184 }
1185
1186 return bDisallow;
1187}
1188
1189static bool lcl_DoDragCells( ScDocShell* pSrcShell, const ScRange& rRange, ScDragSrc nFlags, weld::TreeView& rTreeView )
1190{
1191 bool bDisallow = true;
1192
1193 ScDocument& rSrcDoc = pSrcShell->GetDocument();
1194 ScMarkData aMark(rSrcDoc.GetSheetLimits());
1195 aMark.SelectTable( rRange.aStart.Tab(), true );
1196 aMark.SetMarkArea( rRange );
1197
1198 if ( !rSrcDoc.HasSelectedBlockMatrixFragment( rRange.aStart.Col(), rRange.aStart.Row(),
1199 rRange.aEnd.Col(), rRange.aEnd.Row(),
1200 aMark ) )
1201 {
1202 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
1203 ScClipParam aClipParam(rRange, false);
1204 rSrcDoc.CopyToClip(aClipParam, pClipDoc.get(), &aMark, false, false);
1205 // pClipDoc->ExtendMerge( rRange, sal_True );
1206
1207 TransferableObjectDescriptor aObjDesc;
1208 pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
1209 aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
1210 // maSize is set in ScTransferObj ctor
1211
1212 rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
1213
1214 pTransferObj->SetDragSource( pSrcShell, aMark );
1215 pTransferObj->SetDragSourceFlags( nFlags );
1216
1217 SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->SetDragObject( pTransferObj.get(), nullptr ); // for internal D&D
1218
1219 rtl::Reference<TransferDataContainer> xHelper(pTransferObj.get());
1220 rTreeView.enable_drag_source(xHelper, DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE | DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK);
1221
1222 bDisallow = false;
1223 }
1224
1225 return bDisallow;
1226}
1227
1228IMPL_LINK(ScContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)bool ScContentTree::LinkStubDragBeginHdl(void * instance, bool
& data) { return static_cast<ScContentTree *>(instance
)->DragBeginHdl(data); } bool ScContentTree::DragBeginHdl(
bool& rUnsetDragIcon)
1229{
1230 rUnsetDragIcon = true;
1231
1232 StoreNavigatorSettings();
1233
1234 bool bDisallow = true;
1235
1236 std::unique_ptr<ScDocumentLoader> pDocLoader;
1237
1238 ScModule* pScMod = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
;
1239
1240 ScContentId nType;
1241 sal_uLong nChild;
1242
1243 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1244 if (!m_xTreeView->get_cursor(xEntry.get()))
1245 xEntry.reset();
1246
1247 GetEntryIndexes(nType, nChild, xEntry.get());
1248
1249 if( xEntry &&
1250 (nChild != SC_CONTENT_NOCHILD) &&
1251 (nType != ScContentId::ROOT) &&
1252 (nType != ScContentId::NOTE) &&
1253 (nType != ScContentId::AREALINK) )
1254 {
1255 OUString aText(m_xTreeView->get_text(*xEntry));
1256
1257 ScDocument* pLocalDoc = nullptr; // for URL drop
1258 OUString aDocName;
1259 if (bHiddenDoc)
1260 aDocName = aHiddenName;
1261 else
1262 {
1263 ScDocShell* pDocSh = GetManualOrCurrent();
1264 if (pDocSh)
1265 {
1266 if (pDocSh->HasName())
1267 aDocName = pDocSh->GetMedium()->GetName();
1268 else
1269 pLocalDoc = &pDocSh->GetDocument(); // drop only in this document
1270 }
1271 }
1272
1273 bool bDoLinkTrans = false; // use ScLinkTransferObj
1274 OUString aLinkURL; // for ScLinkTransferObj
1275 OUString aLinkText;
1276
1277 sal_uInt16 nDropMode = pParentWindow->GetDropMode();
1278 switch ( nDropMode )
1279 {
1280 case SC_DROPMODE_URL0:
1281 {
1282 OUString aUrl = aDocName + "#" + aText;
1283
1284 pScMod->SetDragJump( pLocalDoc, aUrl, aText );
1285
1286 if (!aDocName.isEmpty())
1287 {
1288 // provide URL to outside only if the document has a name
1289 // (without name, only internal D&D via SetDragJump)
1290
1291 aLinkURL = aUrl;
1292 aLinkText = aText;
1293 }
1294 bDoLinkTrans = true;
1295 }
1296 break;
1297 case SC_DROPMODE_LINK1:
1298 {
1299 if ( !aDocName.isEmpty() ) // link only to named documents
1300 {
1301 // for internal D&D, set flag to insert a link
1302
1303 switch ( nType )
1304 {
1305 case ScContentId::TABLE:
1306 pScMod->SetDragLink( aDocName, aText, EMPTY_OUSTRINGScGlobal::GetEmptyOUString() );
1307 bDoLinkTrans = true;
1308 break;
1309 case ScContentId::RANGENAME:
1310 case ScContentId::DBAREA:
1311 pScMod->SetDragLink( aDocName, EMPTY_OUSTRINGScGlobal::GetEmptyOUString(), aText );
1312 bDoLinkTrans = true;
1313 break;
1314
1315 // other types cannot be linked
1316 default: break;
1317 }
1318 }
1319 }
1320 break;
1321 case SC_DROPMODE_COPY2:
1322 {
1323 ScDocShell* pSrcShell = nullptr;
1324 if ( bHiddenDoc )
1325 {
1326 OUString aFilter, aOptions;
1327 OUString aURL = aHiddenName;
1328 pDocLoader.reset(new ScDocumentLoader( aURL, aFilter, aOptions ));
1329 if (!pDocLoader->IsError())
1330 pSrcShell = pDocLoader->GetDocShell();
1331 }
1332 else
1333 pSrcShell = GetManualOrCurrent();
1334
1335 if ( pSrcShell )
1336 {
1337 ScDocument& rSrcDoc = pSrcShell->GetDocument();
1338 if ( nType == ScContentId::RANGENAME || nType == ScContentId::DBAREA )
1339 {
1340 ScRange aRange;
1341 if ( lcl_GetRange( rSrcDoc, nType, aText, aRange ) )
1342 {
1343 bDisallow = lcl_DoDragCells( pSrcShell, aRange, ScDragSrc::Navigator, *m_xTreeView );
1344 }
1345 }
1346 else if ( nType == ScContentId::TABLE )
1347 {
1348 SCTAB nTab;
1349 if ( rSrcDoc.GetTable( aText, nTab ) )
1350 {
1351 ScRange aRange(0, 0, nTab, rSrcDoc.MaxCol(), rSrcDoc.MaxRow(), nTab);
1352 bDisallow = lcl_DoDragCells( pSrcShell, aRange, (ScDragSrc::Navigator | ScDragSrc::Table), *m_xTreeView );
1353 }
1354 }
1355 else if ( nType == ScContentId::GRAPHIC || nType == ScContentId::OLEOBJECT ||
1356 nType == ScContentId::DRAWING )
1357 {
1358 bDisallow = lcl_DoDragObject( pSrcShell, aText, nType, *m_xTreeView );
1359
1360 // during ExecuteDrag the navigator can be deleted
1361 // -> don't access member anymore !!!
1362 }
1363 }
1364 }
1365 break;
1366 }
1367
1368 if (bDoLinkTrans)
1369 {
1370 if (!aLinkURL.isEmpty())
1371 m_xTransferObj->SetLinkURL(aLinkURL, aLinkText);
1372
1373 rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj.get());
1374 m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPYMOVEcss::datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE | DND_ACTION_LINKcss::datatransfer::dnd::DNDConstants::ACTION_LINK);
1375
1376 bDisallow = false;
1377 }
1378 }
1379
1380 return bDisallow;
1381}
1382
1383void ScContentTree::LoadFile( const OUString& rUrl )
1384{
1385 OUString aDocName = rUrl;
1386 sal_Int32 nPos = aDocName.indexOf('#');
1387 if ( nPos != -1 )
1388 aDocName = aDocName.copy(0, nPos); // only the name without #...
1389
1390 OUString aURL = aDocName;
1391 OUString aFilter, aOptions;
1392 ScDocumentLoader aLoader( aURL, aFilter, aOptions );
1393 if ( aLoader.IsError() )
1394 return;
1395
1396 bHiddenDoc = true;
1397 aHiddenName = aDocName;
1398 aHiddenTitle = aLoader.GetTitle();
1399 pHiddenDocument = aLoader.GetDocument();
1400
1401 Refresh(); // get content from loaded document
1402
1403 pHiddenDocument = nullptr;
1404
1405 pParentWindow->GetDocNames( &aHiddenTitle ); // fill list
1406
1407 // document is closed again by ScDocumentLoader in dtor
1408}
1409
1410void ScContentTree::SetRootType( ScContentId nNew )
1411{
1412 if ( nNew != nRootType )
1413 {
1414 nRootType = nNew;
1415 Refresh();
1416
1417 ScNavipiCfg& rCfg = SC_MOD()( static_cast<ScModule*>(SfxApplication::GetModule(SfxToolsModule
::Calc)) )
->GetNavipiCfg();
1418 rCfg.SetRootType( nRootType );
1419 }
1420}
1421
1422void ScContentTree::ToggleRoot() // after selection
1423{
1424 ScContentId nNew = ScContentId::ROOT;
1425 if ( nRootType == ScContentId::ROOT )
1426 {
1427 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
1428 if (m_xTreeView->get_cursor(xEntry.get()))
1429 {
1430 std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get()));
1431 if (!m_xTreeView->iter_parent(*xParent))
1432 xParent.reset();
1433
1434 for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
1435 {
1436 if (!m_aRootNodes[static_cast<ScContentId>(i)])
1437 continue;
1438 if ((m_xTreeView->iter_compare(*xEntry, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0) ||
1439 (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0))
1440 {
1441 nNew = static_cast<ScContentId>(i);
1442 }
1443 }
1444 }
1445 }
1446
1447 SetRootType( nNew );
1448}
1449
1450void ScContentTree::ResetManualDoc()
1451{
1452 aManualDoc.clear();
1453 bHiddenDoc = false;
1454
1455 ActiveDocChanged();
1456}
1457
1458void ScContentTree::ActiveDocChanged()
1459{
1460 if ( !bHiddenDoc && aManualDoc.isEmpty() )
1461 Refresh(); // content only if automatic
1462
1463 // if flag active Listbox must be updated
1464
1465 OUString aCurrent;
1466 if ( bHiddenDoc )
1467 aCurrent = aHiddenTitle;
1468 else
1469 {
1470 ScDocShell* pSh = GetManualOrCurrent();
1471 if (pSh)
1472 aCurrent = pSh->GetTitle();
1473 else
1474 {
1475 // document is no longer available
1476
1477 aManualDoc.clear(); // again automatically
1478 Refresh();
1479 pSh = GetManualOrCurrent(); // should be active now
1480 if (pSh)
1481 aCurrent = pSh->GetTitle();
1482 }
1483 }
1484 pParentWindow->GetDocNames( &aCurrent ); // select
1485}
1486
1487void ScContentTree::SetManualDoc(const OUString& rName)
1488{
1489 aManualDoc = rName;
1490 if (!bHiddenDoc)
1491 {
1492 Refresh();
1493 pParentWindow->GetDocNames( &aManualDoc ); // select
1494 }
1495}
1496
1497void ScContentTree::SelectDoc(const OUString& rName) // rName like shown in Menu/Listbox
1498{
1499 if ( rName == pParentWindow->aStrActiveWin )
1500 {
1501 ResetManualDoc();
1502 return;
1503 }
1504
1505 // omit "active" or "inactive"
1506
1507 OUString aRealName = rName;
1508 sal_Int32 nLen = rName.getLength();
1509 sal_Int32 nActiveStart = nLen - pParentWindow->aStrActive.getLength();
1510 if ( rName.copy( nActiveStart ) == pParentWindow->aStrActive )
1511 aRealName = rName.copy( 0, nActiveStart );
1512 sal_Int32 nNotActiveStart = nLen - pParentWindow->aStrNotActive.getLength();
1513 if ( rName.copy( nNotActiveStart ) == pParentWindow->aStrNotActive )
1514 aRealName = rName.copy( 0, nNotActiveStart );
1515
1516 bool bLoaded = false;
1517
1518 // Is it a normally loaded document?
1519
1520 SfxObjectShell* pSh = SfxObjectShell::GetFirst();
1521 while ( pSh && !bLoaded )
1522 {
1523 if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
1524 if ( pSh->GetTitle() == aRealName )
1525 bLoaded = true;
1526 pSh = SfxObjectShell::GetNext( *pSh );
1527 }
1528
1529 if (bLoaded)
1530 {
1531 bHiddenDoc = false;
1532 SetManualDoc(aRealName);
1533 }
1534 else if (!aHiddenTitle.isEmpty()) // hidden selected
1535 {
1536 if (!bHiddenDoc)
1537 LoadFile(aHiddenName);
1538 }
1539 else
1540 {
1541 OSL_FAIL("SelectDoc: not found")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sc/source/ui/navipi/content.cxx"
":" "1541" ": "), "%s", "SelectDoc: not found"); } } while (
false)
;
1542 }
1543}
1544
1545void ScContentTree::SelectEntryByName(const ScContentId nRoot, const OUString& rName)
1546{
1547 weld::TreeIter* pParent = m_aRootNodes[nRoot].get();
1
'pParent' initialized here
1548
1549 if (pParent || !m_xTreeView->iter_has_child(*pParent))
2
Assuming 'pParent' is null
3
Forming reference to null pointer
1550 return;
1551
1552 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
1553 bool bEntry = m_xTreeView->iter_children(*xEntry);
1554
1555 while (bEntry)
1556 {
1557 if (m_xTreeView->get_text(*xEntry) == rName)
1558 {
1559 m_xTreeView->select(*xEntry);
1560 m_xTreeView->set_cursor(*xEntry);
1561
1562 // Scroll to the selected item
1563 m_xTreeView->scroll_to_row(*xEntry);
1564
1565 StoreNavigatorSettings();
1566
1567 return;
1568 }
1569 bEntry = m_xTreeView->iter_next(*xEntry);
1570 }
1571}
1572
1573void ScContentTree::ApplyNavigatorSettings(bool bRestorePos, int nScrollPos)
1574{
1575 const ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
1576 if( !pSettings )
1577 return;
1578
1579 ScContentId nRootSel = pSettings->GetRootSelected();
1580 auto nChildSel = pSettings->GetChildSelected();
1581
1582 // tdf#133079 ensure Sheet root is selected if nothing
1583 // else would be
1584 if (nRootSel == ScContentId::ROOT)
1585 {
1586 nRootSel = ScContentId::TABLE;
1587 nChildSel = SC_CONTENT_NOCHILD;
1588 }
1589
1590 for( int i = 1; i <= int(ScContentId::LAST); ++i )
1591 {
1592 ScContentId nEntry = static_cast<ScContentId>(i);
1593 if( m_aRootNodes[ nEntry ] )
1594 {
1595 // gray or ungray
1596 if (!m_xTreeView->iter_has_child(*m_aRootNodes[nEntry]))
1597 m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], false);
1598 else
1599 m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], true);
1600
1601 // expand
1602 bool bExp = pSettings->IsExpanded( nEntry );
1603 if (bExp != m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]))
1604 {
1605 if( bExp )
1606 m_xTreeView->expand_row(*m_aRootNodes[nEntry]);
1607 else
1608 m_xTreeView->collapse_row(*m_aRootNodes[nEntry]);
1609 }
1610
1611 // select
1612 if( nRootSel == nEntry )
1613 {
1614 if (bRestorePos)
1615 m_xTreeView->vadjustment_set_value(nScrollPos);
1616
1617 std::unique_ptr<weld::TreeIter> xEntry;
1618 if (bExp && (nChildSel != SC_CONTENT_NOCHILD))
1619 {
1620 xEntry = m_xTreeView->make_iterator(m_aRootNodes[nEntry].get());
1621 if (!m_xTreeView->iter_children(*xEntry) || !m_xTreeView->iter_nth_sibling(*xEntry, nChildSel))
1622 xEntry.reset();
1623 }
1624 m_xTreeView->select(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
1625 m_xTreeView->set_cursor(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
1626 }
1627 }
1628 }
1629}
1630
1631void ScContentTree::StoreNavigatorSettings() const
1632{
1633 ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
1634 if( !pSettings )
1635 return;
1636
1637 for( int i = 1; i <= int(ScContentId::LAST); ++i )
1638 {
1639 ScContentId nEntry = static_cast<ScContentId>(i);
1640 bool bExp = m_aRootNodes[nEntry] && m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]);
1641 pSettings->SetExpanded( nEntry, bExp );
1642 }
1643
1644 std::unique_ptr<weld::TreeIter> xCurEntry(m_xTreeView->make_iterator());
1645 if (!m_xTreeView->get_cursor(xCurEntry.get()))
1646 xCurEntry.reset();
1647
1648 ScContentId nRoot;
1649 sal_uLong nChild;
1650 GetEntryIndexes(nRoot, nChild, xCurEntry.get());
1651
1652 pSettings->SetRootSelected( nRoot );
1653 pSettings->SetChildSelected( nChild );
1654}
1655
1656/* vim:set shiftwidth=4 softtabstop=4 expandtab: */