1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
41 #include <edglbldc.hxx>
42 #include <section.hxx>
50 #include <strings.hrc>
51 #include <bitmaps.hlst>
52 #include <swabstdlg.hxx>
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;
66 class SwGlobalFrameListener_Impl
: public SfxListener
70 explicit SwGlobalFrameListener_Impl(SfxViewFrame
& rFrame
)
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
)
91 enum GLOBAL_CONTEXT_IDX
94 IDX_STR_EDIT_CONTENT
= 1,
95 IDX_STR_EDIT_INSERT
= 2,
99 IDX_STR_INSERT_TEXT
= 6,
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
[] =
129 SwGlobalTree::SwGlobalTree(std::unique_ptr
<weld::TreeView
> xTreeView
, SwNavigationPI
* pDialog
)
130 : m_xTreeView(std::move(xTreeView
))
131 , m_aDropTargetHelper(*this)
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
);
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))
178 if (rWidget
.get_drag_source() == &rWidget
) // internal drag
179 m_rTreeView
.MoveSelectionTo(xDropEntry
.get());
182 TransferableDataHelper
aData( rEvt
.maDropEvent
.Transferable
);
185 const SwGlblDocContent
* pCnt
= xDropEntry
?
186 weld::fromId
<const SwGlblDocContent
*>(rWidget
.get_id(*xDropEntry
)) :
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
):
195 size_t nEntryCount
= rWidget
.n_children();
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.
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())
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
);
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
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
;
265 IMPL_LINK(SwGlobalTree
, CommandHdl
, const CommandEvent
&, rCEvt
, bool)
267 if (rCEvt
.GetCommand() != CommandEventId::ContextMenu
)
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
);
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;
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
;
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
;
350 nRet
|= MenuEnableFlags::Update
|MenuEnableFlags::Delete
;
352 nRet
|= MenuEnableFlags::UpdateSel
;
356 IMPL_LINK(SwGlobalTree
, QueryTooltipHdl
, const weld::TreeIter
&, rIter
, OUString
)
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
;
372 IMPL_LINK_NOARG(SwGlobalTree
, SelectHdl
, weld::TreeView
&, void)
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
) &&
408 IMPL_LINK_NOARG(SwGlobalTree
, FocusInHdl
, weld::Widget
&, void)
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())
424 GetParentWindow()->ToggleTree();
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
);
448 m_xTreeView
->set_font_color(*xEntry
, COL_AUTO
);
449 bEntry
= m_xTreeView
->iter_next(*xEntry
);
450 assert(bEntry
|| i
== nCount
- 1);
455 int nOldSelEntry
= m_xTreeView
->get_selected_index();
456 OUString sEntryName
; // Name of the entry
458 if (nOldSelEntry
!= -1)
460 sEntryName
= m_xTreeView
->get_text(nOldSelEntry
);
461 nSelPos
= nOldSelEntry
;
463 m_xTreeView
->freeze();
464 m_xTreeView
->clear();
467 for (size_t i
= 0; i
< nCount
; ++i
)
469 const SwGlblDocContent
* pCont
= (*m_pSwGlblDocContents
)[i
].get();
471 OUString
sId(weld::toId(pCont
));
474 switch (pCont
->GetType())
476 case GLBLDOC_UNKNOWN
:
477 sEntry
= m_aContextStrings
[IDX_STR_INSERT_TEXT
];
479 case GLBLDOC_TOXBASE
:
481 const SwTOXBase
* pBase
= pCont
->GetTOX();
482 sEntry
= pBase
->GetTitle();
483 aImage
= RID_BMP_NAVI_INDEX
;
486 case GLBLDOC_SECTION
:
488 const SwSection
* pSect
= pCont
->GetSection();
489 sEntry
= pSect
->GetSectionName();
490 aImage
= RID_BMP_DROP_REGION
;
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
)
507 m_xTreeView
->select(nSelEntry
);
508 else if (nSelPos
!= -1 && o3tl::make_unsigned(nSelPos
) < nCount
)
509 m_xTreeView
->select(nSelPos
);
511 m_xTreeView
->select(0);
516 void SwGlobalTree::InsertRegion( const SwGlblDocContent
* pCont
, const OUString
* pFileName
)
518 Sequence
< OUString
> aFileNames
;
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();
545 case GLBLDOC_TOXBASE
:
547 const SwTOXBase
* pBase
= pCont
->GetTOX();
549 nSlot
= FN_INSERT_MULTI_TOX
;
552 case GLBLDOC_SECTION
:
565 m_pActiveShell
->GetView().GetViewFrame().GetDispatcher()->Execute(nSlot
);
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
;
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();
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());
606 else if (rSelectedPopupEntry
== u
"updateindex")
608 nSlot
= FN_UPDATE_TOX
;
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
;
619 else if (rSelectedPopupEntry
== u
"editcontent")
621 OSL_ENSURE(pCont
, "edit without entry ? " );
627 else if (rSelectedPopupEntry
== u
"editlink")
629 OSL_ENSURE(pCont
, "edit without entry ? " );
632 SfxStringItem
aName(FN_EDIT_REGION
,
633 pCont
->GetSection()->GetSectionName());
634 rDispatch
.ExecuteList(FN_EDIT_REGION
, SfxCallMode::ASYNCHRON
,
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
,
653 pTempContents
.reset(new SwGlblDocContents
);
654 m_pActiveShell
->GetGlobalDocContent(*pTempContents
);
656 pTempContents
.reset();
657 m_pActiveShell
->EndAction();
660 else if (rSelectedPopupEntry
== u
"insertindex")
665 RES_FRM_SIZE
, RES_FRM_SIZE
,
666 RES_LR_SPACE
, RES_LR_SPACE
,
667 RES_BACKGROUND
, RES_BACKGROUND
,
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
,
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
);
691 else if (rSelectedPopupEntry
== u
"insertfile")
693 m_oDocContent
= std::move(oContCopy
);
694 InsertRegion( &*m_oDocContent
);
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
}));
711 SfxFrame
* pFrame
= pItem
? pItem
->GetFrame() : nullptr;
712 SfxViewFrame
* pViewFrame
= pFrame
? pFrame
->GetCurrentViewFrame() : nullptr;
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())
726 // Due to the update the entries are invalid
731 m_xTreeView
->select(nEntry
);
733 nEntry
= m_xTreeView
->get_selected_index();
734 pCont
= nEntry
!= -1 ? weld::fromId
<SwGlblDocContent
*>(m_xTreeView
->get_id(nEntry
)) : nullptr;
741 if(pBool
->GetValue())
743 InsertRegion(pCont
, &sNewFile
);
747 pViewFrame
->GetDispatcher()->Execute(SID_CLOSEWIN
, SfxCallMode::SYNCHRON
);
756 else if (rSelectedPopupEntry
== u
"inserttext")
759 m_pActiveShell
->InsertGlobalDocContent(*pCont
);
762 m_pActiveShell
->SplitNode(); // Empty document
763 m_pActiveShell
->Up( false );
765 m_pActiveShell
->GetView().GetEditWin().GrabFocus();
767 else if (rSelectedPopupEntry
== u
"update")
773 rDispatch
.Execute(nSlot
);
774 if (Update(bUpdateHard
))
778 IMPL_LINK_NOARG(SwGlobalTree
, Timeout
, Timer
*, void)
780 SwView
* pView
= GetParentWindow()->GetCreateView();
781 if (pView
&& pView
->GetEditWin().HasFocus())
789 void SwGlobalTree::UpdateTracking()
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())
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
);
816 case GLBLDOC_TOXBASE
:
818 const OUString sName
= pCont
->GetTOX()->GetTOXName();
819 if (!m_pActiveShell
->GotoNextTOXBase(&sName
))
820 m_pActiveShell
->GotoPrevTOXBase(&sName
);
823 case GLBLDOC_SECTION
:
829 void SwGlobalTree::ShowTree()
831 m_aUpdateTimer
.Start();
836 void SwGlobalTree::HideTree()
838 m_aUpdateTimer
.Stop();
842 void SwGlobalTree::ExecCommand(std::u16string_view rCmd
)
844 int nEntry
= m_xTreeView
->get_selected_index();
849 const SwGlblDocContent
* pCont
= weld::fromId
<const SwGlblDocContent
*>(
850 m_xTreeView
->get_id(nEntry
));
855 if (m_xTreeView
->count_selected_rows() == 1)
858 int nSource
= nEntry
;
860 if (rCmd
== u
"movedown")
862 int nEntryCount
= m_xTreeView
->n_children();
863 bMove
= nEntryCount
> nSource
+ 1;
866 else if (rCmd
== u
"moveup")
868 bMove
= 0 != nSource
;
871 if( bMove
&& m_pActiveShell
->MoveGlobalDocContent(
872 *m_pSwGlblDocContents
, nSource
, nSource
+ 1, nDest
) &&
879 bool SwGlobalTree::Update(bool bHard
)
881 SwView
* pActView
= GetParentWindow()->GetCreateView();
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
);
897 m_pActiveShell
->GetGlobalDocContent(*m_pSwGlblDocContents
);
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
)
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
);
920 eType
!= pRight
->GetType() ||
922 eType
== GLBLDOC_SECTION
&&
923 pLeft
->GetSection()->GetSectionName() != sTemp
926 eType
== GLBLDOC_TOXBASE
&&
927 pLeft
->GetTOX()->GetTitle() != sTemp
937 *m_pSwGlblDocContents
= std::move( aTempContents
);
944 m_xTreeView
->clear();
945 if(m_pSwGlblDocContents
)
946 m_pSwGlblDocContents
->clear();
948 // FIXME: Implement a test for changes!
952 void SwGlobalTree::OpenDoc(const SwGlblDocContent
* pCont
)
954 const OUString
sFileName(pCont
->GetSection()->GetLinkFileName().getToken(0,
955 sfx2::cTokenSeparator
));
957 const SfxObjectShell
* pCurr
= SfxObjectShell::GetFirst();
958 while( !bFound
&& pCurr
)
960 if(pCurr
->GetMedium() &&
961 pCurr
->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri
) == sFileName
)
964 SwGlobalTree::SetShowShell(pCurr
);
965 Application::PostUserEvent(LINK(this, SwGlobalTree
, ShowFrameHdl
));
969 pCurr
= SfxObjectShell::GetNext(*pCurr
);
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
)
992 m_pActiveShell
->GetView().GetEditWin().GrabFocus();
997 SwNavigationPI
* SwGlobalTree::GetParentWindow()
1002 IMPL_STATIC_LINK_NOARG(SwGlobalTree
, ShowFrameHdl
, void*, void)
1004 SfxViewFrame
* pFirst
= s_pShowShell
? SfxViewFrame::GetFirst(s_pShowShell
) : nullptr;
1007 SwGlobalTree::SetShowShell(nullptr);
1010 void SwGlobalTree::InsertRegion( const SwGlblDocContent
* _pContent
, const Sequence
< OUString
>& _rFiles
)
1012 sal_Int32 nFiles
= _rFiles
.getLength();
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();
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;
1027 for (size_t nContent
= 0; nContent
< m_pSwGlblDocContents
->size();
1030 if( *_pContent
== *(*m_pSwGlblDocContents
)[ nContent
] )
1032 nAnchorContent
= nContent
;
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();
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())
1066 sTempSectionName
= sSectionName
+ ":" + OUString::number( 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
);
1088 rSh
.MoveGlobalDocContent(
1089 *m_pSwGlblDocContents
, nEntryCount
, nEntryCount
+ nFiles
, nEntryCount
- nFiles
);
1097 IMPL_LINK( SwGlobalTree
, DialogClosedHdl
, sfx2::FileDialogHelper
*, _pFileDlg
, void )
1099 if ( ERRCODE_NONE
!= _pFileDlg
->GetError() )
1102 SfxMediumList
aMedList(m_pDocInserter
->CreateMediumList());
1103 if ( aMedList
.empty() )
1106 Sequence
< OUString
>aFileNames( aMedList
.size() );
1107 OUString
* pFileNames
= aFileNames
.getArray();
1109 for (const std::unique_ptr
<SfxMedium
>& pMed
: aMedList
)
1111 // tdf#127978 - don't URL encode filename for navigator's tooltip
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;
1136 SfxListener::Notify(rBC
, rHint
);
1137 if (rHint
.GetId() == SfxHintId::SwNavigatorUpdateTracking
)
1142 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */