Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/fpicker/source/office/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 56 kB image not shown  

Quelle  fileview.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 <sal/config.h>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <svtools/svtresid.hxx>
#include <svtools/imagemgr.hxx>
#include <svtools/querydelete.hxx>
#include <svtools/strings.hrc>
#include <bitmaps.hlst>
#include "contentenumeration.hxx"
#include <com/sun/star/task/InteractionHandler.hpp>
#include <com/sun/star/ucb/XProgressHandler.hpp>
#include <com/sun/star/ucb/XContent.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/ucb/CommandAbortedException.hpp>
#include <com/sun/star/ucb/XCommandInfo.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>

#include <algorithm>
#include <string_view>
#include <vector>
#include <tools/debug.hxx>
#include <tools/urlobj.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <ucbhelper/content.hxx>
#include <ucbhelper/commandenvironment.hxx>
#include <rtl/math.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/typed_flags_set.hxx>
#include <o3tl/string_view.hxx>
#include <osl/mutex.hxx>
#include <osl/conditn.hxx>
#include <salhelper/timer.hxx>
#include <svtools/urlfilter.hxx>
#include <unotools/collatorwrapper.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/intlwrapper.hxx>
#include <unotools/syslocale.hxx>
#include <vcl/svapp.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/event.hxx>
#include <vcl/settings.hxx>
#include <vcl/timer.hxx>
#include <memory>
#include "fileview.hxx"

using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::task;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::beans;
using namespace ::comphelper;
using ::svt::SortingData_Impl;
using ::svt::FolderDescriptor;

constexpr OUStringLiteral ALL_FILES_FILTER = u"*.*";

#define COLUMN_TITLE        1
#define COLUMN_TYPE         2
#define COLUMN_SIZE         3
#define COLUMN_DATE         4

#define QUICK_SEARCH_TIMEOUT    1500    // time in mSec before the quicksearch string will be reset

namespace {

enum class FileViewFlags
{
    NONE               = 0x00,
    MULTISELECTION     = 0x02,
    SHOW_TYPE          = 0x04,
    SHOW_NONE          = 0x20,
};

}

namespace o3tl
{
    template<> struct typed_flags<FileViewFlags> : is_typed_flags<FileViewFlags, 0x26> {};
}

namespace
{

    //= CallbackTimer

    class CallbackTimer : public ::salhelper::Timer
    {
    protected:
        SvtFileView_Impl* const m_pTimeoutHandler;

    public:
        explicit CallbackTimer( SvtFileView_Impl* _pHandler ) : m_pTimeoutHandler( _pHandler ) { }

    protected:
        virtual void SAL_CALL onShot() override;
    };

class ViewTabListBox_Impl
{
private:
    rtl::Reference< ::ucbhelper::CommandEnvironment >    mxCmdEnv;
    std::unique_ptr<weld::TreeView> mxTreeView;
    std::unique_ptr<weld::TreeIter> mxScratchIter;

    ::osl::Mutex            maMutex;
    SvtFileView_Impl*       mpParent;
    Timer                   maResetQuickSearch { "fpicker SvtFileView_Impl maResetQuickSearch" };
    OUString                maQuickSearchText;
    sal_uInt32              mnSearchIndex;
    bool                    mbEnableDelete;
    bool                    mbEditing;
    bool const              mbShowType;

    void            DeleteEntries();
    void            DoQuickSearch( sal_Unicode rChar );
    bool            Kill( const OUString& rURL );

public:
    ViewTabListBox_Impl(std::unique_ptr<weld::TreeView> xTreeView, weld::Window* pTopLevel, SvtFileView_Impl* pParent, FileViewFlags nFlags);

    std::unique_ptr<weld::TreeIter> make_iterator() const { return mxTreeView->make_iterator(); }
    void insert(const OUString &rEntry, const OUString& rId, const OUString& rImage, weld::TreeIter& rIter)
    {
        mxTreeView->insert(nullptr, -1, &rEntry, &rId, nullptr, nullptr, false, &rIter);
        mxTreeView->set_image(rIter, rImage);
    }
    void append(const OUString& rId, const OUString& rStr, const OUString& rType, const OUString& rSize, const OUString& rDate, const OUString& rImage)
    {
        mxTreeView->insert(nullptr, -1, &rStr, &rId, nullptr, nullptr, false, mxScratchIter.get());
        mxTreeView->set_image(*mxScratchIter, rImage);
        int nCol = 1;
        if (mbShowType)
            mxTreeView->set_text(*mxScratchIter, rType, nCol++);
        mxTreeView->set_text(*mxScratchIter, rSize, nCol++);
        mxTreeView->set_text(*mxScratchIter, rDate, nCol++);
    }

    void scroll_to_row(const weld::TreeIter& rIter) { mxTreeView->scroll_to_row(rIter); }
    void set_cursor(int nPos) { mxTreeView->set_cursor(nPos); }
    void set_cursor(const weld::TreeIter& rIter) { mxTreeView->set_cursor(rIter); }
    bool get_cursor(weld::TreeIter* pIter) const { return mxTreeView->get_cursor(pIter); }
    bool get_iter_first(weld::TreeIter& rIter) const { return mxTreeView->get_iter_first(rIter); }
    bool get_selected(weld::TreeIter* pIter) const { return mxTreeView->get_selected(pIter); }

    OUString get_selected_text() const
    {
        // tdf#131898 only care about column 0
        int nIndex = mxTreeView->get_selected_index();
        return nIndex != -1 ? mxTreeView->get_text(nIndex, 0) : OUString();
    }

    void unselect_all() { mxTreeView->unselect_all(); }

    OUString get_id(const weld::TreeIter& rIter) { return mxTreeView->get_id(rIter); }

    void connect_row_activated(const Link<weld::TreeView&, bool>& rLink) { mxTreeView->connect_row_activated(rLink); }
    void connect_changed(const Link<weld::TreeView&, void>& rLink)
    {
        mxTreeView->connect_selection_changed(rLink);
    }

    int n_children() const { return mxTreeView->n_children(); }

    void freeze() { mxTreeView->freeze(); }
    void thaw() { mxTreeView->thaw(); }

    void show() { mxTreeView->show(); }
    void hide() { mxTreeView->hide(); }
    bool get_visible() const { return mxTreeView->get_visible(); }

    int count_selected_rows() const { return mxTreeView->count_selected_rows(); }

    void grab_focus() { mxTreeView->grab_focus(); }
    bool has_focus() const { return mxTreeView->has_focus(); }

    void set_help_id(const OUString& rHelpId) { mxTreeView->set_help_id(rHelpId); }
    OUString get_help_id() const { return mxTreeView->get_help_id(); }

    bool IsEditingActive() const { return mbEditing; }

    void end_editing()
    {
        mxTreeView->end_editing();
        mxTreeView->connect_editing(Link<const weld::TreeIter&, bool>(), Link<const IterString&, bool>());
        mbEditing = false;
    }

    void selected_foreach(const std::function<bool(weld::TreeIter&)>& func)
    {
        mxTreeView->selected_foreach(func);
    }

    weld::TreeView* getWidget() const
    {
        return mxTreeView.get();
    }

    void            clear() { mxTreeView->clear(); }

    void            EnableDelete( bool bEnable ) { mbEnableDelete = bEnable; }
    bool            TypeColumnVisible() const { return mbShowType; }

    const rtl::Reference< ::ucbhelper::CommandEnvironment >& GetCommandEnvironment() const { return mxCmdEnv; }

    DECL_LINK(ResetQuickSearch_Impl, Timer *, void);
    DECL_LINK(CommandHdl, const CommandEvent&, bool);
    DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
    typedef std::pair<const weld::TreeIter&, OUString> IterString;
    DECL_LINK(EditedEntryHdl, const IterString&, bool);
    DECL_LINK(KeyInputHdl, const KeyEvent&, bool);

