Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / utlui / glbltree.cxx
blob9ce80bf0f3fea0c87f9c03a9b798ea1afe2f9bfb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <o3tl/safeint.hxx>
21 #include <svl/stritem.hxx>
22 #include <sfx2/fcontnr.hxx>
23 #include <sfx2/linkmgr.hxx>
24 #include <sfx2/dispatch.hxx>
25 #include <sfx2/viewfrm.hxx>
26 #include <sfx2/docfile.hxx>
27 #include <sfx2/docfilt.hxx>
28 #include <vcl/commandevent.hxx>
29 #include <vcl/event.hxx>
30 #include <sot/filelist.hxx>
31 #include <svl/eitem.hxx>
32 #include <vcl/graphicfilter.hxx>
33 #include <osl/diagnose.h>
35 #include <sfx2/docinsert.hxx>
36 #include <sfx2/filedlghelper.hxx>
38 #include <wrtsh.hxx>
39 #include <view.hxx>
40 #include <docsh.hxx>
41 #include <edglbldc.hxx>
42 #include <section.hxx>
43 #include <tox.hxx>
44 #include <navipi.hxx>
45 #include <edtwin.hxx>
46 #include <toxmgr.hxx>
48 #include <cmdid.h>
49 #include <helpids.h>
50 #include <strings.hrc>
51 #include <bitmaps.hlst>
52 #include <swabstdlg.hxx>
53 #include <memory>
55 #include <sfx2/event.hxx>
56 #include <unotxvw.hxx>
58 using namespace ::com::sun::star::uno;
60 #define GLOBAL_UPDATE_TIMEOUT 2000
62 const SfxObjectShell* SwGlobalTree::s_pShowShell = nullptr;
64 namespace {
66 class SwGlobalFrameListener_Impl : public SfxListener
68 bool m_bValid;
69 public:
70 explicit SwGlobalFrameListener_Impl(SfxViewFrame& rFrame)
71 : m_bValid(true)
73 StartListening(rFrame);
76 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
78 bool IsValid() const {return m_bValid;}
83 void SwGlobalFrameListener_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
85 if( rHint.GetId() == SfxHintId::Dying)
86 m_bValid = false;
89 namespace {
91 enum GLOBAL_CONTEXT_IDX
93 IDX_STR_UPDATE = 0,
94 IDX_STR_EDIT_CONTENT = 1,
95 IDX_STR_EDIT_INSERT = 2,
96 IDX_STR_INDEX = 3,
97 IDX_STR_FILE = 4,
98 IDX_STR_NEW_FILE = 5,
99 IDX_STR_INSERT_TEXT = 6,
100 IDX_STR_DELETE = 7,
101 IDX_STR_UPDATE_SEL = 8,
102 IDX_STR_UPDATE_INDEX = 9,
103 IDX_STR_UPDATE_LINK = 10,
104 IDX_STR_UPDATE_ALL = 11,
105 IDX_STR_BROKEN_LINK = 12,
106 IDX_STR_EDIT_LINK = 13
111 const TranslateId GLOBAL_CONTEXT_ARY[] =
113 STR_UPDATE,
114 STR_EDIT_CONTENT,
115 STR_EDIT_INSERT,
116 STR_INDEX,
117 STR_FILE,
118 STR_NEW_FILE,
119 STR_INSERT_TEXT,
120 STR_DELETE,
121 STR_UPDATE_SEL,
122 STR_UPDATE_INDEX,
123 STR_UPDATE_LINK,
124 STR_UPDATE_ALL,
125 STR_BROKEN_LINK,
126 STR_EDIT_LINK
129 SwGlobalTree::SwGlobalTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog)
130 : m_xTreeView(std::move(xTreeView))
131 , m_aDropTargetHelper(*this)
132 , m_pDialog(pDialog)
133 , m_aUpdateTimer("SwGlobalTree m_aUpdateTimer")
134 , m_pActiveShell(nullptr)
136 m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
137 m_xTreeView->get_text_height() * 14);
139 m_aUpdateTimer.SetTimeout(GLOBAL_UPDATE_TIMEOUT);
140 m_aUpdateTimer.SetInvokeHandler(LINK(this, SwGlobalTree, Timeout));
141 m_aUpdateTimer.Start();
142 for (sal_uInt16 i = 0; i < GLOBAL_CONTEXT_COUNT; i++)
144 m_aContextStrings[i] = SwResId(GLOBAL_CONTEXT_ARY[i]);
146 m_xTreeView->set_help_id(HID_NAVIGATOR_GLOB_TREELIST);
147 Select();
148 m_xTreeView->connect_row_activated(LINK(this, SwGlobalTree, DoubleClickHdl));
149 m_xTreeView->connect_changed(LINK(this, SwGlobalTree, SelectHdl));
150 m_xTreeView->connect_focus_in(LINK(this, SwGlobalTree, FocusInHdl));
151 m_xTreeView->connect_key_press(LINK(this, SwGlobalTree, KeyInputHdl));
152 m_xTreeView->connect_popup_menu(LINK(this, SwGlobalTree, CommandHdl));
153 m_xTreeView->connect_query_tooltip(LINK(this, SwGlobalTree, QueryTooltipHdl));
156 SwGlobalTree::~SwGlobalTree()
158 m_pSwGlblDocContents.reset();
159 m_pDocInserter.reset();
160 m_aUpdateTimer.Stop();
163 SwGlobalTreeDropTarget::SwGlobalTreeDropTarget(SwGlobalTree& rTreeView)
164 : DropTargetHelper(rTreeView.get_widget().get_drop_target())
165 , m_rTreeView(rTreeView)
169 sal_Int8 SwGlobalTreeDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt )
171 sal_Int8 nRet = DND_ACTION_NONE;
173 weld::TreeView& rWidget = m_rTreeView.get_widget();
174 std::unique_ptr<weld::TreeIter> xDropEntry(rWidget.make_iterator());
175 if (!rWidget.get_dest_row_at_pos(rEvt.maPosPixel, xDropEntry.get(), true))
176 xDropEntry.reset();
178 if (rWidget.get_drag_source() == &rWidget) // internal drag
179 m_rTreeView.MoveSelectionTo(xDropEntry.get());
180 else
182 TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
184 OUString sFileName;
185 const SwGlblDocContent* pCnt = xDropEntry ?
186 weld::fromId<const SwGlblDocContent*>(rWidget.get_id(*xDropEntry)) :
187 nullptr;
188 if( aData.HasFormat( SotClipboardFormatId::FILE_LIST ))
190 nRet = rEvt.mnAction;
191 SwGlblDocContents aTempContents;
192 int nAbsContPos = xDropEntry ?
193 rWidget.get_iter_index_in_parent(*xDropEntry):
194 - 1;
195 size_t nEntryCount = rWidget.n_children();
197 // Get data
198 FileList aFileList;
199 aData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList );
200 for ( size_t n = aFileList.Count(); n--; )
202 sFileName = aFileList.GetFile(n);
203 m_rTreeView.InsertRegion(pCnt, &sFileName);
204 // The list of contents must be newly fetched after inserting,
205 // to not work on an old content.
206 if(n)
208 if (const SwWrtShell* pSh = m_rTreeView.GetActiveWrtShell())
210 pSh->GetGlobalDocContent(aTempContents);
211 // If the file was successfully inserted,
212 // then the next content must also be fetched.
213 if(nEntryCount < aTempContents.size())
215 nEntryCount++;
216 nAbsContPos++;
217 pCnt = aTempContents[ nAbsContPos ].get();
223 else if( !(sFileName =
224 SwNavigationPI::CreateDropFileName( aData )).isEmpty())
226 INetURLObject aTemp(sFileName);
227 GraphicDescriptor aDesc(aTemp);
228 if( !aDesc.Detect() ) // accept no graphics
230 nRet = rEvt.mnAction;
231 m_rTreeView.InsertRegion(pCnt, &sFileName);
235 return nRet;
238 sal_Int8 SwGlobalTreeDropTarget::AcceptDrop( const AcceptDropEvent& rEvt )
240 // to enable the autoscroll when we're close to the edges
241 weld::TreeView& rWidget = m_rTreeView.get_widget();
242 rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
244 sal_Int8 nRet = rEvt.mnAction;
246 if (rWidget.get_drag_source() == &rWidget) // internal drag
247 return nRet;
249 if (IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE) ||
250 IsDropFormatSupported( SotClipboardFormatId::STRING) ||
251 IsDropFormatSupported( SotClipboardFormatId::FILE_LIST) ||
252 IsDropFormatSupported( SotClipboardFormatId::SOLK) ||
253 IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK )||
254 IsDropFormatSupported( SotClipboardFormatId::FILECONTENT) ||
255 IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR) ||
256 IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR) ||
257 IsDropFormatSupported( SotClipboardFormatId::FILENAME))
259 nRet = DND_ACTION_LINK;
262 return nRet;
265 IMPL_LINK(SwGlobalTree, CommandHdl, const CommandEvent&, rCEvt, bool)
267 if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
268 return false;
270 bool bPop = false;
271 if (m_pActiveShell && !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
273 std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/swriter/ui/mastercontextmenu.ui"));
274 std::unique_ptr<weld::Menu> xPopup = xBuilder->weld_menu("navmenu");
276 const MenuEnableFlags nEnableFlags = GetEnableFlags();
278 xPopup->set_sensitive("updatesel", bool(nEnableFlags & MenuEnableFlags::UpdateSel));
280 xPopup->set_sensitive("editlink", bool(nEnableFlags & MenuEnableFlags::EditLink));
282 //disabling if applicable
283 xPopup->set_sensitive("insertindex", bool(nEnableFlags & MenuEnableFlags::InsertIdx ));
284 xPopup->set_sensitive("insertfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
285 xPopup->set_sensitive("insertnewfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
286 xPopup->set_sensitive("inserttext", bool(nEnableFlags & MenuEnableFlags::InsertText));
288 xPopup->set_sensitive("update", bool(nEnableFlags & MenuEnableFlags::Update));
289 xPopup->set_sensitive("insert", bool(nEnableFlags & MenuEnableFlags::InsertIdx));
290 xPopup->set_sensitive("editcontent", bool(nEnableFlags & MenuEnableFlags::Edit));
291 xPopup->set_sensitive("deleteentry", bool(nEnableFlags & MenuEnableFlags::Delete));
293 OUString sCommand = xPopup->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
294 if (!sCommand.isEmpty())
295 ExecuteContextMenuAction(sCommand);
297 bPop = true;
299 return bPop;
302 void SwGlobalTree::TbxMenuHdl(std::u16string_view rCommand, weld::Menu& rMenu)
304 const MenuEnableFlags nEnableFlags = GetEnableFlags();
305 if (rCommand == u"insert")
307 rMenu.set_sensitive("insertindex", bool(nEnableFlags & MenuEnableFlags::InsertIdx));
308 rMenu.set_sensitive("insertfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
309 rMenu.set_sensitive("insertnewfile", bool(nEnableFlags & MenuEnableFlags::InsertFile));
310 rMenu.set_sensitive("inserttext", bool(nEnableFlags & MenuEnableFlags::InsertText));
312 else if (rCommand == u"update")
314 rMenu.set_sensitive("updatesel", bool(nEnableFlags & MenuEnableFlags::UpdateSel));
318 MenuEnableFlags SwGlobalTree::GetEnableFlags() const
320 std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
321 bool bEntry = m_xTreeView->get_selected(xEntry.get());
323 int nSelCount = m_xTreeView->count_selected_rows();
324 size_t nEntryCount = m_xTreeView->n_children();
325 std::unique_ptr<weld::TreeIter> xPrevEntry;
326 bool bPrevEntry = false;
327 if (bEntry)
329 xPrevEntry = m_xTreeView->make_iterator(xEntry.get());
330 bPrevEntry = m_xTreeView->iter_previous(*xPrevEntry);
333 MenuEnableFlags nRet = MenuEnableFlags::NONE;
334 if(nSelCount == 1 || !nEntryCount)
335 nRet |= MenuEnableFlags::InsertIdx|MenuEnableFlags::InsertFile;
336 if(nSelCount == 1)
338 nRet |= MenuEnableFlags::Edit;
339 if (bEntry && weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry))->GetType() != GLBLDOC_UNKNOWN &&
340 (!bPrevEntry || weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xPrevEntry))->GetType() != GLBLDOC_UNKNOWN))
341 nRet |= MenuEnableFlags::InsertText;
342 if (bEntry && GLBLDOC_SECTION == weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry))->GetType())
343 nRet |= MenuEnableFlags::EditLink;
345 else if(!nEntryCount)
347 nRet |= MenuEnableFlags::InsertText;
349 if(nEntryCount)
350 nRet |= MenuEnableFlags::Update|MenuEnableFlags::Delete;
351 if(nSelCount)
352 nRet |= MenuEnableFlags::UpdateSel;
353 return nRet;
356 IMPL_LINK(SwGlobalTree, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString)
358 OUString sEntry;
360 const SwGlblDocContent* pCont = weld::fromId<const SwGlblDocContent*>(m_xTreeView->get_id(rIter));
361 if (pCont && GLBLDOC_SECTION == pCont->GetType())
363 const SwSection* pSect = pCont->GetSection();
364 sEntry = pSect->GetLinkFileName().getToken(0, sfx2::cTokenSeparator);
365 if (!pSect->IsConnectFlag())
366 sEntry = m_aContextStrings[IDX_STR_BROKEN_LINK] + sEntry;
369 return sEntry;
372 IMPL_LINK_NOARG(SwGlobalTree, SelectHdl, weld::TreeView&, void)
374 Select();
377 void SwGlobalTree::Select()
379 int nSelCount = m_xTreeView->count_selected_rows();
380 int nSel = m_xTreeView->get_selected_index();
381 int nAbsPos = nSel != -1 ? nSel : 0;
382 SwNavigationPI* pNavi = GetParentWindow();
383 bool bReadonly = !m_pActiveShell ||
384 m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
385 pNavi->m_xGlobalToolBox->set_item_sensitive("edit", nSelCount == 1 && !bReadonly);
386 pNavi->m_xGlobalToolBox->set_item_sensitive("insert", nSelCount <= 1 && !bReadonly);
387 pNavi->m_xGlobalToolBox->set_item_sensitive("update", m_xTreeView->n_children() > 0 && !bReadonly);
388 pNavi->m_xGlobalToolBox->set_item_sensitive("moveup",
389 nSelCount == 1 && nAbsPos && !bReadonly);
390 pNavi->m_xGlobalToolBox->set_item_sensitive("movedown",
391 nSelCount == 1 && nAbsPos < m_xTreeView->n_children() - 1 && !bReadonly);
395 void SwGlobalTree::MoveSelectionTo(const weld::TreeIter* pDropEntry)
397 int nSource = m_xTreeView->get_selected_index();
399 int nDest = pDropEntry ? m_xTreeView->get_iter_index_in_parent(*pDropEntry)
400 : m_pSwGlblDocContents->size();
402 if (m_pActiveShell->MoveGlobalDocContent(
403 *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) &&
404 Update( false ))
405 Display();
408 IMPL_LINK_NOARG(SwGlobalTree, FocusInHdl, weld::Widget&, void)
410 if (Update(false))
411 Display();
414 IMPL_LINK(SwGlobalTree, KeyInputHdl, const KeyEvent&, rKEvt, bool)
416 bool bHandled = false;
417 const vcl::KeyCode aCode = rKEvt.GetKeyCode();
418 if (aCode.GetCode() == KEY_RETURN)
420 switch (aCode.GetModifier())
422 case KEY_MOD2:
423 // Switch boxes
424 GetParentWindow()->ToggleTree();
425 bHandled = true;
426 break;
429 return bHandled;
432 void SwGlobalTree::Display(bool bOnlyUpdateUserData)
434 size_t nCount = m_pSwGlblDocContents->size();
435 size_t nChildren = m_xTreeView->n_children();
436 if (bOnlyUpdateUserData && nChildren == m_pSwGlblDocContents->size())
438 std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator();
439 bool bEntry = m_xTreeView->get_iter_first(*xEntry);
440 for (size_t i = 0; i < nCount && bEntry; i++)
442 const SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get();
443 OUString sId(weld::toId(pCont));
444 m_xTreeView->set_id(*xEntry, sId);
445 if (pCont->GetType() == GLBLDOC_SECTION && !pCont->GetSection()->IsConnectFlag())
446 m_xTreeView->set_font_color(*xEntry, COL_LIGHTRED);
447 else
448 m_xTreeView->set_font_color(*xEntry, COL_AUTO);
449 bEntry = m_xTreeView->iter_next(*xEntry);
450 assert(bEntry || i == nCount - 1);
453 else
455 int nOldSelEntry = m_xTreeView->get_selected_index();
456 OUString sEntryName; // Name of the entry
457 int nSelPos = -1;
458 if (nOldSelEntry != -1)
460 sEntryName = m_xTreeView->get_text(nOldSelEntry);
461 nSelPos = nOldSelEntry;
463 m_xTreeView->freeze();
464 m_xTreeView->clear();
466 int nSelEntry = -1;
467 for (size_t i = 0; i < nCount; ++i)
469 const SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get();
471 OUString sId(weld::toId(pCont));
472 OUString sEntry;
473 OUString aImage;
474 switch (pCont->GetType())
476 case GLBLDOC_UNKNOWN:
477 sEntry = m_aContextStrings[IDX_STR_INSERT_TEXT];
478 break;
479 case GLBLDOC_TOXBASE:
481 const SwTOXBase* pBase = pCont->GetTOX();
482 sEntry = pBase->GetTitle();
483 aImage = RID_BMP_NAVI_INDEX;
485 break;
486 case GLBLDOC_SECTION:
488 const SwSection* pSect = pCont->GetSection();
489 sEntry = pSect->GetSectionName();
490 aImage = RID_BMP_DROP_REGION;
492 break;
495 m_xTreeView->append(sId, sEntry);
496 if (!aImage.isEmpty())
497 m_xTreeView->set_image(i, aImage);
499 if (pCont->GetType() == GLBLDOC_SECTION && !pCont->GetSection()->IsConnectFlag())
500 m_xTreeView->set_font_color(i, COL_LIGHTRED);
502 if (sEntry == sEntryName)
503 nSelEntry = i;
505 m_xTreeView->thaw();
506 if (nSelEntry != -1)
507 m_xTreeView->select(nSelEntry);
508 else if (nSelPos != -1 && o3tl::make_unsigned(nSelPos) < nCount)
509 m_xTreeView->select(nSelPos);
510 else if (nCount)
511 m_xTreeView->select(0);
512 Select();
516 void SwGlobalTree::InsertRegion( const SwGlblDocContent* pCont, const OUString* pFileName )
518 Sequence< OUString > aFileNames;
519 if ( !pFileName )
521 SwNavigationPI* pNavi = GetParentWindow();
522 m_pDocInserter.reset(new ::sfx2::DocumentInserter(pNavi->GetFrameWeld(), "swriter", sfx2::DocumentInserter::Mode::InsertMulti));
523 m_pDocInserter->StartExecuteModal( LINK( this, SwGlobalTree, DialogClosedHdl ) );
525 else if ( !pFileName->isEmpty() )
527 aFileNames.realloc(1);
528 INetURLObject aFileName;
529 aFileName.SetSmartURL( *pFileName );
530 // tdf#127978 - don't URL encode filename for navigator's tooltip
531 aFileNames.getArray()[0]
532 = aFileName.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous);
533 InsertRegion( pCont, aFileNames );
537 void SwGlobalTree::EditContent(const SwGlblDocContent* pCont )
539 sal_uInt16 nSlot = 0;
540 switch( pCont->GetType() )
542 case GLBLDOC_UNKNOWN:
543 m_pActiveShell->GetView().GetEditWin().GrabFocus();
544 break;
545 case GLBLDOC_TOXBASE:
547 const SwTOXBase* pBase = pCont->GetTOX();
548 if(pBase)
549 nSlot = FN_INSERT_MULTI_TOX;
551 break;
552 case GLBLDOC_SECTION:
554 OpenDoc(pCont);
556 nSlot = 0;
557 pCont = nullptr;
559 break;
561 if(pCont)
562 GotoContent(pCont);
563 if(nSlot)
565 m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->Execute(nSlot);
566 if(Update( false ))
567 Display();
571 void SwGlobalTree::ExecuteContextMenuAction(std::u16string_view rSelectedPopupEntry)
573 bool bUpdateHard = false;
575 int nEntry = m_xTreeView->get_selected_index();
576 SwGlblDocContent* pCont = nEntry != -1 ? weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry)) : nullptr;
577 // If a RequestHelp is called during the dialogue,
578 // then the content gets lost. Because of that a copy
579 // is created in which only the DocPos is set correctly.
580 std::optional<SwGlblDocContent> oContCopy;
581 if(pCont)
582 oContCopy.emplace(pCont->GetDocPos());
583 SfxDispatcher& rDispatch = *m_pActiveShell->GetView().GetViewFrame().GetDispatcher();
584 sal_uInt16 nSlot = 0;
585 if (rSelectedPopupEntry == u"updatesel")
587 // Two passes: first update the areas, then the directories.
588 m_xTreeView->selected_foreach([this](weld::TreeIter& rSelEntry){
589 SwGlblDocContent* pContent = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry));
590 if (GLBLDOC_SECTION == pContent->GetType() &&
591 pContent->GetSection()->IsConnected())
593 const_cast<SwSection*>(pContent->GetSection())->UpdateNow();
595 return false;
597 m_xTreeView->selected_foreach([this](weld::TreeIter& rSelEntry){
598 SwGlblDocContent* pContent = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry));
599 if (GLBLDOC_TOXBASE == pContent->GetType())
600 m_pActiveShell->UpdateTableOf(*pContent->GetTOX());
601 return false;
604 bUpdateHard = true;
606 else if (rSelectedPopupEntry == u"updateindex")
608 nSlot = FN_UPDATE_TOX;
609 bUpdateHard = true;
611 else if (rSelectedPopupEntry == u"updatelinks" || rSelectedPopupEntry == u"updateall")
613 m_pActiveShell->GetLinkManager().UpdateAllLinks(true, false, nullptr);
614 if (rSelectedPopupEntry == u"updateall")
615 nSlot = FN_UPDATE_TOX;
616 pCont = nullptr;
617 bUpdateHard = true;
619 else if (rSelectedPopupEntry == u"editcontent")
621 OSL_ENSURE(pCont, "edit without entry ? " );
622 if (pCont)
624 EditContent(pCont);
627 else if (rSelectedPopupEntry == u"editlink")
629 OSL_ENSURE(pCont, "edit without entry ? " );
630 if (pCont)
632 SfxStringItem aName(FN_EDIT_REGION,
633 pCont->GetSection()->GetSectionName());
634 rDispatch.ExecuteList(FN_EDIT_REGION, SfxCallMode::ASYNCHRON,
635 { &aName });
638 else if (rSelectedPopupEntry == u"deleteentry")
640 // If several entries selected, then after each delete the array
641 // must be refilled. So you do not have to remember anything,
642 // deleting begins at the end.
643 std::vector<int> aRows = m_xTreeView->get_selected_rows();
644 std::sort(aRows.begin(), aRows.end());
646 std::unique_ptr<SwGlblDocContents> pTempContents;
647 m_pActiveShell->StartAction();
648 for (auto iter = aRows.rbegin(); iter != aRows.rend(); ++iter)
650 m_pActiveShell->DeleteGlobalDocContent(
651 pTempContents ? *pTempContents : *m_pSwGlblDocContents,
652 *iter);
653 pTempContents.reset(new SwGlblDocContents);
654 m_pActiveShell->GetGlobalDocContent(*pTempContents);
656 pTempContents.reset();
657 m_pActiveShell->EndAction();
658 pCont = nullptr;
660 else if (rSelectedPopupEntry == u"insertindex")
662 if(oContCopy)
664 SfxItemSetFixed<
665 RES_FRM_SIZE, RES_FRM_SIZE,
666 RES_LR_SPACE, RES_LR_SPACE,
667 RES_BACKGROUND, RES_BACKGROUND,
668 RES_COL, RES_COL,
669 SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE,
670 FN_PARAM_TOX_TYPE, FN_PARAM_TOX_TYPE>
671 aSet( m_pActiveShell->GetView().GetPool() );
673 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
674 ScopedVclPtr<AbstractMultiTOXTabDialog> pDlg(pFact->CreateMultiTOXTabDialog(
675 m_xTreeView.get(), aSet,
676 *m_pActiveShell,
677 nullptr,
678 true));
679 if(RET_OK == pDlg->Execute())
681 SwTOXDescription& rDesc = pDlg->GetTOXDescription(
682 pDlg->GetCurrentTOXType());
683 SwTOXMgr aMgr(m_pActiveShell);
684 SwTOXBase* pToInsert = nullptr;
685 if(aMgr.UpdateOrInsertTOX(rDesc, &pToInsert, pDlg->GetOutputItemSet()))
686 m_pActiveShell->InsertGlobalDocContent( *oContCopy, *pToInsert );
688 pCont = nullptr;
691 else if (rSelectedPopupEntry == u"insertfile")
693 m_oDocContent = std::move(oContCopy);
694 InsertRegion( &*m_oDocContent );
695 pCont = nullptr;
697 else if (rSelectedPopupEntry == u"insertnewfile")
699 SfxViewFrame& rGlobFrame = m_pActiveShell->GetView().GetViewFrame();
700 SwGlobalFrameListener_Impl aFrameListener(rGlobFrame);
702 // Creating a new doc
703 SfxStringItem aFactory(SID_NEWDOCDIRECT,
704 SwDocShell::Factory().GetFilterContainer()->GetName());
706 const SfxFrameItem* pItem = static_cast<const SfxFrameItem*>(
707 rDispatch.ExecuteList(SID_NEWDOCDIRECT,
708 SfxCallMode::SYNCHRON, { &aFactory }));
710 // save at
711 SfxFrame* pFrame = pItem ? pItem->GetFrame() : nullptr;
712 SfxViewFrame* pViewFrame = pFrame ? pFrame->GetCurrentViewFrame() : nullptr;
713 if (pViewFrame)
715 const SfxBoolItem* pBool = static_cast<const SfxBoolItem*>(
716 pViewFrame->GetDispatcher()->Execute(
717 SID_SAVEASDOC, SfxCallMode::SYNCHRON ));
718 SfxObjectShell& rObj = *pViewFrame->GetObjectShell();
719 const SfxMedium* pMedium = rObj.GetMedium();
720 OUString sNewFile(pMedium->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri));
721 // Insert the area with the Doc-Name
722 // Bring the own Doc in the foreground
723 if(aFrameListener.IsValid() && !sNewFile.isEmpty())
725 rGlobFrame.ToTop();
726 // Due to the update the entries are invalid
727 if (nEntry != -1)
729 Update( false );
730 Display();
731 m_xTreeView->select(nEntry);
732 Select();
733 nEntry = m_xTreeView->get_selected_index();
734 pCont = nEntry != -1 ? weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry)) : nullptr;
736 else
738 nEntry = -1;
739 pCont = nullptr;
741 if(pBool->GetValue())
743 InsertRegion(pCont, &sNewFile);
744 pViewFrame->ToTop();
746 else
747 pViewFrame->GetDispatcher()->Execute(SID_CLOSEWIN, SfxCallMode::SYNCHRON);
749 else
751 pViewFrame->ToTop();
752 return;
756 else if (rSelectedPopupEntry == u"inserttext")
758 if (pCont)
759 m_pActiveShell->InsertGlobalDocContent(*pCont);
760 else
762 m_pActiveShell->SplitNode(); // Empty document
763 m_pActiveShell->Up( false );
765 m_pActiveShell->GetView().GetEditWin().GrabFocus();
767 else if (rSelectedPopupEntry == u"update")
768 pCont = nullptr;
770 if (pCont)
771 GotoContent(pCont);
772 if (nSlot)
773 rDispatch.Execute(nSlot);
774 if (Update(bUpdateHard))
775 Display();
778 IMPL_LINK_NOARG(SwGlobalTree, Timeout, Timer *, void)
780 SwView* pView = GetParentWindow()->GetCreateView();
781 if (pView && pView->GetEditWin().HasFocus())
783 if (Update(false))
784 Display();
785 UpdateTracking();
789 void SwGlobalTree::UpdateTracking()
791 if (!m_pActiveShell)
792 return;
794 // track section at cursor position in document
795 m_xTreeView->unselect_all();
797 const SwSection* pActiveShellCurrSection = m_pActiveShell->GetCurrSection();
798 if (pActiveShellCurrSection)
800 const SwSection* pSection = pActiveShellCurrSection;
801 while (SwSection* pParent = pSection->GetParent())
802 pSection = pParent;
803 m_xTreeView->select_text(pSection->GetSectionName());
807 void SwGlobalTree::GotoContent(const SwGlblDocContent* pCont)
809 m_pActiveShell->EnterStdMode();
811 switch( pCont->GetType() )
813 case GLBLDOC_UNKNOWN:
814 m_pActiveShell->GotoGlobalDocContent(*pCont);
815 break;
816 case GLBLDOC_TOXBASE:
818 const OUString sName = pCont->GetTOX()->GetTOXName();
819 if (!m_pActiveShell->GotoNextTOXBase(&sName))
820 m_pActiveShell->GotoPrevTOXBase(&sName);
822 break;
823 case GLBLDOC_SECTION:
824 break;
829 void SwGlobalTree::ShowTree()
831 m_aUpdateTimer.Start();
832 m_xTreeView->show();
833 UpdateTracking();
836 void SwGlobalTree::HideTree()
838 m_aUpdateTimer.Stop();
839 m_xTreeView->hide();
842 void SwGlobalTree::ExecCommand(std::u16string_view rCmd)
844 int nEntry = m_xTreeView->get_selected_index();
845 if (nEntry == -1)
846 return;
847 if (rCmd == u"edit")
849 const SwGlblDocContent* pCont = weld::fromId<const SwGlblDocContent*>(
850 m_xTreeView->get_id(nEntry));
851 EditContent(pCont);
853 else
855 if (m_xTreeView->count_selected_rows() == 1)
857 bool bMove = false;
858 int nSource = nEntry;
859 int nDest = nSource;
860 if (rCmd == u"movedown")
862 int nEntryCount = m_xTreeView->n_children();
863 bMove = nEntryCount > nSource + 1;
864 nDest+= 2;
866 else if (rCmd == u"moveup")
868 bMove = 0 != nSource;
869 nDest--;
871 if( bMove && m_pActiveShell->MoveGlobalDocContent(
872 *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) &&
873 Update( false ))
874 Display();
879 bool SwGlobalTree::Update(bool bHard)
881 SwView* pActView = GetParentWindow()->GetCreateView();
882 bool bRet = false;
883 if (pActView && pActView->GetWrtShellPtr())
885 const SwWrtShell* pOldShell = m_pActiveShell;
886 m_pActiveShell = pActView->GetWrtShellPtr();
887 if(m_pActiveShell != pOldShell)
889 m_pSwGlblDocContents.reset();
890 if (!IsListening(*m_pActiveShell->GetView().GetDocShell()))
891 StartListening(*m_pActiveShell->GetView().GetDocShell());
893 if(!m_pSwGlblDocContents)
895 m_pSwGlblDocContents.reset(new SwGlblDocContents);
896 bRet = true;
897 m_pActiveShell->GetGlobalDocContent(*m_pSwGlblDocContents);
899 else
901 bool bCopy = false;
902 SwGlblDocContents aTempContents;
903 m_pActiveShell->GetGlobalDocContent(aTempContents);
904 size_t nChildren = m_xTreeView->n_children();
905 if (aTempContents.size() != m_pSwGlblDocContents->size() ||
906 aTempContents.size() != nChildren)
908 bRet = true;
909 bCopy = true;
911 else
913 for(size_t i = 0; i < aTempContents.size() && !bCopy; i++)
915 SwGlblDocContent* pLeft = aTempContents[i].get();
916 SwGlblDocContent* pRight = (*m_pSwGlblDocContents)[i].get();
917 GlobalDocContentType eType = pLeft->GetType();
918 OUString sTemp = m_xTreeView->get_text(i);
919 if (
920 eType != pRight->GetType() ||
922 eType == GLBLDOC_SECTION &&
923 pLeft->GetSection()->GetSectionName() != sTemp
924 ) ||
926 eType == GLBLDOC_TOXBASE &&
927 pLeft->GetTOX()->GetTitle() != sTemp
931 bCopy = true;
935 if (bCopy || bHard)
937 *m_pSwGlblDocContents = std::move( aTempContents );
938 bRet = true;
942 else
944 m_xTreeView->clear();
945 if(m_pSwGlblDocContents)
946 m_pSwGlblDocContents->clear();
948 // FIXME: Implement a test for changes!
949 return bRet;
952 void SwGlobalTree::OpenDoc(const SwGlblDocContent* pCont)
954 const OUString sFileName(pCont->GetSection()->GetLinkFileName().getToken(0,
955 sfx2::cTokenSeparator));
956 bool bFound = false;
957 const SfxObjectShell* pCurr = SfxObjectShell::GetFirst();
958 while( !bFound && pCurr )
960 if(pCurr->GetMedium() &&
961 pCurr->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri) == sFileName)
963 bFound = true;
964 SwGlobalTree::SetShowShell(pCurr);
965 Application::PostUserEvent(LINK(this, SwGlobalTree, ShowFrameHdl));
966 pCurr = nullptr;
968 else
969 pCurr = SfxObjectShell::GetNext(*pCurr);
971 if(!bFound)
973 SfxStringItem aURL(SID_FILE_NAME, sFileName);
974 SfxBoolItem aReadOnly(SID_DOC_READONLY, false);
975 SfxStringItem aTargetFrameName( SID_TARGETNAME, "_blank" );
976 SfxStringItem aReferer(SID_REFERER, m_pActiveShell->GetView().GetDocShell()->GetTitle());
977 m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->
978 ExecuteList(SID_OPENDOC, SfxCallMode::ASYNCHRON,
979 { &aURL, &aReadOnly, &aReferer, &aTargetFrameName });
983 IMPL_LINK_NOARG( SwGlobalTree, DoubleClickHdl, weld::TreeView&, bool)
985 int nEntry = m_xTreeView->get_cursor_index();
986 SwGlblDocContent* pCont = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry));
987 if (pCont->GetType() == GLBLDOC_SECTION)
988 OpenDoc(pCont);
989 else
991 GotoContent(pCont);
992 m_pActiveShell->GetView().GetEditWin().GrabFocus();
994 return false;
997 SwNavigationPI* SwGlobalTree::GetParentWindow()
999 return m_pDialog;
1002 IMPL_STATIC_LINK_NOARG(SwGlobalTree, ShowFrameHdl, void*, void)
1004 SfxViewFrame* pFirst = s_pShowShell ? SfxViewFrame::GetFirst(s_pShowShell) : nullptr;
1005 if (pFirst)
1006 pFirst->ToTop();
1007 SwGlobalTree::SetShowShell(nullptr);
1010 void SwGlobalTree::InsertRegion( const SwGlblDocContent* _pContent, const Sequence< OUString >& _rFiles )
1012 sal_Int32 nFiles = _rFiles.getLength();
1013 if (!nFiles)
1014 return;
1016 size_t nEntryCount = m_xTreeView->n_children();
1018 bool bMove = _pContent == nullptr;
1019 const OUString* pFileNames = _rFiles.getConstArray();
1020 SwWrtShell& rSh = GetParentWindow()->GetCreateView()->GetWrtShell();
1021 rSh.StartAction();
1022 // after insertion of the first new content the 'pCont' parameter becomes invalid
1023 // find the index of the 'anchor' content to always use a current anchor content
1024 size_t nAnchorContent = m_pSwGlblDocContents->size() - 1;
1025 if (!bMove)
1027 for (size_t nContent = 0; nContent < m_pSwGlblDocContents->size();
1028 ++nContent)
1030 if( *_pContent == *(*m_pSwGlblDocContents)[ nContent ] )
1032 nAnchorContent = nContent;
1033 break;
1037 SwGlblDocContents aTempContents;
1038 for ( sal_Int32 nFile = 0; nFile < nFiles; ++nFile )
1040 //update the global document content after each inserted document
1041 rSh.GetGlobalDocContent(aTempContents);
1042 SwGlblDocContent* pAnchorContent = nullptr;
1043 OSL_ENSURE(aTempContents.size() > (nAnchorContent + nFile), "invalid anchor content -> last insertion failed");
1044 if ( aTempContents.size() > (nAnchorContent + nFile) )
1045 pAnchorContent = aTempContents[nAnchorContent + nFile].get();
1046 else
1047 pAnchorContent = aTempContents.back().get();
1048 OUString sFileName(pFileNames[nFile]);
1049 INetURLObject aFileUrl;
1050 aFileUrl.SetSmartURL( sFileName );
1051 OUString sSectionName(aFileUrl.GetLastName(
1052 INetURLObject::DecodeMechanism::Unambiguous).getToken(0, sfx2::cTokenSeparator));
1053 sal_uInt16 nSectCount = rSh.GetSectionFormatCount();
1054 OUString sTempSectionName(sSectionName);
1055 sal_uInt16 nAddNumber = 0;
1056 sal_uInt16 nCount = 0;
1057 // if applicable: add index if the range name is already in use.
1058 while ( nCount < nSectCount )
1060 const SwSectionFormat& rFormat = rSh.GetSectionFormat(nCount);
1061 if ((rFormat.GetSection()->GetSectionName() == sTempSectionName)
1062 && rFormat.IsInNodesArr())
1064 nCount = 0;
1065 nAddNumber++;
1066 sTempSectionName = sSectionName + ":" + OUString::number( nAddNumber );
1068 else
1069 nCount++;
1072 if ( nAddNumber )
1073 sSectionName = sTempSectionName;
1075 SwSectionData aSectionData(SectionType::Content, sSectionName);
1076 aSectionData.SetProtectFlag(true);
1077 aSectionData.SetHidden(false);
1079 aSectionData.SetLinkFileName(sFileName);
1080 aSectionData.SetType(SectionType::FileLink);
1081 aSectionData.SetLinkFilePassword( OUString() );
1083 rSh.InsertGlobalDocContent( *pAnchorContent, aSectionData );
1085 if (bMove)
1087 Update( false );
1088 rSh.MoveGlobalDocContent(
1089 *m_pSwGlblDocContents, nEntryCount, nEntryCount + nFiles, nEntryCount - nFiles );
1091 rSh.EndAction();
1092 Update( false );
1093 Display();
1097 IMPL_LINK( SwGlobalTree, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
1099 if ( ERRCODE_NONE != _pFileDlg->GetError() )
1100 return;
1102 SfxMediumList aMedList(m_pDocInserter->CreateMediumList());
1103 if ( aMedList.empty() )
1104 return;
1106 Sequence< OUString >aFileNames( aMedList.size() );
1107 OUString* pFileNames = aFileNames.getArray();
1108 sal_Int32 nPos = 0;
1109 for (const std::unique_ptr<SfxMedium>& pMed : aMedList)
1111 // tdf#127978 - don't URL encode filename for navigator's tooltip
1112 OUString sFileName
1113 = pMed->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)
1114 + OUStringChar(sfx2::cTokenSeparator)
1115 + pMed->GetFilter()->GetFilterName()
1116 + OUStringChar(sfx2::cTokenSeparator);
1117 pFileNames[nPos++] = sFileName;
1119 InsertRegion( &*m_oDocContent, aFileNames );
1120 m_oDocContent.reset();
1123 void SwGlobalTree::Notify(SfxBroadcaster& rBC, SfxHint const& rHint)
1125 SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint));
1126 SwXTextView* pDyingShell = nullptr;
1127 if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed")
1128 pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
1129 if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
1131 EndListening(*m_pActiveShell->GetView().GetDocShell());
1132 m_pActiveShell = nullptr;
1134 else
1136 SfxListener::Notify(rBC, rHint);
1137 if (rHint.GetId() == SfxHintId::SwNavigatorUpdateTracking)
1138 UpdateTracking();
1142 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */