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 <svl/stritem.hxx>
21 #include <sfx2/fcontnr.hxx>
22 #include <sfx2/linkmgr.hxx>
23 #include <sfx2/dispatch.hxx>
24 #include <sfx2/viewfrm.hxx>
25 #include <svl/urihelper.hxx>
26 #include <sfx2/docfile.hxx>
27 #include <sfx2/docfilt.hxx>
28 #include <vcl/help.hxx>
29 #include <sot/filelist.hxx>
30 #include <svl/eitem.hxx>
31 #include <svl/urlbmk.hxx>
32 #include <svx/svxids.hrc>
33 #include <vcl/graphicfilter.hxx>
34 #include <vcl/settings.hxx>
35 
36 #include <vcl/treelistentry.hxx>
37 #include <sfx2/docinsert.hxx>
38 #include <sfx2/filedlghelper.hxx>
39 
40 #include <sfx2/app.hxx>
41 #include <swmodule.hxx>
42 #include <wrtsh.hxx>
43 #include <view.hxx>
44 #include <docsh.hxx>
45 #include <content.hxx>
46 #include <edglbldc.hxx>
47 #include <section.hxx>
48 #include <tox.hxx>
49 #include <cnttab.hxx>
50 #include <navipi.hxx>
51 #include <navicont.hxx>
52 #include <edtwin.hxx>
53 #include <uitool.hxx>
54 #include <toxmgr.hxx>
55 
56 #include <cmdid.h>
57 #include <helpids.h>
58 #include <strings.hrc>
59 #include <globals.hrc>
60 #include <bitmaps.hlst>
61 #include <swabstdlg.hxx>
62 #include <memory>
63 
64 using namespace ::com::sun::star::uno;
65 
66 // Context menu for GlobalTree
67 #define CTX_INSERT_ANY_INDEX 10
68 #define CTX_INSERT_FILE     11
69 #define CTX_INSERT_NEW_FILE 12
70 #define CTX_INSERT_TEXT     13
71 
72 #define CTX_UPDATE_SEL      20
73 #define CTX_UPDATE_INDEX    21
74 #define CTX_UPDATE_LINK     22
75 #define CTX_UPDATE_ALL      23
76 
77 #define CTX_UPDATE          1
78 #define CTX_INSERT          2
79 #define CTX_EDIT            3
80 #define CTX_DELETE          4
81 #define CTX_EDIT_LINK       5
82 
83 #define GLOBAL_UPDATE_TIMEOUT 2000
84 
85 // TabPos: push to left
86 #define  GLBL_TABPOS_SUB 5
87 
88 const SfxObjectShell* SwGlobalTree::pShowShell = nullptr;
89 static const char* aHelpForMenu[] =
90 {
91     nullptr,
92     HID_GLBLTREE_UPDATE,        //CTX_UPDATE
93     HID_GLBLTREE_INSERT,        //CTX_INSERT
94     HID_GLBLTREE_EDIT,          //CTX_EDIT
95     HID_GLBLTREE_DEL,           //CTX_DELETE
96     HID_GLBLTREE_EDIT_LINK,     //CTX_EDIT_LINK
97     nullptr,
98     nullptr,
99     nullptr,
100     nullptr,
101     HID_GLBLTREE_INS_IDX,       //CTX_INSERT_ANY_INDEX
102     HID_GLBLTREE_INS_FILE,      //CTX_INSERT_FILE
103     HID_GLBLTREE_INS_NEW_FILE,  //CTX_INSERT_NEW_FILE
104     HID_GLBLTREE_INS_TEXT,      //CTX_INSERT_TEXT
105     nullptr,
106     nullptr,
107     nullptr,
108     nullptr,
109     nullptr,
110     nullptr,
111     HID_GLBLTREE_UPD_SEL,       //CTX_UPDATE_SEL
112     HID_GLBLTREE_UPD_IDX,       //CTX_UPDATE_INDEX
113     HID_GLBLTREE_UPD_LINK,      //CTX_UPDATE_LINK
114     HID_GLBLTREEUPD_ALL         //CTX_UPDATE_ALL
115 };
116 
117 class SwGlobalFrameListener_Impl : public SfxListener
118 {
119     bool bValid;
120 public:
SwGlobalFrameListener_Impl(SfxViewFrame & rFrame)121     explicit SwGlobalFrameListener_Impl(SfxViewFrame& rFrame)
122         : bValid(true)
123     {
124         StartListening(rFrame);
125     }
126 
127     virtual void        Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
128 
IsValid() const129     bool                IsValid() const {return bValid;}
130 };
131 
Notify(SfxBroadcaster &,const SfxHint & rHint)132 void SwGlobalFrameListener_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
133 {
134     if( rHint.GetId() == SfxHintId::Dying)
135         bValid = false;
136 }
137 
138 enum GLOBAL_CONTEXT_IDX
139 {
140     IDX_STR_UPDATE = 0,
141     IDX_STR_EDIT_CONTENT = 1,
142     IDX_STR_EDIT_INSERT = 2,
143     IDX_STR_INDEX = 3,
144     IDX_STR_FILE = 4,
145     IDX_STR_NEW_FILE = 5,
146     IDX_STR_INSERT_TEXT = 6,
147     IDX_STR_DELETE = 7,
148     IDX_STR_UPDATE_SEL = 8,
149     IDX_STR_UPDATE_INDEX = 9,
150     IDX_STR_UPDATE_LINK = 10,
151     IDX_STR_UPDATE_ALL = 11,
152     IDX_STR_BROKEN_LINK = 12,
153     IDX_STR_EDIT_LINK = 13
154 };
155 
156 static const char* GLOBAL_CONTEXT_ARY[] =
157 {
158     STR_UPDATE,
159     STR_EDIT_CONTENT,
160     STR_EDIT_INSERT,
161     STR_INDEX,
162     STR_FILE,
163     STR_NEW_FILE,
164     STR_INSERT_TEXT,
165     STR_DELETE,
166     STR_UPDATE_SEL,
167     STR_UPDATE_INDEX,
168     STR_UPDATE_LINK,
169     STR_UPDATE_ALL,
170     STR_BROKEN_LINK,
171     STR_EDIT_LINK
172 };
173 
SwGlobalTree(vcl::Window * pParent,SwNavigationPI * pDialog)174 SwGlobalTree::SwGlobalTree(vcl::Window* pParent, SwNavigationPI* pDialog)
175     : SvTreeListBox(pParent)
176     , m_xDialog(pDialog)
177     , m_pActiveShell(nullptr)
178     , m_pEmphasisEntry(nullptr)
179     , m_pDDSource(nullptr)
180     , m_bIsInternalDrag(false)
181     , m_bLastEntryEmphasis(false)
182 {
183     SetDragDropMode(DragDropMode::APP_COPY  |
184                     DragDropMode::CTRL_MOVE |
185                     DragDropMode::ENABLE_TOP );
186 
187     m_aUpdateTimer.SetTimeout(GLOBAL_UPDATE_TIMEOUT);
188     m_aUpdateTimer.SetInvokeHandler(LINK(this, SwGlobalTree, Timeout));
189     m_aUpdateTimer.Start();
190     for (sal_uInt16 i = 0; i < GLOBAL_CONTEXT_COUNT; i++)
191     {
192         m_aContextStrings[i] = SwResId(GLOBAL_CONTEXT_ARY[i]);
193     }
194     SetHelpId(HID_NAVIGATOR_GLOB_TREELIST);
195     SelectHdl();
196     SetDoubleClickHdl(LINK(this, SwGlobalTree, DoubleClickHdl));
197     EnableContextMenuHandling();
198 }
199 
~SwGlobalTree()200 SwGlobalTree::~SwGlobalTree()
201 {
202     disposeOnce();
203 }
204 
dispose()205 void SwGlobalTree::dispose()
206 {
207     m_pSwGlblDocContents.reset();
208     m_pDocInserter.reset();
209     m_aUpdateTimer.Stop();
210     m_xDialog.clear();
211     SvTreeListBox::dispose();
212 }
213 
GetOptimalSize() const214 Size SwGlobalTree::GetOptimalSize() const
215 {
216     return LogicToPixel(Size(110, 112), MapMode(MapUnit::MapAppFont));
217 }
218 
ExecuteDrop(const ExecuteDropEvent & rEvt)219 sal_Int8 SwGlobalTree::ExecuteDrop( const ExecuteDropEvent& rEvt )
220 {
221     sal_Int8 nRet = DND_ACTION_NONE;
222     SvTreeListEntry* pLast = LastVisible();
223     if(m_pEmphasisEntry)
224     {
225         ImplShowTargetEmphasis( Prev(m_pEmphasisEntry), false );
226         m_pEmphasisEntry = nullptr;
227     }
228     else if(m_bLastEntryEmphasis && pLast)
229     {
230         ImplShowTargetEmphasis( pLast, false);
231     }
232 
233     SvTreeListEntry* pDropEntry = m_bLastEntryEmphasis ? nullptr : GetEntry(rEvt.maPosPixel);
234     if( m_bIsInternalDrag )
235     {
236         SvTreeListEntry* pDummy = nullptr;
237         sal_uLong nInsertionPos = TREELIST_APPEND;
238         NotifyMoving( pDropEntry, m_pDDSource, pDummy, nInsertionPos );
239     }
240     else
241     {
242         TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
243 
244         OUString sFileName;
245         const SwGlblDocContent* pCnt = pDropEntry ?
246                     static_cast<const SwGlblDocContent*>(pDropEntry->GetUserData()) :
247                             nullptr;
248         if( aData.HasFormat( SotClipboardFormatId::FILE_LIST ))
249         {
250             nRet = rEvt.mnAction;
251             std::unique_ptr<SwGlblDocContents> pTempContents(new SwGlblDocContents);
252             int nAbsContPos = pDropEntry ?
253                                 static_cast<int>(GetModel()->GetAbsPos(pDropEntry)):
254                                     - 1;
255             sal_uLong nEntryCount = GetEntryCount();
256 
257             // Get data
258             FileList aFileList;
259             aData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList );
260             for ( size_t n = aFileList.Count(); n--; )
261             {
262                 sFileName = aFileList.GetFile(n);
263                 InsertRegion(pCnt, &sFileName);
264                 // The list of contents must be newly fetched after inserting,
265                 // to not work on an old content.
266                 if(n)
267                 {
268                     m_pActiveShell->GetGlobalDocContent(*pTempContents);
269                     // If the file was successfully inserted,
270                     // then the next content must also be fetched.
271                     if(nEntryCount < pTempContents->size())
272                     {
273                         nEntryCount++;
274                         nAbsContPos++;
275                         pCnt = (*pTempContents)[ nAbsContPos ].get();
276                     }
277                 }
278             }
279         }
280         else if( !(sFileName =
281                         SwNavigationPI::CreateDropFileName( aData )).isEmpty())
282         {
283             INetURLObject aTemp(sFileName);
284             GraphicDescriptor aDesc(aTemp);
285             if( !aDesc.Detect() )   // accept no graphics
286             {
287                 nRet = rEvt.mnAction;
288                 InsertRegion(pCnt, &sFileName);
289             }
290         }
291     }
292     m_bLastEntryEmphasis = false;
293     return nRet;
294 
295 }
296 
AcceptDrop(const AcceptDropEvent & rEvt)297 sal_Int8 SwGlobalTree::AcceptDrop( const AcceptDropEvent& rEvt )
298 {
299     sal_Int8 nRet = rEvt.mnAction;
300 
301     //initiate scrolling
302     GetDropTarget( rEvt.maPosPixel );
303     SvTreeListEntry* pLast = LastVisible();
304     if( rEvt.mbLeaving )
305     {
306         if( m_pEmphasisEntry )
307         {
308             ImplShowTargetEmphasis( Prev(m_pEmphasisEntry), false );
309             m_pEmphasisEntry = nullptr;
310         }
311         else if(m_bLastEntryEmphasis && pLast)
312         {
313             ImplShowTargetEmphasis( pLast, false);
314         }
315         m_bLastEntryEmphasis = false;
316     }
317     else
318     {
319         SvTreeListEntry* pDropEntry = GetEntry( rEvt.maPosPixel );
320         if(m_bIsInternalDrag)
321         {
322             if( m_pDDSource != pDropEntry )
323                 nRet = rEvt.mnAction;
324         }
325         else if( IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
326                   IsDropFormatSupported( SotClipboardFormatId::STRING ) ||
327                   IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
328                   IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
329                    IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK )||
330                    IsDropFormatSupported( SotClipboardFormatId::FILECONTENT ) ||
331                    IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) ||
332                    IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
333                    IsDropFormatSupported( SotClipboardFormatId::FILENAME ))
334                 nRet = DND_ACTION_LINK;
335 
336         if(m_pEmphasisEntry && m_pEmphasisEntry != pDropEntry)
337             ImplShowTargetEmphasis( Prev(m_pEmphasisEntry), false );
338         else if(pLast && m_bLastEntryEmphasis  && pDropEntry)
339         {
340             ImplShowTargetEmphasis( pLast, false);
341             m_bLastEntryEmphasis = false;
342         }
343 
344         if(pDropEntry)
345             ImplShowTargetEmphasis( Prev(pDropEntry), DND_ACTION_NONE != nRet );
346         else if(pLast)
347         {
348             ImplShowTargetEmphasis( pLast, DND_ACTION_NONE != nRet );
349             m_bLastEntryEmphasis = true;
350         }
351         m_pEmphasisEntry = pDropEntry;
352     }
353     return nRet;
354 }
355 
CreateContextMenu()356 VclPtr<PopupMenu> SwGlobalTree::CreateContextMenu()
357 {
358     VclPtr<PopupMenu> pPop;
359     if(m_pActiveShell &&
360         !m_pActiveShell->GetView().GetDocShell()->IsReadOnly())
361     {
362         const MenuEnableFlags nEnableFlags = GetEnableFlags();
363         pPop = VclPtr<PopupMenu>::Create();
364         VclPtrInstance<PopupMenu> pSubPop1;
365         VclPtrInstance<PopupMenu> pSubPop2;
366 
367         for (sal_uInt16 i = CTX_UPDATE_SEL; i <= CTX_UPDATE_ALL; i++)
368         {
369             pSubPop2->InsertItem( i, m_aContextStrings[IDX_STR_UPDATE_SEL + i - CTX_UPDATE_SEL] );
370             pSubPop2->SetHelpId(i, aHelpForMenu[i]);
371         }
372         pSubPop2->EnableItem(CTX_UPDATE_SEL, bool(nEnableFlags & MenuEnableFlags::UpdateSel));
373 
374         pSubPop1->InsertItem(CTX_INSERT_ANY_INDEX, m_aContextStrings[IDX_STR_INDEX]);
375         pSubPop1->SetHelpId(CTX_INSERT_ANY_INDEX, aHelpForMenu[CTX_INSERT_ANY_INDEX]);
376         pSubPop1->InsertItem(CTX_INSERT_FILE, m_aContextStrings[IDX_STR_FILE]);
377         pSubPop1->SetHelpId(CTX_INSERT_FILE, aHelpForMenu[CTX_INSERT_FILE]);
378         pSubPop1->InsertItem(CTX_INSERT_NEW_FILE, m_aContextStrings[IDX_STR_NEW_FILE]);
379         pSubPop1->SetHelpId(CTX_INSERT_NEW_FILE, aHelpForMenu[CTX_INSERT_NEW_FILE]);
380         pSubPop1->InsertItem(CTX_INSERT_TEXT, m_aContextStrings[IDX_STR_INSERT_TEXT]);
381         pSubPop1->SetHelpId(CTX_INSERT_TEXT, aHelpForMenu[CTX_INSERT_TEXT]);
382 
383         pPop->InsertItem(CTX_UPDATE, m_aContextStrings[IDX_STR_UPDATE]);
384         pPop->SetHelpId(CTX_UPDATE, aHelpForMenu[CTX_UPDATE]);
385         pPop->InsertItem(CTX_EDIT, m_aContextStrings[IDX_STR_EDIT_CONTENT]);
386         pPop->SetHelpId(CTX_EDIT, aHelpForMenu[CTX_EDIT]);
387         if(nEnableFlags&MenuEnableFlags::EditLink)
388         {
389             pPop->InsertItem(CTX_EDIT_LINK, m_aContextStrings[IDX_STR_EDIT_LINK]);
390             pPop->SetHelpId(CTX_EDIT_LINK, aHelpForMenu[CTX_EDIT_LINK]);
391         }
392         pPop->InsertItem(CTX_INSERT, m_aContextStrings[IDX_STR_EDIT_INSERT]);
393         pPop->SetHelpId(CTX_INSERT, aHelpForMenu[CTX_INSERT]);
394         pPop->InsertSeparator() ;
395         pPop->InsertItem(CTX_DELETE, m_aContextStrings[IDX_STR_DELETE]);
396         pPop->SetHelpId(CTX_DELETE, aHelpForMenu[CTX_DELETE]);
397 
398         //disabling if applicable
399         pSubPop1->EnableItem(CTX_INSERT_ANY_INDEX,  bool(nEnableFlags & MenuEnableFlags::InsertIdx ));
400         pSubPop1->EnableItem(CTX_INSERT_TEXT,       bool(nEnableFlags & MenuEnableFlags::InsertText));
401         pSubPop1->EnableItem(CTX_INSERT_FILE,       bool(nEnableFlags & MenuEnableFlags::InsertFile));
402         pSubPop1->EnableItem(CTX_INSERT_NEW_FILE,   bool(nEnableFlags & MenuEnableFlags::InsertFile));
403 
404         pPop->EnableItem(CTX_UPDATE,    bool(nEnableFlags & MenuEnableFlags::Update));
405         pPop->EnableItem(CTX_INSERT,    bool(nEnableFlags & MenuEnableFlags::InsertIdx));
406         pPop->EnableItem(CTX_EDIT,      bool(nEnableFlags & MenuEnableFlags::Edit));
407         pPop->EnableItem(CTX_DELETE,    bool(nEnableFlags & MenuEnableFlags::Delete));
408 
409         pPop->SetPopupMenu( CTX_INSERT, pSubPop1 );
410         pPop->SetPopupMenu( CTX_UPDATE, pSubPop2 );
411     }
412     return pPop;
413 }
414 
TbxMenuHdl(sal_uInt16 nTbxId,ToolBox * pBox)415 void SwGlobalTree::TbxMenuHdl(sal_uInt16 nTbxId, ToolBox* pBox)
416 {
417     const MenuEnableFlags nEnableFlags = GetEnableFlags();
418     const OUString sCommand(pBox->GetItemCommand(nTbxId));
419     if (sCommand == "insert")
420     {
421         ScopedVclPtrInstance<PopupMenu> pMenu;
422         for (sal_uInt16 i = CTX_INSERT_ANY_INDEX; i <= CTX_INSERT_TEXT; ++i)
423         {
424             pMenu->InsertItem( i, m_aContextStrings[IDX_STR_INDEX + i - CTX_INSERT_ANY_INDEX] );
425             pMenu->SetHelpId(i, aHelpForMenu[i] );
426         }
427         pMenu->EnableItem(CTX_INSERT_ANY_INDEX, bool(nEnableFlags & MenuEnableFlags::InsertIdx ));
428         pMenu->EnableItem(CTX_INSERT_TEXT,      bool(nEnableFlags & MenuEnableFlags::InsertText));
429         pMenu->EnableItem(CTX_INSERT_FILE,      bool(nEnableFlags & MenuEnableFlags::InsertFile));
430         pMenu->EnableItem(CTX_INSERT_NEW_FILE,  bool(nEnableFlags & MenuEnableFlags::InsertFile));
431         pMenu->SetSelectHdl(LINK(this, SwGlobalTree, PopupHdl));
432         pMenu->Execute(pBox, pBox->GetItemRect(nTbxId));
433         pMenu.disposeAndClear();
434         pBox->EndSelection();
435         pBox->Invalidate();
436     }
437     else if (sCommand == "update")
438     {
439         ScopedVclPtrInstance<PopupMenu> pMenu;
440         for (sal_uInt16 i = CTX_UPDATE_SEL; i <= CTX_UPDATE_ALL; i++)
441         {
442             pMenu->InsertItem( i, m_aContextStrings[IDX_STR_UPDATE_SEL + i - CTX_UPDATE_SEL] );
443             pMenu->SetHelpId(i, aHelpForMenu[i] );
444         }
445         pMenu->EnableItem(CTX_UPDATE_SEL, bool(nEnableFlags & MenuEnableFlags::UpdateSel));
446         pMenu->SetSelectHdl(LINK(this, SwGlobalTree, PopupHdl));
447         pMenu->Execute(pBox, pBox->GetItemRect(nTbxId));
448         pMenu.disposeAndClear();
449         pBox->EndSelection();
450         pBox->Invalidate();
451     }
452 }
453 
GetEnableFlags() const454 MenuEnableFlags  SwGlobalTree::GetEnableFlags() const
455 {
456     SvTreeListEntry* pEntry = FirstSelected();
457     sal_uLong nSelCount = GetSelectionCount();
458     sal_uLong nEntryCount = GetEntryCount();
459     SvTreeListEntry* pPrevEntry = pEntry ? Prev(pEntry) : nullptr;
460 
461     MenuEnableFlags nRet = MenuEnableFlags::NONE;
462     if(nSelCount == 1 || !nEntryCount)
463         nRet |= MenuEnableFlags::InsertIdx|MenuEnableFlags::InsertFile;
464     if(nSelCount == 1)
465     {
466         nRet |= MenuEnableFlags::Edit;
467         if (pEntry && static_cast<SwGlblDocContent*>(pEntry->GetUserData())->GetType() != GLBLDOC_UNKNOWN &&
468                     (!pPrevEntry || static_cast<SwGlblDocContent*>(pPrevEntry->GetUserData())->GetType() != GLBLDOC_UNKNOWN))
469             nRet |= MenuEnableFlags::InsertText;
470         if (pEntry && GLBLDOC_SECTION == static_cast<SwGlblDocContent*>(pEntry->GetUserData())->GetType())
471             nRet |= MenuEnableFlags::EditLink;
472     }
473     else if(!nEntryCount)
474     {
475         nRet |= MenuEnableFlags::InsertText;
476     }
477     if(nEntryCount)
478         nRet |= MenuEnableFlags::Update|MenuEnableFlags::Delete;
479     if(nSelCount)
480         nRet |= MenuEnableFlags::UpdateSel;
481     return nRet;
482 }
483 
RequestHelp(const HelpEvent & rHEvt)484 void     SwGlobalTree::RequestHelp( const HelpEvent& rHEvt )
485 {
486     bool bParent = true;
487     Update(true);
488     Display(true);
489     if( rHEvt.GetMode() & HelpEventMode::QUICK )
490     {
491         Point aPos( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ));
492         SvTreeListEntry* pEntry = GetEntry( aPos );
493         const SwGlblDocContent* pCont = pEntry ?
494                             static_cast<const SwGlblDocContent*>(pEntry->GetUserData()) : nullptr;
495         if( pCont &&  GLBLDOC_SECTION == pCont->GetType())
496         {
497             bParent = false;
498             SvLBoxTab* pTab;
499             SvLBoxItem* pItem = GetItem( pEntry, aPos.X(), &pTab );
500             if (pItem && SvLBoxItemType::String == pItem->GetType())
501             {
502                 const SwSection* pSect = pCont->GetSection();
503                 OUString sEntry = pSect->GetLinkFileName().getToken(0, sfx2::cTokenSeparator);
504                 if(!pSect->IsConnectFlag())
505                     sEntry = m_aContextStrings[IDX_STR_BROKEN_LINK] + sEntry;
506                 Point aEntryPos = GetEntryPosition( pEntry );
507 
508                 aEntryPos.setX( GetTabPos( pEntry, pTab ) );
509                 Size aSize(pItem->GetWidth(this, pEntry), pItem->GetHeight(this, pEntry));
510 
511                 if((aEntryPos.X() + aSize.Width()) > GetSizePixel().Width())
512                     aSize.setWidth( GetSizePixel().Width() - aEntryPos.X() );
513 
514                 aEntryPos = OutputToScreenPixel(aEntryPos);
515                 tools::Rectangle aItemRect( aEntryPos, aSize );
516                 if(Help::IsBalloonHelpEnabled())
517                 {
518                     aEntryPos.AdjustX(aSize.Width() );
519                     Help::ShowBalloon( this, aEntryPos, aItemRect, sEntry );
520                 }
521                 else
522                     Help::ShowQuickHelp( this, aItemRect, sEntry,
523                         QuickHelpFlags::Left|QuickHelpFlags::VCenter );
524             }
525         }
526     }
527 
528     if(bParent)
529         SvTreeListBox::RequestHelp(rHEvt);
530 }
531 
SelectHdl()532 void     SwGlobalTree::SelectHdl()
533 {
534 
535     sal_uLong nSelCount = GetSelectionCount();
536     SvTreeListEntry* pSel = FirstSelected();
537     sal_uLong nAbsPos = pSel ? GetModel()->GetAbsPos(pSel) : 0;
538     SwNavigationPI* pNavi = GetParentWindow();
539     bool bReadonly = !m_pActiveShell ||
540                 m_pActiveShell->GetView().GetDocShell()->IsReadOnly();
541     pNavi->m_aGlobalToolBox->EnableItem(pNavi->m_aGlobalToolBox->GetItemId("edit"),  nSelCount == 1 && !bReadonly);
542     pNavi->m_aGlobalToolBox->EnableItem(pNavi->m_aGlobalToolBox->GetItemId("insert"),  nSelCount <= 1 && !bReadonly);
543     pNavi->m_aGlobalToolBox->EnableItem(pNavi->m_aGlobalToolBox->GetItemId("update"),  GetEntryCount() > 0 && !bReadonly);
544     pNavi->m_aGlobalToolBox->EnableItem(pNavi->m_aGlobalToolBox->GetItemId("up"),
545                     nSelCount == 1 && nAbsPos && !bReadonly);
546     pNavi->m_aGlobalToolBox->EnableItem(pNavi->m_aGlobalToolBox->GetItemId("down"),
547                     nSelCount == 1 && nAbsPos < GetEntryCount() - 1 && !bReadonly);
548 
549 }
550 
DeselectHdl()551 void     SwGlobalTree::DeselectHdl()
552 {
553     SelectHdl();
554 }
555 
NotifyStartDrag(TransferDataContainer &,SvTreeListEntry * pEntry)556 DragDropMode SwGlobalTree::NotifyStartDrag( TransferDataContainer& ,
557                                                 SvTreeListEntry* pEntry )
558 {
559     m_bIsInternalDrag = true;
560     m_pDDSource = pEntry;
561     return DragDropMode::CTRL_MOVE;
562 }
563 
GetTabPos(SvTreeListEntry *,SvLBoxTab * pTab)564 sal_IntPtr SwGlobalTree::GetTabPos( SvTreeListEntry*, SvLBoxTab* pTab)
565 {
566     return pTab->GetPos() - GLBL_TABPOS_SUB;
567 }
568 
NotifyMoving(SvTreeListEntry * pTarget,SvTreeListEntry * pSource,SvTreeListEntry * &,sal_uLong &)569 TriState SwGlobalTree::NotifyMoving(   SvTreeListEntry*  pTarget,
570                                         SvTreeListEntry*  pSource,
571                                         SvTreeListEntry*&,
572                                         sal_uLong&
573                                     )
574 {
575     SvTreeList* _pModel = GetModel();
576     sal_uLong nSource = _pModel->GetAbsPos(pSource);
577     sal_uLong nDest   = pTarget ? _pModel->GetAbsPos(pTarget) : m_pSwGlblDocContents->size();
578 
579     if( m_pActiveShell->MoveGlobalDocContent(
580             *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) &&
581             Update( false ))
582         Display();
583 
584     return TRISTATE_FALSE;
585 }
586 
NotifyCopying(SvTreeListEntry *,SvTreeListEntry *,SvTreeListEntry * &,sal_uLong &)587 TriState SwGlobalTree::NotifyCopying(  SvTreeListEntry*  /*pTarget*/,
588                                         SvTreeListEntry*  /*pEntry*/,
589                                         SvTreeListEntry*& /*rpNewParent*/,
590                                         sal_uLong&        /*rNewChildPos*/
591                                     )
592 {
593     return TRISTATE_FALSE;
594 }
595 
NotifyAcceptDrop(SvTreeListEntry * pEntry)596 bool SwGlobalTree::NotifyAcceptDrop( SvTreeListEntry* pEntry)
597 {
598     return pEntry != nullptr;
599 }
600 
StartDrag(sal_Int8 nAction,const Point & rPt)601 void SwGlobalTree::StartDrag( sal_Int8 nAction, const Point& rPt )
602 {
603     if( 1 == GetSelectionCount() )
604         SvTreeListBox::StartDrag( nAction, rPt );
605 }
606 
DragFinished(sal_Int8 nAction)607 void SwGlobalTree::DragFinished( sal_Int8 nAction )
608 {
609     SvTreeListBox::DragFinished( nAction );
610     m_bIsInternalDrag = false;
611 }
612 
613 // If a Ctrl+DoubleClick is executed in an empty area,
614 // then the base function of the control should be called.
615 
MouseButtonDown(const MouseEvent & rMEvt)616 void  SwGlobalTree::MouseButtonDown( const MouseEvent& rMEvt )
617 {
618     Point aPos( rMEvt.GetPosPixel());
619     SvTreeListEntry* pEntry = GetEntry( aPos, true );
620     if( !pEntry && rMEvt.IsLeft() && rMEvt.IsMod1() && (rMEvt.GetClicks() % 2) == 0)
621         Control::MouseButtonDown( rMEvt );
622     else
623         SvTreeListBox::MouseButtonDown( rMEvt );
624 }
625 
GetFocus()626 void     SwGlobalTree::GetFocus()
627 {
628     if(Update( false ))
629         Display();
630     SvTreeListBox::GetFocus();
631 }
632 
KeyInput(const KeyEvent & rKEvt)633 void     SwGlobalTree::KeyInput(const KeyEvent& rKEvt)
634 {
635     const vcl::KeyCode aCode = rKEvt.GetKeyCode();
636     if(aCode.GetCode() == KEY_RETURN)
637     {
638         switch(aCode.GetModifier())
639         {
640             case KEY_MOD2:
641                 // Switch boxes
642                 GetParentWindow()->ToggleTree();
643             break;
644         }
645     }
646     else
647         SvTreeListBox::KeyInput(rKEvt);
648 }
649 
Clear()650 void SwGlobalTree::Clear()
651 {
652     m_pEmphasisEntry = nullptr;
653     SvTreeListBox::Clear();
654 }
655 
Display(bool bOnlyUpdateUserData)656 void SwGlobalTree::Display(bool bOnlyUpdateUserData)
657 {
658     size_t nCount = m_pSwGlblDocContents->size();
659     if(bOnlyUpdateUserData && GetEntryCount() == m_pSwGlblDocContents->size())
660     {
661         SvTreeListEntry* pEntry = First();
662         for (size_t i = 0; i < nCount && pEntry; i++)
663         {
664             SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get();
665             pEntry->SetUserData(pCont);
666             pEntry = Next(pEntry);
667             assert(pEntry || i == nCount - 1);
668         }
669     }
670     else
671     {
672         SetUpdateMode( false );
673         SvTreeListEntry* pOldSelEntry = FirstSelected();
674         OUString sEntryName;  // Name of the entry
675         sal_uLong nSelPos = TREELIST_ENTRY_NOTFOUND;
676         if(pOldSelEntry)
677         {
678             sEntryName = GetEntryText(pOldSelEntry);
679             nSelPos = GetModel()->GetAbsPos(pOldSelEntry);
680         }
681         Clear();
682         if(!m_pSwGlblDocContents)
683             Update( false );
684 
685         SvTreeListEntry* pSelEntry = nullptr;
686         for( size_t i = 0; i < nCount; i++)
687         {
688             SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get();
689             OUString sEntry;
690             Image aImage;
691             switch( pCont->GetType()  )
692             {
693                 case GLBLDOC_UNKNOWN:
694                 {
695                     sEntry = m_aContextStrings[IDX_STR_INSERT_TEXT];
696                 }
697                 break;
698                 case GLBLDOC_TOXBASE:
699                 {
700                     const SwTOXBase* pBase = pCont->GetTOX();
701                     sEntry = pBase->GetTitle();
702                     aImage = Image(StockImage::Yes, RID_BMP_NAVI_INDEX);
703                 }
704                 break;
705                 case GLBLDOC_SECTION:
706                 {
707                     const SwSection* pSect = pCont->GetSection();
708                     sEntry = pSect->GetSectionName();
709                     aImage = Image(StockImage::Yes, RID_BMP_DROP_REGION);
710                 }
711                 break;
712             }
713             SvTreeListEntry* pEntry = InsertEntry(sEntry, aImage, aImage,
714                         nullptr, false, TREELIST_APPEND, pCont);
715             if(sEntry == sEntryName)
716             {
717                 pSelEntry = pEntry;
718             }
719         }
720         if(pSelEntry)
721         {
722             Select(pSelEntry);
723         }
724         else if(nSelPos != TREELIST_ENTRY_NOTFOUND && nSelPos < nCount)
725         {
726             Select(GetEntry(nSelPos));
727         }
728         else if(nCount)
729             Select(First());
730         else
731             SelectHdl();
732         SetUpdateMode( true );
733     }
734 }
735 
InsertRegion(const SwGlblDocContent * pCont,const OUString * pFileName)736 void SwGlobalTree::InsertRegion( const SwGlblDocContent* pCont, const OUString* pFileName )
737 {
738     Sequence< OUString > aFileNames;
739     if ( !pFileName )
740     {
741         m_pDocInserter.reset(new ::sfx2::DocumentInserter(GetFrameWeld(), "swriter", sfx2::DocumentInserter::Mode::InsertMulti));
742         m_pDocInserter->StartExecuteModal( LINK( this, SwGlobalTree, DialogClosedHdl ) );
743     }
744     else if ( !pFileName->isEmpty() )
745     {
746         aFileNames.realloc(1);
747         INetURLObject aFileName;
748         aFileName.SetSmartURL( *pFileName );
749         aFileNames.getArray()[0] = aFileName.GetMainURL( INetURLObject::DecodeMechanism::NONE );
750         InsertRegion( pCont, aFileNames );
751     }
752 }
753 
EditContent(const SwGlblDocContent * pCont)754 void    SwGlobalTree::EditContent(const SwGlblDocContent* pCont )
755 {
756     sal_uInt16 nSlot = 0;
757     switch( pCont->GetType() )
758     {
759         case GLBLDOC_UNKNOWN:
760             m_pActiveShell->GetView().GetEditWin().GrabFocus();
761         break;
762         case GLBLDOC_TOXBASE:
763         {
764             const SwTOXBase* pBase = pCont->GetTOX();
765             if(pBase)
766                 nSlot = FN_INSERT_MULTI_TOX;
767         }
768         break;
769         case GLBLDOC_SECTION:
770         {
771             OpenDoc(pCont);
772 
773             nSlot = 0;
774             pCont = nullptr;
775         }
776         break;
777     }
778     if(pCont)
779         GotoContent(pCont);
780     if(nSlot)
781     {
782         m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->Execute(nSlot);
783         if(Update( false ))
784             Display();
785     }
786 }
787 
IMPL_LINK(SwGlobalTree,PopupHdl,Menu *,pMenu,bool)788 IMPL_LINK( SwGlobalTree, PopupHdl, Menu* , pMenu, bool)
789 {
790     ExecuteContextMenuAction( pMenu->GetCurItemId());
791     return true;
792 }
793 
ExecuteContextMenuAction(sal_uInt16 nSelectedPopupEntry)794 void    SwGlobalTree::ExecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry )
795 {
796     bool bUpdateHard = false;
797 
798     SvTreeListEntry* pEntry = FirstSelected();
799     SwGlblDocContent* pCont = pEntry ? static_cast<SwGlblDocContent*>(pEntry->GetUserData()) : nullptr;
800     // If a RequestHelp is called during the dialogue,
801     // then the content gets lost. Because of that a copy
802     // is created in which only the DocPos is set correctly.
803     std::unique_ptr<SwGlblDocContent> pContCopy;
804     if(pCont)
805         pContCopy.reset(new SwGlblDocContent(pCont->GetDocPos()));
806     SfxDispatcher& rDispatch = *m_pActiveShell->GetView().GetViewFrame()->GetDispatcher();
807     sal_uInt16 nSlot = 0;
808     switch( nSelectedPopupEntry )
809     {
810         case CTX_UPDATE_SEL:
811         {
812             // Two passes: first update the areas, then the directories.
813             SvTreeListEntry* pSelEntry = FirstSelected();
814             while( pSelEntry )
815             {
816                 SwGlblDocContent* pContent = static_cast<SwGlblDocContent*>(pSelEntry->GetUserData());
817                 if(GLBLDOC_SECTION == pContent->GetType() &&
818                     pContent->GetSection()->IsConnected())
819                 {
820                     const_cast<SwSection*>(pContent->GetSection())->UpdateNow();
821                 }
822 
823                 pSelEntry = NextSelected(pSelEntry);
824             }
825             pSelEntry = FirstSelected();
826             while( pSelEntry )
827             {
828                 SwGlblDocContent* pContent = static_cast<SwGlblDocContent*>(pSelEntry->GetUserData());
829                 if(GLBLDOC_TOXBASE == pContent->GetType())
830                     m_pActiveShell->UpdateTableOf(*pContent->GetTOX());
831                 pSelEntry = NextSelected(pSelEntry);
832             }
833             bUpdateHard = true;
834         }
835         break;
836         case CTX_UPDATE_INDEX:
837         {
838             nSlot = FN_UPDATE_TOX;
839             bUpdateHard = true;
840         }
841         break;
842         case CTX_UPDATE_LINK:
843         case CTX_UPDATE_ALL:
844         {
845             m_pActiveShell->GetLinkManager().UpdateAllLinks(true, false, nullptr);
846             if(CTX_UPDATE_ALL == nSelectedPopupEntry)
847                 nSlot = FN_UPDATE_TOX;
848             pCont = nullptr;
849             bUpdateHard = true;
850         }
851         break;
852         case CTX_EDIT:
853         {
854             OSL_ENSURE(pCont, "edit without entry ? " );
855             if (pCont)
856             {
857                 EditContent(pCont);
858             }
859         }
860         break;
861         case CTX_EDIT_LINK:
862         {
863             OSL_ENSURE(pCont, "edit without entry ? " );
864             if (pCont)
865             {
866                 SfxStringItem aName(FN_EDIT_REGION,
867                         pCont->GetSection()->GetSectionName());
868                 rDispatch.ExecuteList(FN_EDIT_REGION, SfxCallMode::ASYNCHRON,
869                         { &aName });
870             }
871         }
872         break;
873         case CTX_DELETE:
874         {
875             // If several entries selected, then after each delete the array
876             // must be refilled. So you do not have to remember anything,
877             // deleting begins at the end.
878             SvTreeListEntry* pSelEntry = LastSelected();
879             std::unique_ptr<SwGlblDocContents> pTempContents;
880             m_pActiveShell->StartAction();
881             while(pSelEntry)
882             {
883                 m_pActiveShell->DeleteGlobalDocContent(
884                     pTempContents ? *pTempContents : *m_pSwGlblDocContents,
885                                      GetModel()->GetAbsPos(pSelEntry));
886                 pSelEntry = PrevSelected(pSelEntry);
887                 if(pSelEntry)
888                 {
889                     pTempContents.reset(new SwGlblDocContents);
890                     m_pActiveShell->GetGlobalDocContent(*pTempContents);
891                 }
892             }
893             pTempContents.reset();
894             m_pActiveShell->EndAction();
895             pCont = nullptr;
896         }
897         break;
898         case CTX_INSERT_ANY_INDEX:
899         {
900             if(pContCopy)
901             {
902                 SfxItemSet aSet(
903                     m_pActiveShell->GetView().GetPool(),
904                     svl::Items<
905                         RES_FRM_SIZE, RES_FRM_SIZE,
906                         RES_LR_SPACE, RES_LR_SPACE,
907                         RES_BACKGROUND, RES_BACKGROUND,
908                         RES_COL, RES_COL,
909                         SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE,
910                         FN_PARAM_TOX_TYPE, FN_PARAM_TOX_TYPE>{});
911 
912                 SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
913                 ScopedVclPtr<AbstractMultiTOXTabDialog> pDlg(pFact->CreateMultiTOXTabDialog(
914                                                         GetFrameWeld(), aSet,
915                                                         *m_pActiveShell,
916                                                         nullptr,
917                                                         true));
918                 if(RET_OK == pDlg->Execute())
919                 {
920                     SwTOXDescription&  rDesc = pDlg->GetTOXDescription(
921                                                 pDlg->GetCurrentTOXType());
922                     SwTOXMgr aMgr(m_pActiveShell);
923                     SwTOXBase* pToInsert = nullptr;
924                     if(aMgr.UpdateOrInsertTOX(rDesc, &pToInsert, pDlg->GetOutputItemSet()))
925                         m_pActiveShell->InsertGlobalDocContent( *pContCopy, *pToInsert );
926                 }
927                 pCont = nullptr;
928             }
929         }
930         break;
931         case CTX_INSERT_FILE:
932         {
933             m_pDocContent = std::move(pContCopy);
934             InsertRegion( m_pDocContent.get() );
935             pCont = nullptr;
936         }
937         break;
938         case CTX_INSERT_NEW_FILE:
939         {
940             SfxViewFrame* pGlobFrame = m_pActiveShell->GetView().GetViewFrame();
941             SwGlobalFrameListener_Impl aFrameListener(*pGlobFrame);
942 
943             sal_uLong nEntryPos = pEntry ? GetModel()->GetAbsPos(pEntry) : sal_uLong(-1);
944             // Creating a new doc
945             SfxStringItem aFactory(SID_NEWDOCDIRECT,
946                             SwDocShell::Factory().GetFilterContainer()->GetName());
947 
948             const SfxFrameItem* pItem = static_cast<const SfxFrameItem*>(
949                             rDispatch.ExecuteList(SID_NEWDOCDIRECT,
950                                 SfxCallMode::SYNCHRON, { &aFactory }));
951 
952             // save at
953             SfxFrame* pFrame = pItem ? pItem->GetFrame() : nullptr;
954             SfxViewFrame* pViewFrame = pFrame ? pFrame->GetCurrentViewFrame() : nullptr;
955             if (pViewFrame)
956             {
957                 const SfxBoolItem* pBool = static_cast<const SfxBoolItem*>(
958                         pViewFrame->GetDispatcher()->Execute(
959                                 SID_SAVEASDOC, SfxCallMode::SYNCHRON ));
960                 SfxObjectShell& rObj = *pViewFrame->GetObjectShell();
961                 const SfxMedium* pMedium = rObj.GetMedium();
962                 OUString sNewFile(pMedium->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri));
963                 // Insert the area with the Doc-Name
964                 // Bring the own Doc in the foreground
965                 if(aFrameListener.IsValid() && !sNewFile.isEmpty())
966                 {
967                     pGlobFrame->ToTop();
968                     // Due to the update the entries are invalid
969                     if(nEntryPos != sal_uLong(-1))
970                     {
971                         Update( false );
972                         Display();
973                         Select(GetModel()->GetEntryAtAbsPos(nEntryPos));
974                         pEntry = FirstSelected();
975                         pCont = pEntry ? static_cast<SwGlblDocContent*>(pEntry->GetUserData()) : nullptr;
976                     }
977                     else
978                     {
979                         pEntry = nullptr;
980                         pCont = nullptr;
981                     }
982                     if(pBool->GetValue())
983                     {
984                         InsertRegion(pCont, &sNewFile);
985                         pViewFrame->ToTop();
986                     }
987                     else
988                         pViewFrame->GetDispatcher()->Execute(SID_CLOSEWIN,
989                                                 SfxCallMode::SYNCHRON);
990                 }
991                 else
992                 {
993                     pViewFrame->ToTop();
994                     return;
995                 }
996             }
997         }
998         break;
999         case CTX_INSERT_TEXT:
1000         {
1001             if(pCont)
1002                 m_pActiveShell->InsertGlobalDocContent(*pCont);
1003             else
1004             {
1005                 m_pActiveShell->SplitNode(); // Empty document
1006                 m_pActiveShell->Up( false );
1007             }
1008             m_pActiveShell->GetView().GetEditWin().GrabFocus();
1009         }
1010         break;
1011         case CTX_UPDATE:
1012             pCont = nullptr;
1013         break;
1014         default:;
1015         // here nothing happens
1016     }
1017     if(pCont)
1018         GotoContent(pCont);
1019     if(nSlot)
1020         rDispatch.Execute(nSlot);
1021     if (Update(bUpdateHard))
1022         Display();
1023 }
1024 
IMPL_LINK_NOARG(SwGlobalTree,Timeout,Timer *,void)1025 IMPL_LINK_NOARG(SwGlobalTree, Timeout, Timer *, void)
1026 {
1027     if(!IsDisposed() && !HasFocus() && Update( false ))
1028         Display();
1029 }
1030 
GotoContent(const SwGlblDocContent * pCont)1031 void SwGlobalTree::GotoContent(const SwGlblDocContent* pCont)
1032 {
1033     m_pActiveShell->EnterStdMode();
1034 
1035     switch( pCont->GetType()  )
1036     {
1037         case GLBLDOC_UNKNOWN:
1038             m_pActiveShell->GotoGlobalDocContent(*pCont);
1039         break;
1040         case GLBLDOC_TOXBASE:
1041         {
1042             const OUString sName = pCont->GetTOX()->GetTOXName();
1043             if (!m_pActiveShell->GotoNextTOXBase(&sName))
1044                 m_pActiveShell->GotoPrevTOXBase(&sName);
1045         }
1046         break;
1047         case GLBLDOC_SECTION:
1048         break;
1049     }
1050 
1051 }
1052 
ShowTree()1053 void    SwGlobalTree::ShowTree()
1054 {
1055     m_aUpdateTimer.Start();
1056     SvTreeListBox::Show();
1057 }
1058 
HideTree()1059 void    SwGlobalTree::HideTree()
1060 {
1061     m_aUpdateTimer.Stop();
1062     SvTreeListBox::Hide();
1063 }
1064 
ExecCommand(const OUString & rCmd)1065 void    SwGlobalTree::ExecCommand(const OUString &rCmd)
1066 {
1067     SvTreeListEntry* pEntry = FirstSelected();
1068     OSL_ENSURE(pEntry, "It explodes in the next moment");
1069     if (rCmd == "edit")
1070     {
1071         const SwGlblDocContent* pCont = static_cast<const SwGlblDocContent*>(
1072                                                 pEntry->GetUserData());
1073         EditContent(pCont);
1074     }
1075     else
1076     {
1077         if(GetSelectionCount() == 1)
1078         {
1079             bool bMove = false;
1080             sal_uLong nSource = GetModel()->GetAbsPos(pEntry);
1081             sal_uLong nDest = nSource;
1082             if (rCmd == "down")
1083             {
1084                 sal_uLong nEntryCount = GetEntryCount();
1085                 bMove = nEntryCount > nSource + 1;
1086                 nDest+= 2;
1087             }
1088             else if (rCmd == "up")
1089             {
1090                 bMove = 0 != nSource;
1091                 nDest--;
1092             }
1093             if( bMove && m_pActiveShell->MoveGlobalDocContent(
1094                 *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) &&
1095                     Update( false ))
1096                 Display();
1097         }
1098     }
1099 }
1100 
Update(bool bHard)1101 bool    SwGlobalTree::Update(bool bHard)
1102 {
1103     SwView* pActView = GetParentWindow()->GetCreateView();
1104     bool bRet = false;
1105     if (pActView && pActView->GetWrtShellPtr())
1106     {
1107         const SwWrtShell* pOldShell = m_pActiveShell;
1108         m_pActiveShell = pActView->GetWrtShellPtr();
1109         if(m_pActiveShell != pOldShell)
1110         {
1111             m_pSwGlblDocContents.reset();
1112         }
1113         if(!m_pSwGlblDocContents)
1114         {
1115             m_pSwGlblDocContents.reset(new SwGlblDocContents);
1116             bRet = true;
1117             m_pActiveShell->GetGlobalDocContent(*m_pSwGlblDocContents);
1118         }
1119         else
1120         {
1121             bool bCopy = false;
1122             std::unique_ptr<SwGlblDocContents> pTempContents(new SwGlblDocContents);
1123             m_pActiveShell->GetGlobalDocContent(*pTempContents);
1124             if(pTempContents->size() != m_pSwGlblDocContents->size() ||
1125                     pTempContents->size() != GetEntryCount())
1126             {
1127                 bRet = true;
1128                 bCopy = true;
1129             }
1130             else
1131             {
1132                 for(size_t i = 0; i < pTempContents->size() && !bCopy; i++)
1133                 {
1134                     SwGlblDocContent* pLeft = (*pTempContents)[i].get();
1135                     SwGlblDocContent* pRight = (*m_pSwGlblDocContents)[i].get();
1136                     GlobalDocContentType eType = pLeft->GetType();
1137                     SvTreeListEntry* pEntry = GetEntry(i);
1138                     OUString sTemp = GetEntryText(pEntry);
1139                     if (
1140                          eType != pRight->GetType() ||
1141                          (
1142                            eType == GLBLDOC_SECTION &&
1143                            pLeft->GetSection()->GetSectionName() != sTemp
1144                          ) ||
1145                          (
1146                            eType == GLBLDOC_TOXBASE &&
1147                            pLeft->GetTOX()->GetTitle() != sTemp
1148                          )
1149                        )
1150                     {
1151                         bCopy = bRet = true;
1152                     }
1153                 }
1154             }
1155             if(bCopy || bHard)
1156             {
1157                 *m_pSwGlblDocContents = std::move( *pTempContents );
1158             }
1159         }
1160     }
1161     else
1162     {
1163         Clear();
1164         if(m_pSwGlblDocContents)
1165             m_pSwGlblDocContents->clear();
1166     }
1167     // FIXME: Implement a test for changes!
1168     return bRet;
1169 }
1170 
OpenDoc(const SwGlblDocContent * pCont)1171 void SwGlobalTree::OpenDoc(const SwGlblDocContent* pCont)
1172 {
1173     const OUString sFileName(pCont->GetSection()->GetLinkFileName().getToken(0,
1174             sfx2::cTokenSeparator));
1175     bool bFound = false;
1176     const SfxObjectShell* pCurr = SfxObjectShell::GetFirst();
1177     while( !bFound && pCurr )
1178     {
1179         if(pCurr->GetMedium() &&
1180            pCurr->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri) == sFileName)
1181         {
1182             bFound = true;
1183             SwGlobalTree::SetShowShell(pCurr);
1184             Application::PostUserEvent( LINK( this, SwGlobalTree, ShowFrameHdl ), nullptr, true );
1185             pCurr = nullptr;
1186         }
1187         else
1188             pCurr = SfxObjectShell::GetNext(*pCurr);
1189     }
1190     if(!bFound)
1191     {
1192         SfxStringItem aURL(SID_FILE_NAME, sFileName);
1193         SfxBoolItem aReadOnly(SID_DOC_READONLY, false);
1194         SfxStringItem aTargetFrameName( SID_TARGETNAME, "_blank" );
1195         SfxStringItem aReferer(SID_REFERER, m_pActiveShell->GetView().GetDocShell()->GetTitle());
1196         m_pActiveShell->GetView().GetViewFrame()->GetDispatcher()->
1197                 ExecuteList(SID_OPENDOC, SfxCallMode::ASYNCHRON,
1198                         { &aURL, &aReadOnly, &aReferer, &aTargetFrameName });
1199     }
1200 }
1201 
IMPL_LINK_NOARG(SwGlobalTree,DoubleClickHdl,SvTreeListBox *,bool)1202 IMPL_LINK_NOARG( SwGlobalTree, DoubleClickHdl, SvTreeListBox*, bool)
1203 {
1204     SvTreeListEntry* pEntry = GetCurEntry();
1205     SwGlblDocContent* pCont = static_cast<SwGlblDocContent*>(pEntry->GetUserData());
1206     if(pCont->GetType() == GLBLDOC_SECTION)
1207         OpenDoc(pCont);
1208     else
1209     {
1210         GotoContent(pCont);
1211         m_pActiveShell->GetView().GetEditWin().GrabFocus();
1212     }
1213     return false;
1214 }
1215 
GetParentWindow()1216 SwNavigationPI* SwGlobalTree::GetParentWindow()
1217 {
1218     return m_xDialog;
1219 }
1220 
IMPL_STATIC_LINK_NOARG(SwGlobalTree,ShowFrameHdl,void *,void)1221 IMPL_STATIC_LINK_NOARG(SwGlobalTree, ShowFrameHdl, void*, void)
1222 {
1223     SfxViewFrame* pFirst = pShowShell ? SfxViewFrame::GetFirst(pShowShell) : nullptr;
1224     if (pFirst)
1225         pFirst->ToTop();
1226     SwGlobalTree::SetShowShell(nullptr);
1227 }
1228 
InitEntry(SvTreeListEntry * pEntry,const OUString & rStr,const Image & rImg1,const Image & rImg2)1229 void SwGlobalTree::InitEntry(SvTreeListEntry* pEntry,
1230         const OUString& rStr ,const Image& rImg1,const Image& rImg2)
1231 {
1232     const size_t nColToHilite = 1; //0==Bitmap;1=="Column1";2=="Column2"
1233     SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2 );
1234     SvLBoxString& rCol = static_cast<SvLBoxString&>(pEntry->GetItem( nColToHilite ));
1235     pEntry->ReplaceItem(std::make_unique<SwLBoxString>(rCol.GetText()), nColToHilite);
1236 }
1237 
Paint(const Point & rPos,SvTreeListBox & rDev,vcl::RenderContext & rRenderContext,const SvViewDataEntry * pView,const SvTreeListEntry & rEntry)1238 void SwLBoxString::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
1239                          const SvViewDataEntry* pView, const SvTreeListEntry& rEntry)
1240 {
1241     SwGlblDocContent* pCont = static_cast<SwGlblDocContent*>(rEntry.GetUserData());
1242     if (pCont->GetType() == GLBLDOC_SECTION &&
1243       !pCont->GetSection()->IsConnectFlag())
1244     {
1245         rRenderContext.Push(PushFlags::FONT);
1246         vcl::Font aOldFont(rRenderContext.GetFont());
1247         vcl::Font aFont(rRenderContext.GetFont());
1248         aFont.SetColor(COL_LIGHTRED);
1249         rRenderContext.SetFont(aFont);
1250         rRenderContext.DrawText(rPos, GetText());
1251         rRenderContext.Pop();
1252     }
1253     else
1254         SvLBoxString::Paint(rPos, rDev, rRenderContext, pView, rEntry);
1255 }
1256 
DataChanged(const DataChangedEvent & rDCEvt)1257 void    SwGlobalTree::DataChanged( const DataChangedEvent& rDCEvt )
1258 {
1259     if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
1260          (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1261     {
1262         Update(true);
1263     }
1264     SvTreeListBox::DataChanged( rDCEvt );
1265 }
1266 
InsertRegion(const SwGlblDocContent * _pContent,const Sequence<OUString> & _rFiles)1267 void SwGlobalTree::InsertRegion( const SwGlblDocContent* _pContent, const Sequence< OUString >& _rFiles )
1268 {
1269     sal_Int32 nFiles = _rFiles.getLength();
1270     if ( !nFiles )
1271         return;
1272 
1273     bool bMove = false;
1274     if ( !_pContent )
1275     {
1276         SvTreeListEntry* pLast = LastVisible();
1277         _pContent = static_cast<SwGlblDocContent*>(pLast->GetUserData());
1278         bMove = true;
1279     }
1280     sal_uLong nEntryCount = GetEntryCount();
1281     const OUString* pFileNames = _rFiles.getConstArray();
1282     SwWrtShell& rSh = GetParentWindow()->GetCreateView()->GetWrtShell();
1283     rSh.StartAction();
1284     // after insertion of the first new content the 'pCont' parameter becomes invalid
1285     // find the index of the 'anchor' content to always use a current anchor content
1286     size_t nAnchorContent = m_pSwGlblDocContents->size() - 1;
1287     if ( !bMove )
1288     {
1289         for (size_t nContent = 0; nContent < m_pSwGlblDocContents->size();
1290                 ++nContent)
1291         {
1292             if( *_pContent == *(*m_pSwGlblDocContents)[ nContent ] )
1293             {
1294                 nAnchorContent = nContent;
1295                 break;
1296             }
1297         }
1298     }
1299     SwGlblDocContents aTempContents;
1300     for ( sal_Int32 nFile = 0; nFile < nFiles; ++nFile )
1301     {
1302         //update the global document content after each inserted document
1303         rSh.GetGlobalDocContent(aTempContents);
1304         SwGlblDocContent* pAnchorContent = nullptr;
1305         OSL_ENSURE(aTempContents.size() > (nAnchorContent + nFile), "invalid anchor content -> last insertion failed");
1306         if ( aTempContents.size() > (nAnchorContent + nFile) )
1307             pAnchorContent = aTempContents[nAnchorContent + nFile].get();
1308         else
1309             pAnchorContent = aTempContents.back().get();
1310         OUString sFileName(pFileNames[nFile]);
1311         INetURLObject aFileUrl;
1312         aFileUrl.SetSmartURL( sFileName );
1313         OUString sSectionName(aFileUrl.GetLastName(
1314             INetURLObject::DecodeMechanism::Unambiguous).getToken(0, sfx2::cTokenSeparator));
1315         sal_uInt16 nSectCount = rSh.GetSectionFormatCount();
1316         OUString sTempSectionName(sSectionName);
1317         sal_uInt16 nAddNumber = 0;
1318         sal_uInt16 nCount = 0;
1319         // if applicable: add index if the range name is already in use.
1320         while ( nCount < nSectCount )
1321         {
1322             const SwSectionFormat& rFormat = rSh.GetSectionFormat(nCount);
1323             if ((rFormat.GetSection()->GetSectionName() == sTempSectionName)
1324                 && rFormat.IsInNodesArr())
1325             {
1326                 nCount = 0;
1327                 nAddNumber++;
1328                 sTempSectionName = sSectionName + ":" + OUString::number( nAddNumber );
1329             }
1330             else
1331                 nCount++;
1332         }
1333 
1334         if ( nAddNumber )
1335             sSectionName = sTempSectionName;
1336 
1337         SwSectionData aSectionData(CONTENT_SECTION, sSectionName);
1338         aSectionData.SetProtectFlag(true);
1339         aSectionData.SetHidden(false);
1340 
1341         aSectionData.SetLinkFileName(sFileName);
1342         aSectionData.SetType(FILE_LINK_SECTION);
1343         aSectionData.SetLinkFilePassword( OUString() );
1344 
1345         rSh.InsertGlobalDocContent( *pAnchorContent, aSectionData );
1346     }
1347     if ( bMove )
1348     {
1349         Update( false );
1350         rSh.MoveGlobalDocContent(
1351             *m_pSwGlblDocContents, nEntryCount, nEntryCount + nFiles, nEntryCount - nFiles );
1352     }
1353     rSh.EndAction();
1354     Update( false );
1355     Display();
1356 
1357 }
1358 
IMPL_LINK(SwGlobalTree,DialogClosedHdl,sfx2::FileDialogHelper *,_pFileDlg,void)1359 IMPL_LINK( SwGlobalTree, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
1360 {
1361     if ( ERRCODE_NONE != _pFileDlg->GetError() )
1362         return;
1363 
1364     SfxMediumList aMedList(m_pDocInserter->CreateMediumList());
1365     if ( !aMedList.empty() )
1366     {
1367         Sequence< OUString >aFileNames( aMedList.size() );
1368         OUString* pFileNames = aFileNames.getArray();
1369         sal_Int32 nPos = 0;
1370         for (const std::unique_ptr<SfxMedium>& pMed : aMedList)
1371         {
1372             OUString sFileName = pMed->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::NONE )
1373                 + OUStringChar(sfx2::cTokenSeparator)
1374                 + pMed->GetFilter()->GetFilterName()
1375                 + OUStringChar(sfx2::cTokenSeparator);
1376             pFileNames[nPos++] = sFileName;
1377         }
1378         InsertRegion( m_pDocContent.get(), aFileNames );
1379         m_pDocContent.reset();
1380     }
1381 }
1382 
1383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1384