    void            ExecuteContextMenuAction(std::u16string_view rSelectedPopentry);
};

}

//= SvtFileView_Impl
class SvtFileView_Impl  :public ::svt::IEnumerationResultHandler
{
protected:
    SvtFileView*                        m_pAntiImpl;
    Link<SvtFileView*,void>             m_aSelectHandler;

    ::rtl::Reference< ::svt::FileViewContentEnumerator >
                                        m_xContentEnumerator;
    Link<void*,void>                    m_aCurrentAsyncActionHandler;
    ::osl::Condition                    m_aAsyncActionFinished;
    ::rtl::Reference< ::salhelper::Timer > m_xCancelAsyncTimer;
    ::svt::EnumerationResult            m_eAsyncActionResult;
    bool                                m_bRunningAsyncAction;
    bool                                m_bAsyncActionCancelled;

public:

    ::std::vector<std::unique_ptr<SortingData_Impl>>  maContent;
    ::std::vector<std::unique_ptr<SvtContentEntry>> maEntries;
    ::osl::Mutex                        maMutex;

    weld::Window*           m_pTopLevel;
    std::unique_ptr<ViewTabListBox_Impl> mxView;
    std::unique_ptr<weld::IconView> mxIconView;
    sal_uInt16              mnSortColumn;
    bool                    mbAscending     : 1;
    bool const              mbOnlyFolder    : 1;
    sal_Int16               mnSuspendSelectCallback : 1;
    bool                    mbIsFirstResort : 1;

    IntlWrapper const       aIntlWrapper;

    OUString                maViewURL;
    OUString                maCurrentFilter;
    OUString                maFolderImage;
    Link<SvtFileView*,void> maOpenDoneLink;
    Link<SvtFileView*,bool> maDoubleClickHandler;

    Reference< XCommandEnvironment >    mxCmdEnv;

    SvtFileView_Impl(SvtFileView* pAntiImpl, weld::Window* pTopLevel,
                     std::unique_ptr<weld::TreeView> xTreeView,
                     std::unique_ptr<weld::IconView> xIconView,
                     Reference < XCommandEnvironment > const & xEnv,
                     FileViewFlags nFlags,
                     bool bOnlyFolder);

    virtual ~SvtFileView_Impl();

    void                    Clear();

    FileViewResult          GetFolderContent_Impl(
        std::u16string_view rFolder,
        const FileViewAsyncAction* pAsyncDescriptor,
        const css::uno::Sequence< OUString >& rDenyList );

    FileViewResult          GetFolderContent_Impl(
        const FolderDescriptor& _rFolder,
        const FileViewAsyncAction* pAsyncDescriptor,
        const css::uno::Sequence< OUString >& rDenyList );
    void                    FilterFolderContent_Impl( std::u16string_view rFilter );
    void                    CancelRunningAsyncAction();

    void                    OpenFolder_Impl();
    static OUString         ReplaceTabWithString(const OUString& rValue);
    void                    CreateDisplayText_Impl();
    void                    SortFolderContent_Impl();

    void                    EntryRemoved( std::u16string_view rURL );
    void                    EntryRenamed( OUString& rURL,
                                          const OUString& rName );
    const SortingData_Impl& FolderInserted( const OUString& rURL,
                                            const OUString& rTitle );

    int                     GetEntryPos( std::u16string_view rURL );

    void                    SetViewMode( FileViewMode eMode );

    inline void             EnableDelete( bool bEnable );

    void                    Resort_Impl( sal_Int16 nColumn, bool bAscending );
    bool                    SearchNextEntry( sal_uInt32 &nIndex,
                                             std::u16string_view rTitle,
                                             bool bWrapAround );

    void                    SetSelectHandler( const Link<SvtFileView*,void>& rHdl );
    void                    SetDoubleClickHandler(const Link<SvtFileView*,bool>& rHdl);

    void                    ResetCursor();

    void EndEditing()
    {
        if (mxView->IsEditingActive())
            mxView->end_editing();
    }

    void onTimeout();

    void grab_focus()
    {
        if (mxView->get_visible())
            mxView->grab_focus();
        else
            mxIconView->grab_focus();
    }

    bool has_focus() const
    {
        return mxView->has_focus() || mxIconView->has_focus();
    }

    int GetSortColumn() const
    {
        sal_uInt16 nOldSortID = mnSortColumn;
        // skip "TYPE"
        if (!mxView->TypeColumnVisible() && nOldSortID != COLUMN_TITLE)
            --nOldSortID;
        return nOldSortID - 1;
    }

protected:
    DECL_LINK(ChangedHdl, weld::TreeView&, void);
    DECL_LINK(SelectionChangedHdl, weld::IconView&, void);
    DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
    DECL_LINK(ItemActivatedHdl, weld::IconView&, bool);

    // IEnumerationResultHandler overridables
    virtual void        enumerationDone( ::svt::EnumerationResult eResult ) override;
            void        implEnumerationSuccess();
};

inline void SvtFileView_Impl::EnableDelete( bool bEnable )
{
    mxView->EnableDelete( bEnable );
}

namespace
{
    // functions -------------------------------------------------------------

    OUString CreateExactSizeText( sal_Int64 nSize )
    {
        double fSize( static_cast<double>(nSize) );
        int nDec;

        tools::Long nMega = 1024 * 1024;
        tools::Long nGiga = nMega * 1024;

        OUString aUnitStr(' ');

        if ( nSize < 10000 )
        {
            aUnitStr += SvtResId(STR_SVT_BYTES );
            nDec = 0;
        }
        else if ( nSize < nMega )
        {
            fSize /= 1024;
            aUnitStr += SvtResId(STR_SVT_KB);
            nDec = 1;
        }
        else if ( nSize < nGiga )
        {
            fSize /= nMega;
            aUnitStr += SvtResId(STR_SVT_MB);
            nDec = 2;
        }
        else
        {
            fSize /= nGiga;
            aUnitStr += SvtResId(STR_SVT_GB);
            nDec = 3;
        }

        OUString aSizeStr =
            ::rtl::math::doubleToUString( fSize,
                    rtl_math_StringFormat_F, nDec,
                    SvtSysLocale().GetLocaleData().getNumDecimalSep()[0]) +
            aUnitStr;

        return aSizeStr;
    }
}

ViewTabListBox_Impl::ViewTabListBox_Impl(std::unique_ptr<weld::TreeView> xTreeView,
                                         weld::Window* pTopLevel,
                                         SvtFileView_Impl* pParent,
                                         FileViewFlags nFlags)
    : mxTreeView(std::move(xTreeView))
    , mxScratchIter(mxTreeView->make_iterator())
    , mpParent( pParent )
    , mnSearchIndex( 0 )
    , mbEnableDelete( false )
    , mbEditing( false )
    , mbShowType(nFlags & FileViewFlags::SHOW_TYPE)
{
    std::vector<int> aWidths { 180 };
    if (nFlags & FileViewFlags::SHOW_TYPE)
        aWidths.push_back(140);
    aWidths.push_back(80);
    mxTreeView->set_column_fixed_widths(aWidths);

    if (nFlags & FileViewFlags::MULTISELECTION)
        mxTreeView->set_selection_mode(SelectionMode::Multiple);

    maResetQuickSearch.SetTimeout( QUICK_SEARCH_TIMEOUT );
    maResetQuickSearch.SetInvokeHandler( LINK( this, ViewTabListBox_Impl, ResetQuickSearch_Impl ) );

    const Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
    Reference< XInteractionHandler > xInteractionHandler(
        InteractionHandler::createWithParent(xContext, pTopLevel->GetXWindow()), UNO_QUERY_THROW);

    mxCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() );

    mxTreeView->connect_popup_menu(LINK(this, ViewTabListBox_Impl, CommandHdl));
    mxTreeView->connect_key_press(LINK(this, ViewTabListBox_Impl, KeyInputHdl));
}

