diff options
Diffstat (limited to 'sw/source/uibase/utlui/glbltree.cxx')
-rw-r--r-- | sw/source/uibase/utlui/glbltree.cxx | 1185 |
1 files changed, 1185 insertions, 0 deletions
diff --git a/sw/source/uibase/utlui/glbltree.cxx b/sw/source/uibase/utlui/glbltree.cxx new file mode 100644 index 0000000000..4ddf32dd02 --- /dev/null +++ b/sw/source/uibase/utlui/glbltree.cxx @@ -0,0 +1,1185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <o3tl/safeint.hxx> +#include <svl/stritem.hxx> +#include <sfx2/fcontnr.hxx> +#include <sfx2/linkmgr.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/docfilt.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <sot/filelist.hxx> +#include <svl/eitem.hxx> +#include <vcl/graphicfilter.hxx> +#include <osl/diagnose.h> + +#include <sfx2/docinsert.hxx> +#include <sfx2/filedlghelper.hxx> + +#include <wrtsh.hxx> +#include <view.hxx> +#include <docsh.hxx> +#include <edglbldc.hxx> +#include <section.hxx> +#include <tox.hxx> +#include <navipi.hxx> +#include <edtwin.hxx> +#include <toxmgr.hxx> + +#include <cmdid.h> +#include <helpids.h> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <swabstdlg.hxx> +#include <memory> + +#include <sfx2/event.hxx> +#include <unotxvw.hxx> + +using namespace ::com::sun::star::uno; + +#define GLOBAL_UPDATE_TIMEOUT 2000 + +const SfxObjectShell* SwGlobalTree::s_pShowShell = nullptr; + +namespace { + +class SwGlobalFrameListener_Impl : public SfxListener +{ + bool m_bValid; +public: + explicit SwGlobalFrameListener_Impl(SfxViewFrame& rFrame) + : m_bValid(true) + { + StartListening(rFrame); + } + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; + + bool IsValid() const {return m_bValid;} +}; + +} + +void SwGlobalFrameListener_Impl::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + if( rHint.GetId() == SfxHintId::Dying) + m_bValid = false; +} + +namespace { + +enum GLOBAL_CONTEXT_IDX +{ + IDX_STR_UPDATE = 0, + IDX_STR_EDIT_CONTENT = 1, + IDX_STR_EDIT_INSERT = 2, + IDX_STR_INDEX = 3, + IDX_STR_FILE = 4, + IDX_STR_NEW_FILE = 5, + IDX_STR_INSERT_TEXT = 6, + IDX_STR_DELETE = 7, + IDX_STR_UPDATE_SEL = 8, + IDX_STR_UPDATE_INDEX = 9, + IDX_STR_UPDATE_LINK = 10, + IDX_STR_UPDATE_ALL = 11, + IDX_STR_BROKEN_LINK = 12, + IDX_STR_EDIT_LINK = 13 +}; + +} + +const TranslateId GLOBAL_CONTEXT_ARY[] = +{ + STR_UPDATE, + STR_EDIT_CONTENT, + STR_EDIT_INSERT, + STR_INDEX, + STR_FILE, + STR_NEW_FILE, + STR_INSERT_TEXT, + STR_DELETE, + STR_UPDATE_SEL, + STR_UPDATE_INDEX, + STR_UPDATE_LINK, + STR_UPDATE_ALL, + STR_BROKEN_LINK, + STR_EDIT_LINK +}; + +SwGlobalTree::SwGlobalTree(std::unique_ptr<weld::TreeView> xTreeView, SwNavigationPI* pDialog) + : m_xTreeView(std::move(xTreeView)) + , m_aDropTargetHelper(*this) + , m_pDialog(pDialog) + , m_aUpdateTimer("SwGlobalTree m_aUpdateTimer") + , m_pActiveShell(nullptr) +{ + m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30, + m_xTreeView->get_text_height() * 14); + + m_aUpdateTimer.SetTimeout(GLOBAL_UPDATE_TIMEOUT); + m_aUpdateTimer.SetInvokeHandler(LINK(this, SwGlobalTree, Timeout)); + m_aUpdateTimer.Start(); + for (sal_uInt16 i = 0; i < GLOBAL_CONTEXT_COUNT; i++) + { + m_aContextStrings[i] = SwResId(GLOBAL_CONTEXT_ARY[i]); + } + m_xTreeView->set_help_id(HID_NAVIGATOR_GLOB_TREELIST); + Select(); + m_xTreeView->connect_row_activated(LINK(this, SwGlobalTree, DoubleClickHdl)); + m_xTreeView->connect_changed(LINK(this, SwGlobalTree, SelectHdl)); + m_xTreeView->connect_focus_in(LINK(this, SwGlobalTree, FocusInHdl)); + m_xTreeView->connect_key_press(LINK(this, SwGlobalTree, KeyInputHdl)); + m_xTreeView->connect_popup_menu(LINK(this, SwGlobalTree, CommandHdl)); + m_xTreeView->connect_query_tooltip(LINK(this, SwGlobalTree, QueryTooltipHdl)); +} + +SwGlobalTree::~SwGlobalTree() +{ + m_pSwGlblDocContents.reset(); + m_pDocInserter.reset(); + m_aUpdateTimer.Stop(); +} + +SwGlobalTreeDropTarget::SwGlobalTreeDropTarget(SwGlobalTree& rTreeView) + : DropTargetHelper(rTreeView.get_widget().get_drop_target()) + , m_rTreeView(rTreeView) +{ +} + +sal_Int8 SwGlobalTreeDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + sal_Int8 nRet = DND_ACTION_NONE; + + weld::TreeView& rWidget = m_rTreeView.get_widget(); + std::unique_ptr<weld::TreeIter> xDropEntry(rWidget.make_iterator()); + if (!rWidget.get_dest_row_at_pos(rEvt.maPosPixel, xDropEntry.get(), true)) + xDropEntry.reset(); + + if (rWidget.get_drag_source() == &rWidget) // internal drag + m_rTreeView.MoveSelectionTo(xDropEntry.get()); + else + { + TransferableDataHelper aData( rEvt.maDropEvent.Transferable ); + + OUString sFileName; + const SwGlblDocContent* pCnt = xDropEntry ? + weld::fromId<const SwGlblDocContent*>(rWidget.get_id(*xDropEntry)) : + nullptr; + if( aData.HasFormat( SotClipboardFormatId::FILE_LIST )) + { + nRet = rEvt.mnAction; + SwGlblDocContents aTempContents; + int nAbsContPos = xDropEntry ? + rWidget.get_iter_index_in_parent(*xDropEntry): + - 1; + size_t nEntryCount = rWidget.n_children(); + + // Get data + FileList aFileList; + aData.GetFileList( SotClipboardFormatId::FILE_LIST, aFileList ); + for ( size_t n = aFileList.Count(); n--; ) + { + sFileName = aFileList.GetFile(n); + m_rTreeView.InsertRegion(pCnt, &sFileName); + // The list of contents must be newly fetched after inserting, + // to not work on an old content. + if(n) + { + if (const SwWrtShell* pSh = m_rTreeView.GetActiveWrtShell()) + { + pSh->GetGlobalDocContent(aTempContents); + // If the file was successfully inserted, + // then the next content must also be fetched. + if(nEntryCount < aTempContents.size()) + { + nEntryCount++; + nAbsContPos++; + pCnt = aTempContents[ nAbsContPos ].get(); + } + } + } + } + } + else if( !(sFileName = + SwNavigationPI::CreateDropFileName( aData )).isEmpty()) + { + INetURLObject aTemp(sFileName); + GraphicDescriptor aDesc(aTemp); + if( !aDesc.Detect() ) // accept no graphics + { + nRet = rEvt.mnAction; + m_rTreeView.InsertRegion(pCnt, &sFileName); + } + } + } + return nRet; +} + +sal_Int8 SwGlobalTreeDropTarget::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + // to enable the autoscroll when we're close to the edges + weld::TreeView& rWidget = m_rTreeView.get_widget(); + rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true); + + sal_Int8 nRet = rEvt.mnAction; + + if (rWidget.get_drag_source() == &rWidget) // internal drag + return nRet; + + if (IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE) || + IsDropFormatSupported( SotClipboardFormatId::STRING) || + IsDropFormatSupported( SotClipboardFormatId::FILE_LIST) || + IsDropFormatSupported( SotClipboardFormatId::SOLK) || + IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK )|| + IsDropFormatSupported( SotClipboardFormatId::FILECONTENT) || + IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR) || + IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR) || + IsDropFormatSupported( SotClipboardFormatId::FILENAME)) + { + nRet = DND_ACTION_LINK; + } + + return nRet; +} + +IMPL_LINK(SwGlobalTree, CommandHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu) + return false; + + bool bPop = false; + if (m_pActiveShell && !m_pActiveShell->GetView().GetDocShell()->IsReadOnly()) + { + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/swriter/ui/mastercontextmenu.ui")); + std::unique_ptr<weld::Menu> xPopup = xBuilder->weld_menu("navmenu"); + std::unique_ptr<weld::Menu> xSubPopup = xBuilder->weld_menu("insertmenu"); + + const MenuEnableFlags nEnableFlags = GetEnableFlags(); + + xPopup->set_sensitive("updatesel", bool(nEnableFlags & MenuEnableFlags::UpdateSel)); + + xPopup->set_sensitive("editlink", bool(nEnableFlags & MenuEnableFlags::EditLink)); + + //disabling if applicable + xSubPopup->set_sensitive("insertindex", bool(nEnableFlags & MenuEnableFlags::InsertIdx )); + xSubPopup->set_sensitive("insertfile", bool(nEnableFlags & MenuEnableFlags::InsertFile)); + xSubPopup->set_sensitive("insertnewfile", bool(nEnableFlags & MenuEnableFlags::InsertFile)); + xSubPopup->set_sensitive("inserttext", bool(nEnableFlags & MenuEnableFlags::InsertText)); + + xPopup->set_sensitive("update", bool(nEnableFlags & MenuEnableFlags::Update)); + xPopup->set_sensitive("insert", bool(nEnableFlags & MenuEnableFlags::InsertIdx)); + xPopup->set_sensitive("editcontent", bool(nEnableFlags & MenuEnableFlags::Edit)); + xPopup->set_sensitive("deleteentry", bool(nEnableFlags & MenuEnableFlags::Delete)); + + OUString sCommand = xPopup->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))); + if (!sCommand.isEmpty()) + ExecuteContextMenuAction(sCommand); + + bPop = true; + } + return bPop; +} + +void SwGlobalTree::TbxMenuHdl(std::u16string_view rCommand, weld::Menu& rMenu) +{ + const MenuEnableFlags nEnableFlags = GetEnableFlags(); + if (rCommand == u"insert") + { + rMenu.set_sensitive("insertindex", bool(nEnableFlags & MenuEnableFlags::InsertIdx)); + rMenu.set_sensitive("insertfile", bool(nEnableFlags & MenuEnableFlags::InsertFile)); + rMenu.set_sensitive("insertnewfile", bool(nEnableFlags & MenuEnableFlags::InsertFile)); + rMenu.set_sensitive("inserttext", bool(nEnableFlags & MenuEnableFlags::InsertText)); + } + else if (rCommand == u"update") + { + rMenu.set_sensitive("updatesel", bool(nEnableFlags & MenuEnableFlags::UpdateSel)); + } +} + +MenuEnableFlags SwGlobalTree::GetEnableFlags() const +{ + std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator()); + bool bEntry = m_xTreeView->get_selected(xEntry.get()); + + int nSelCount = m_xTreeView->count_selected_rows(); + size_t nEntryCount = m_xTreeView->n_children(); + std::unique_ptr<weld::TreeIter> xPrevEntry; + bool bPrevEntry = false; + if (bEntry) + { + xPrevEntry = m_xTreeView->make_iterator(xEntry.get()); + bPrevEntry = m_xTreeView->iter_previous(*xPrevEntry); + } + + MenuEnableFlags nRet = MenuEnableFlags::NONE; + if(nSelCount == 1 || !nEntryCount) + nRet |= MenuEnableFlags::InsertIdx|MenuEnableFlags::InsertFile; + if(nSelCount == 1) + { + nRet |= MenuEnableFlags::Edit; + if (bEntry && weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry))->GetType() != GLBLDOC_UNKNOWN && + (!bPrevEntry || weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xPrevEntry))->GetType() != GLBLDOC_UNKNOWN)) + nRet |= MenuEnableFlags::InsertText; + if (bEntry && GLBLDOC_SECTION == weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(*xEntry))->GetType()) + nRet |= MenuEnableFlags::EditLink; + } + else if(!nEntryCount) + { + nRet |= MenuEnableFlags::InsertText; + } + if(nEntryCount) + nRet |= MenuEnableFlags::Update|MenuEnableFlags::Delete; + if(nSelCount) + nRet |= MenuEnableFlags::UpdateSel; + return nRet; +} + +IMPL_LINK(SwGlobalTree, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sEntry; + + const SwGlblDocContent* pCont = weld::fromId<const SwGlblDocContent*>(m_xTreeView->get_id(rIter)); + if (pCont && GLBLDOC_SECTION == pCont->GetType()) + { + const SwSection* pSect = pCont->GetSection(); + sEntry = pSect->GetLinkFileName().getToken(0, sfx2::cTokenSeparator); + if (!pSect->IsConnectFlag()) + sEntry = m_aContextStrings[IDX_STR_BROKEN_LINK] + sEntry; + } + + return sEntry; +} + +IMPL_LINK_NOARG(SwGlobalTree, SelectHdl, weld::TreeView&, void) +{ + Select(); +} + +void SwGlobalTree::Select() +{ + int nSelCount = m_xTreeView->count_selected_rows(); + int nSel = m_xTreeView->get_selected_index(); + int nAbsPos = nSel != -1 ? nSel : 0; + SwNavigationPI* pNavi = GetParentWindow(); + bool bReadonly = !m_pActiveShell || + m_pActiveShell->GetView().GetDocShell()->IsReadOnly(); + pNavi->m_xGlobalToolBox->set_item_sensitive("edit", nSelCount == 1 && !bReadonly); + pNavi->m_xGlobalToolBox->set_item_sensitive("insert", nSelCount <= 1 && !bReadonly); + pNavi->m_xGlobalToolBox->set_item_sensitive("update", m_xTreeView->n_children() > 0 && !bReadonly); + pNavi->m_xGlobalToolBox->set_item_sensitive("moveup", + nSelCount == 1 && nAbsPos && !bReadonly); + pNavi->m_xGlobalToolBox->set_item_sensitive("movedown", + nSelCount == 1 && nAbsPos < m_xTreeView->n_children() - 1 && !bReadonly); + +} + +void SwGlobalTree::MoveSelectionTo(const weld::TreeIter* pDropEntry) +{ + int nSource = m_xTreeView->get_selected_index(); + + int nDest = pDropEntry ? m_xTreeView->get_iter_index_in_parent(*pDropEntry) + : m_pSwGlblDocContents->size(); + + if (m_pActiveShell->MoveGlobalDocContent( + *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) && + Update( false )) + Display(); +} + +IMPL_LINK_NOARG(SwGlobalTree, FocusInHdl, weld::Widget&, void) +{ + if (Update(false)) + Display(); +} + +IMPL_LINK(SwGlobalTree, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + const vcl::KeyCode aCode = rKEvt.GetKeyCode(); + if (aCode.GetCode() == KEY_RETURN) + { + switch (aCode.GetModifier()) + { + case KEY_MOD2: + // Switch boxes + GetParentWindow()->ToggleTree(); + bHandled = true; + break; + } + } + return bHandled; +} + +void SwGlobalTree::Display(bool bOnlyUpdateUserData) +{ + size_t nCount = m_pSwGlblDocContents->size(); + size_t nChildren = m_xTreeView->n_children(); + if (bOnlyUpdateUserData && nChildren == m_pSwGlblDocContents->size()) + { + std::unique_ptr<weld::TreeIter> xEntry = m_xTreeView->make_iterator(); + bool bEntry = m_xTreeView->get_iter_first(*xEntry); + for (size_t i = 0; i < nCount && bEntry; i++) + { + const SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get(); + OUString sId(weld::toId(pCont)); + m_xTreeView->set_id(*xEntry, sId); + if (pCont->GetType() == GLBLDOC_SECTION && !pCont->GetSection()->IsConnectFlag()) + m_xTreeView->set_font_color(*xEntry, COL_LIGHTRED); + else + m_xTreeView->set_font_color(*xEntry, COL_AUTO); + bEntry = m_xTreeView->iter_next(*xEntry); + assert(bEntry || i == nCount - 1); + } + } + else + { + int nOldSelEntry = m_xTreeView->get_selected_index(); + OUString sEntryName; // Name of the entry + int nSelPos = -1; + if (nOldSelEntry != -1) + { + sEntryName = m_xTreeView->get_text(nOldSelEntry); + nSelPos = nOldSelEntry; + } + m_xTreeView->freeze(); + m_xTreeView->clear(); + + int nSelEntry = -1; + for (size_t i = 0; i < nCount; ++i) + { + const SwGlblDocContent* pCont = (*m_pSwGlblDocContents)[i].get(); + + OUString sId(weld::toId(pCont)); + OUString sEntry; + OUString aImage; + switch (pCont->GetType()) + { + case GLBLDOC_UNKNOWN: + sEntry = m_aContextStrings[IDX_STR_INSERT_TEXT]; + break; + case GLBLDOC_TOXBASE: + { + const SwTOXBase* pBase = pCont->GetTOX(); + sEntry = pBase->GetTitle(); + aImage = RID_BMP_NAVI_INDEX; + } + break; + case GLBLDOC_SECTION: + { + const SwSection* pSect = pCont->GetSection(); + sEntry = pSect->GetSectionName(); + aImage = RID_BMP_DROP_REGION; + } + break; + } + + m_xTreeView->append(sId, sEntry); + if (!aImage.isEmpty()) + m_xTreeView->set_image(i, aImage); + + if (pCont->GetType() == GLBLDOC_SECTION && !pCont->GetSection()->IsConnectFlag()) + m_xTreeView->set_font_color(i, COL_LIGHTRED); + + if (sEntry == sEntryName) + nSelEntry = i; + } + m_xTreeView->thaw(); + if (nSelEntry != -1) + m_xTreeView->select(nSelEntry); + else if (nSelPos != -1 && o3tl::make_unsigned(nSelPos) < nCount) + m_xTreeView->select(nSelPos); + else if (nCount) + m_xTreeView->select(0); + Select(); + } +} + +void SwGlobalTree::InsertRegion( const SwGlblDocContent* pCont, const OUString* pFileName ) +{ + Sequence< OUString > aFileNames; + if ( !pFileName ) + { + SwNavigationPI* pNavi = GetParentWindow(); + m_pDocInserter.reset(new ::sfx2::DocumentInserter(pNavi->GetFrameWeld(), "swriter", sfx2::DocumentInserter::Mode::InsertMulti)); + m_pDocInserter->StartExecuteModal( LINK( this, SwGlobalTree, DialogClosedHdl ) ); + } + else if ( !pFileName->isEmpty() ) + { + aFileNames.realloc(1); + INetURLObject aFileName; + aFileName.SetSmartURL( *pFileName ); + // tdf#127978 - don't URL encode filename for navigator's tooltip + aFileNames.getArray()[0] + = aFileName.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous); + InsertRegion( pCont, aFileNames ); + } +} + +void SwGlobalTree::EditContent(const SwGlblDocContent* pCont ) +{ + sal_uInt16 nSlot = 0; + switch( pCont->GetType() ) + { + case GLBLDOC_UNKNOWN: + m_pActiveShell->GetView().GetEditWin().GrabFocus(); + break; + case GLBLDOC_TOXBASE: + { + const SwTOXBase* pBase = pCont->GetTOX(); + if(pBase) + nSlot = FN_INSERT_MULTI_TOX; + } + break; + case GLBLDOC_SECTION: + { + OpenDoc(pCont); + + nSlot = 0; + pCont = nullptr; + } + break; + } + if(pCont) + GotoContent(pCont); + if(nSlot) + { + m_pActiveShell->GetView().GetViewFrame().GetDispatcher()->Execute(nSlot); + if(Update( false )) + Display(); + } +} + +void SwGlobalTree::ExecuteContextMenuAction(std::u16string_view rSelectedPopupEntry) +{ + bool bUpdateHard = false; + + int nEntry = m_xTreeView->get_selected_index(); + SwGlblDocContent* pCont = nEntry != -1 ? weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry)) : nullptr; + // If a RequestHelp is called during the dialogue, + // then the content gets lost. Because of that a copy + // is created in which only the DocPos is set correctly. + std::optional<SwGlblDocContent> oContCopy; + if(pCont) + oContCopy.emplace(pCont->GetDocPos()); + SfxDispatcher& rDispatch = *m_pActiveShell->GetView().GetViewFrame().GetDispatcher(); + sal_uInt16 nSlot = 0; + if (rSelectedPopupEntry == u"updatesel") + { + // Two passes: first update the areas, then the directories. + m_xTreeView->selected_foreach([this](weld::TreeIter& rSelEntry){ + SwGlblDocContent* pContent = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry)); + if (GLBLDOC_SECTION == pContent->GetType() && + pContent->GetSection()->IsConnected()) + { + const_cast<SwSection*>(pContent->GetSection())->UpdateNow(); + } + return false; + }); + m_xTreeView->selected_foreach([this](weld::TreeIter& rSelEntry){ + SwGlblDocContent* pContent = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(rSelEntry)); + if (GLBLDOC_TOXBASE == pContent->GetType()) + m_pActiveShell->UpdateTableOf(*pContent->GetTOX()); + return false; + }); + + bUpdateHard = true; + } + else if (rSelectedPopupEntry == u"updateindex") + { + nSlot = FN_UPDATE_TOX; + bUpdateHard = true; + } + else if (rSelectedPopupEntry == u"updatelinks" || rSelectedPopupEntry == u"updateall") + { + m_pActiveShell->GetLinkManager().UpdateAllLinks(true, false, nullptr); + if (rSelectedPopupEntry == u"updateall") + nSlot = FN_UPDATE_TOX; + pCont = nullptr; + bUpdateHard = true; + } + else if (rSelectedPopupEntry == u"editcontent") + { + OSL_ENSURE(pCont, "edit without entry ? " ); + if (pCont) + { + EditContent(pCont); + } + } + else if (rSelectedPopupEntry == u"editlink") + { + OSL_ENSURE(pCont, "edit without entry ? " ); + if (pCont) + { + SfxStringItem aName(FN_EDIT_REGION, + pCont->GetSection()->GetSectionName()); + rDispatch.ExecuteList(FN_EDIT_REGION, SfxCallMode::ASYNCHRON, + { &aName }); + } + } + else if (rSelectedPopupEntry == u"deleteentry") + { + // If several entries selected, then after each delete the array + // must be refilled. So you do not have to remember anything, + // deleting begins at the end. + std::vector<int> aRows = m_xTreeView->get_selected_rows(); + std::sort(aRows.begin(), aRows.end()); + + std::unique_ptr<SwGlblDocContents> pTempContents; + m_pActiveShell->StartAction(); + for (auto iter = aRows.rbegin(); iter != aRows.rend(); ++iter) + { + m_pActiveShell->DeleteGlobalDocContent( + pTempContents ? *pTempContents : *m_pSwGlblDocContents, + *iter); + pTempContents.reset(new SwGlblDocContents); + m_pActiveShell->GetGlobalDocContent(*pTempContents); + } + pTempContents.reset(); + m_pActiveShell->EndAction(); + pCont = nullptr; + } + else if (rSelectedPopupEntry == u"insertindex") + { + if(oContCopy) + { + SfxItemSetFixed< + RES_FRM_SIZE, RES_FRM_SIZE, + RES_LR_SPACE, RES_LR_SPACE, + RES_BACKGROUND, RES_BACKGROUND, + RES_COL, RES_COL, + SID_ATTR_PAGE_SIZE, SID_ATTR_PAGE_SIZE, + FN_PARAM_TOX_TYPE, FN_PARAM_TOX_TYPE> + aSet( m_pActiveShell->GetView().GetPool() ); + + SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create(); + ScopedVclPtr<AbstractMultiTOXTabDialog> pDlg(pFact->CreateMultiTOXTabDialog( + m_xTreeView.get(), aSet, + *m_pActiveShell, + nullptr, + true)); + if(RET_OK == pDlg->Execute()) + { + SwTOXDescription& rDesc = pDlg->GetTOXDescription( + pDlg->GetCurrentTOXType()); + SwTOXMgr aMgr(m_pActiveShell); + SwTOXBase* pToInsert = nullptr; + if(aMgr.UpdateOrInsertTOX(rDesc, &pToInsert, pDlg->GetOutputItemSet())) + m_pActiveShell->InsertGlobalDocContent( *oContCopy, *pToInsert ); + } + pCont = nullptr; + } + } + else if (rSelectedPopupEntry == u"insertfile") + { + m_oDocContent = std::move(oContCopy); + InsertRegion( &*m_oDocContent ); + pCont = nullptr; + } + else if (rSelectedPopupEntry == u"insertnewfile") + { + SfxViewFrame& rGlobFrame = m_pActiveShell->GetView().GetViewFrame(); + SwGlobalFrameListener_Impl aFrameListener(rGlobFrame); + + // Creating a new doc + SfxStringItem aFactory(SID_NEWDOCDIRECT, + SwDocShell::Factory().GetFilterContainer()->GetName()); + + SfxPoolItemHolder aResult( + rDispatch.ExecuteList(SID_NEWDOCDIRECT, + SfxCallMode::SYNCHRON, { &aFactory })); + const SfxFrameItem* pItem(static_cast<const SfxFrameItem*>(aResult.getItem())); + + // save at + SfxFrame* pFrame = pItem ? pItem->GetFrame() : nullptr; + SfxViewFrame* pViewFrame = pFrame ? pFrame->GetCurrentViewFrame() : nullptr; + if (pViewFrame) + { + aResult = pViewFrame->GetDispatcher()->Execute( + SID_SAVEASDOC, SfxCallMode::SYNCHRON ); + const SfxBoolItem* pBool(static_cast<const SfxBoolItem*>(aResult.getItem())); + SfxObjectShell& rObj = *pViewFrame->GetObjectShell(); + const SfxMedium* pMedium = rObj.GetMedium(); + OUString sNewFile(pMedium->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri)); + // Insert the area with the Doc-Name + // Bring the own Doc in the foreground + if(aFrameListener.IsValid() && !sNewFile.isEmpty()) + { + rGlobFrame.ToTop(); + // Due to the update the entries are invalid + if (nEntry != -1) + { + Update( false ); + Display(); + m_xTreeView->select(nEntry); + Select(); + nEntry = m_xTreeView->get_selected_index(); + pCont = nEntry != -1 ? weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry)) : nullptr; + } + else + { + nEntry = -1; + pCont = nullptr; + } + if(pBool->GetValue()) + { + InsertRegion(pCont, &sNewFile); + pViewFrame->ToTop(); + } + else + pViewFrame->GetDispatcher()->Execute(SID_CLOSEWIN, SfxCallMode::SYNCHRON); + } + else + { + pViewFrame->ToTop(); + return; + } + } + } + else if (rSelectedPopupEntry == u"inserttext") + { + if (pCont) + m_pActiveShell->InsertGlobalDocContent(*pCont); + else + { + m_pActiveShell->SplitNode(); // Empty document + m_pActiveShell->Up( false ); + } + m_pActiveShell->GetView().GetEditWin().GrabFocus(); + } + else if (rSelectedPopupEntry == u"update") + pCont = nullptr; + + if (pCont) + GotoContent(pCont); + if (nSlot) + rDispatch.Execute(nSlot); + if (Update(bUpdateHard)) + Display(); +} + +IMPL_LINK_NOARG(SwGlobalTree, Timeout, Timer *, void) +{ + SwView* pView = GetParentWindow()->GetCreateView(); + if (pView && pView->GetEditWin().HasFocus()) + { + if (Update(false)) + Display(); + UpdateTracking(); + } +} + +// track GlobalDocContentType at the cursor position in the document +void SwGlobalTree::UpdateTracking() +{ + if (!m_pActiveShell) + return; + + m_xTreeView->unselect_all(); + + const SwSection* pActiveShellCurrSection = m_pActiveShell->GetCurrSection(); + if (pActiveShellCurrSection) + { + const SwSection* pSection = pActiveShellCurrSection; + while (SwSection* pParent = pSection->GetParent()) + pSection = pParent; + for (const std::unique_ptr<SwGlblDocContent>& rGlblDocContent : *m_pSwGlblDocContents) + { + if (rGlblDocContent->GetType() == GlobalDocContentType::GLBLDOC_UNKNOWN) + continue; + if ((pSection->GetType() == SectionType::ToxContent + && rGlblDocContent->GetTOX() == pSection->GetTOXBase()) + || (pSection->GetType() != SectionType::ToxContent + && rGlblDocContent->GetSection() == pSection)) + { + const OUString& rId(weld::toId(rGlblDocContent.get())); + m_xTreeView->select(m_xTreeView->find_id(rId)); + break; + } + } + } + else + { + const SwCursor* pCursor = m_pActiveShell->GetCursor(); + const SwNode& rNode = pCursor->GetPoint()->GetNode(); + if (rNode.IsTextNode()) + { + // only the first text node in each series of text nodes is stored in the + // SwGlblDocContents array + SwNodeIndex aIdx(rNode); + do + { + --aIdx; + } while (aIdx.GetNode().IsTextNode()); + ++aIdx; + SwNodeOffset aTextNodeIndex(aIdx.GetNode().GetIndex()); + for (const std::unique_ptr<SwGlblDocContent>& rGlblDocContent : *m_pSwGlblDocContents) + { + if (rGlblDocContent->GetType() == GlobalDocContentType::GLBLDOC_UNKNOWN + && rGlblDocContent->GetDocPos() == aTextNodeIndex) + { + const OUString& rId(weld::toId(rGlblDocContent.get())); + m_xTreeView->select(m_xTreeView->find_id(rId)); + } + } + } + } + + Select(); +} + +void SwGlobalTree::GotoContent(const SwGlblDocContent* pCont) +{ + m_pActiveShell->EnterStdMode(); + + switch( pCont->GetType() ) + { + case GLBLDOC_UNKNOWN: + m_pActiveShell->GotoGlobalDocContent(*pCont); + break; + case GLBLDOC_TOXBASE: + { + const OUString sName = pCont->GetTOX()->GetTOXName(); + if (!m_pActiveShell->GotoNextTOXBase(&sName)) + m_pActiveShell->GotoPrevTOXBase(&sName); + } + break; + case GLBLDOC_SECTION: + break; + } + +} + +void SwGlobalTree::ShowTree() +{ + m_aUpdateTimer.Start(); + m_xTreeView->show(); + UpdateTracking(); +} + +void SwGlobalTree::HideTree() +{ + m_aUpdateTimer.Stop(); + m_xTreeView->hide(); +} + +void SwGlobalTree::ExecCommand(std::u16string_view rCmd) +{ + int nEntry = m_xTreeView->get_selected_index(); + if (nEntry == -1) + return; + if (rCmd == u"edit") + { + const SwGlblDocContent* pCont = weld::fromId<const SwGlblDocContent*>( + m_xTreeView->get_id(nEntry)); + EditContent(pCont); + } + else + { + if (m_xTreeView->count_selected_rows() == 1) + { + bool bMove = false; + int nSource = nEntry; + int nDest = nSource; + if (rCmd == u"movedown") + { + int nEntryCount = m_xTreeView->n_children(); + bMove = nEntryCount > nSource + 1; + nDest+= 2; + } + else if (rCmd == u"moveup") + { + bMove = 0 != nSource; + nDest--; + } + if( bMove && m_pActiveShell->MoveGlobalDocContent( + *m_pSwGlblDocContents, nSource, nSource + 1, nDest ) && + Update( false )) + Display(); + } + } +} + +bool SwGlobalTree::Update(bool bHard) +{ + SwView* pActView = GetParentWindow()->GetCreateView(); + bool bRet = false; + if (pActView && pActView->GetWrtShellPtr()) + { + const SwWrtShell* pOldShell = m_pActiveShell; + m_pActiveShell = pActView->GetWrtShellPtr(); + if(m_pActiveShell != pOldShell) + { + m_pSwGlblDocContents.reset(); + if (!IsListening(*m_pActiveShell->GetView().GetDocShell())) + StartListening(*m_pActiveShell->GetView().GetDocShell()); + } + if(!m_pSwGlblDocContents) + { + m_pSwGlblDocContents.reset(new SwGlblDocContents); + bRet = true; + m_pActiveShell->GetGlobalDocContent(*m_pSwGlblDocContents); + } + else + { + bool bCopy = false; + SwGlblDocContents aTempContents; + m_pActiveShell->GetGlobalDocContent(aTempContents); + size_t nChildren = m_xTreeView->n_children(); + if (aTempContents.size() != m_pSwGlblDocContents->size() || + aTempContents.size() != nChildren) + { + bRet = true; + bCopy = true; + } + else + { + for(size_t i = 0; i < aTempContents.size() && !bCopy; i++) + { + SwGlblDocContent* pLeft = aTempContents[i].get(); + SwGlblDocContent* pRight = (*m_pSwGlblDocContents)[i].get(); + GlobalDocContentType eType = pLeft->GetType(); + OUString sTemp = m_xTreeView->get_text(i); + if ( + eType != pRight->GetType() || + ( + eType == GLBLDOC_SECTION && + pLeft->GetSection()->GetSectionName() != sTemp + ) || + ( + eType == GLBLDOC_TOXBASE && + pLeft->GetTOX()->GetTitle() != sTemp + ) + ) + { + bCopy = true; + } + } + } + if (bCopy || bHard) + { + *m_pSwGlblDocContents = std::move( aTempContents ); + bRet = true; + } + } + } + else + { + m_xTreeView->clear(); + if(m_pSwGlblDocContents) + m_pSwGlblDocContents->clear(); + } + // FIXME: Implement a test for changes! + return bRet; +} + +void SwGlobalTree::OpenDoc(const SwGlblDocContent* pCont) +{ + const OUString sFileName(pCont->GetSection()->GetLinkFileName().getToken(0, + sfx2::cTokenSeparator)); + bool bFound = false; + const SfxObjectShell* pCurr = SfxObjectShell::GetFirst(); + while( !bFound && pCurr ) + { + if(pCurr->GetMedium() && + pCurr->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri) == sFileName) + { + bFound = true; + SwGlobalTree::SetShowShell(pCurr); + Application::PostUserEvent(LINK(this, SwGlobalTree, ShowFrameHdl)); + pCurr = nullptr; + } + else + pCurr = SfxObjectShell::GetNext(*pCurr); + } + if(!bFound) + { + SfxStringItem aURL(SID_FILE_NAME, sFileName); + SfxBoolItem aReadOnly(SID_DOC_READONLY, false); + SfxStringItem aTargetFrameName( SID_TARGETNAME, "_blank" ); + SfxStringItem aReferer(SID_REFERER, m_pActiveShell->GetView().GetDocShell()->GetTitle()); + m_pActiveShell->GetView().GetViewFrame().GetDispatcher()-> + ExecuteList(SID_OPENDOC, SfxCallMode::ASYNCHRON, + { &aURL, &aReadOnly, &aReferer, &aTargetFrameName }); + } +} + +IMPL_LINK_NOARG( SwGlobalTree, DoubleClickHdl, weld::TreeView&, bool) +{ + int nEntry = m_xTreeView->get_cursor_index(); + SwGlblDocContent* pCont = weld::fromId<SwGlblDocContent*>(m_xTreeView->get_id(nEntry)); + if (pCont->GetType() == GLBLDOC_SECTION) + OpenDoc(pCont); + else + { + GotoContent(pCont); + m_pActiveShell->GetView().GetEditWin().GrabFocus(); + } + return false; +} + +SwNavigationPI* SwGlobalTree::GetParentWindow() +{ + return m_pDialog; +} + +IMPL_STATIC_LINK_NOARG(SwGlobalTree, ShowFrameHdl, void*, void) +{ + SfxViewFrame* pFirst = s_pShowShell ? SfxViewFrame::GetFirst(s_pShowShell) : nullptr; + if (pFirst) + pFirst->ToTop(); + SwGlobalTree::SetShowShell(nullptr); +} + +void SwGlobalTree::InsertRegion( const SwGlblDocContent* _pContent, const Sequence< OUString >& _rFiles ) +{ + sal_Int32 nFiles = _rFiles.getLength(); + if (!nFiles) + return; + + size_t nEntryCount = m_xTreeView->n_children(); + + bool bMove = _pContent == nullptr; + const OUString* pFileNames = _rFiles.getConstArray(); + SwWrtShell& rSh = GetParentWindow()->GetCreateView()->GetWrtShell(); + rSh.StartAction(); + // after insertion of the first new content the 'pCont' parameter becomes invalid + // find the index of the 'anchor' content to always use a current anchor content + size_t nAnchorContent = m_pSwGlblDocContents->size() - 1; + if (!bMove) + { + for (size_t nContent = 0; nContent < m_pSwGlblDocContents->size(); + ++nContent) + { + if( *_pContent == *(*m_pSwGlblDocContents)[ nContent ] ) + { + nAnchorContent = nContent; + break; + } + } + } + SwGlblDocContents aTempContents; + for ( sal_Int32 nFile = 0; nFile < nFiles; ++nFile ) + { + //update the global document content after each inserted document + rSh.GetGlobalDocContent(aTempContents); + SwGlblDocContent* pAnchorContent = nullptr; + OSL_ENSURE(aTempContents.size() > (nAnchorContent + nFile), "invalid anchor content -> last insertion failed"); + if ( aTempContents.size() > (nAnchorContent + nFile) ) + pAnchorContent = aTempContents[nAnchorContent + nFile].get(); + else + pAnchorContent = aTempContents.back().get(); + OUString sFileName(pFileNames[nFile]); + INetURLObject aFileUrl; + aFileUrl.SetSmartURL( sFileName ); + OUString sSectionName(aFileUrl.GetLastName( + INetURLObject::DecodeMechanism::Unambiguous).getToken(0, sfx2::cTokenSeparator)); + sal_uInt16 nSectCount = rSh.GetSectionFormatCount(); + OUString sTempSectionName(sSectionName); + sal_uInt16 nAddNumber = 0; + sal_uInt16 nCount = 0; + // if applicable: add index if the range name is already in use. + while ( nCount < nSectCount ) + { + const SwSectionFormat& rFormat = rSh.GetSectionFormat(nCount); + if ((rFormat.GetSection()->GetSectionName() == sTempSectionName) + && rFormat.IsInNodesArr()) + { + nCount = 0; + nAddNumber++; + sTempSectionName = sSectionName + ":" + OUString::number( nAddNumber ); + } + else + nCount++; + } + + if ( nAddNumber ) + sSectionName = sTempSectionName; + + SwSectionData aSectionData(SectionType::Content, sSectionName); + aSectionData.SetProtectFlag(true); + aSectionData.SetHidden(false); + + aSectionData.SetLinkFileName(sFileName); + aSectionData.SetType(SectionType::FileLink); + aSectionData.SetLinkFilePassword( OUString() ); + + rSh.InsertGlobalDocContent( *pAnchorContent, aSectionData ); + } + if (bMove) + { + Update( false ); + rSh.MoveGlobalDocContent( + *m_pSwGlblDocContents, nEntryCount, nEntryCount + nFiles, nEntryCount - nFiles ); + } + rSh.EndAction(); + Update( false ); + Display(); + +} + +IMPL_LINK( SwGlobalTree, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void ) +{ + if ( ERRCODE_NONE != _pFileDlg->GetError() ) + return; + + SfxMediumList aMedList(m_pDocInserter->CreateMediumList()); + if ( aMedList.empty() ) + return; + + Sequence< OUString >aFileNames( aMedList.size() ); + OUString* pFileNames = aFileNames.getArray(); + sal_Int32 nPos = 0; + for (const std::unique_ptr<SfxMedium>& pMed : aMedList) + { + // tdf#127978 - don't URL encode filename for navigator's tooltip + OUString sFileName + = pMed->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous) + + OUStringChar(sfx2::cTokenSeparator) + + pMed->GetFilter()->GetFilterName() + + OUStringChar(sfx2::cTokenSeparator); + pFileNames[nPos++] = sFileName; + } + InsertRegion( &*m_oDocContent, aFileNames ); + m_oDocContent.reset(); +} + +void SwGlobalTree::Notify(SfxBroadcaster& rBC, SfxHint const& rHint) +{ + SfxViewEventHint const*const pVEHint(dynamic_cast<SfxViewEventHint const*>(&rHint)); + SwXTextView* pDyingShell = nullptr; + if (m_pActiveShell && pVEHint && pVEHint->GetEventName() == "OnViewClosed") + pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get()); + if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView()) + { + EndListening(*m_pActiveShell->GetView().GetDocShell()); + m_pActiveShell = nullptr; + } + else + { + SfxListener::Notify(rBC, rHint); + if (rHint.GetId() == SfxHintId::SwNavigatorUpdateTracking) + UpdateTracking(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |