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 
21 #include <basobj.hxx>
22 #include <bastypes.hxx>
23 #include <bastype2.hxx>
24 #include <strings.hrc>
25 #include <bitmaps.hlst>
26 #include <iderid.hxx>
27 #include <tools/urlobj.hxx>
28 #include <tools/diagnose_ex.h>
29 #include <svtools/imagemgr.hxx>
30 #include <com/sun/star/script/XLibraryContainerPassword.hpp>
31 #include <com/sun/star/frame/ModuleManager.hpp>
32 #include <comphelper/processfactory.hxx>
33 #include <sfx2/dispatch.hxx>
34 #include <sfx2/sfxsids.hrc>
35 
36 #include <initializer_list>
37 #include <memory>
38 #include <string_view>
39 
40 #include <com/sun/star/script/ModuleType.hpp>
41 #include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
42 #include <com/sun/star/lang/XServiceInfo.hpp>
43 #include <com/sun/star/container/XNamed.hpp>
44 
45 namespace basctl
46 {
47 
48 using namespace ::com::sun::star::uno;
49 using namespace ::com::sun::star;
50 
getObjectName(const uno::Reference<container::XNameContainer> & rLib,const OUString & rModName,OUString & rObjName)51 void ModuleInfoHelper::getObjectName( const uno::Reference< container::XNameContainer >& rLib, const OUString& rModName, OUString& rObjName )
52 {
53     try
54     {
55         uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( rLib, uno::UNO_QUERY );
56         if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( rModName ) )
57         {
58             script::ModuleInfo aModuleInfo = xVBAModuleInfo->getModuleInfo( rModName );
59             uno::Any aObject( aModuleInfo.ModuleObject );
60             uno::Reference< lang::XServiceInfo > xServiceInfo( aObject, uno::UNO_QUERY );
61             if( xServiceInfo.is() && xServiceInfo->supportsService( "ooo.vba.excel.Worksheet" ) )
62             {
63                 uno::Reference< container::XNamed > xNamed( aObject, uno::UNO_QUERY );
64                 if( xNamed.is() )
65                     rObjName = xNamed->getName();
66             }
67         }
68     }
69     catch(const uno::Exception& )
70     {
71     }
72 }
73 
getModuleType(const uno::Reference<container::XNameContainer> & rLib,const OUString & rModName)74 sal_Int32 ModuleInfoHelper::getModuleType(  const uno::Reference< container::XNameContainer >& rLib, const OUString& rModName )
75 {
76     sal_Int32 nType = script::ModuleType::NORMAL;
77     uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( rLib, uno::UNO_QUERY );
78     if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( rModName ) )
79     {
80         script::ModuleInfo aModuleInfo = xVBAModuleInfo->getModuleInfo( rModName );
81         nType = aModuleInfo.ModuleType;
82     }
83     return nType;
84 }
85 
~Entry()86 Entry::~Entry()
87 { }
88 
DocumentEntry(ScriptDocument const & rDocument,LibraryLocation eLocation,EntryType eType)89 DocumentEntry::DocumentEntry (
90     ScriptDocument const& rDocument,
91     LibraryLocation eLocation,
92     EntryType eType
93 ) :
94     Entry(eType),
95     m_aDocument(rDocument),
96     m_eLocation(eLocation)
97 {
98     OSL_ENSURE( m_aDocument.isValid(), "DocumentEntry::DocumentEntry: illegal document!" );
99 }
100 
~DocumentEntry()101 DocumentEntry::~DocumentEntry()
102 { }
103 
LibEntry(ScriptDocument const & rDocument,LibraryLocation eLocation,OUString const & rLibName)104 LibEntry::LibEntry (
105     ScriptDocument const& rDocument,
106     LibraryLocation eLocation,
107     OUString const& rLibName
108 ) :
109     DocumentEntry(rDocument, eLocation, OBJ_TYPE_LIBRARY),
110     m_aLibName(rLibName)
111 { }
112 
~LibEntry()113 LibEntry::~LibEntry()
114 { }
115 
EntryDescriptor()116 EntryDescriptor::EntryDescriptor () :
117     m_aDocument(ScriptDocument::getApplicationScriptDocument()),
118     m_eLocation(LIBRARY_LOCATION_UNKNOWN),
119     m_eType(OBJ_TYPE_UNKNOWN)
120 { }
121 
EntryDescriptor(ScriptDocument const & rDocument,LibraryLocation eLocation,OUString const & rLibName,OUString const & rLibSubName,OUString const & rName,EntryType eType)122 EntryDescriptor::EntryDescriptor (
123     ScriptDocument const& rDocument,
124     LibraryLocation eLocation,
125     OUString const& rLibName,
126     OUString const& rLibSubName,
127     OUString const& rName,
128     EntryType eType
129 ) :
130     m_aDocument(rDocument),
131     m_eLocation(eLocation),
132     m_aLibName(rLibName),
133     m_aLibSubName(rLibSubName),
134     m_aName(rName),
135     m_eType(eType)
136 {
137     OSL_ENSURE( m_aDocument.isValid(), "EntryDescriptor::EntryDescriptor: invalid document!" );
138 }
139 
EntryDescriptor(ScriptDocument const & rDocument,LibraryLocation eLocation,OUString const & rLibName,OUString const & rLibSubName,OUString const & rName,OUString const & rMethodName,EntryType eType)140 EntryDescriptor::EntryDescriptor (
141     ScriptDocument const& rDocument,
142     LibraryLocation eLocation,
143     OUString const& rLibName,
144     OUString const& rLibSubName,
145     OUString const& rName,
146     OUString const& rMethodName,
147     EntryType eType
148 ) :
149     m_aDocument(rDocument),
150     m_eLocation(eLocation),
151     m_aLibName(rLibName),
152     m_aLibSubName(rLibSubName),
153     m_aName(rName),
154     m_aMethodName(rMethodName),
155     m_eType(eType)
156 {
157     OSL_ENSURE( m_aDocument.isValid(), "EntryDescriptor::EntryDescriptor: invalid document!" );
158 }
159 
SbTreeListBox(std::unique_ptr<weld::TreeView> xControl,weld::Window * pTopLevel)160 SbTreeListBox::SbTreeListBox(std::unique_ptr<weld::TreeView> xControl, weld::Window* pTopLevel)
161     : m_xControl(std::move(xControl))
162     , m_xScratchIter(m_xControl->make_iterator())
163     , m_pTopLevel(pTopLevel)
164     , m_bFreezeOnFirstAddRemove(false)
165     , m_aNotifier(*this)
166 {
167     m_xControl->connect_row_activated(LINK(this, SbTreeListBox, OpenCurrentHdl));
168     m_xControl->connect_expanding(LINK(this, SbTreeListBox, RequestingChildrenHdl));
169     nMode = BrowseMode::All;   // everything
170 }
171 
~SbTreeListBox()172 SbTreeListBox::~SbTreeListBox()
173 {
174     m_aNotifier.dispose();
175 
176     bool bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
177     while (bValidIter)
178     {
179         Entry* pBasicEntry = reinterpret_cast<Entry*>(m_xControl->get_id(*m_xScratchIter).toInt64());
180         delete pBasicEntry;
181         bValidIter = m_xControl->iter_next(*m_xScratchIter);
182     }
183 }
184 
ScanEntry(const ScriptDocument & rDocument,LibraryLocation eLocation)185 void SbTreeListBox::ScanEntry( const ScriptDocument& rDocument, LibraryLocation eLocation )
186 {
187     OSL_ENSURE( rDocument.isAlive(), "TreeListBox::ScanEntry: illegal document!" );
188     if ( !rDocument.isAlive() )
189         return;
190 
191     // can be called multiple times for updating!
192 
193     // actually test if basic's in the tree already?!
194     // level 1: BasicManager (application, document, ...)
195     bool bDocumentRootEntry = FindRootEntry(rDocument, eLocation, *m_xScratchIter);
196     if (bDocumentRootEntry && m_xControl->get_row_expanded(*m_xScratchIter))
197         ImpCreateLibEntries(*m_xScratchIter, rDocument, eLocation);
198     if (!bDocumentRootEntry)
199     {
200         OUString aRootName(GetRootEntryName(rDocument, eLocation));
201         OUString aImage(GetRootEntryBitmaps(rDocument));
202         AddEntry(aRootName, aImage, nullptr, true, std::make_unique<DocumentEntry>(rDocument, eLocation));
203     }
204 }
205 
ImpCreateLibEntries(const weld::TreeIter & rIter,const ScriptDocument & rDocument,LibraryLocation eLocation)206 void SbTreeListBox::ImpCreateLibEntries(const weld::TreeIter& rIter, const ScriptDocument& rDocument, LibraryLocation eLocation)
207 {
208     // get a sorted list of library names
209     Sequence< OUString > aLibNames( rDocument.getLibraryNames() );
210     sal_Int32 nLibCount = aLibNames.getLength();
211     const OUString* pLibNames = aLibNames.getConstArray();
212 
213     for ( sal_Int32 i = 0 ; i < nLibCount ; i++ )
214     {
215         OUString aLibName = pLibNames[ i ];
216 
217         if ( eLocation == rDocument.getLibraryLocation( aLibName ) )
218         {
219             // check, if the module library is loaded
220             bool bModLibLoaded = false;
221             Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
222             if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryLoaded( aLibName ) )
223                 bModLibLoaded = true;
224 
225             // check, if the dialog library is loaded
226             bool bDlgLibLoaded = false;
227             Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
228             if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryLoaded( aLibName ) )
229                 bDlgLibLoaded = true;
230 
231             bool bLoaded = bModLibLoaded || bDlgLibLoaded;
232 
233             // if only one of the libraries is loaded, load also the other
234             if ( bLoaded )
235             {
236                 if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
237                     xModLibContainer->loadLibrary( aLibName );
238 
239                 if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) )
240                     xDlgLibContainer->loadLibrary( aLibName );
241             }
242 
243             // create tree list box entry
244             OUString sId;
245             if ( ( nMode & BrowseMode::Dialogs ) && !( nMode & BrowseMode::Modules ) )
246                 sId = bLoaded ? std::u16string_view(u"" RID_BMP_DLGLIB) : std::u16string_view(u"" RID_BMP_DLGLIBNOTLOADED);
247             else
248                 sId = bLoaded ? OUStringLiteral(u"" RID_BMP_MODLIB) : OUStringLiteral(u"" RID_BMP_MODLIBNOTLOADED);
249             std::unique_ptr<weld::TreeIter> xLibRootEntry(m_xControl->make_iterator(&rIter));
250             bool bLibRootEntry = FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xLibRootEntry);
251             if (bLibRootEntry)
252             {
253                 SetEntryBitmaps(*xLibRootEntry, sId);
254                 bool bRowExpanded = m_xControl->get_row_expanded(*xLibRootEntry);
255                 bool bRowExpandAttempted = !m_xControl->get_children_on_demand(*xLibRootEntry);
256                 if (bRowExpanded || bRowExpandAttempted)
257                     ImpCreateLibSubEntries(*xLibRootEntry, rDocument, aLibName);
258             }
259             else
260             {
261                 AddEntry(aLibName, sId, &rIter, true, std::make_unique<Entry>(OBJ_TYPE_LIBRARY));
262             }
263         }
264     }
265 }
266 
ImpCreateLibSubEntries(const weld::TreeIter & rLibRootEntry,const ScriptDocument & rDocument,const OUString & rLibName)267 void SbTreeListBox::ImpCreateLibSubEntries(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName)
268 {
269     // modules
270     if ( nMode & BrowseMode::Modules )
271     {
272         Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
273 
274         if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) && xModLibContainer->isLibraryLoaded( rLibName ) )
275         {
276             try
277             {
278                 if( rDocument.isInVBAMode() )
279                 {
280                     ImpCreateLibSubEntriesInVBAMode(rLibRootEntry, rDocument, rLibName);
281                 }
282                 else
283                 {
284                     // get a sorted list of module names
285                     Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName );
286                     sal_Int32 nModCount = aModNames.getLength();
287                     const OUString* pModNames = aModNames.getConstArray();
288 
289                     auto xTreeIter = m_xControl->make_iterator();
290 
291                     for ( sal_Int32 i = 0 ; i < nModCount ; i++ )
292                     {
293                         OUString aModName = pModNames[ i ];
294                         m_xControl->copy_iterator(rLibRootEntry, *xTreeIter);
295                         bool bModuleEntry = FindEntry(aModName, OBJ_TYPE_MODULE, *xTreeIter);
296                         if (!bModuleEntry)
297                         {
298                             AddEntry(aModName, RID_BMP_MODULE, &rLibRootEntry, false, std::make_unique<Entry>(OBJ_TYPE_MODULE), xTreeIter.get());
299                         }
300 
301                         // methods
302                         if ( nMode & BrowseMode::Subs )
303                         {
304                             Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName );
305                             sal_Int32 nCount = aNames.getLength();
306                             const OUString* pNames = aNames.getConstArray();
307 
308                             auto xSubTreeIter = m_xControl->make_iterator();
309 
310                             for ( sal_Int32 j = 0 ; j < nCount ; j++ )
311                             {
312                                 OUString aName = pNames[ j ];
313                                 m_xControl->copy_iterator(*xTreeIter, *xSubTreeIter);
314                                 bool bEntry = FindEntry(aName, OBJ_TYPE_METHOD, *xSubTreeIter);
315                                 if (!bEntry)
316                                 {
317                                     AddEntry(aName, RID_BMP_MACRO, xTreeIter.get(), false, std::make_unique<Entry>(OBJ_TYPE_METHOD));
318                                 }
319                             }
320                         }
321                     }
322                 }
323             }
324             catch ( const container::NoSuchElementException& )
325             {
326                 DBG_UNHANDLED_EXCEPTION("basctl.basicide");
327             }
328         }
329     }
330 
331     // dialogs
332     if ( !(nMode & BrowseMode::Dialogs) )
333          return;
334 
335     Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
336 
337     if ( !(xDlgLibContainer.is() && xDlgLibContainer->hasByName( rLibName ) && xDlgLibContainer->isLibraryLoaded( rLibName )) )
338         return;
339 
340     try
341     {
342         // get a sorted list of dialog names
343         Sequence< OUString > aDlgNames( rDocument.getObjectNames( E_DIALOGS, rLibName ) );
344         sal_Int32 nDlgCount = aDlgNames.getLength();
345         const OUString* pDlgNames = aDlgNames.getConstArray();
346 
347         auto xTreeIter = m_xControl->make_iterator();
348 
349         for ( sal_Int32 i = 0 ; i < nDlgCount ; i++ )
350         {
351             OUString aDlgName = pDlgNames[ i ];
352             m_xControl->copy_iterator(rLibRootEntry, *xTreeIter);
353             bool bDialogEntry = FindEntry(aDlgName, OBJ_TYPE_DIALOG, *xTreeIter);
354             if (!bDialogEntry)
355             {
356                 AddEntry(aDlgName, RID_BMP_DIALOG, &rLibRootEntry, false, std::make_unique<Entry>(OBJ_TYPE_DIALOG));
357             }
358         }
359     }
360     catch (const container::NoSuchElementException& )
361     {
362         DBG_UNHANDLED_EXCEPTION("basctl.basicide");
363     }
364 }
365 
ImpCreateLibSubEntriesInVBAMode(const weld::TreeIter & rLibRootEntry,const ScriptDocument & rDocument,const OUString & rLibName)366 void SbTreeListBox::ImpCreateLibSubEntriesInVBAMode(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName )
367 {
368     auto const aEntries = {
369         std::make_pair( OBJ_TYPE_DOCUMENT_OBJECTS, IDEResId(RID_STR_DOCUMENT_OBJECTS) ),
370         std::make_pair( OBJ_TYPE_USERFORMS, IDEResId(RID_STR_USERFORMS) ),
371         std::make_pair( OBJ_TYPE_NORMAL_MODULES, IDEResId(RID_STR_NORMAL_MODULES) ),
372         std::make_pair( OBJ_TYPE_CLASS_MODULES, IDEResId(RID_STR_CLASS_MODULES) ) };
373     for( auto const & iter: aEntries )
374     {
375         EntryType eType = iter.first;
376         OUString const & aEntryName = iter.second;
377         std::unique_ptr<weld::TreeIter> xLibSubRootEntry(m_xControl->make_iterator(&rLibRootEntry));
378         bool bLibSubRootEntry = FindEntry(aEntryName, eType, *xLibSubRootEntry);
379         if (bLibSubRootEntry)
380         {
381             SetEntryBitmaps(*xLibSubRootEntry, RID_BMP_MODLIB);
382             if (m_xControl->get_row_expanded(*xLibSubRootEntry))
383                 ImpCreateLibSubSubEntriesInVBAMode(*xLibSubRootEntry, rDocument, rLibName);
384         }
385         else
386         {
387             m_xControl->copy_iterator(rLibRootEntry, *xLibSubRootEntry);
388             AddEntry(aEntryName, RID_BMP_MODLIB, xLibSubRootEntry.get(), true, std::make_unique<Entry>(eType));
389         }
390     }
391 }
392 
ImpCreateLibSubSubEntriesInVBAMode(const weld::TreeIter & rLibSubRootEntry,const ScriptDocument & rDocument,const OUString & rLibName)393 void SbTreeListBox::ImpCreateLibSubSubEntriesInVBAMode(const weld::TreeIter& rLibSubRootEntry, const ScriptDocument& rDocument, const OUString& rLibName)
394 {
395     uno::Reference< container::XNameContainer > xLib = rDocument.getOrCreateLibrary( E_SCRIPTS, rLibName );
396     if( !xLib.is() )
397         return;
398 
399     try
400     {
401         // get a sorted list of module names
402         Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName );
403         sal_Int32 nModCount = aModNames.getLength();
404         const OUString* pModNames = aModNames.getConstArray();
405 
406         EntryDescriptor aDesc(GetEntryDescriptor(&rLibSubRootEntry));
407         EntryType eCurrentType(aDesc.GetType());
408 
409         for ( sal_Int32 i = 0 ; i < nModCount ; i++ )
410         {
411             OUString aModName = pModNames[ i ];
412             EntryType eType = OBJ_TYPE_UNKNOWN;
413             switch( ModuleInfoHelper::getModuleType( xLib, aModName ) )
414             {
415                 case script::ModuleType::DOCUMENT:
416                     eType = OBJ_TYPE_DOCUMENT_OBJECTS;
417                     break;
418                 case script::ModuleType::FORM:
419                     eType = OBJ_TYPE_USERFORMS;
420                     break;
421                 case script::ModuleType::NORMAL:
422                     eType = OBJ_TYPE_NORMAL_MODULES;
423                     break;
424                 case script::ModuleType::CLASS:
425                     eType = OBJ_TYPE_CLASS_MODULES;
426                     break;
427             }
428             if( eType != eCurrentType )
429                 continue;
430 
431             // display a nice friendly name in the ObjectModule tab,
432                // combining the objectname and module name, e.g. Sheet1 ( Financials )
433             OUString aEntryName = aModName;
434             if( eType == OBJ_TYPE_DOCUMENT_OBJECTS )
435             {
436                 OUString sObjName;
437                 ModuleInfoHelper::getObjectName( xLib, aModName, sObjName );
438                 if( !sObjName.isEmpty() )
439                 {
440                     aEntryName += " (" + sObjName + ")";
441                 }
442             }
443             std::unique_ptr<weld::TreeIter> xModuleEntry(m_xControl->make_iterator(&rLibSubRootEntry));
444             bool bModuleEntry = FindEntry(aEntryName, OBJ_TYPE_MODULE, *xModuleEntry);
445             if (!bModuleEntry)
446             {
447                 m_xControl->copy_iterator(rLibSubRootEntry, *xModuleEntry);
448                 AddEntry(aEntryName, RID_BMP_MODULE, xModuleEntry.get(), false,
449                          std::make_unique<Entry>(OBJ_TYPE_MODULE));
450             }
451 
452             // methods
453             if ( nMode & BrowseMode::Subs )
454             {
455                 Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName );
456                 sal_Int32 nCount = aNames.getLength();
457                 const OUString* pNames = aNames.getConstArray();
458 
459                 for ( sal_Int32 j = 0 ; j < nCount ; j++ )
460                 {
461                     OUString aName = pNames[ j ];
462                     std::unique_ptr<weld::TreeIter> xEntry(m_xControl->make_iterator(xModuleEntry.get()));
463                     bool bEntry = FindEntry(aName, OBJ_TYPE_METHOD, *xEntry);
464                     if (!bEntry)
465                     {
466                         AddEntry(aName, RID_BMP_MACRO, xModuleEntry.get(), false, std::make_unique<Entry>(OBJ_TYPE_METHOD));
467                     }
468                 }
469             }
470         }
471     }
472     catch ( const container::NoSuchElementException& )
473     {
474         DBG_UNHANDLED_EXCEPTION("basctl.basicide");
475     }
476 }
477 
ImpFindEntry(weld::TreeIter & rIter,std::u16string_view rText)478 bool SbTreeListBox::ImpFindEntry(weld::TreeIter& rIter, std::u16string_view rText)
479 {
480     bool bValidIter = m_xControl->iter_children(rIter);
481     while (bValidIter)
482     {
483         if (rText == m_xControl->get_text(rIter))
484             return true;
485         bValidIter = m_xControl->iter_next_sibling(rIter);
486     }
487     return false;
488 }
489 
onDocumentCreated(const ScriptDocument &)490 void SbTreeListBox::onDocumentCreated( const ScriptDocument& /*_rDocument*/ )
491 {
492     UpdateEntries();
493 }
494 
onDocumentOpened(const ScriptDocument &)495 void SbTreeListBox::onDocumentOpened( const ScriptDocument& /*_rDocument*/ )
496 {
497     UpdateEntries();
498 }
499 
onDocumentSave(const ScriptDocument &)500 void SbTreeListBox::onDocumentSave( const ScriptDocument& /*_rDocument*/ )
501 {
502     // not interested in
503 }
504 
onDocumentSaveDone(const ScriptDocument &)505 void SbTreeListBox::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ )
506 {
507     // not interested in
508 }
509 
onDocumentSaveAs(const ScriptDocument &)510 void SbTreeListBox::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ )
511 {
512     // not interested in
513 }
514 
onDocumentSaveAsDone(const ScriptDocument &)515 void SbTreeListBox::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ )
516 {
517     UpdateEntries();
518 }
519 
onDocumentClosed(const ScriptDocument & rDocument)520 void SbTreeListBox::onDocumentClosed( const ScriptDocument& rDocument )
521 {
522     UpdateEntries();
523     // The document is not yet actually deleted, so we need to remove its entry
524     // manually.
525     RemoveEntry(rDocument);
526 }
527 
onDocumentTitleChanged(const ScriptDocument &)528 void SbTreeListBox::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ )
529 {
530     // not interested in
531 }
532 
onDocumentModeChanged(const ScriptDocument &)533 void SbTreeListBox::onDocumentModeChanged( const ScriptDocument& /*_rDocument*/ )
534 {
535     // not interested in
536 }
537 
UpdateEntries()538 void SbTreeListBox::UpdateEntries()
539 {
540     bool bValidIter = m_xControl->get_selected(m_xScratchIter.get());
541     EntryDescriptor aCurDesc(GetEntryDescriptor(bValidIter ? m_xScratchIter.get() : nullptr));
542 
543     // removing the invalid entries
544     std::unique_ptr<weld::TreeIter> xLastValid(m_xControl->make_iterator(nullptr));
545     bool bLastValid = false;
546     bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
547     while (bValidIter)
548     {
549         if (IsValidEntry(*m_xScratchIter))
550         {
551             m_xControl->copy_iterator(*m_xScratchIter, *xLastValid);
552             bLastValid = true;
553         }
554         else
555             RemoveEntry(*m_xScratchIter);
556         if (bLastValid)
557         {
558             m_xControl->copy_iterator(*xLastValid, *m_xScratchIter);
559             bValidIter = m_xControl->iter_next(*m_xScratchIter);
560         }
561         else
562             bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
563     }
564 
565     ScanAllEntries();
566 
567     SetCurrentEntry( aCurDesc );
568 }
569 
570 // Removes the entry from the tree.
RemoveEntry(const weld::TreeIter & rIter)571 void SbTreeListBox::RemoveEntry(const weld::TreeIter& rIter)
572 {
573     if (m_bFreezeOnFirstAddRemove)
574     {
575         m_xControl->freeze();
576         m_bFreezeOnFirstAddRemove = false;
577     }
578 
579     // removing the associated user data
580     Entry* pBasicEntry = reinterpret_cast<Entry*>(m_xControl->get_id(rIter).toInt64());
581     delete pBasicEntry;
582     // removing the entry
583     m_xControl->remove(rIter);
584 }
585 
586 // Removes the entry of rDocument.
RemoveEntry(ScriptDocument const & rDocument)587 void SbTreeListBox::RemoveEntry (ScriptDocument const& rDocument)
588 {
589     // finding the entry of rDocument
590     bool bValidIter = m_xControl->get_iter_first(*m_xScratchIter);
591     while (bValidIter)
592     {
593         if (rDocument == GetEntryDescriptor(m_xScratchIter.get()).GetDocument())
594         {
595             RemoveEntry(*m_xScratchIter);
596             break;
597         }
598         bValidIter = m_xControl->iter_next(*m_xScratchIter);
599     }
600 }
601 
FindEntry(std::u16string_view rText,EntryType eType,weld::TreeIter & rIter)602 bool SbTreeListBox::FindEntry(std::u16string_view rText, EntryType eType, weld::TreeIter& rIter)
603 {
604     bool bValidIter = m_xControl->iter_children(rIter);
605     while (bValidIter)
606     {
607         Entry* pBasicEntry = reinterpret_cast<Entry*>(m_xControl->get_id(rIter).toInt64());
608         assert(pBasicEntry && "FindEntry: no Entry ?!");
609         if (pBasicEntry->GetType() == eType && rText == m_xControl->get_text(rIter))
610             return true;
611         bValidIter = m_xControl->iter_next_sibling(rIter);
612     }
613     return false;
614 }
615 
IsEntryProtected(const weld::TreeIter * pEntry)616 bool SbTreeListBox::IsEntryProtected(const weld::TreeIter* pEntry)
617 {
618     bool bProtected = false;
619     if (pEntry && m_xControl->get_iter_depth(*pEntry) == 1)
620     {
621         EntryDescriptor aDesc(GetEntryDescriptor(pEntry));
622         const ScriptDocument& rDocument( aDesc.GetDocument() );
623         OSL_ENSURE( rDocument.isAlive(), "TreeListBox::IsEntryProtected: no document, or document is dead!" );
624         if ( rDocument.isAlive() )
625         {
626             const OUString& aOULibName( aDesc.GetLibName() );
627             Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
628             if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) )
629             {
630                 Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
631                 if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) )
632                 {
633                     bProtected = true;
634                 }
635             }
636         }
637     }
638     return bProtected;
639 }
640 
AddEntry(const OUString & rText,const OUString & rImage,const weld::TreeIter * pParent,bool bChildrenOnDemand,std::unique_ptr<Entry> && rUserData,weld::TreeIter * pRet)641 void SbTreeListBox::AddEntry(
642     const OUString& rText,
643     const OUString& rImage,
644     const weld::TreeIter* pParent,
645     bool bChildrenOnDemand,
646     std::unique_ptr<Entry>&& rUserData,
647     weld::TreeIter* pRet)
648 {
649     if (m_bFreezeOnFirstAddRemove)
650     {
651         m_xControl->freeze();
652         m_bFreezeOnFirstAddRemove= false;
653     }
654     std::unique_ptr<weld::TreeIter> xScratch = pRet ? nullptr : m_xControl->make_iterator();
655     if (!pRet)
656         pRet = xScratch.get();
657     OUString sId(OUString::number(reinterpret_cast<sal_uInt64>(rUserData.release())));
658     m_xControl->insert(pParent, -1, &rText, &sId, nullptr, nullptr, bChildrenOnDemand, pRet);
659     m_xControl->set_image(*pRet, rImage);
660 }
661 
SetEntryBitmaps(const weld::TreeIter & rIter,const OUString & rImage)662 void SbTreeListBox::SetEntryBitmaps(const weld::TreeIter& rIter, const OUString& rImage)
663 {
664     m_xControl->set_image(rIter, rImage, -1);
665 }
666 
GetLibraryType() const667 LibraryType SbTreeListBox::GetLibraryType() const
668 {
669     LibraryType eType = LibraryType::All;
670     if ( ( nMode & BrowseMode::Modules ) && !( nMode & BrowseMode::Dialogs ) )
671         eType = LibraryType::Module;
672     else if ( !( nMode & BrowseMode::Modules ) && ( nMode & BrowseMode::Dialogs ) )
673         eType = LibraryType::Dialog;
674     return eType;
675 }
676 
GetRootEntryName(const ScriptDocument & rDocument,LibraryLocation eLocation) const677 OUString SbTreeListBox::GetRootEntryName( const ScriptDocument& rDocument, LibraryLocation eLocation ) const
678 {
679     return rDocument.getTitle( eLocation, GetLibraryType() );
680 }
681 
GetRootEntryBitmaps(const ScriptDocument & rDocument)682 OUString SbTreeListBox::GetRootEntryBitmaps(const ScriptDocument& rDocument)
683 {
684     OSL_ENSURE( rDocument.isValid(), "TreeListBox::GetRootEntryBitmaps: illegal document!" );
685     if (!rDocument.isValid())
686         return OUString();
687 
688     if ( rDocument.isDocument() )
689     {
690         OUString sFactoryURL;
691         Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
692         Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xContext) );
693         try
694         {
695             OUString sModule( xModuleManager->identify( rDocument.getDocument() ) );
696             Sequence< beans::PropertyValue > aModuleDescr;
697             xModuleManager->getByName( sModule ) >>= aModuleDescr;
698             sal_Int32 nCount = aModuleDescr.getLength();
699             const beans::PropertyValue* pModuleDescr = aModuleDescr.getConstArray();
700             for ( sal_Int32 i = 0; i < nCount; ++i )
701             {
702                 if ( pModuleDescr[ i ].Name == "ooSetupFactoryEmptyDocumentURL" )
703                 {
704                     pModuleDescr[ i ].Value >>= sFactoryURL;
705                     break;
706                 }
707             }
708         }
709         catch( const Exception& )
710         {
711             DBG_UNHANDLED_EXCEPTION("basctl.basicide");
712         }
713 
714         if ( !sFactoryURL.isEmpty() )
715         {
716             return SvFileInformationManager::GetFileImageId(INetURLObject(sFactoryURL));
717         }
718         else
719         {
720             // default icon
721             return RID_BMP_DOCUMENT;
722         }
723     }
724     return RID_BMP_INSTALLATION;
725 }
726 
SetCurrentEntry(EntryDescriptor const & rDesc)727 void SbTreeListBox::SetCurrentEntry (EntryDescriptor const & rDesc)
728 {
729     bool bCurEntry = false;
730     auto xCurIter = m_xControl->make_iterator();
731     EntryDescriptor aDesc = rDesc;
732     if ( aDesc.GetType() == OBJ_TYPE_UNKNOWN )
733     {
734         aDesc = EntryDescriptor(
735             ScriptDocument::getApplicationScriptDocument(),
736             LIBRARY_LOCATION_USER, "Standard",
737             OUString(), ".", OBJ_TYPE_UNKNOWN
738         );
739     }
740     ScriptDocument aDocument = aDesc.GetDocument();
741     OSL_ENSURE( aDocument.isValid(), "TreeListBox::SetCurrentEntry: invalid document!" );
742     LibraryLocation eLocation = aDesc.GetLocation();
743     bool bRootEntry = FindRootEntry(aDocument, eLocation, *m_xScratchIter);
744     if (bRootEntry)
745     {
746         m_xControl->copy_iterator(*m_xScratchIter, *xCurIter);
747         bCurEntry = true;
748         const OUString& aLibName( aDesc.GetLibName() );
749         if ( !aLibName.isEmpty() )
750         {
751             m_xControl->expand_row(*m_xScratchIter);
752             auto xLibIter = m_xControl->make_iterator(m_xScratchIter.get());
753             bool bLibEntry = FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xLibIter);
754             if (bLibEntry)
755             {
756                 m_xControl->copy_iterator(*xLibIter, *xCurIter);
757                 const OUString& aLibSubName( aDesc.GetLibSubName() );
758                 if( !aLibSubName.isEmpty() )
759                 {
760                     m_xControl->expand_row(*xLibIter);
761                     auto xSubLibIter = m_xControl->make_iterator(xLibIter.get());
762                     bool bSubLibEntry = ImpFindEntry(*xSubLibIter, aLibSubName);
763                     if (bSubLibEntry)
764                     {
765                         m_xControl->copy_iterator(*xSubLibIter, *xCurIter);
766                     }
767                 }
768                 const OUString& aName( aDesc.GetName() );
769                 if ( !aName.isEmpty() )
770                 {
771                     m_xControl->expand_row(*xCurIter);
772                     EntryType eType = OBJ_TYPE_MODULE;
773                     if ( aDesc.GetType() == OBJ_TYPE_DIALOG )
774                         eType = OBJ_TYPE_DIALOG;
775                     auto xEntryIter = m_xControl->make_iterator(xCurIter.get());
776                     bool bEntry = FindEntry(aName, eType, *xEntryIter);
777                     if (bEntry)
778                     {
779                         m_xControl->copy_iterator(*xEntryIter, *xCurIter);
780                         const OUString& aMethodName( aDesc.GetMethodName() );
781                         if (!aMethodName.isEmpty())
782                         {
783                             m_xControl->expand_row(*xCurIter);
784                             auto xSubEntryIter = m_xControl->make_iterator(xCurIter.get());
785                             bool bSubEntry = FindEntry(aMethodName, OBJ_TYPE_METHOD, *xSubEntryIter);
786                             if (bSubEntry)
787                             {
788                                 m_xControl->copy_iterator(*xSubEntryIter, *xCurIter);
789                             }
790                             else
791                             {
792                                 m_xControl->copy_iterator(*xCurIter, *xSubEntryIter);
793                                 if (m_xControl->iter_children(*xSubEntryIter))
794                                     m_xControl->copy_iterator(*xSubEntryIter, *xCurIter);
795                             }
796                         }
797                     }
798                     else
799                     {
800                         auto xSubEntryIter = m_xControl->make_iterator(xCurIter.get());
801                         if (m_xControl->iter_children(*xSubEntryIter))
802                             m_xControl->copy_iterator(*xSubEntryIter, *xCurIter);
803                     }
804                 }
805             }
806             else
807             {
808                 auto xSubLibIter = m_xControl->make_iterator(m_xScratchIter.get());
809                 if (m_xControl->iter_children(*xSubLibIter))
810                     m_xControl->copy_iterator(*xLibIter, *xCurIter);
811             }
812         }
813     }
814     else
815     {
816         bCurEntry = m_xControl->get_iter_first(*xCurIter);
817     }
818 
819     if (!bCurEntry)
820         return;
821 
822     m_xControl->set_cursor(*xCurIter);
823 }
824 
IMPL_LINK_NOARG(SbTreeListBox,OpenCurrentHdl,weld::TreeView &,bool)825 IMPL_LINK_NOARG(SbTreeListBox, OpenCurrentHdl, weld::TreeView&, bool)
826 {
827     bool bValidIter = m_xControl->get_cursor(m_xScratchIter.get());
828     if (!bValidIter)
829         return true;
830     if (!m_xControl->get_row_expanded(*m_xScratchIter))
831         m_xControl->expand_row(*m_xScratchIter);
832     else
833         m_xControl->collapse_row(*m_xScratchIter);
834 
835     EntryDescriptor aDesc = GetEntryDescriptor(m_xScratchIter.get());
836     switch (aDesc.GetType())
837     {
838         case OBJ_TYPE_METHOD:
839         case OBJ_TYPE_MODULE:
840         case OBJ_TYPE_DIALOG:
841             if (SfxDispatcher* pDispatcher = GetDispatcher())
842             {
843                 SbxItem aSbxItem(
844                     SID_BASICIDE_ARG_SBX, aDesc.GetDocument(),
845                     aDesc.GetLibName(), aDesc.GetName(), aDesc.GetMethodName(),
846                     ConvertType(aDesc.GetType())
847                 );
848                 pDispatcher->ExecuteList(
849                     SID_BASICIDE_SHOWSBX, SfxCallMode::SYNCHRON,
850                     { &aSbxItem }
851                 );
852             }
853             break;
854 
855         default:
856             break;
857     }
858     return true;
859 }
860 
861 } // namespace basctl
862 
863 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
864