IMPL_LINK_NOARG(ViewTabListBox_Impl, EditingEntryHdl, const weld::TreeIter&, bool)
{
    return mbEditing;
}

IMPL_LINK_NOARG(ViewTabListBox_Impl, ResetQuickSearch_Impl, Timer *, void)
{
    ::osl::MutexGuard aGuard( maMutex );

    maQuickSearchText.clear();
    mnSearchIndex = 0;
}

IMPL_LINK(ViewTabListBox_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{
    if (mbEditing)
        return false;

    bool bHandled = false;

    const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
    if ( 0 == rKeyCode.GetModifier() )
    {
        if ( ( rKeyCode.GetCode() == KEY_DELETE ) &&
                  mbEnableDelete )
        {
            ResetQuickSearch_Impl( nullptr );
            DeleteEntries();
            bHandled = true;
        }
        else if ( ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_NUM ) ||
                  ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_ALPHA ) )
        {
            DoQuickSearch( rKEvt.GetCharCode() );
            bHandled = true;
        }
    }

    if (!bHandled)
        ResetQuickSearch_Impl( nullptr );
    return bHandled;
}

IMPL_LINK(ViewTabListBox_Impl, CommandHdl, const CommandEvent&, rCEvt, bool)
{
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
        return false;

    bool bEnableDelete = mbEnableDelete;
    bool bEnableRename = true;

    int nCount = 0;
    mxTreeView->selected_foreach([this, &nCount, &bEnableDelete, &bEnableRename](weld::TreeIter& rEntry){
        ++nCount;

        ::ucbhelper::Content aCnt;
        try
        {
            OUString aURL(weld::fromId<SvtContentEntry*>(
                mxTreeView->get_id(rEntry))->maURL);
            aCnt = ::ucbhelper::Content( aURL, mxCmdEnv, comphelper::getProcessComponentContext() );
        }
        catch( Exception const & )
        {
            bEnableDelete = bEnableRename = false;
        }

        if ( bEnableDelete )
        {
            try
            {
                Reference< XCommandInfo > aCommands = aCnt.getCommands();
                if ( aCommands.is() )
                    bEnableDelete = aCommands->hasCommandByName( u"delete"_ustr );
                else
                    bEnableDelete = false;
            }
            catch( Exception const & )
            {
                bEnableDelete = false;
            }
        }

        if ( bEnableRename )
        {
            try
            {
                Reference< XPropertySetInfo > aProps = aCnt.getProperties();
                if ( aProps.is() )
                {
                    Property aProp = aProps->getPropertyByName(u"Title"_ustr);
                    bEnableRename
                        = !( aProp.Attributes & PropertyAttribute::READONLY );
                }
                else
                    bEnableRename = false;
            }
            catch( Exception const & )
            {
                bEnableRename = false;
            }
        }

        bool bStop = !bEnableDelete && !bEnableRename;
        return bStop;
    });

    if (nCount == 0)
        bEnableDelete = false;
    if (nCount != 1)
        bEnableRename = false;

    if (bEnableDelete || bEnableRename)
    {
        std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxTreeView.get(), u"svt/ui/fileviewmenu.ui"_ustr));
        auto xContextMenu = xBuilder->weld_menu(u"menu"_ustr);
        xContextMenu->set_visible(u"delete"_ustr, bEnableDelete);
        xContextMenu->set_visible(u"rename"_ustr, bEnableRename);
        OUString sCommand(xContextMenu->popup_at_rect(mxTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
        ExecuteContextMenuAction(sCommand);
    }

    return true;
}

void ViewTabListBox_Impl::ExecuteContextMenuAction(std::u16string_view rSelectedPopupEntry)
{
    if (rSelectedPopupEntry == u"delete")
        DeleteEntries();
    else if (rSelectedPopupEntry == u"rename")
    {
        std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
        if (mxTreeView->get_selected(xEntry.get()))
        {
            mbEditing = true;

            mxTreeView->connect_editing(LINK(this, ViewTabListBox_Impl, EditingEntryHdl),
                                        LINK(this, ViewTabListBox_Impl, EditedEntryHdl));

            mxTreeView->start_editing(*xEntry);
        }
    }
}

void ViewTabListBox_Impl::DeleteEntries()
{
    short eResult = svtools::QUERYDELETE_YES;

    mxTreeView->selected_foreach([this, &eResult](weld::TreeIter& rCurEntry){
        OUString aURL;
        if (!mxTreeView->get_id(rCurEntry).isEmpty())
            aURL = weld::fromId<SvtContentEntry*>(mxTreeView->get_id(rCurEntry))->maURL;
        if (aURL.isEmpty())
        {
            mxTreeView->unselect(rCurEntry);
            return false;
        }

        bool canDelete = true;
        try
        {
            ::ucbhelper::Content aCnt( aURL, mxCmdEnv, comphelper::getProcessComponentContext() );
            Reference< XCommandInfo > aCommands = aCnt.getCommands();
            if ( aCommands.is() )
                canDelete = aCommands->hasCommandByName( u"delete"_ustr );
            else
                canDelete = false;
        }
        catch( Exception const & )
        {
            canDelete = false;
        }

        if (!canDelete)
        {
            mxTreeView->unselect(rCurEntry);
            return false// process next entry
        }

        if ( eResult != svtools::QUERYDELETE_ALL )
        {
            INetURLObject aObj( aURL );
            svtools::QueryDeleteDlg_Impl aDlg(
                mxTreeView.get(), aObj.GetLastName(INetURLObject::DecodeMechanism::WithCharset));

            if (mxTreeView->count_selected_rows() > 1)
                aDlg.EnableAllButton();

            eResult = aDlg.run();
        }

        bool bDeleted = false;

        if (eResult == svtools::QUERYDELETE_ALL || eResult == svtools::QUERYDELETE_YES)
        {
            if ( Kill( aURL ) )
            {
                mpParent->EntryRemoved( aURL );
                bDeleted = true;
            }
        }

        if (!bDeleted)
            mxTreeView->unselect(rCurEntry);

        return false;
    });

    mxTreeView->remove_selection();
}

IMPL_LINK(ViewTabListBox_Impl, EditedEntryHdl, const IterString&, rIterString, bool)
{
    mbEditing = false;

    mxTreeView->connect_editing(Link<const weld::TreeIter&, bool>(), Link<const IterString&, bool>());

    const weld::TreeIter& rEntry = rIterString.first;
    OUString sNewText = rIterString.second;

    if (sNewText.isEmpty())
        return false;

    bool bRet = false;

    OUString aURL;
    SvtContentEntry* pData = weld::fromId<SvtContentEntry*>(mxTreeView->get_id(rEntry));

    if ( pData )
        aURL = pData->maURL;

    if ( aURL.isEmpty() )
        return bRet;

    try
    {
        OUString aPropName( u"Title"_ustr );
        bool canRename = true;
        ::ucbhelper::Content aContent( aURL, mxCmdEnv, comphelper::getProcessComponentContext() );

        try
        {
            Reference< XPropertySetInfo > aProps = aContent.getProperties();
            if ( aProps.is() )
            {
                Property aProp = aProps->getPropertyByName( aPropName );
                canRename = !( aProp.Attributes & PropertyAttribute::READONLY );
            }
            else
            {
                canRename = false;
            }
        }
        catch ( Exception const & )
        {
            canRename = false;
        }

        if ( canRename )
        {
            Any aValue;
            aValue <<= sNewText;
            aContent.setPropertyValue( aPropName, aValue );
            mpParent->EntryRenamed(aURL, sNewText);

            if (pData)
                pData->maURL = aURL;

            mxTreeView->set_id(rEntry, weld::toId(pData));

            bRet = true;
        }
    }
    catch( Exception const & )
    {
    }

    return bRet;
}

