Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  glbltree.cxx   Sprache: C

 
/* -*- 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&&nbsp;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_selection_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 );
            size_t n = aFileList.Count();
            while (n)
            {
                --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(), u"modules/swriter/ui/mastercontextmenu.ui"_ustr));
        std::unique_ptr<weld::Menu> xPopup = xBuilder->weld_menu(u"navmenu"_ustr);
        std::unique_ptr<weld::Menu> xSubPopup = xBuilder->weld_menu(u"insertmenu"_ustr);

        const MenuEnableFlags nEnableFlags = GetEnableFlags();

        xPopup->set_sensitive(u"updatesel"_ustr, bool(nEnableFlags & MenuEnableFlags::UpdateSel));

        xPopup->set_sensitive(u"editlink"_ustr, bool(nEnableFlags & MenuEnableFlags::EditLink));

        //disabling if applicable
        xSubPopup->set_sensitive(u"insertindex"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertIdx ));
        xSubPopup->set_sensitive(u"insertfile"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertFile));
        xSubPopup->set_sensitive(u"insertnewfile"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertFile));
        xSubPopup->set_sensitive(u"inserttext"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertText));

        xPopup->set_sensitive(u"update"_ustr, bool(nEnableFlags & MenuEnableFlags::Update));
        xPopup->set_sensitive(u"insert"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertIdx));
        xPopup->set_sensitive(u"editcontent"_ustr, bool(nEnableFlags & MenuEnableFlags::Edit));
        xPopup->set_sensitive(u"deleteentry"_ustr, 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(u"insertindex"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertIdx));
        rMenu.set_sensitive(u"insertfile"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertFile));
        rMenu.set_sensitive(u"insertnewfile"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertFile));
        rMenu.set_sensitive(u"inserttext"_ustr, bool(nEnableFlags & MenuEnableFlags::InsertText));
    }
    else if (rCommand == u"update")
    {
        rMenu.set_sensitive(u"updatesel"_ustr, 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(u"edit"_ustr,  nSelCount == 1 && !bReadonly);
    pNavi->m_xGlobalToolBox->set_item_sensitive(u"insert"_ustr,  nSelCount <= 1 && !bReadonly);
    pNavi->m_xGlobalToolBox->set_item_sensitive(u"update"_ustr,  m_xTreeView->n_children() > 0 && !bReadonly);
    pNavi->m_xGlobalToolBox->set_item_sensitive(u"moveup"_ustr,
                    nSelCount == 1 && nAbsPos && !bReadonly);
    pNavi->m_xGlobalToolBox->set_item_sensitive(u"movedown"_ustr,
                    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().toString();
                    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(), u"swriter"_ustr, 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::WithCharset);
        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(truefalse, nullptr, u""_ustr);
        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().toString());
            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 aId(weld::toId(rGlblDocContent.get()));
                m_xTreeView->select(m_xTreeView->find_id(aId));
                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 aId(weld::toId(rGlblDocContent.get()));
                    m_xTreeView->select(m_xTreeView->find_id(aId));
                }
            }
        }
    }

    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 UIName 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, u"_blank"_ustr );
        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, UIName(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
        pFileNames[nPos++]
            = pMed->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::Unambiguous)
            + OUStringChar(sfx2::cTokenSeparator)
            + pMed->GetFilter()->GetFilterName()
            + OUStringChar(sfx2::cTokenSeparator);
    }
    InsertRegion( &*m_oDocContent, aFileNames );
    m_oDocContent.reset();
}

void SwGlobalTree::Notify(SfxBroadcaster& rBC, SfxHint const& rHint)
{
    if (rHint.GetId() == SfxHintId::ThisIsAnSfxEventHint)
    {
        const SfxEventHint* pEventHint = static_cast<const SfxEventHint*>(&rHint);
        if (pEventHint->GetEventId() == SfxEventHintId::CloseView)
        {
            SfxViewEventHint const*const pVEHint(static_cast<SfxViewEventHint const*>(&rHint));
            if (m_pActiveShell)
            {
                SwXTextView* pDyingShell = dynamic_cast<SwXTextView*>(pVEHint->GetController().get());
                if (pDyingShell && pDyingShell->GetView() == &m_pActiveShell->GetView())
                {
                    EndListening(*m_pActiveShell->GetView().GetDocShell());
                    m_pActiveShell = nullptr;
                }
            }
            return;
        }
    }
    SfxListener::Notify(rBC, rHint);
    if (rHint.GetId() == SfxHintId::SwNavigatorUpdateTracking)
        UpdateTracking();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.15 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge