1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 #include <osl/diagnose.h>
23 #include <svtools/svtresid.hxx>
24 #include <svtools/imagemgr.hxx>
25 #include <svtools/querydelete.hxx>
26 #include <svtools/strings.hrc>
27 #include <bitmaps.hlst>
28 #include <toolkit/helper/vclunohelper.hxx>
29 #include "contentenumeration.hxx"
30 #include <com/sun/star/task/InteractionHandler.hpp>
31 #include <com/sun/star/ucb/XProgressHandler.hpp>
32 #include <com/sun/star/ucb/XContent.hpp>
33 #include <com/sun/star/container/XChild.hpp>
34 #include <com/sun/star/ucb/CommandAbortedException.hpp>
35 #include <com/sun/star/ucb/XCommandInfo.hpp>
36 #include <com/sun/star/beans/XPropertySetInfo.hpp>
37 #include <com/sun/star/beans/PropertyAttribute.hpp>
38 
39 #include <algorithm>
40 #include <vector>
41 #include <tools/debug.hxx>
42 #include <tools/urlobj.hxx>
43 #include <comphelper/processfactory.hxx>
44 #include <comphelper/string.hxx>
45 #include <ucbhelper/content.hxx>
46 #include <ucbhelper/commandenvironment.hxx>
47 #include <rtl/math.hxx>
48 #include <o3tl/typed_flags_set.hxx>
49 #include <osl/mutex.hxx>
50 #include <osl/conditn.hxx>
51 #include <salhelper/timer.hxx>
52 #include <svtools/urlfilter.hxx>
53 #include <unotools/collatorwrapper.hxx>
54 #include <unotools/localedatawrapper.hxx>
55 #include <unotools/intlwrapper.hxx>
56 #include <unotools/syslocale.hxx>
57 #include <vcl/svapp.hxx>
58 #include <vcl/commandevent.hxx>
59 #include <vcl/event.hxx>
60 #include <vcl/settings.hxx>
61 #include <vcl/timer.hxx>
62 #include <memory>
63 #include "fileview.hxx"
64 
65 using namespace ::com::sun::star::lang;
66 using namespace ::com::sun::star::sdbc;
67 using namespace ::com::sun::star::task;
68 using namespace ::com::sun::star::ucb;
69 using namespace ::com::sun::star::uno;
70 using namespace ::com::sun::star::io;
71 using namespace ::com::sun::star::beans;
72 using namespace ::comphelper;
73 using ::svt::SortingData_Impl;
74 using ::svt::FolderDescriptor;
75 
76 #define ALL_FILES_FILTER    "*.*"
77 
78 #define COLUMN_TITLE        1
79 #define COLUMN_TYPE         2
80 #define COLUMN_SIZE         3
81 #define COLUMN_DATE         4
82 
83 #define QUICK_SEARCH_TIMEOUT    1500    // time in mSec before the quicksearch string will be reset
84 
85 enum class FileViewFlags
86 {
87     NONE               = 0x00,
88     MULTISELECTION     = 0x02,
89     SHOW_TYPE          = 0x04,
90     SHOW_NONE          = 0x20,
91 };
92 namespace o3tl
93 {
94     template<> struct typed_flags<FileViewFlags> : is_typed_flags<FileViewFlags, 0x26> {};
95 }
96 
97 namespace
98 {
99 
100     //= CallbackTimer
101 
102     class CallbackTimer : public ::salhelper::Timer
103     {
104     protected:
105         SvtFileView_Impl* const m_pTimeoutHandler;
106 
107     public:
CallbackTimer(SvtFileView_Impl * _pHandler)108         explicit CallbackTimer( SvtFileView_Impl* _pHandler ) : m_pTimeoutHandler( _pHandler ) { }
109 
110     protected:
111         virtual void SAL_CALL onShot() override;
112     };
113 
114 
115 }
116 
117 class ViewTabListBox_Impl
118 {
119 private:
120     Reference< XCommandEnvironment >    mxCmdEnv;
121     std::unique_ptr<weld::TreeView> mxTreeView;
122     std::unique_ptr<weld::TreeIter> mxScratchIter;
123 
124     ::osl::Mutex            maMutex;
125     SvtFileView_Impl*       mpParent;
126     Timer                   maResetQuickSearch;
127     OUString                maQuickSearchText;
128     sal_uInt32              mnSearchIndex;
129     bool                    mbEnableDelete;
130     bool                    mbEditing;
131     bool const              mbShowType;
132 
133     void            DeleteEntries();
134     void            DoQuickSearch( sal_Unicode rChar );
135     bool            Kill( const OUString& rURL );
136 
137 public:
138     ViewTabListBox_Impl(std::unique_ptr<weld::TreeView> xTreeView, weld::Window* pTopLevel, SvtFileView_Impl* pParent, FileViewFlags nFlags);
139 
make_iterator() const140     std::unique_ptr<weld::TreeIter> make_iterator() const { return mxTreeView->make_iterator(); }
insert(const OUString & rEntry,const OUString & rId,const OUString & rImage,weld::TreeIter & rIter)141     void insert(const OUString &rEntry, const OUString& rId, const OUString& rImage, weld::TreeIter& rIter)
142     {
143         mxTreeView->insert(nullptr, -1, &rEntry, &rId, nullptr, nullptr, &rImage, false, &rIter);
144     }
append(const OUString & rId,const OUString & rStr,const OUString & rType,const OUString & rSize,const OUString & rDate,const OUString & rImage)145     void append(const OUString& rId, const OUString& rStr, const OUString& rType, const OUString& rSize, const OUString& rDate, const OUString& rImage)
146     {
147         mxTreeView->insert(nullptr, -1, &rStr, &rId, nullptr, nullptr, &rImage, false, mxScratchIter.get());
148         int nCol = 1;
149         if (mbShowType)
150             mxTreeView->set_text(*mxScratchIter, rType, nCol++);
151         mxTreeView->set_text(*mxScratchIter, rSize, nCol++);
152         mxTreeView->set_text(*mxScratchIter, rDate, nCol++);
153     }
154 
scroll_to_row(const weld::TreeIter & rIter)155     void scroll_to_row(const weld::TreeIter& rIter) { mxTreeView->scroll_to_row(rIter); }
set_cursor(int nPos)156     void set_cursor(int nPos) { mxTreeView->set_cursor(nPos); }
set_cursor(const weld::TreeIter & rIter)157     void set_cursor(const weld::TreeIter& rIter) { mxTreeView->set_cursor(rIter); }
get_cursor(weld::TreeIter * pIter) const158     bool get_cursor(weld::TreeIter* pIter) const { return mxTreeView->get_cursor(pIter); }
get_iter_first(weld::TreeIter & rIter) const159     bool get_iter_first(weld::TreeIter& rIter) const { return mxTreeView->get_iter_first(rIter); }
get_selected(weld::TreeIter * pIter) const160     bool get_selected(weld::TreeIter* pIter) const { return mxTreeView->get_selected(pIter); }
161 
get_selected_text() const162     OUString get_selected_text() const
163     {
164         // tdf#131898 only care about column 0
165         int nIndex = mxTreeView->get_selected_index();
166         return nIndex != -1 ? mxTreeView->get_text(nIndex, 0) : OUString();
167     }
168 
unselect_all()169     void unselect_all() { mxTreeView->unselect_all(); }
170 
get_id(const weld::TreeIter & rIter)171     OUString get_id(const weld::TreeIter& rIter) { return mxTreeView->get_id(rIter); }
172 
connect_row_activated(const Link<weld::TreeView &,bool> & rLink)173     void connect_row_activated(const Link<weld::TreeView&, bool>& rLink) { mxTreeView->connect_row_activated(rLink); }
connect_changed(const Link<weld::TreeView &,void> & rLink)174     void connect_changed(const Link<weld::TreeView&, void>& rLink) { mxTreeView->connect_changed(rLink); }
175 
n_children() const176     int n_children() const { return mxTreeView->n_children(); }
177 
freeze()178     void freeze() { mxTreeView->freeze(); }
thaw()179     void thaw() { mxTreeView->thaw(); }
180 
show()181     void show() { mxTreeView->show(); }
hide()182     void hide() { mxTreeView->hide(); }
get_visible() const183     bool get_visible() const { return mxTreeView->get_visible(); }
184 
count_selected_rows() const185     int count_selected_rows() const { return mxTreeView->count_selected_rows(); }
186 
grab_focus()187     void grab_focus() { mxTreeView->grab_focus(); }
has_focus() const188     bool has_focus() const { return mxTreeView->has_focus(); }
189 
set_help_id(const OString & rHelpId)190     void set_help_id(const OString& rHelpId) { mxTreeView->set_help_id(rHelpId); }
get_help_id() const191     OString get_help_id() const { return mxTreeView->get_help_id(); }
192 
IsEditingActive() const193     bool IsEditingActive() const { return mbEditing; }
194 
end_editing()195     void end_editing()
196     {
197         mxTreeView->end_editing();
198         mxTreeView->connect_editing(Link<const weld::TreeIter&, bool>(), Link<const IterString&, bool>());
199         mbEditing = false;
200     }
201 
selected_foreach(const std::function<bool (weld::TreeIter &)> & func)202     void selected_foreach(const std::function<bool(weld::TreeIter&)>& func)
203     {
204         mxTreeView->selected_foreach(func);
205     }
206 
getWidget() const207     weld::TreeView* getWidget() const
208     {
209         return mxTreeView.get();
210     }
211 
clear()212     void            clear() { mxTreeView->clear(); }
213 
EnableDelete(bool bEnable)214     void            EnableDelete( bool bEnable ) { mbEnableDelete = bEnable; }
TypeColumnVisible() const215     bool            TypeColumnVisible() const { return mbShowType; }
216 
GetCommandEnvironment() const217     const Reference< XCommandEnvironment >& GetCommandEnvironment() const { return mxCmdEnv; }
218 
219     DECL_LINK(ResetQuickSearch_Impl, Timer *, void);
220     DECL_LINK(CommandHdl, const CommandEvent&, bool);
221     DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool);
222     typedef std::pair<const weld::TreeIter&, OUString> IterString;
223     DECL_LINK(EditedEntryHdl, const IterString&, bool);
224     DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
225 
226     void            ExecuteContextMenuAction(const OString& rSelectedPopentry);
227 };
228 
229 //= SvtFileView_Impl
230 class SvtFileView_Impl  :public ::svt::IEnumerationResultHandler
231 {
232 protected:
233     SvtFileView*                        m_pAntiImpl;
234     Link<SvtFileView*,void>             m_aSelectHandler;
235 
236     ::rtl::Reference< ::svt::FileViewContentEnumerator >
237                                         m_xContentEnumerator;
238     Link<void*,void>                    m_aCurrentAsyncActionHandler;
239     ::osl::Condition                    m_aAsyncActionFinished;
240     ::rtl::Reference< ::salhelper::Timer > m_xCancelAsyncTimer;
241     ::svt::EnumerationResult            m_eAsyncActionResult;
242     bool                                m_bRunningAsyncAction;
243     bool                                m_bAsyncActionCancelled;
244 
245 public:
246 
247     ::std::vector<std::unique_ptr<SortingData_Impl>>  maContent;
248     ::std::vector<std::unique_ptr<SvtContentEntry>> maEntries;
249     ::osl::Mutex                        maMutex;
250 
251     weld::Window*           m_pTopLevel;
252     std::unique_ptr<ViewTabListBox_Impl> mxView;
253     std::unique_ptr<weld::IconView> mxIconView;
254     sal_uInt16              mnSortColumn;
255     bool                    mbAscending     : 1;
256     bool const              mbOnlyFolder    : 1;
257     sal_Int16               mnSuspendSelectCallback : 1;
258     bool                    mbIsFirstResort : 1;
259 
260     IntlWrapper const       aIntlWrapper;
261 
262     OUString                maViewURL;
263     OUString                maCurrentFilter;
264     OUString                maFolderImage;
265     Link<SvtFileView*,void> maOpenDoneLink;
266     Link<SvtFileView*,bool> maDoubleClickHandler;
267 
268     Reference< XCommandEnvironment >    mxCmdEnv;
269 
270     SvtFileView_Impl(SvtFileView* pAntiImpl, weld::Window* pTopLevel,
271                      std::unique_ptr<weld::TreeView> xTreeView,
272                      std::unique_ptr<weld::IconView> xIconView,
273                      Reference < XCommandEnvironment > const & xEnv,
274                      FileViewFlags nFlags,
275                      bool bOnlyFolder);
276 
277     virtual ~SvtFileView_Impl();
278 
279     void                    Clear();
280 
281     FileViewResult          GetFolderContent_Impl(
282         const OUString& rFolder,
283         const FileViewAsyncAction* pAsyncDescriptor,
284         const css::uno::Sequence< OUString >& rBlackList );
285 
286     FileViewResult          GetFolderContent_Impl(
287         const FolderDescriptor& _rFolder,
288         const FileViewAsyncAction* pAsyncDescriptor,
289         const css::uno::Sequence< OUString >& rBlackList );
290     void                    FilterFolderContent_Impl( const OUString &rFilter );
291     void                    CancelRunningAsyncAction();
292 
293     void                    OpenFolder_Impl();
294     static OUString         ReplaceTabWithString(const OUString& rValue);
295     void                    CreateDisplayText_Impl();
296     void                    SortFolderContent_Impl();
297 
298     void                    EntryRemoved( const OUString& rURL );
299     void                    EntryRenamed( OUString& rURL,
300                                           const OUString& rName );
301     const SortingData_Impl& FolderInserted( const OUString& rURL,
302                                             const OUString& rTitle );
303 
304     int                     GetEntryPos( const OUString& rURL );
305 
306     void                    SetViewMode( FileViewMode eMode );
307 
308     inline void             EnableDelete( bool bEnable );
309 
310     void                    Resort_Impl( sal_Int16 nColumn, bool bAscending );
311     bool                    SearchNextEntry( sal_uInt32 &nIndex,
312                                              const OUString& rTitle,
313                                              bool bWrapAround );
314 
315     void                    SetSelectHandler( const Link<SvtFileView*,void>& rHdl );
316     void                    SetDoubleClickHandler(const Link<SvtFileView*,bool>& rHdl);
317 
318     void                    ResetCursor();
319 
EndEditing()320     void EndEditing()
321     {
322         if (mxView->IsEditingActive())
323             mxView->end_editing();
324     }
325 
326     void onTimeout();
327 
grab_focus()328     void grab_focus()
329     {
330         if (mxView->get_visible())
331             mxView->grab_focus();
332         else
333             mxIconView->grab_focus();
334     }
335 
has_focus() const336     bool has_focus() const
337     {
338         return mxView->has_focus() || mxIconView->has_focus();
339     }
340 
GetSortColumn() const341     int GetSortColumn() const
342     {
343         sal_uInt16 nOldSortID = mnSortColumn;
344         // skip "TYPE"
345         if (!mxView->TypeColumnVisible() && nOldSortID != COLUMN_TITLE)
346             --nOldSortID;
347         return nOldSortID - 1;
348     }
349 
350 protected:
351     DECL_LINK(ChangedHdl, weld::TreeView&, void);
352     DECL_LINK(SelectionChangedHdl, weld::IconView&, void);
353     DECL_LINK(RowActivatedHdl, weld::TreeView&, bool);
354     DECL_LINK(ItemActivatedHdl, weld::IconView&, bool);
355 
356     // IEnumerationResultHandler overridables
357     virtual void        enumerationDone( ::svt::EnumerationResult eResult ) override;
358             void        implEnumerationSuccess();
359 };
360 
EnableDelete(bool bEnable)361 inline void SvtFileView_Impl::EnableDelete( bool bEnable )
362 {
363     mxView->EnableDelete( bEnable );
364 }
365 
366 namespace
367 {
368     // functions -------------------------------------------------------------
369 
CreateExactSizeText(sal_Int64 nSize)370     OUString CreateExactSizeText( sal_Int64 nSize )
371     {
372         double fSize( static_cast<double>(nSize) );
373         int nDec;
374 
375         long nMega = 1024 * 1024;
376         long nGiga = nMega * 1024;
377 
378         OUString aUnitStr(' ');
379 
380         if ( nSize < 10000 )
381         {
382             aUnitStr += SvtResId(STR_SVT_BYTES );
383             nDec = 0;
384         }
385         else if ( nSize < nMega )
386         {
387             fSize /= 1024;
388             aUnitStr += SvtResId(STR_SVT_KB);
389             nDec = 1;
390         }
391         else if ( nSize < nGiga )
392         {
393             fSize /= nMega;
394             aUnitStr += SvtResId(STR_SVT_MB);
395             nDec = 2;
396         }
397         else
398         {
399             fSize /= nGiga;
400             aUnitStr += SvtResId(STR_SVT_GB);
401             nDec = 3;
402         }
403 
404         OUString aSizeStr( ::rtl::math::doubleToUString( fSize,
405                     rtl_math_StringFormat_F, nDec,
406                     SvtSysLocale().GetLocaleData().getNumDecimalSep()[0]) );
407         aSizeStr += aUnitStr;
408 
409         return aSizeStr;
410     }
411 }
412 
ViewTabListBox_Impl(std::unique_ptr<weld::TreeView> xTreeView,weld::Window * pTopLevel,SvtFileView_Impl * pParent,FileViewFlags nFlags)413 ViewTabListBox_Impl::ViewTabListBox_Impl(std::unique_ptr<weld::TreeView> xTreeView,
414                                          weld::Window* pTopLevel,
415                                          SvtFileView_Impl* pParent,
416                                          FileViewFlags nFlags)
417     : mxTreeView(std::move(xTreeView))
418     , mxScratchIter(mxTreeView->make_iterator())
419     , mpParent( pParent )
420     , mnSearchIndex( 0 )
421     , mbEnableDelete( false )
422     , mbEditing( false )
423     , mbShowType(nFlags & FileViewFlags::SHOW_TYPE)
424 {
425     std::vector<int> aWidths;
426     aWidths.push_back(180);
427     if (nFlags & FileViewFlags::SHOW_TYPE)
428         aWidths.push_back(140);
429     aWidths.push_back(80);
430     mxTreeView->set_column_fixed_widths(aWidths);
431 
432     if (nFlags & FileViewFlags::MULTISELECTION)
433         mxTreeView->set_selection_mode(SelectionMode::Multiple);
434 
435     maResetQuickSearch.SetTimeout( QUICK_SEARCH_TIMEOUT );
436     maResetQuickSearch.SetInvokeHandler( LINK( this, ViewTabListBox_Impl, ResetQuickSearch_Impl ) );
437 
438     Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
439     Reference< XInteractionHandler > xInteractionHandler(
440         InteractionHandler::createWithParent(xContext, pTopLevel->GetXWindow()), UNO_QUERY_THROW);
441 
442     mxCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() );
443 
444     mxTreeView->connect_popup_menu(LINK(this, ViewTabListBox_Impl, CommandHdl));
445     mxTreeView->connect_key_press(LINK(this, ViewTabListBox_Impl, KeyInputHdl));
446 }
447 
IMPL_LINK_NOARG(ViewTabListBox_Impl,EditingEntryHdl,const weld::TreeIter &,bool)448 IMPL_LINK_NOARG(ViewTabListBox_Impl, EditingEntryHdl, const weld::TreeIter&, bool)
449 {
450     return mbEditing;
451 }
452 
IMPL_LINK_NOARG(ViewTabListBox_Impl,ResetQuickSearch_Impl,Timer *,void)453 IMPL_LINK_NOARG(ViewTabListBox_Impl, ResetQuickSearch_Impl, Timer *, void)
454 {
455     ::osl::MutexGuard aGuard( maMutex );
456 
457     maQuickSearchText.clear();
458     mnSearchIndex = 0;
459 }
460 
IMPL_LINK(ViewTabListBox_Impl,KeyInputHdl,const KeyEvent &,rKEvt,bool)461 IMPL_LINK(ViewTabListBox_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
462 {
463     if (mbEditing)
464         return false;
465 
466     bool bHandled = false;
467 
468     const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
469     if ( 0 == rKeyCode.GetModifier() )
470     {
471         if ( ( rKeyCode.GetCode() == KEY_DELETE ) &&
472                   mbEnableDelete )
473         {
474             ResetQuickSearch_Impl( nullptr );
475             DeleteEntries();
476             bHandled = true;
477         }
478         else if ( ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_NUM ) ||
479                   ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_ALPHA ) )
480         {
481             DoQuickSearch( rKEvt.GetCharCode() );
482             bHandled = true;
483         }
484     }
485 
486     if (!bHandled)
487         ResetQuickSearch_Impl( nullptr );
488     return bHandled;
489 }
490 
IMPL_LINK(ViewTabListBox_Impl,CommandHdl,const CommandEvent &,rCEvt,bool)491 IMPL_LINK(ViewTabListBox_Impl, CommandHdl, const CommandEvent&, rCEvt, bool)
492 {
493     if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
494         return false;
495 
496     bool bEnableDelete = mbEnableDelete;
497     bool bEnableRename = true;
498 
499     int nCount = 0;
500     mxTreeView->selected_foreach([this, &nCount, &bEnableDelete, &bEnableRename](weld::TreeIter& rEntry){
501         ++nCount;
502 
503         ::ucbhelper::Content aCnt;
504         try
505         {
506             OUString aURL(reinterpret_cast<SvtContentEntry*>(
507                 mxTreeView->get_id(rEntry).toInt64())->maURL);
508             aCnt = ::ucbhelper::Content( aURL, mxCmdEnv, comphelper::getProcessComponentContext() );
509         }
510         catch( Exception const & )
511         {
512             bEnableDelete = bEnableRename = false;
513         }
514 
515         if ( bEnableDelete )
516         {
517             try
518             {
519                 Reference< XCommandInfo > aCommands = aCnt.getCommands();
520                 if ( aCommands.is() )
521                     bEnableDelete = aCommands->hasCommandByName( "delete" );
522                 else
523                     bEnableDelete = false;
524             }
525             catch( Exception const & )
526             {
527                 bEnableDelete = false;
528             }
529         }
530 
531         if ( bEnableRename )
532         {
533             try
534             {
535                 Reference< XPropertySetInfo > aProps = aCnt.getProperties();
536                 if ( aProps.is() )
537                 {
538                     Property aProp = aProps->getPropertyByName("Title");
539                     bEnableRename
540                         = !( aProp.Attributes & PropertyAttribute::READONLY );
541                 }
542                 else
543                     bEnableRename = false;
544             }
545             catch( Exception const & )
546             {
547                 bEnableRename = false;
548             }
549         }
550 
551         bool bStop = !bEnableDelete && !bEnableRename;
552         return bStop;
553     });
554 
555     if (nCount == 0)
556         bEnableDelete = false;
557     if (nCount != 1)
558         bEnableRename = false;
559 
560     if (bEnableDelete || bEnableRename)
561     {
562         std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(mxTreeView.get(), "svt/ui/fileviewmenu.ui"));
563         auto xContextMenu = xBuilder->weld_menu("menu");
564         xContextMenu->set_visible("delete", bEnableDelete);
565         xContextMenu->set_visible("rename", bEnableRename);
566         OString sCommand(xContextMenu->popup_at_rect(mxTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
567         ExecuteContextMenuAction(sCommand);
568     }
569 
570     return true;
571 }
572 
ExecuteContextMenuAction(const OString & rSelectedPopupEntry)573 void ViewTabListBox_Impl::ExecuteContextMenuAction(const OString& rSelectedPopupEntry)
574 {
575     if (rSelectedPopupEntry == "delete")
576         DeleteEntries();
577     else if (rSelectedPopupEntry == "rename")
578     {
579         std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
580         if (mxTreeView->get_selected(xEntry.get()))
581         {
582             mbEditing = true;
583 
584             mxTreeView->connect_editing(LINK(this, ViewTabListBox_Impl, EditingEntryHdl),
585                                         LINK(this, ViewTabListBox_Impl, EditedEntryHdl));
586 
587             mxTreeView->start_editing(*xEntry);
588         }
589     }
590 }
591 
DeleteEntries()592 void ViewTabListBox_Impl::DeleteEntries()
593 {
594     short eResult = svtools::QUERYDELETE_YES;
595 
596     mxTreeView->selected_foreach([this, &eResult](weld::TreeIter& rCurEntry){
597         OUString aURL;
598         if (!mxTreeView->get_id(rCurEntry).isEmpty())
599             aURL = reinterpret_cast<SvtContentEntry*>(mxTreeView->get_id(rCurEntry).toInt64())->maURL;
600         if (aURL.isEmpty())
601         {
602             mxTreeView->unselect(rCurEntry);
603             return false;
604         }
605 
606         bool canDelete = true;
607         try
608         {
609             ::ucbhelper::Content aCnt( aURL, mxCmdEnv, comphelper::getProcessComponentContext() );
610             Reference< XCommandInfo > aCommands = aCnt.getCommands();
611             if ( aCommands.is() )
612                 canDelete = aCommands->hasCommandByName( "delete" );
613             else
614                 canDelete = false;
615         }
616         catch( Exception const & )
617         {
618             canDelete = false;
619         }
620 
621         if (!canDelete)
622         {
623             mxTreeView->unselect(rCurEntry);
624             return false; // process next entry
625         }
626 
627         if ( eResult != svtools::QUERYDELETE_ALL )
628         {
629             INetURLObject aObj( aURL );
630             svtools::QueryDeleteDlg_Impl aDlg(
631                 mxTreeView.get(), aObj.GetLastName(INetURLObject::DecodeMechanism::WithCharset));
632 
633             if (mxTreeView->count_selected_rows() > 1)
634                 aDlg.EnableAllButton();
635 
636             eResult = aDlg.run();
637         }
638 
639         if ( ( eResult == svtools::QUERYDELETE_ALL ) ||
640              ( eResult == svtools::QUERYDELETE_YES ) )
641         {
642             if ( Kill( aURL ) )
643             {
644                 delete reinterpret_cast<SvtContentEntry*>(mxTreeView->get_id(rCurEntry).toInt64());
645                 mpParent->EntryRemoved( aURL );
646             }
647         }
648 
649         return false;
650     });
651 
652     mxTreeView->remove_selection();
653 }
654 
IMPL_LINK(ViewTabListBox_Impl,EditedEntryHdl,const IterString &,rIterString,bool)655 IMPL_LINK(ViewTabListBox_Impl, EditedEntryHdl, const IterString&, rIterString, bool)
656 {
657     mbEditing = false;
658 
659     mxTreeView->connect_editing(Link<const weld::TreeIter&, bool>(), Link<const IterString&, bool>());
660 
661     const weld::TreeIter& rEntry = rIterString.first;
662     OUString sNewText = rIterString.second;
663 
664     if (sNewText.isEmpty())
665         return false;
666 
667     bool bRet = false;
668 
669     OUString aURL;
670     SvtContentEntry* pData = reinterpret_cast<SvtContentEntry*>(mxTreeView->get_id(rEntry).toInt64());
671 
672     if ( pData )
673         aURL = pData->maURL;
674 
675     if ( aURL.isEmpty() )
676         return bRet;
677 
678     try
679     {
680         OUString aPropName( "Title" );
681         bool canRename = true;
682         ::ucbhelper::Content aContent( aURL, mxCmdEnv, comphelper::getProcessComponentContext() );
683 
684         try
685         {
686             Reference< XPropertySetInfo > aProps = aContent.getProperties();
687             if ( aProps.is() )
688             {
689                 Property aProp = aProps->getPropertyByName( aPropName );
690                 canRename = !( aProp.Attributes & PropertyAttribute::READONLY );
691             }
692             else
693             {
694                 canRename = false;
695             }
696         }
697         catch ( Exception const & )
698         {
699             canRename = false;
700         }
701 
702         if ( canRename )
703         {
704             Any aValue;
705             aValue <<= sNewText;
706             aContent.setPropertyValue( aPropName, aValue );
707             mpParent->EntryRenamed(aURL, sNewText);
708 
709             if (pData)
710                 pData->maURL = aURL;
711 
712             mxTreeView->set_id(rEntry, OUString::number(reinterpret_cast<sal_Int64>(pData)));
713 
714             bRet = true;
715         }
716     }
717     catch( Exception const & )
718     {
719     }
720 
721     return bRet;
722 }
723 
DoQuickSearch(sal_Unicode rChar)724 void ViewTabListBox_Impl::DoQuickSearch( sal_Unicode rChar )
725 {
726     ::osl::MutexGuard aGuard( maMutex );
727 
728     maResetQuickSearch.Stop();
729 
730     OUString    aLastText = maQuickSearchText;
731     sal_uInt32  aLastPos = mnSearchIndex;
732 
733     maQuickSearchText += OUString(rChar).toAsciiLowerCase();
734 
735     bool bFound = mpParent->SearchNextEntry( mnSearchIndex, maQuickSearchText, false );
736 
737     if ( !bFound && ( aLastText.getLength() == 1 ) &&
738          ( aLastText == OUStringChar(rChar) ) )
739     {
740         mnSearchIndex = aLastPos + 1;
741         maQuickSearchText = aLastText;
742         bFound = mpParent->SearchNextEntry( mnSearchIndex, maQuickSearchText, true );
743     }
744 
745     if (bFound)
746     {
747         mxTreeView->unselect_all();
748         mxTreeView->select(mnSearchIndex);
749         mxTreeView->set_cursor(mnSearchIndex);
750         mxTreeView->scroll_to_row(mnSearchIndex);
751     }
752 
753     maResetQuickSearch.Start();
754 }
755 
Kill(const OUString & rContent)756 bool ViewTabListBox_Impl::Kill( const OUString& rContent )
757 {
758     bool bRet = true;
759 
760     try
761     {
762         ::ucbhelper::Content aCnt( rContent, mxCmdEnv, comphelper::getProcessComponentContext() );
763         aCnt.executeCommand( "delete", makeAny( true ) );
764     }
765     catch( css::ucb::CommandAbortedException const & )
766     {
767         SAL_INFO( "svtools.contnr", "CommandAbortedException" );
768         bRet = false;
769     }
770     catch( Exception const & )
771     {
772         SAL_INFO( "svtools.contnr", "Any other exception" );
773         bRet = false;
774     }
775 
776     return bRet;
777 }
778 
SvtFileView(weld::Window * pTopLevel,std::unique_ptr<weld::TreeView> xTreeView,std::unique_ptr<weld::IconView> xIconView,bool bOnlyFolder,bool bMultiSelection,bool bShowType)779 SvtFileView::SvtFileView(weld::Window* pTopLevel,
780                          std::unique_ptr<weld::TreeView> xTreeView,
781                          std::unique_ptr<weld::IconView> xIconView,
782                          bool bOnlyFolder, bool bMultiSelection, bool bShowType )
783 {
784     FileViewFlags nFlags = FileViewFlags::NONE;
785     if ( bMultiSelection )
786         nFlags |= FileViewFlags::MULTISELECTION;
787     if ( bShowType )
788         nFlags |= FileViewFlags::SHOW_TYPE;
789 
790     Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
791     Reference< XInteractionHandler > xInteractionHandler(
792         InteractionHandler::createWithParent(xContext, pTopLevel->GetXWindow()), UNO_QUERY_THROW);
793     Reference < XCommandEnvironment > xCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() );
794 
795     mpImpl.reset(new SvtFileView_Impl(this, pTopLevel, std::move(xTreeView), std::move(xIconView), xCmdEnv, nFlags, bOnlyFolder));
796 
797     weld::TreeView* pView = mpImpl->mxView->getWidget();
798     pView->connect_column_clicked(LINK(this, SvtFileView, HeaderSelect_Impl));
799 }
800 
grab_focus()801 void SvtFileView::grab_focus()
802 {
803     mpImpl->grab_focus();
804 }
805 
has_focus() const806 bool SvtFileView::has_focus() const
807 {
808     return mpImpl->has_focus();
809 }
810 
~SvtFileView()811 SvtFileView::~SvtFileView()
812 {
813 }
814 
SetViewMode(FileViewMode eMode)815 void SvtFileView::SetViewMode( FileViewMode eMode )
816 {
817     mpImpl->SetViewMode( eMode );
818 }
819 
GetURL(const weld::TreeIter & rEntry) const820 OUString SvtFileView::GetURL(const weld::TreeIter& rEntry) const
821 {
822     SvtContentEntry* pEntry;
823     if (mpImpl->mxView->get_visible())
824         pEntry = reinterpret_cast<SvtContentEntry*>(mpImpl->mxView->get_id(rEntry).toInt64());
825     else
826         pEntry = reinterpret_cast<SvtContentEntry*>(mpImpl->mxIconView->get_id(rEntry).toInt64());
827     if (pEntry)
828         return pEntry->maURL;
829     return OUString();
830 }
831 
GetCurrentURL() const832 OUString SvtFileView::GetCurrentURL() const
833 {
834     SvtContentEntry* pEntry = nullptr;
835     OUString aURL;
836     if (mpImpl->mxView->get_visible())
837     {
838         std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxView->make_iterator();
839         if (mpImpl->mxView->get_selected(xEntry.get()))
840             pEntry = reinterpret_cast<SvtContentEntry*>(mpImpl->mxView->get_id(*xEntry).toInt64());
841     }
842     else
843     {
844         std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxIconView->make_iterator();
845         if (mpImpl->mxIconView->get_selected(xEntry.get()))
846             pEntry = reinterpret_cast<SvtContentEntry*>(mpImpl->mxIconView->get_id(*xEntry).toInt64());
847     }
848     if (pEntry)
849         aURL = pEntry->maURL;
850     return aURL;
851 }
852 
CreatedFolder(const OUString & rUrl,const OUString & rNewFolder)853 void SvtFileView::CreatedFolder( const OUString& rUrl, const OUString& rNewFolder )
854 {
855     const SortingData_Impl& rEntry = mpImpl->FolderInserted( rUrl, rNewFolder );
856 
857     mpImpl->maEntries.emplace_back(std::make_unique<SvtContentEntry>(rUrl, true));
858     OUString sId(OUString::number(reinterpret_cast<sal_Int64>(mpImpl->maEntries.back().get())));
859 
860     std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxView->make_iterator();
861     mpImpl->mxView->insert(rEntry.maDisplayName, sId, mpImpl->maFolderImage, *xEntry);
862     mpImpl->mxView->scroll_to_row(*xEntry);
863 
864     std::unique_ptr<weld::TreeIter> xIconEntry = mpImpl->mxIconView->make_iterator();
865     mpImpl->mxIconView->insert(-1, &rEntry.maDisplayName, &sId, &mpImpl->maFolderImage, xIconEntry.get());
866     mpImpl->mxIconView->scroll_to_item(*xIconEntry);
867 }
868 
PreviousLevel(const FileViewAsyncAction * pAsyncDescriptor)869 FileViewResult SvtFileView::PreviousLevel( const FileViewAsyncAction* pAsyncDescriptor )
870 {
871     FileViewResult eResult = eFailure;
872 
873     OUString sParentURL;
874     if ( GetParentURL( sParentURL ) )
875         eResult = Initialize( sParentURL, mpImpl->maCurrentFilter, pAsyncDescriptor, maBlackList );
876 
877     return eResult;
878 }
879 
GetParentURL(OUString & rParentURL) const880 bool SvtFileView::GetParentURL( OUString& rParentURL ) const
881 {
882     bool bRet = false;
883     try
884     {
885         ::ucbhelper::Content aCnt( mpImpl->maViewURL, mpImpl->mxCmdEnv, comphelper::getProcessComponentContext() );
886         Reference< XContent > xContent( aCnt.get() );
887         Reference< css::container::XChild > xChild( xContent, UNO_QUERY );
888         if ( xChild.is() )
889         {
890             Reference< XContent > xParent( xChild->getParent(), UNO_QUERY );
891             if ( xParent.is() )
892             {
893                 rParentURL = xParent->getIdentifier()->getContentIdentifier();
894                 bRet = !rParentURL.isEmpty() && rParentURL != mpImpl->maViewURL;
895             }
896         }
897     }
898     catch( Exception const & )
899     {
900         // perhaps an unknown url protocol (e.g. "private:newdoc")
901     }
902 
903     return bRet;
904 }
905 
get_help_id() const906 OString SvtFileView::get_help_id() const
907 {
908     return mpImpl->mxView->get_help_id();
909 }
910 
set_help_id(const OString & rHelpId)911 void SvtFileView::set_help_id(const OString& rHelpId)
912 {
913     mpImpl->mxView->set_help_id(rHelpId);
914 }
915 
get_selected_text() const916 OUString SvtFileView::get_selected_text() const
917 {
918     if (mpImpl->mxView->get_visible())
919         return mpImpl->mxView->get_selected_text();
920     return mpImpl->mxIconView->get_selected_text();
921 }
922 
Initialize(const OUString & rURL,const OUString & rFilter,const FileViewAsyncAction * pAsyncDescriptor,const css::uno::Sequence<OUString> & rBlackList)923 FileViewResult SvtFileView::Initialize(
924     const OUString& rURL,
925     const OUString& rFilter,
926     const FileViewAsyncAction* pAsyncDescriptor,
927     const css::uno::Sequence< OUString >& rBlackList )
928 {
929     weld::WaitObject aWaitCursor(mpImpl->m_pTopLevel);
930     maBlackList = rBlackList;
931 
932     OUString sPushURL( mpImpl->maViewURL );
933 
934     mpImpl->maViewURL = rURL;
935     FileViewResult eResult = ExecuteFilter( rFilter, pAsyncDescriptor );
936     switch ( eResult )
937     {
938     case eFailure:
939     case eTimeout:
940         mpImpl->maViewURL = sPushURL;
941         return eResult;
942 
943     case eStillRunning:
944         OSL_ENSURE( pAsyncDescriptor, "SvtFileView::Initialize: we told it to read synchronously!" );
945         [[fallthrough]];
946     case eSuccess:
947         return eResult;
948     }
949 
950     OSL_FAIL( "SvtFileView::Initialize: unreachable!" );
951     return eFailure;
952 }
953 
ExecuteFilter(const OUString & rFilter,const FileViewAsyncAction * pAsyncDescriptor)954 FileViewResult SvtFileView::ExecuteFilter( const OUString& rFilter, const FileViewAsyncAction* pAsyncDescriptor )
955 {
956     mpImpl->maCurrentFilter = rFilter.toAsciiLowerCase();
957 
958     mpImpl->Clear();
959     FileViewResult eResult = mpImpl->GetFolderContent_Impl(mpImpl->maViewURL, pAsyncDescriptor, maBlackList);
960     OSL_ENSURE( ( eResult != eStillRunning ) || pAsyncDescriptor, "SvtFileView::ExecuteFilter: we told it to read synchronously!" );
961     return eResult;
962 }
963 
CancelRunningAsyncAction()964 void SvtFileView::CancelRunningAsyncAction()
965 {
966     mpImpl->CancelRunningAsyncAction();
967 }
968 
SetNoSelection()969 void SvtFileView::SetNoSelection()
970 {
971     mpImpl->mxView->unselect_all();
972     mpImpl->mxIconView->unselect_all();
973 }
974 
SetSelectHdl(const Link<SvtFileView *,void> & rHdl)975 void SvtFileView::SetSelectHdl(const Link<SvtFileView*,void>& rHdl)
976 {
977     mpImpl->SetSelectHandler(rHdl);
978 }
979 
SetDoubleClickHdl(const Link<SvtFileView *,bool> & rHdl)980 void SvtFileView::SetDoubleClickHdl(const Link<SvtFileView*,bool>& rHdl)
981 {
982     mpImpl->SetDoubleClickHandler(rHdl);
983 }
984 
GetSelectionCount() const985 sal_uInt32 SvtFileView::GetSelectionCount() const
986 {
987     if (mpImpl->mxView->get_visible())
988         return mpImpl->mxView->count_selected_rows();
989     return mpImpl->mxIconView->count_selected_items();
990 }
991 
FirstSelected() const992 SvtContentEntry* SvtFileView::FirstSelected() const
993 {
994     if (mpImpl->mxView->get_visible())
995     {
996         SvtContentEntry* pRet = nullptr;
997         std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxView->make_iterator();
998         if (mpImpl->mxView->get_selected(xEntry.get()))
999             pRet = reinterpret_cast<SvtContentEntry*>(mpImpl->mxView->get_id(*xEntry).toInt64());
1000         return pRet;
1001     }
1002 
1003     SvtContentEntry* pRet = nullptr;
1004     std::unique_ptr<weld::TreeIter> xEntry = mpImpl->mxIconView->make_iterator();
1005     if (mpImpl->mxIconView->get_selected(xEntry.get()))
1006         pRet = reinterpret_cast<SvtContentEntry*>(mpImpl->mxIconView->get_id(*xEntry).toInt64());
1007     return pRet;
1008 }
1009 
GetViewURL() const1010 const OUString& SvtFileView::GetViewURL() const
1011 {
1012     return mpImpl->maViewURL;
1013 }
1014 
SetOpenDoneHdl(const Link<SvtFileView *,void> & rHdl)1015 void SvtFileView::SetOpenDoneHdl( const Link<SvtFileView*,void>& rHdl )
1016 {
1017     mpImpl->maOpenDoneLink = rHdl;
1018 }
1019 
EnableDelete(bool bEnable)1020 void SvtFileView::EnableDelete( bool bEnable )
1021 {
1022     mpImpl->EnableDelete( bEnable );
1023 }
1024 
EndInplaceEditing()1025 void SvtFileView::EndInplaceEditing()
1026 {
1027     return mpImpl->EndEditing();
1028 }
1029 
IMPL_LINK(SvtFileView,HeaderSelect_Impl,int,nColumn,void)1030 IMPL_LINK(SvtFileView, HeaderSelect_Impl, int, nColumn, void)
1031 {
1032     sal_uInt16 nItemID = nColumn + 1;
1033     // skip "TYPE"
1034     if (!mpImpl->mxView->TypeColumnVisible() && nItemID != COLUMN_TITLE)
1035         ++nItemID;
1036 
1037     weld::TreeView* pView = mpImpl->mxView->getWidget();
1038     bool bSortAtoZ = mpImpl->mbAscending;
1039 
1040     //set new arrow positions in headerbar
1041     if (nItemID != mpImpl->mnSortColumn)
1042     {
1043         // remove old indicator, new will be created in OpenFolder_Impl
1044         pView->set_sort_indicator(TRISTATE_INDET, mpImpl->GetSortColumn());
1045     }
1046     else
1047         bSortAtoZ = !bSortAtoZ;
1048 
1049     mpImpl->Resort_Impl(nItemID, bSortAtoZ);
1050 }
1051 
GetConfigString() const1052 OUString SvtFileView::GetConfigString() const
1053 {
1054     // sort order
1055     OUString sRet = OUString::number( mpImpl->mnSortColumn ) + ";";
1056 
1057     bool bUp = mpImpl->mbAscending;
1058     sRet += (bUp ? OUStringLiteral("1") : OUStringLiteral("0")) + ";";
1059 
1060     weld::TreeView* pView = mpImpl->mxView->getWidget();
1061     sal_uInt16 nCount = mpImpl->mxView->TypeColumnVisible() ? 4 : 3;
1062     for (sal_uInt16 i = 0; i < nCount; ++i)
1063     {
1064         sal_uInt16 nId = i + 1;
1065         // skip "TYPE"
1066         if (!mpImpl->mxView->TypeColumnVisible() && nId != COLUMN_TITLE)
1067             ++nId;
1068 
1069         sRet += OUString::number( nId )
1070                 + ";"
1071                 + OUString::number(pView->get_column_width(i))
1072                 + ";";
1073     }
1074 
1075     return comphelper::string::stripEnd(sRet, ';');
1076 }
1077 
GetContent()1078 ::std::vector< SvtContentEntry > SvtFileView::GetContent()
1079 {
1080     ::std::vector< SvtContentEntry > aContent;
1081 
1082     for(auto const& elem : mpImpl->maContent)
1083     {
1084         SvtContentEntry aEntry( elem->maTargetURL, elem->mbIsFolder );
1085         aContent.push_back( aEntry );
1086     }
1087 
1088     return aContent;
1089 }
1090 
SetConfigString(const OUString & rCfgStr)1091 void SvtFileView::SetConfigString(const OUString& rCfgStr)
1092 {
1093     sal_Int32 nIdx = 0;
1094     mpImpl->mnSortColumn = static_cast<sal_uInt16>(rCfgStr.getToken( 0, ';', nIdx ).toInt32());
1095     mpImpl->mbAscending = static_cast<bool>(static_cast<sal_uInt16>(rCfgStr.getToken( 0, ';', nIdx ).toInt32()));
1096 
1097     std::vector<int> aWidths(mpImpl->mxView->TypeColumnVisible() ? 4 : 3, -1);
1098 
1099     while ( nIdx != -1 )
1100     {
1101         sal_uInt16 nItemId = static_cast<sal_uInt16>(rCfgStr.getToken( 0, ';', nIdx ).toInt32());
1102 
1103         int nWidth = rCfgStr.getToken( 0, ';', nIdx ).toInt32();
1104 
1105         // skip "TYPE"
1106         if (!mpImpl->mxView->TypeColumnVisible() && nItemId != COLUMN_TITLE)
1107             --nItemId;
1108         int nColumn = nItemId - 1;
1109 
1110         if (nColumn >= 0 && static_cast<unsigned int>(nColumn) < aWidths.size())
1111             aWidths[nColumn] = nWidth;
1112     }
1113 
1114     weld::TreeView* pView = mpImpl->mxView->getWidget();
1115     pView->set_column_fixed_widths(aWidths);
1116 }
1117 
1118 // class 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)1119 SvtFileView_Impl::SvtFileView_Impl(SvtFileView* pAntiImpl, weld::Window* pTopLevel,
1120                                    std::unique_ptr<weld::TreeView> xTreeView,
1121                                    std::unique_ptr<weld::IconView> xIconView,
1122                                    Reference < XCommandEnvironment > const & xEnv,
1123                                    FileViewFlags nFlags, bool bOnlyFolder)
1124     : m_pAntiImpl                ( pAntiImpl )
1125     , m_eAsyncActionResult       ( ::svt::EnumerationResult::ERROR )
1126     , m_bRunningAsyncAction      ( false )
1127     , m_bAsyncActionCancelled    ( false )
1128     , m_pTopLevel                ( pTopLevel )
1129     , mxView(new ViewTabListBox_Impl(std::move(xTreeView), pTopLevel, this, nFlags))
1130     , mxIconView(std::move(xIconView))
1131     , mnSortColumn               ( COLUMN_TITLE )
1132     , mbAscending                ( true )
1133     , mbOnlyFolder               ( bOnlyFolder )
1134     , mnSuspendSelectCallback    ( 0 )
1135     , mbIsFirstResort            ( true )
1136     , aIntlWrapper               ( Application::GetSettings().GetLanguageTag() )
1137     , maFolderImage              (RID_BMP_FOLDER)
1138     , mxCmdEnv ( xEnv )
1139 {
1140     weld::TreeView* pWidget = mxView->getWidget();
1141 
1142     // set the width to something small so its the parent that decides the final
1143     // width
1144     Size aSize(42, pWidget->get_height_rows(7));
1145     pWidget->set_size_request(aSize.Width(), aSize.Height());
1146     mxIconView->set_size_request(aSize.Width(), aSize.Height());
1147 }
1148 
~SvtFileView_Impl()1149 SvtFileView_Impl::~SvtFileView_Impl()
1150 {
1151     Clear();
1152 }
1153 
Clear()1154 void SvtFileView_Impl::Clear()
1155 {
1156     ::osl::MutexGuard aGuard( maMutex );
1157 
1158     maContent.clear();
1159 }
1160 
GetFolderContent_Impl(const OUString & rFolder,const FileViewAsyncAction * pAsyncDescriptor,const css::uno::Sequence<OUString> & rBlackList)1161 FileViewResult SvtFileView_Impl::GetFolderContent_Impl(
1162     const OUString& rFolder,
1163     const FileViewAsyncAction* pAsyncDescriptor,
1164     const css::uno::Sequence< OUString >& rBlackList )
1165 {
1166     ::osl::ClearableMutexGuard aGuard( maMutex );
1167     INetURLObject aFolderObj( rFolder );
1168     DBG_ASSERT( aFolderObj.GetProtocol() != INetProtocol::NotValid, "Invalid URL!" );
1169 
1170     FolderDescriptor aFolder( aFolderObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1171 
1172     aGuard.clear();
1173     return GetFolderContent_Impl( aFolder, pAsyncDescriptor, rBlackList );
1174 }
1175 
GetFolderContent_Impl(const FolderDescriptor & _rFolder,const FileViewAsyncAction * pAsyncDescriptor,const css::uno::Sequence<OUString> & rBlackList)1176 FileViewResult SvtFileView_Impl::GetFolderContent_Impl(
1177     const FolderDescriptor& _rFolder,
1178     const FileViewAsyncAction* pAsyncDescriptor,
1179     const css::uno::Sequence< OUString >& rBlackList )
1180 {
1181     DBG_TESTSOLARMUTEX();
1182     ::osl::ClearableMutexGuard aGuard( maMutex );
1183 
1184     OSL_ENSURE( !m_xContentEnumerator.is(), "SvtFileView_Impl::GetFolderContent_Impl: still running another enumeration!" );
1185     m_xContentEnumerator.set(new ::svt::FileViewContentEnumerator(
1186         mxView->GetCommandEnvironment(), maContent, maMutex));
1187         // TODO: should we cache and re-use this thread?
1188 
1189     if ( !pAsyncDescriptor )
1190     {
1191         ::svt::EnumerationResult eResult = m_xContentEnumerator->enumerateFolderContentSync( _rFolder, rBlackList );
1192         if ( ::svt::EnumerationResult::SUCCESS == eResult )
1193         {
1194             implEnumerationSuccess();
1195             m_xContentEnumerator.clear();
1196             return eSuccess;
1197         }
1198         m_xContentEnumerator.clear();
1199         return eFailure;
1200     }
1201 
1202     m_bRunningAsyncAction = true;
1203     m_bAsyncActionCancelled = false;
1204     m_eAsyncActionResult = ::svt::EnumerationResult::ERROR;
1205     m_aAsyncActionFinished.reset();
1206 
1207     // don't (yet) set m_aCurrentAsyncActionHandler to pTimeout->aFinishHandler.
1208     // By definition, this handler *only* gets called when the result cannot be obtained
1209     // during the minimum wait time, so it is only set below, when needed.
1210     m_aCurrentAsyncActionHandler = Link<void*,void>();
1211 
1212     // minimum time to wait
1213     std::unique_ptr< TimeValue > pTimeout( new TimeValue );
1214     sal_Int32 nMinTimeout = pAsyncDescriptor->nMinTimeout;
1215     OSL_ENSURE( nMinTimeout > 0, "SvtFileView_Impl::GetFolderContent_Impl: invalid minimum timeout!" );
1216     if ( nMinTimeout <= 0 )
1217         nMinTimeout = sal_Int32( 1000 );
1218     pTimeout->Seconds = nMinTimeout / 1000L;
1219     pTimeout->Nanosec = ( nMinTimeout % 1000L ) * 1000000L;
1220 
1221     m_xContentEnumerator->enumerateFolderContent( _rFolder, this );
1222 
1223     // wait until the enumeration is finished
1224     // for this, release our own mutex (which is used by the enumerator thread)
1225     aGuard.clear();
1226 
1227     ::osl::Condition::Result eResult = ::osl::Condition::result_ok;
1228     {
1229         // also release the SolarMutex. Not all code which is needed during the enumeration
1230         // is Solar-Thread-Safe, in particular there is some code which needs to access
1231         // string resources (and our resource system relies on the SolarMutex :()
1232         SolarMutexReleaser aSolarRelease;
1233 
1234         // now wait. Note that if we didn't get a pAsyncDescriptor, then this is an infinite wait.
1235         eResult = m_aAsyncActionFinished.wait( pTimeout.get() );
1236     }
1237 
1238     ::osl::MutexGuard aGuard2( maMutex );
1239     if ( ::osl::Condition::result_timeout == eResult )
1240     {
1241         // maximum time to wait
1242         OSL_ENSURE(!m_xCancelAsyncTimer,
1243                    "SvtFileView_Impl::GetFolderContent_Impl: there's still a previous timer!");
1244         m_xCancelAsyncTimer.set(new CallbackTimer(this));
1245         sal_Int32 nMaxTimeout = pAsyncDescriptor->nMaxTimeout;
1246         OSL_ENSURE( nMaxTimeout > nMinTimeout,
1247             "SvtFileView_Impl::GetFolderContent_Impl: invalid maximum timeout!" );
1248         if ( nMaxTimeout <= nMinTimeout )
1249             nMaxTimeout = nMinTimeout + 5000;
1250         m_xCancelAsyncTimer->setRemainingTime( salhelper::TTimeValue( nMaxTimeout - nMinTimeout ) );
1251             // we already waited for nMinTimeout milliseconds, so take this into account
1252         m_xCancelAsyncTimer->start();
1253 
1254         m_aCurrentAsyncActionHandler = pAsyncDescriptor->aFinishHandler;
1255         DBG_ASSERT( m_aCurrentAsyncActionHandler.IsSet(), "SvtFileView_Impl::GetFolderContent_Impl: nobody interested when it's finished?" );
1256         maEntries.clear();
1257         mxView->clear();
1258         mxIconView->clear();
1259         return eStillRunning;
1260     }
1261 
1262     m_bRunningAsyncAction = false;
1263     switch ( m_eAsyncActionResult )
1264     {
1265     case ::svt::EnumerationResult::SUCCESS:
1266         return eSuccess;
1267 
1268     case ::svt::EnumerationResult::ERROR:
1269         return eFailure;
1270     }
1271 
1272     SAL_WARN( "svtools.contnr", "SvtFileView_Impl::GetFolderContent_Impl: unreachable!" );
1273     return eFailure;
1274 }
1275 
FilterFolderContent_Impl(const OUString & rFilter)1276 void SvtFileView_Impl::FilterFolderContent_Impl( const OUString &rFilter )
1277 {
1278     if ( rFilter.isEmpty() || ( rFilter == ALL_FILES_FILTER ) )
1279         // when replacing names, there is always something to filter (no view of ".nametranslation.table")
1280         return;
1281 
1282     ::osl::MutexGuard aGuard( maMutex );
1283 
1284     if ( maContent.empty() )
1285         return;
1286 
1287     // collect the filter tokens
1288     ::std::vector< WildCard > aFilters;
1289     FilterMatch::createWildCardFilterList(rFilter,aFilters);
1290 
1291 
1292     // do the filtering
1293     maContent.erase(std::remove_if(maContent.begin(), maContent.end(),
1294         [&aFilters](const std::unique_ptr<SortingData_Impl>& rxContent) {
1295             if (rxContent->mbIsFolder)
1296                 return false;
1297             // normalize the content title (we always match case-insensitive)
1298             // 91872 - 11.09.2001 - frank.schoenheit@sun.com
1299             OUString sCompareString = rxContent->GetFileName(); // filter works on file name, not on title!
1300             return std::none_of(aFilters.begin(), aFilters.end(), FilterMatch(sCompareString));
1301         }),
1302         maContent.end());
1303 }
1304 
IMPL_LINK_NOARG(SvtFileView_Impl,ChangedHdl,weld::TreeView &,void)1305 IMPL_LINK_NOARG(SvtFileView_Impl, ChangedHdl, weld::TreeView&, void)
1306 {
1307     if (!mnSuspendSelectCallback)
1308         m_aSelectHandler.Call(m_pAntiImpl);
1309 }
1310 
IMPL_LINK_NOARG(SvtFileView_Impl,SelectionChangedHdl,weld::IconView &,void)1311 IMPL_LINK_NOARG(SvtFileView_Impl, SelectionChangedHdl, weld::IconView&, void)
1312 {
1313     if (!mnSuspendSelectCallback)
1314         m_aSelectHandler.Call(m_pAntiImpl);
1315 }
1316 
SetSelectHandler(const Link<SvtFileView *,void> & rHdl)1317 void SvtFileView_Impl::SetSelectHandler(const Link<SvtFileView*,void>& rHdl)
1318 {
1319     m_aSelectHandler = rHdl;
1320 
1321     mxView->connect_changed(LINK(this, SvtFileView_Impl, ChangedHdl));
1322     mxIconView->connect_selection_changed(LINK(this, SvtFileView_Impl, SelectionChangedHdl));
1323 }
1324 
IMPL_LINK_NOARG(SvtFileView_Impl,RowActivatedHdl,weld::TreeView &,bool)1325 IMPL_LINK_NOARG(SvtFileView_Impl, RowActivatedHdl, weld::TreeView&, bool)
1326 {
1327     return maDoubleClickHandler.Call(m_pAntiImpl);
1328 }
1329 
IMPL_LINK_NOARG(SvtFileView_Impl,ItemActivatedHdl,weld::IconView &,bool)1330 IMPL_LINK_NOARG(SvtFileView_Impl, ItemActivatedHdl, weld::IconView&, bool)
1331 {
1332     return maDoubleClickHandler.Call(m_pAntiImpl);
1333 }
1334 
SetDoubleClickHandler(const Link<SvtFileView *,bool> & rHdl)1335 void SvtFileView_Impl::SetDoubleClickHandler(const Link<SvtFileView*,bool>& rHdl)
1336 {
1337     maDoubleClickHandler = rHdl;
1338 
1339     mxView->connect_row_activated(LINK(this, SvtFileView_Impl, RowActivatedHdl));
1340     mxIconView->connect_item_activated(LINK(this, SvtFileView_Impl, ItemActivatedHdl));
1341 }
1342 
OpenFolder_Impl()1343 void SvtFileView_Impl::OpenFolder_Impl()
1344 {
1345     ::osl::MutexGuard aGuard( maMutex );
1346 
1347     mxView->freeze();
1348     mxIconView->freeze();
1349     maEntries.clear();
1350     mxView->clear();
1351     mxIconView->clear();
1352 
1353     for (auto const& elem : maContent)
1354     {
1355         if (mbOnlyFolder && !elem->mbIsFolder)
1356             continue;
1357 
1358         // insert entry and set user data
1359         maEntries.emplace_back(std::make_unique<SvtContentEntry>(elem->maTargetURL, elem->mbIsFolder));
1360         OUString sId(OUString::number(reinterpret_cast<sal_Int64>(maEntries.back().get())));
1361         mxView->append(sId, elem->maDisplayName, elem->maType, elem->maDisplaySize, elem->maDisplayDate, elem->maImage);
1362         mxIconView->append(sId, elem->maDisplayName, elem->maImage);
1363     }
1364 
1365     ++mnSuspendSelectCallback;
1366     mxView->thaw();
1367 
1368     //set sort indicator
1369     weld::TreeView* pView = mxView->getWidget();
1370     pView->set_sort_indicator(mbAscending ? TRISTATE_TRUE : TRISTATE_FALSE, GetSortColumn());
1371 
1372     mxIconView->thaw();
1373     --mnSuspendSelectCallback;
1374 
1375     ResetCursor();
1376 }
1377 
ResetCursor()1378 void SvtFileView_Impl::ResetCursor()
1379 {
1380     if (mxView->get_visible())
1381     {
1382         // deselect
1383         mxView->unselect_all();
1384         std::unique_ptr<weld::TreeIter> xFirst = mxView->make_iterator();
1385         if (mxView->get_iter_first(*xFirst))
1386         {
1387             // set cursor to the first entry
1388             mxView->set_cursor(*xFirst);
1389         }
1390     }
1391     else
1392     {
1393         // deselect
1394         mxIconView->unselect_all();
1395         std::unique_ptr<weld::TreeIter> xFirst = mxIconView->make_iterator();
1396         if (mxIconView->get_iter_first(*xFirst))
1397         {
1398             // set cursor to the first entry
1399             mxIconView->set_cursor(*xFirst);
1400         }
1401     }
1402 }
1403 
CancelRunningAsyncAction()1404 void SvtFileView_Impl::CancelRunningAsyncAction()
1405 {
1406     DBG_TESTSOLARMUTEX();
1407     ::osl::MutexGuard aGuard( maMutex );
1408     if ( !m_xContentEnumerator.is() )
1409         return;
1410 
1411     m_bAsyncActionCancelled = true;
1412     m_xContentEnumerator->cancel();
1413     m_bRunningAsyncAction = false;
1414 
1415     m_xContentEnumerator.clear();
1416     if ( m_xCancelAsyncTimer.is() && m_xCancelAsyncTimer->isTicking() )
1417         m_xCancelAsyncTimer->stop();
1418     m_xCancelAsyncTimer.clear();
1419 }
1420 
1421 
onTimeout()1422 void SvtFileView_Impl::onTimeout()
1423 {
1424     SolarMutexGuard aSolarGuard;
1425     ::osl::MutexGuard aGuard( maMutex );
1426     if ( !m_bRunningAsyncAction )
1427         // there might have been a race condition while we waited for the mutex
1428         return;
1429 
1430     CancelRunningAsyncAction();
1431 
1432     if ( m_aCurrentAsyncActionHandler.IsSet() )
1433     {
1434         Application::PostUserEvent( m_aCurrentAsyncActionHandler, reinterpret_cast< void* >( eTimeout ) );
1435         m_aCurrentAsyncActionHandler = Link<void*,void>();
1436     }
1437 }
1438 
1439 
enumerationDone(::svt::EnumerationResult eResult)1440 void SvtFileView_Impl::enumerationDone( ::svt::EnumerationResult eResult )
1441 {
1442     SolarMutexGuard aSolarGuard;
1443     ::osl::MutexGuard aGuard( maMutex );
1444 
1445     m_xContentEnumerator.clear();
1446     if ( m_xCancelAsyncTimer.is() && m_xCancelAsyncTimer->isTicking() )
1447         m_xCancelAsyncTimer->stop();
1448     m_xCancelAsyncTimer.clear();
1449 
1450     if ( m_bAsyncActionCancelled )
1451         // this is to prevent race conditions
1452         return;
1453 
1454     m_eAsyncActionResult = eResult;
1455     m_bRunningAsyncAction = false;
1456 
1457     m_aAsyncActionFinished.set();
1458 
1459     if ( svt::EnumerationResult::SUCCESS == eResult )
1460         implEnumerationSuccess();
1461 
1462     if ( m_aCurrentAsyncActionHandler.IsSet() )
1463     {
1464         Application::PostUserEvent( m_aCurrentAsyncActionHandler, reinterpret_cast< void* >( m_eAsyncActionResult ) );
1465         m_aCurrentAsyncActionHandler = Link<void*,void>();
1466     }
1467 }
1468 
1469 
implEnumerationSuccess()1470 void SvtFileView_Impl::implEnumerationSuccess()
1471 {
1472     FilterFolderContent_Impl( maCurrentFilter );
1473     SortFolderContent_Impl();
1474     CreateDisplayText_Impl();
1475     OpenFolder_Impl();
1476     maOpenDoneLink.Call( m_pAntiImpl );
1477 }
1478 
ReplaceTabWithString(const OUString & rValue)1479 OUString SvtFileView_Impl::ReplaceTabWithString(const OUString& rValue)
1480 {
1481     OUString const aTab( "\t" );
1482     OUString const aTabString( "%09" );
1483 
1484     sal_Int32 iPos;
1485     OUString aValue(rValue);
1486     while ( ( iPos = aValue.indexOf( aTab ) ) >= 0 )
1487         aValue = aValue.replaceAt( iPos, 1, aTabString );
1488     return aValue;
1489 }
1490 
CreateDisplayText_Impl()1491 void SvtFileView_Impl::CreateDisplayText_Impl()
1492 {
1493     ::osl::MutexGuard aGuard( maMutex );
1494 
1495     OUString const aDateSep( ", " );
1496 
1497     for (auto const& elem : maContent)
1498     {
1499         // title, type, size, date
1500         elem->maDisplayName = ReplaceTabWithString(elem->GetTitle());
1501         // folders don't have a size
1502         if ( ! elem->mbIsFolder )
1503             elem->maDisplaySize = CreateExactSizeText( elem->maSize );
1504         // set the date, but volumes have no date
1505         if ( ! elem->mbIsFolder || ! elem->mbIsVolume )
1506         {
1507             SvtSysLocale aSysLocale;
1508             const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
1509             elem->maDisplayDate = rLocaleData.getDate( elem->maModDate )
1510                                   + aDateSep
1511                                   + rLocaleData.getTime( elem->maModDate, false );
1512         }
1513 
1514         // detect image
1515         if ( elem->mbIsFolder )
1516         {
1517             ::svtools::VolumeInfo aVolInfo( elem->mbIsVolume, elem->mbIsRemote,
1518                                             elem->mbIsRemoveable, elem->mbIsFloppy,
1519                                             elem->mbIsCompactDisc );
1520             elem->maImage = SvFileInformationManager::GetFolderImageId(aVolInfo);
1521         }
1522         else
1523             elem->maImage = SvFileInformationManager::GetFileImageId(INetURLObject(elem->maTargetURL));
1524     }
1525 }
1526 
Resort_Impl(sal_Int16 nColumn,bool bAscending)1527 void SvtFileView_Impl::Resort_Impl( sal_Int16 nColumn, bool bAscending )
1528 {
1529     // TODO: IconView ()
1530     ::osl::MutexGuard aGuard( maMutex );
1531 
1532     if ( ( nColumn == mnSortColumn ) &&
1533          ( bAscending == mbAscending ) )
1534          return;
1535 
1536     // reset the quick search index
1537     mxView->ResetQuickSearch_Impl( nullptr );
1538 
1539     std::unique_ptr<weld::TreeIter> xEntry(mxView->make_iterator());
1540     bool bEntry = mxView->get_cursor(xEntry.get());
1541 
1542     OUString aEntryURL;
1543     if (bEntry && !mxView->get_id(*xEntry).isEmpty())
1544         aEntryURL = reinterpret_cast<SvtContentEntry*>(mxView->get_id(*xEntry).toInt64())->maURL;
1545 
1546     mnSortColumn = nColumn;
1547     mbAscending = bAscending;
1548 
1549     SortFolderContent_Impl();
1550     OpenFolder_Impl();
1551 
1552     if ( !mbIsFirstResort )
1553     {
1554         int nPos = GetEntryPos( aEntryURL );
1555         if (nPos != -1 && nPos < mxView->n_children())
1556         {
1557             ++mnSuspendSelectCallback;  // #i15668#
1558             mxView->set_cursor(nPos);
1559             --mnSuspendSelectCallback;
1560         }
1561     }
1562     else
1563         mbIsFirstResort = false;
1564 }
1565 
1566 static bool                     gbAscending = true;
1567 static sal_Int16                gnColumn = COLUMN_TITLE;
1568 static const CollatorWrapper*   pCollatorWrapper = nullptr;
1569 
1570 /* this function returns true, if aOne is less than aTwo
1571 */
CompareSortingData_Impl(std::unique_ptr<SortingData_Impl> const & aOne,std::unique_ptr<SortingData_Impl> const & aTwo)1572 static bool CompareSortingData_Impl( std::unique_ptr<SortingData_Impl> const & aOne, std::unique_ptr<SortingData_Impl> const & aTwo )
1573 {
1574     DBG_ASSERT( pCollatorWrapper, "*CompareSortingData_Impl(): Can't work this way!" );
1575 
1576     sal_Int32 nComp;
1577     bool      bRet = false;
1578     bool      bEqual = false;
1579 
1580     if ( aOne->mbIsFolder != aTwo->mbIsFolder )
1581     {
1582         bRet = aOne->mbIsFolder;
1583 
1584         // !!! pb: #100376# folder always on top
1585         if ( !gbAscending )
1586             bRet = !bRet;
1587     }
1588     else
1589     {
1590         switch ( gnColumn )
1591         {
1592             case COLUMN_TITLE:
1593                 // compare case insensitive first
1594                 nComp = pCollatorWrapper->compareString( aOne->GetLowerTitle(), aTwo->GetLowerTitle() );
1595 
1596                 if ( nComp == 0 )
1597                     nComp = pCollatorWrapper->compareString( aOne->GetTitle(), aTwo->GetTitle() );
1598 
1599                 if ( nComp < 0 )
1600                     bRet = true;
1601                 else if ( nComp > 0 )
1602                     bRet = false;
1603                 else
1604                     bEqual = true;
1605                 break;
1606             case COLUMN_TYPE:
1607                 nComp = pCollatorWrapper->compareString( aOne->maType, aTwo->maType );
1608                 if ( nComp < 0 )
1609                     bRet = true;
1610                 else if ( nComp > 0 )
1611                     bRet = false;
1612                 else
1613                     bEqual = true;
1614                 break;
1615             case COLUMN_SIZE:
1616                 if ( aOne->maSize < aTwo->maSize )
1617                     bRet = true;
1618                 else if ( aOne->maSize > aTwo->maSize )
1619                     bRet = false;
1620                 else
1621                     bEqual = true;
1622                 break;
1623             case COLUMN_DATE:
1624                 if ( aOne->maModDate < aTwo->maModDate )
1625                     bRet = true;
1626                 else if ( aOne->maModDate > aTwo->maModDate )
1627                     bRet = false;
1628                 else
1629                     bEqual = true;
1630                 break;
1631             default:
1632                 SAL_INFO( "svtools.contnr", "CompareSortingData_Impl: Compare unknown type!" );
1633                 bRet = false;
1634         }
1635     }
1636 
1637     // when the two elements are equal, we must not return sal_True (which would
1638     // happen if we just return ! ( a < b ) when not sorting ascending )
1639     if ( bEqual )
1640         return false;
1641 
1642     return gbAscending ? bRet : !bRet;
1643 }
1644 
1645 
SortFolderContent_Impl()1646 void SvtFileView_Impl::SortFolderContent_Impl()
1647 {
1648     ::osl::MutexGuard aGuard( maMutex );
1649 
1650     if ( maContent.size() > 1 )
1651     {
1652         gbAscending = mbAscending;
1653         gnColumn = mnSortColumn;
1654         pCollatorWrapper = aIntlWrapper.getCaseCollator();
1655 
1656         std::stable_sort( maContent.begin(), maContent.end(), CompareSortingData_Impl );
1657 
1658         pCollatorWrapper = nullptr;
1659     }
1660 }
1661 
1662 
EntryRemoved(const OUString & rURL)1663 void SvtFileView_Impl::EntryRemoved( const OUString& rURL )
1664 {
1665     ::osl::MutexGuard aGuard( maMutex );
1666 
1667     maContent.erase(std::find_if(maContent.begin(), maContent.end(),
1668                      [&](const std::unique_ptr<SortingData_Impl> & data) { return data->maTargetURL == rURL; }));
1669 }
1670 
1671 
EntryRenamed(OUString & rURL,const OUString & rTitle)1672 void SvtFileView_Impl::EntryRenamed( OUString& rURL,
1673                                      const OUString& rTitle )
1674 {
1675     ::osl::MutexGuard aGuard( maMutex );
1676 
1677     auto aFoundElem = std::find_if(maContent.begin(), maContent.end(),
1678                      [&](const std::unique_ptr<SortingData_Impl> & data) { return data->maTargetURL == rURL; });
1679     if (aFoundElem != maContent.end())
1680     {
1681         (*aFoundElem)->SetNewTitle( rTitle );
1682         (*aFoundElem)->maDisplayName = ReplaceTabWithString(rTitle);
1683 
1684         INetURLObject aURLObj( rURL );
1685         aURLObj.setName( rTitle, INetURLObject::EncodeMechanism::All );
1686 
1687         rURL = aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1688 
1689         (*aFoundElem)->maTargetURL = rURL;
1690     }
1691 }
1692 
FolderInserted(const OUString & rURL,const OUString & rTitle)1693 const SortingData_Impl& SvtFileView_Impl::FolderInserted( const OUString& rURL, const OUString& rTitle )
1694 {
1695     ::osl::MutexGuard aGuard( maMutex );
1696 
1697     std::unique_ptr<SortingData_Impl> pData(new SortingData_Impl);
1698 
1699     pData->SetNewTitle( rTitle );
1700     pData->maSize        = 0;
1701     pData->mbIsFolder    = true;
1702     pData->maTargetURL   = rURL;
1703 
1704     ::svtools::VolumeInfo aVolInfo;
1705     pData->maType = SvFileInformationManager::GetFolderDescription( aVolInfo );
1706     pData->maImage = SvFileInformationManager::GetFolderImageId( aVolInfo );
1707 
1708     OUString const aDateSep( ", " );
1709 
1710     // title, type, size, date
1711     pData->maDisplayName = ReplaceTabWithString(pData->GetTitle());
1712     // set the date
1713     SvtSysLocale aSysLocale;
1714     const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
1715     pData->maDisplayDate = rLocaleData.getDate( pData->maModDate )
1716                            + aDateSep
1717                            + rLocaleData.getTime( pData->maModDate );
1718 
1719     maContent.push_back( std::move(pData) );
1720 
1721     return *maContent.back();
1722 }
1723 
GetEntryPos(const OUString & rURL)1724 int SvtFileView_Impl::GetEntryPos(const OUString& rURL)
1725 {
1726     ::osl::MutexGuard aGuard( maMutex );
1727 
1728     auto aFoundElem = std::find_if(maContent.begin(), maContent.end(),
1729           [&](const std::unique_ptr<SortingData_Impl> & data) { return data->maTargetURL == rURL; });
1730     return aFoundElem != maContent.end() ? std::distance(maContent.begin(), aFoundElem) : -1;
1731 }
1732 
SetViewMode(FileViewMode eMode)1733 void SvtFileView_Impl::SetViewMode( FileViewMode eMode )
1734 {
1735     switch ( eMode )
1736     {
1737         case eDetailedList:
1738             mxView->show();
1739             mxIconView->hide();
1740             break;
1741 
1742         case eIcon:
1743             mxView->hide();
1744             mxIconView->show();
1745             break;
1746 
1747         default:
1748             mxView->show();
1749             mxIconView->hide();
1750     };
1751 }
1752 
SearchNextEntry(sal_uInt32 & nIndex,const OUString & rTitle,bool bWrapAround)1753 bool SvtFileView_Impl::SearchNextEntry( sal_uInt32& nIndex, const OUString& rTitle, bool bWrapAround )
1754 {
1755     ::osl::MutexGuard aGuard( maMutex );
1756 
1757     sal_uInt32 nEnd = maContent.size();
1758     sal_uInt32 nStart = nIndex;
1759     while ( nIndex < nEnd )
1760     {
1761         SortingData_Impl* pData = maContent[ nIndex ].get();
1762         if ( pData->GetLowerTitle().startsWith( rTitle ) )
1763             return true;
1764         ++nIndex;
1765     }
1766 
1767     if ( bWrapAround )
1768     {
1769         nIndex = 0;
1770         while ( nIndex < nEnd && nIndex <= nStart )
1771         {
1772             SortingData_Impl* pData = maContent[ nIndex ].get();
1773             if ( pData->GetLowerTitle().startsWith( rTitle ) )
1774                 return true;
1775             ++nIndex;
1776         }
1777     }
1778 
1779     return false;
1780 }
1781 
1782 namespace {
onShot()1783     void SAL_CALL CallbackTimer::onShot()
1784     {
1785         OSL_ENSURE( m_pTimeoutHandler, "CallbackTimer::onShot: nobody interested in?" );
1786         SvtFileView_Impl* pHandler( m_pTimeoutHandler );
1787         if ( pHandler )
1788             pHandler->onTimeout();
1789     }
1790 }
1791 
selected_foreach(const std::function<bool (weld::TreeIter &)> & func)1792 void SvtFileView::selected_foreach(const std::function<bool(weld::TreeIter&)>& func)
1793 {
1794     if (mpImpl->mxView->get_visible())
1795         mpImpl->mxView->selected_foreach(func);
1796     else
1797         mpImpl->mxIconView->selected_foreach(func);
1798 }
1799 
identifier() const1800 weld::Widget* SvtFileView::identifier() const
1801 {
1802     return mpImpl->mxView->getWidget();
1803 }
1804 
1805 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1806