void ViewTabListBox_Impl::DoQuickSearch( sal_Unicode rChar )
{
    ::osl::MutexGuard aGuard( maMutex );

    maResetQuickSearch.Stop();

    OUString    aLastText = maQuickSearchText;
    sal_uInt32  aLastPos = mnSearchIndex;

    maQuickSearchText += OUString(rChar).toAsciiLowerCase();

    bool bFound = mpParent->SearchNextEntry( mnSearchIndex, maQuickSearchText, false );

    if ( !bFound && ( aLastText.getLength() == 1 ) &&
         ( aLastText == OUStringChar(rChar) ) )
    {
        mnSearchIndex = aLastPos + 1;
        maQuickSearchText = aLastText;
        bFound = mpParent->SearchNextEntry( mnSearchIndex, maQuickSearchText, true );
    }

    if (bFound)
    {
        mxTreeView->unselect_all();
        mxTreeView->select(mnSearchIndex);
        mxTreeView->set_cursor(mnSearchIndex);
        mxTreeView->scroll_to_row(mnSearchIndex);
    }

    maResetQuickSearch.Start();
}

bool ViewTabListBox_Impl::Kill( const OUString& rContent )
{
    bool bRet = true;

    try
    {
        ::ucbhelper::Content aCnt( rContent, mxCmdEnv, comphelper::getProcessComponentContext() );
        aCnt.executeCommand( u"delete"_ustr, Any( true ) );
    }
    catch( css::ucb::CommandAbortedException const & )
    {
        SAL_INFO( "svtools.contnr""CommandAbortedException" );
        bRet = false;
    }
    catch( Exception const & )
    {
        SAL_INFO( "svtools.contnr""Any other exception" );
        bRet = false;
    }

    return bRet;
}

SvtFileView::SvtFileView(weld::Window* pTopLevel,
                         std::unique_ptr<weld::TreeView> xTreeView,
                         std::unique_ptr<weld::IconView> xIconView,
                         bool bOnlyFolder, bool bMultiSelection, bool bShowType )
{
    FileViewFlags nFlags = FileViewFlags::NONE;
    if ( bMultiSelection )
        nFlags |= FileViewFlags::MULTISELECTION;
    if ( bShowType )
        nFlags |= FileViewFlags::SHOW_TYPE;

    const Reference< XComponentContext >& xContext = ::comphelper::getProcessComponentContext();
    Reference< XInteractionHandler > xInteractionHandler(
        InteractionHandler::createWithParent(xContext, pTopLevel->GetXWindow()), UNO_QUERY_THROW);
    Reference < XCommandEnvironment > xCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() );

    mpImpl.reset(new SvtFileView_Impl(this, pTopLevel, std::move(xTreeView), std::move(xIconView), xCmdEnv, nFlags, bOnlyFolder));

    weld::TreeView* pView = mpImpl->mxView->getWidget();
    pView->connect_column_clicked(LINK(this, SvtFileView, HeaderSelect_Impl));
}

void SvtFileView::grab_focus()
{
    mpImpl->grab_focus();
}

bool SvtFileView::has_focus() const
{
    return mpImpl->has_focus();
}

SvtFileView::~SvtFileView()
{
}

void SvtFileView::SetViewMode( FileViewMode eMode )
{
    mpImpl->SetViewMode( eMode );
}

OUString SvtFileView::GetURL(const weld::TreeIter& rEntry) const
{
    SvtContentEntry* pEntry;
    if (mpImpl->mxView->get_visible())
        pEntry = weld::fromId<SvtContentEntry*>(mpImpl->mxView->get_id(rEntry));
    else
        pEntry = weld::fromId<SvtContentEntry*>(mpImpl->mxIconView->get_id(rEntry));
    if (pEntry)
        return pEntry->maURL;
    return OUString();
}

OUString SvtFileView::GetCurrentURL() const
{
    SvtContentEntry* pEntry = nullptr;
    OUString aURL;
    if (mpImpl->mxView->get_visible())
    {
        std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxView->make_iterator();
        if (mpImpl->mxView->get_selected(xEntry.get()))
            pEntry = weld::fromId<SvtContentEntry*>(mpImpl->mxView->get_id(*xEntry));
    }
    else
    {
        std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxIconView->make_iterator();
        if (mpImpl->mxIconView->get_selected(xEntry.get()))
            pEntry = weld::fromId<SvtContentEntry*>(mpImpl->mxIconView->get_id(*xEntry));
    }
    if (pEntry)
        aURL = pEntry->maURL;
    return aURL;
}

void SvtFileView::CreatedFolder( const OUString& rUrl, const OUString& rNewFolder )
{
    const SortingData_Impl& rEntry = mpImpl->FolderInserted( rUrl, rNewFolder );

    mpImpl->maEntries.emplace_back(std::make_unique<SvtContentEntry>(rUrl, true));
    OUString sId(weld::toId(mpImpl->maEntries.back().get()));

    std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxView->make_iterator();
    mpImpl->mxView->insert(rEntry.maDisplayName, sId, mpImpl->maFolderImage, *xEntry);
    mpImpl->mxView->scroll_to_row(*xEntry);

    std::unique_ptr<weld::TreeIter> xIconEntry = mpImpl->mxIconView->make_iterator();
    mpImpl->mxIconView->insert(-1, &rEntry.maDisplayName, &sId, &mpImpl->maFolderImage, xIconEntry.get());
    mpImpl->mxIconView->scroll_to_item(*xIconEntry);
}

FileViewResult SvtFileView::PreviousLevel( const FileViewAsyncAction* pAsyncDescriptor )
{
    FileViewResult eResult = eFailure;

    OUString sParentURL;
    if ( GetParentURL( sParentURL ) )
        eResult = Initialize( sParentURL, mpImpl->maCurrentFilter, pAsyncDescriptor, maDenyList );

    return eResult;
}

bool SvtFileView::GetParentURL( OUString& rParentURL ) const
{
    bool bRet = false;
    try
    {
        ::ucbhelper::Content aCnt( mpImpl->maViewURL, mpImpl->mxCmdEnv, comphelper::getProcessComponentContext() );
        Reference< XContent > xContent( aCnt.get() );
        Reference< css::container::XChild > xChild( xContent, UNO_QUERY );
        if ( xChild.is() )
        {
            Reference< XContent > xParent( xChild->getParent(), UNO_QUERY );
            if ( xParent.is() )
            {
                rParentURL = xParent->getIdentifier()->getContentIdentifier();
                bRet = !rParentURL.isEmpty() && rParentURL != mpImpl->maViewURL;
            }
        }
    }
    catch( Exception const & )
    {
        // perhaps an unknown url protocol (e.g. "private:newdoc")
    }

    return bRet;
}

OUString SvtFileView::get_help_id() const
{
    return mpImpl->mxView->get_help_id();
}

void SvtFileView::set_help_id(const OUString& rHelpId)
{
    mpImpl->mxView->set_help_id(rHelpId);
}

OUString SvtFileView::get_selected_text() const
{
    if (mpImpl->mxView->get_visible())
        return mpImpl->mxView->get_selected_text();
    return mpImpl->mxIconView->get_selected_text();
}

FileViewResult SvtFileView::Initialize(
    const OUString& rURL,
    const OUString& rFilter,
    const FileViewAsyncAction* pAsyncDescriptor,
    const css::uno::Sequence< OUString >& rDenyList )
{
    weld::WaitObject aWaitCursor(mpImpl->m_pTopLevel);
    maDenyList = rDenyList;

    OUString sPushURL( mpImpl->maViewURL );

    mpImpl->maViewURL = rURL;
    FileViewResult eResult = ExecuteFilter( rFilter, pAsyncDescriptor );
    switch ( eResult )
    {
    case eFailure:
    case eTimeout:
        mpImpl->maViewURL = sPushURL;
        return eResult;

    case eStillRunning:
        OSL_ENSURE( pAsyncDescriptor, "SvtFileView::Initialize: we told it to read synchronously!" );
        [[fallthrough]];
    case eSuccess:
        return eResult;
    }

    OSL_FAIL( "SvtFileView::Initialize: unreachable!" );
    return eFailure;
}

FileViewResult SvtFileView::ExecuteFilter( const OUString& rFilter, const FileViewAsyncAction* pAsyncDescriptor )
{
    mpImpl->maCurrentFilter = rFilter.toAsciiLowerCase();

    mpImpl->Clear();
    FileViewResult eResult = mpImpl->GetFolderContent_Impl(mpImpl->maViewURL, pAsyncDescriptor, maDenyList);
    OSL_ENSURE( ( eResult != eStillRunning ) || pAsyncDescriptor, "SvtFileView::ExecuteFilter: we told it to read synchronously!" );
    return eResult;
}

void SvtFileView::CancelRunningAsyncAction()
{
    mpImpl->CancelRunningAsyncAction();
}

void SvtFileView::SetNoSelection()
{
    mpImpl->mxView->unselect_all();
    mpImpl->mxIconView->unselect_all();
}

void SvtFileView::SetSelectHdl(const Link<SvtFileView*,void>& rHdl)
{
    mpImpl->SetSelectHandler(rHdl);
}

void SvtFileView::SetDoubleClickHdl(const Link<SvtFileView*,bool>& rHdl)
{
    mpImpl->SetDoubleClickHandler(rHdl);
}

sal_uInt32 SvtFileView::GetSelectionCount() const
{
    if (mpImpl->mxView->get_visible())
        return mpImpl->mxView->count_selected_rows();
    return mpImpl->mxIconView->count_selected_items();
}

SvtContentEntry* SvtFileView::FirstSelected() const
{
    if (mpImpl->mxView->get_visible())
    {
        SvtContentEntry* pRet = nullptr;
        std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxView->make_iterator();
        if (mpImpl->mxView->get_selected(xEntry.get()))
            pRet = weld::fromId<SvtContentEntry*>(mpImpl->mxView->get_id(*xEntry));
        return pRet;
    }

    SvtContentEntry* pRet = nullptr;
    std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxIconView->make_iterator();
    if (mpImpl->mxIconView->get_selected(xEntry.get()))
        pRet = weld::fromId<SvtContentEntry*>(mpImpl->mxIconView->get_id(*xEntry));
    return pRet;
}

const OUString& SvtFileView::GetViewURL() const
{
    return mpImpl->maViewURL;
}

void SvtFileView::SetOpenDoneHdl( const Link<SvtFileView*,void>& rHdl )
{
    mpImpl->maOpenDoneLink = rHdl;
}

void SvtFileView::EnableDelete( bool bEnable )
{
    mpImpl->EnableDelete( bEnable );
}

void SvtFileView::EndInplaceEditing()
{
    return mpImpl->EndEditing();
}

IMPL_LINK(SvtFileView, HeaderSelect_Impl, int, nColumn, void)
{
    sal_uInt16 nItemID = nColumn + 1;
    // skip "TYPE"
    if (!mpImpl->mxView->TypeColumnVisible() && nItemID != COLUMN_TITLE)
        ++nItemID;

    weld::TreeView* pView = mpImpl->mxView->getWidget();
    bool bSortAtoZ = mpImpl->mbAscending;

    //set new arrow positions in headerbar
    if (nItemID != mpImpl->mnSortColumn)
    {
        // remove old indicator, new will be created in OpenFolder_Impl
        pView->set_sort_indicator(TRISTATE_INDET, mpImpl->GetSortColumn());
    }
    else
        bSortAtoZ = !bSortAtoZ;

    mpImpl->Resort_Impl(nItemID, bSortAtoZ);
}

OUString SvtFileView::GetConfigString() const
{
    // sort order
    OUString sRet = OUString::number( mpImpl->mnSortColumn ) + ";";

    bool bUp = mpImpl->mbAscending;
    sRet += OUString::Concat(bUp ? std::u16string_view(u"1") : std::u16string_view(u"0")) + ";";

    weld::TreeView* pView = mpImpl->mxView->getWidget();
    sal_uInt16 nCount = mpImpl->mxView->TypeColumnVisible() ? 4 : 3;
    for (sal_uInt16 i = 0; i < nCount; ++i)
    {
        sal_uInt16 nId = i + 1;
        // skip "TYPE"
        if (!mpImpl->mxView->TypeColumnVisible() && nId != COLUMN_TITLE)
            ++nId;

        sRet += OUString::number( nId )
                + ";"
                + OUString::number(pView->get_column_width(i))
                + ";";
    }

    return comphelper::string::stripEnd(sRet, ';');
}

::std::vector< SvtContentEntry > SvtFileView::GetContent()
{
    ::std::vector< SvtContentEntry > aContent;

    for(auto const& elem : mpImpl->maContent)
    {
        SvtContentEntry aEntry( elem->maTargetURL, elem->mbIsFolder );
        aContent.push_back( aEntry );
    }

    return aContent;
}

void SvtFileView::SetConfigString(std::u16string_view rCfgStr)
{
    sal_Int32 nIdx = 0;
    sal_uInt16 nSortColumn = static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rCfgStr, 0, ';', nIdx )));
    bool bAscending = static_cast<bool>(static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rCfgStr, 0, ';', nIdx ))));

    std::vector<int> aWidths(mpImpl->mxView->TypeColumnVisible() ? 4 : 3, -1);

    while ( nIdx != -1 )
    {
        int nItemId = o3tl::toInt32(o3tl::getToken(rCfgStr, 0, ';', nIdx ));

        int nWidth = o3tl::toInt32(o3tl::getToken(rCfgStr, 0, ';', nIdx ));

        // skip "TYPE"
        if (!mpImpl->mxView->TypeColumnVisible() && nItemId != COLUMN_TITLE)
            --nItemId;
        int nColumn = nItemId - 1;

        if (nColumn >= 0 && o3tl::make_unsigned(nColumn) < aWidths.size())
            aWidths[nColumn] = nWidth;
    }

    weld::TreeView* pView = mpImpl->mxView->getWidget();
    pView->set_column_fixed_widths(aWidths);
    if (mpImpl->mnSortColumn != nSortColumn)
        pView->set_sort_indicator(TRISTATE_INDET, mpImpl->GetSortColumn());
    mpImpl->Resort_Impl(nSortColumn, bAscending);
}

SvtFileView_Impl::SvtFileView_Impl(SvtFileView* pAntiImpl, weld::Window* pTopLevel,
                                   std::unique_ptr<weld::TreeView> xTreeView,
                                   std::unique_ptr<weld::IconView> xIconView,
                                   Reference < XCommandEnvironment > const & xEnv,
                                   FileViewFlags nFlags, bool bOnlyFolder)
    : m_pAntiImpl                ( pAntiImpl )
    , m_eAsyncActionResult       ( ::svt::EnumerationResult::ERROR )
    , m_bRunningAsyncAction      ( false )
    , m_bAsyncActionCancelled    ( false )
    , m_pTopLevel                ( pTopLevel )
    , mxView(new ViewTabListBox_Impl(std::move(xTreeView), pTopLevel, this, nFlags))
    , mxIconView(std::move(xIconView))
    , mnSortColumn               ( COLUMN_TITLE )
    , mbAscending                ( true )
    , mbOnlyFolder               ( bOnlyFolder )
    , mnSuspendSelectCallback    ( 0 )
    , mbIsFirstResort            ( true )
    , aIntlWrapper               ( Application::GetSettings().GetLanguageTag() )
    , maFolderImage              (RID_BMP_FOLDER)
    , mxCmdEnv ( xEnv )
{
    weld::TreeView* pWidget = mxView->getWidget();

    // set the width to something small so it's the parent that decides the final
    // width
    Size aSize(42, pWidget->get_height_rows(7));
    pWidget->set_size_request(aSize.Width(), aSize.Height());
    mxIconView->set_size_request(aSize.Width(), aSize.Height());
}

SvtFileView_Impl::~SvtFileView_Impl()
{
    Clear();
}

void SvtFileView_Impl::Clear()
{
    ::osl::MutexGuard aGuard( maMutex );

    maContent.clear();
}

FileViewResult SvtFileView_Impl::GetFolderContent_Impl(
    std::u16string_view rFolder,
    const FileViewAsyncAction* pAsyncDescriptor,
    const css::uno::Sequence< OUString >& rDenyList )
{
    ::osl::ClearableMutexGuard aGuard( maMutex );
    INetURLObject aFolderObj( rFolder );
    DBG_ASSERT( aFolderObj.GetProtocol() != INetProtocol::NotValid, "Invalid URL!" );

    FolderDescriptor aFolder( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );

    aGuard.clear();
    return GetFolderContent_Impl( aFolder, pAsyncDescriptor, rDenyList );
}

FileViewResult SvtFileView_Impl::GetFolderContent_Impl(
    const FolderDescriptor& _rFolder,
    const FileViewAsyncAction* pAsyncDescriptor,
    const css::uno::Sequence< OUString >& rDenyList )
{
    DBG_TESTSOLARMUTEX();
    ::osl::ClearableMutexGuard aGuard( maMutex );

    OSL_ENSURE( !m_xContentEnumerator.is(), "SvtFileView_Impl::GetFolderContent_Impl: still running another enumeration!" );
    m_xContentEnumerator.set(new ::svt::FileViewContentEnumerator(
        mxView->GetCommandEnvironment(), maContent, maMutex));
        // TODO: should we cache and re-use this thread?

    if ( !pAsyncDescriptor )
    {
        ::svt::EnumerationResult eResult = m_xContentEnumerator->enumerateFolderContentSync( _rFolder, rDenyList );
        if ( ::svt::EnumerationResult::SUCCESS == eResult )
        {
            implEnumerationSuccess();
            m_xContentEnumerator.clear();
            return eSuccess;
        }
        m_xContentEnumerator.clear();
        return eFailure;
    }

    m_bRunningAsyncAction = true;
    m_bAsyncActionCancelled = false;
    m_eAsyncActionResult = ::svt::EnumerationResult::ERROR;
    m_aAsyncActionFinished.reset();

    // don't (yet) set m_aCurrentAsyncActionHandler to pTimeout->aFinishHandler.
    // By definition, this handler *only* gets called when the result cannot be obtained
    // during the minimum wait time, so it is only set below, when needed.
    m_aCurrentAsyncActionHandler = Link<void*,void>();

    // minimum time to wait
    TimeValue aTimeout;
    sal_Int32 nMinTimeout = pAsyncDescriptor->nMinTimeout;
    OSL_ENSURE( nMinTimeout > 0, "SvtFileView_Impl::GetFolderContent_Impl: invalid minimum timeout!" );
    if ( nMinTimeout <= 0 )
        nMinTimeout = sal_Int32( 1000 );
    aTimeout.Seconds = nMinTimeout / 1000;
    aTimeout.Nanosec = ( nMinTimeout % 1000 ) * 1000000;

    m_xContentEnumerator->enumerateFolderContent( _rFolder, this );

    // wait until the enumeration is finished
    // for this, release our own mutex (which is used by the enumerator thread)
    aGuard.clear();

    ::osl::Condition::Result eResult = ::osl::Condition::result_ok;
    {
        // also release the SolarMutex. Not all code which is needed during the enumeration
        // is Solar-Thread-Safe, in particular there is some code which needs to access
        // string resources (and our resource system relies on the SolarMutex :()
        SolarMutexReleaser aSolarRelease;

        // now wait. Note that if we didn't get a pAsyncDescriptor, then this is an infinite wait.
        eResult = m_aAsyncActionFinished.wait( &aTimeout );
    }

    ::osl::MutexGuard aGuard2( maMutex );
    if ( ::osl::Condition::result_timeout == eResult )
    {
        // maximum time to wait
        OSL_ENSURE(!m_xCancelAsyncTimer,
                   "SvtFileView_Impl::GetFolderContent_Impl: there's still a previous timer!");
        m_xCancelAsyncTimer.set(new CallbackTimer(this));
        sal_Int32 nMaxTimeout = pAsyncDescriptor->nMaxTimeout;
        OSL_ENSURE( nMaxTimeout > nMinTimeout,
            "SvtFileView_Impl::GetFolderContent_Impl: invalid maximum timeout!" );
        if ( nMaxTimeout <= nMinTimeout )
            nMaxTimeout = nMinTimeout + 5000;
        m_xCancelAsyncTimer->setRemainingTime( salhelper::TTimeValue( nMaxTimeout - nMinTimeout ) );
            // we already waited for nMinTimeout milliseconds, so take this into account
        m_xCancelAsyncTimer->start();

        m_aCurrentAsyncActionHandler = pAsyncDescriptor->aFinishHandler;
        DBG_ASSERT( m_aCurrentAsyncActionHandler.IsSet(), "SvtFileView_Impl::GetFolderContent_Impl: nobody interested when it's finished?" );
        maEntries.clear();
        mxView->clear();
        mxIconView->clear();
        return eStillRunning;
    }

    m_bRunningAsyncAction = false;
    switch ( m_eAsyncActionResult )
    {
    case ::svt::EnumerationResult::SUCCESS:
        return eSuccess;

    case ::svt::EnumerationResult::ERROR:
        return eFailure;
    }

    SAL_WARN( "svtools.contnr""SvtFileView_Impl::GetFolderContent_Impl: unreachable!" );
    return eFailure;
}

void SvtFileView_Impl::FilterFolderContent_Impl( std::u16string_view rFilter )
{
    if ( rFilter.empty() || ( rFilter == ALL_FILES_FILTER ) )
        // when replacing names, there is always something to filter (no view of ".nametranslation.table")
        return;

    ::osl::MutexGuard aGuard( maMutex );

    if ( maContent.empty() )
        return;

    // collect the filter tokens
    ::std::vector< WildCard > aFilters;
    FilterMatch::createWildCardFilterList(rFilter,aFilters);


    // do the filtering
    std::erase_if(maContent,
        [&aFilters](const std::unique_ptr<SortingData_Impl>& rxContent) {
            if (rxContent->mbIsFolder)
                return false;
            // normalize the content title (we always match case-insensitive)
            // 91872 - 11.09.2001 - frank.schoenheit@sun.com
            OUString sCompareString = rxContent->GetFileName(); // filter works on file name, not on title!
            return std::none_of(aFilters.begin(), aFilters.end(), FilterMatch(sCompareString));
        });
}

IMPL_LINK_NOARG(SvtFileView_Impl, ChangedHdl, weld::TreeView&, void)
{
    if (!mnSuspendSelectCallback)
        m_aSelectHandler.Call(m_pAntiImpl);
}

IMPL_LINK_NOARG(SvtFileView_Impl, SelectionChangedHdl, weld::IconView&, void)
{
    if (!mnSuspendSelectCallback)
        m_aSelectHandler.Call(m_pAntiImpl);
}

void SvtFileView_Impl::SetSelectHandler(const Link<SvtFileView*,void>& rHdl)
{
    m_aSelectHandler = rHdl;

    mxView->connect_changed(LINK(this, SvtFileView_Impl, ChangedHdl));
    mxIconView->connect_selection_changed(LINK(this, SvtFileView_Impl, SelectionChangedHdl));
}

IMPL_LINK_NOARG(SvtFileView_Impl, RowActivatedHdl, weld::TreeView&, bool)
{
    return maDoubleClickHandler.Call(m_pAntiImpl);
}

IMPL_LINK_NOARG(SvtFileView_Impl, ItemActivatedHdl, weld::IconView&, bool)
{
    return maDoubleClickHandler.Call(m_pAntiImpl);
}

void SvtFileView_Impl::SetDoubleClickHandler(const Link<SvtFileView*,bool>& rHdl)
{
    maDoubleClickHandler = rHdl;

    mxView->connect_row_activated(LINK(this, SvtFileView_Impl, RowActivatedHdl));
    mxIconView->connect_item_activated(LINK(this, SvtFileView_Impl, ItemActivatedHdl));
}

void SvtFileView_Impl::OpenFolder_Impl()
{
    ::osl::MutexGuard aGuard( maMutex );

    mxView->freeze();
    mxIconView->freeze();
    maEntries.clear();
    mxView->clear();
    mxIconView->clear();

    for (auto const& elem : maContent)
    {
        if (mbOnlyFolder && !elem->mbIsFolder)
            continue;

        // insert entry and set user data
        maEntries.emplace_back(std::make_unique<SvtContentEntry>(elem->maTargetURL, elem->mbIsFolder));
        OUString sId(weld::toId(maEntries.back().get()));
        mxView->append(sId, elem->maDisplayName, elem->maType, elem->maDisplaySize, elem->maDisplayDate, elem->maImage);
        mxIconView->append(sId, elem->maDisplayName, elem->maImage);
    }

    ++mnSuspendSelectCallback;
    mxView->thaw();

    //set sort indicator
    weld::TreeView* pView = mxView->getWidget();
    pView->set_sort_indicator(mbAscending ? TRISTATE_TRUE : TRISTATE_FALSE, GetSortColumn());

    mxIconView->thaw();
    --mnSuspendSelectCallback;

    ResetCursor();
}

void SvtFileView_Impl::ResetCursor()
{
    if (mxView->get_visible())
    {
        std::unique_ptr<weld::TreeIter> xFirst = mxView->make_iterator();
        if (mxView->get_iter_first(*xFirst))
        {
            // set cursor to the first entry
            mxView->set_cursor(*xFirst);
        }
        // deselect
        mxView->unselect_all();
    }
    else
    {
        std::unique_ptr<weld::TreeIter> xFirst = mxIconView->make_iterator();
        if (mxIconView->get_iter_first(*xFirst))
        {
            // set cursor to the first entry
            mxIconView->set_cursor(*xFirst);
        }
        // deselect
        mxIconView->unselect_all();
    }
}

void SvtFileView_Impl::CancelRunningAsyncAction()
{
    DBG_TESTSOLARMUTEX();
    ::osl::MutexGuard aGuard( maMutex );
    if ( !m_xContentEnumerator.is() )
        return;

    m_bAsyncActionCancelled = true;
    m_xContentEnumerator->cancel();
    m_bRunningAsyncAction = false;

    m_xContentEnumerator.clear();
    if ( m_xCancelAsyncTimer.is() && m_xCancelAsyncTimer->isTicking() )
        m_xCancelAsyncTimer->stop();
    m_xCancelAsyncTimer.clear();
}


void SvtFileView_Impl::onTimeout()
{
    SolarMutexGuard aSolarGuard;
    ::osl::MutexGuard aGuard( maMutex );
    if ( !m_bRunningAsyncAction )
        // there might have been a race condition while we waited for the mutex
        return;

    CancelRunningAsyncAction();

    if ( m_aCurrentAsyncActionHandler.IsSet() )
    {
        Application::PostUserEvent( m_aCurrentAsyncActionHandler, reinterpret_castvoid* >( eTimeout ) );
        m_aCurrentAsyncActionHandler = Link<void*,void>();
    }
}


void SvtFileView_Impl::enumerationDone( ::svt::EnumerationResult eResult )
{
    SolarMutexGuard aSolarGuard;
    ::osl::MutexGuard aGuard( maMutex );

    m_xContentEnumerator.clear();
    if ( m_xCancelAsyncTimer.is() && m_xCancelAsyncTimer->isTicking() )
        m_xCancelAsyncTimer->stop();
    m_xCancelAsyncTimer.clear();

    if ( m_bAsyncActionCancelled )
        // this is to prevent race conditions
        return;

    m_eAsyncActionResult = eResult;
    m_bRunningAsyncAction = false;

    m_aAsyncActionFinished.set();

    if ( svt::EnumerationResult::SUCCESS == eResult )
        implEnumerationSuccess();

    if ( m_aCurrentAsyncActionHandler.IsSet() )
    {
        Application::PostUserEvent( m_aCurrentAsyncActionHandler, reinterpret_castvoid* >( m_eAsyncActionResult ) );
        m_aCurrentAsyncActionHandler = Link<void*,void>();
    }
}


void SvtFileView_Impl::implEnumerationSuccess()
{
    FilterFolderContent_Impl( maCurrentFilter );
    SortFolderContent_Impl();
    CreateDisplayText_Impl();
    OpenFolder_Impl();
    maOpenDoneLink.Call( m_pAntiImpl );
}

OUString SvtFileView_Impl::ReplaceTabWithString(const OUString& rValue)
{
    return rValue.replaceAll(u"\t", u"%09");
}

void SvtFileView_Impl::CreateDisplayText_Impl()
{
    ::osl::MutexGuard aGuard( maMutex );

    for (auto const& elem : maContent)
    {
        // title, type, size, date
        elem->maDisplayName = ReplaceTabWithString(elem->GetTitle());
        // folders don't have a size
        if ( ! elem->mbIsFolder )
            elem->maDisplaySize = CreateExactSizeText( elem->maSize );
        // set the date, but volumes have no date
        if ( ! elem->mbIsFolder || ! elem->mbIsVolume )
        {
            SvtSysLocale aSysLocale;
            const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
            elem->maDisplayDate = rLocaleData.getDate( elem->maModDate )
                                  + ", "
                                  + rLocaleData.getTime( elem->maModDate, false );
        }

        // detect image
        if ( elem->mbIsFolder )
        {
            ::svtools::VolumeInfo aVolInfo( elem->mbIsVolume, elem->mbIsRemote,
                                            elem->mbIsRemoveable, elem->mbIsFloppy,
                                            elem->mbIsCompactDisc );
            elem->maImage = SvFileInformationManager::GetFolderImageId(aVolInfo);
        }
        else
            elem->maImage = SvFileInformationManager::GetFileImageId(INetURLObject(elem->maTargetURL));
    }
}

void SvtFileView_Impl::Resort_Impl( sal_Int16 nColumn, bool bAscending )
{
    // TODO: IconView ()
    ::osl::MutexGuard aGuard( maMutex );

    if ( ( nColumn == mnSortColumn ) &&
         ( bAscending == mbAscending ) )
         return;

    // reset the quick search index
    mxView->ResetQuickSearch_Impl( nullptr );

    std::unique_ptr<weld::TreeIter> xEntry(mxView->make_iterator());
    bool bEntry = mxView->get_cursor(xEntry.get());

    OUString aEntryURL;
    if (bEntry && !mxView->get_id(*xEntry).isEmpty())
        aEntryURL = weld::fromId<SvtContentEntry*>(mxView->get_id(*xEntry))->maURL;

    mnSortColumn = nColumn;
    mbAscending = bAscending;

    SortFolderContent_Impl();
    OpenFolder_Impl();

    if ( !mbIsFirstResort )
    {
        int nPos = GetEntryPos( aEntryURL );
        if (nPos != -1 && nPos < mxView->n_children())
        {
            ++mnSuspendSelectCallback;  // #i15668#
            mxView->set_cursor(nPos);
            --mnSuspendSelectCallback;
        }
    }
    else
        mbIsFirstResort = false;
}

static bool                     gbAscending = true;
static sal_Int16                gnColumn = COLUMN_TITLE;
static const CollatorWrapper*   pCollatorWrapper = nullptr;

/* this function returns true, if aOne is less than aTwo
*/

static bool CompareSortingData_Impl( std::unique_ptr<SortingData_Impl> const & aOne, std::unique_ptr<SortingData_Impl> const & aTwo )
{
    assert(pCollatorWrapper && "*CompareSortingData_Impl(): Can't work this way!");

    sal_Int32 nComp;
    bool      bRet = false;
    bool      bEqual = false;

    if ( aOne->mbIsFolder != aTwo->mbIsFolder )
    {
        bRet = aOne->mbIsFolder;

        // !!! pb: #100376# folder always on top
        if ( !gbAscending )
            bRet = !bRet;
    }
    else
    {
        switch ( gnColumn )
        {
            case COLUMN_TITLE:
                // compare case insensitive first
                nComp = pCollatorWrapper->compareString( aOne->GetLowerTitle(), aTwo->GetLowerTitle() );

                if ( nComp == 0 )
                    nComp = pCollatorWrapper->compareString( aOne->GetTitle(), aTwo->GetTitle() );

                if ( nComp < 0 )
                    bRet = true;
                else if ( nComp > 0 )
                    bRet = false;
                else
                    bEqual = true;
                break;
            case COLUMN_TYPE:
                nComp = pCollatorWrapper->compareString( aOne->maType, aTwo->maType );
                if ( nComp < 0 )
                    bRet = true;
                else if ( nComp > 0 )
                    bRet = false;
                else
                    bEqual = true;
                break;
            case COLUMN_SIZE:
                if ( aOne->maSize < aTwo->maSize )
                    bRet = true;
                else if ( aOne->maSize > aTwo->maSize )
                    bRet = false;
                else
                    bEqual = true;
                break;
            case COLUMN_DATE:
                if ( aOne->maModDate < aTwo->maModDate )
                    bRet = true;
                else if ( aOne->maModDate > aTwo->maModDate )
                    bRet = false;
                else
                    bEqual = true;
                break;
            default:
                SAL_INFO( "svtools.contnr""CompareSortingData_Impl: Compare unknown type!" );
                bRet = false;
        }
    }

    // when the two elements are equal, we must not return sal_True (which would
    // happen if we just return ! ( a < b ) when not sorting ascending )
    if ( bEqual )
        return false;

    return gbAscending ? bRet : !bRet;
}


void SvtFileView_Impl::SortFolderContent_Impl()
{
    ::osl::MutexGuard aGuard( maMutex );

    if ( maContent.size() > 1 )
    {
        gbAscending = mbAscending;
        gnColumn = mnSortColumn;
        pCollatorWrapper = aIntlWrapper.getCaseCollator();

        std::stable_sort( maContent.begin(), maContent.end(), CompareSortingData_Impl );

        pCollatorWrapper = nullptr;
    }
}


void SvtFileView_Impl::EntryRemoved( std::u16string_view rURL )
{
    ::osl::MutexGuard aGuard( maMutex );

    maContent.erase(std::find_if(maContent.begin(), maContent.end(),
                     [&](const std::unique_ptr<SortingData_Impl> & data) { return data->maTargetURL == rURL; }));
}


void SvtFileView_Impl::EntryRenamed( OUString& rURL,
                                     const OUString& rTitle )
{
    ::osl::MutexGuard aGuard( maMutex );

    auto aFoundElem = std::find_if(maContent.begin(), maContent.end(),
                     [&](const std::unique_ptr<SortingData_Impl> & data) { return data->maTargetURL == rURL; });
    if (aFoundElem != maContent.end())
    {
        (*aFoundElem)->SetNewTitle( rTitle );
        (*aFoundElem)->maDisplayName = ReplaceTabWithString(rTitle);

        INetURLObject aURLObj( rURL );
        aURLObj.setName( rTitle, INetURLObject::EncodeMechanism::All );

        rURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );

        (*aFoundElem)->maTargetURL = rURL;
    }
}

const SortingData_Impl& SvtFileView_Impl::FolderInserted( const OUString& rURL, const OUString& rTitle )
{
    ::osl::MutexGuard aGuard( maMutex );

    std::unique_ptr<SortingData_Impl> pData(new SortingData_Impl);

    pData->SetNewTitle( rTitle );
    pData->maSize        = 0;
    pData->mbIsFolder    = true;
    pData->maTargetURL   = rURL;

    ::svtools::VolumeInfo aVolInfo;
    pData->maType = SvFileInformationManager::GetFolderDescription( aVolInfo );
    pData->maImage = SvFileInformationManager::GetFolderImageId( aVolInfo );

    // title, type, size, date
    pData->maDisplayName = ReplaceTabWithString(pData->GetTitle());
    // set the date
    SvtSysLocale aSysLocale;
    const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
    pData->maDisplayDate = rLocaleData.getDate( pData->maModDate )
                           + ", "
                           + rLocaleData.getTime( pData->maModDate );

    maContent.push_back( std::move(pData) );

    return *maContent.back();
}

int SvtFileView_Impl::GetEntryPos(std::u16string_view rURL)
{
    ::osl::MutexGuard aGuard( maMutex );

    auto aFoundElem = std::find_if(maContent.begin(), maContent.end(),
          [&](const std::unique_ptr<SortingData_Impl> & data) { return data->maTargetURL == rURL; });
    return aFoundElem != maContent.end() ? std::distance(maContent.begin(), aFoundElem) : -1;
}

void SvtFileView_Impl::SetViewMode( FileViewMode eMode )
{
    switch ( eMode )
    {
        case eDetailedList:
            mxView->show();
            mxIconView->hide();
            break;

        case eIcon:
            mxView->hide();
            mxIconView->show();
            break;

        default:
            mxView->show();
            mxIconView->hide();
    };
}

bool SvtFileView_Impl::SearchNextEntry( sal_uInt32& nIndex, std::u16string_view rTitle, bool bWrapAround )
{
    ::osl::MutexGuard aGuard( maMutex );

    sal_uInt32 nEnd = maContent.size();
    sal_uInt32 nStart = nIndex;
    while ( nIndex < nEnd )
    {
        SortingData_Impl* pData = maContent[ nIndex ].get();
        if ( pData->GetLowerTitle().startsWith( rTitle ) )
            return true;
        ++nIndex;
    }

    if ( bWrapAround )
    {
        nIndex = 0;
        while ( nIndex < nEnd && nIndex <= nStart )
        {
            SortingData_Impl* pData = maContent[ nIndex ].get();
            if ( pData->GetLowerTitle().startsWith( rTitle ) )
                return true;
            ++nIndex;
        }
    }

    return false;
}

namespace {
    void SAL_CALL CallbackTimer::onShot()
    {
        OSL_ENSURE( m_pTimeoutHandler, "CallbackTimer::onShot: nobody interested in?" );
        SvtFileView_Impl* pHandler( m_pTimeoutHandler );
        if ( pHandler )
            pHandler->onTimeout();
    }
}

void SvtFileView::selected_foreach(const std::function<bool(weld::TreeIter&)>& func)
{
    if (mpImpl->mxView->get_visible())
        mpImpl->mxView->selected_foreach(func);
    else
        mpImpl->mxIconView->selected_foreach(func);
}

weld::Widget* SvtFileView::identifier() const
{
    return mpImpl->mxView->getWidget();
}

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

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

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet)  ¤

*© 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.