xref: /core/basctl/source/basicide/bastype2.cxx (revision 44688e49)
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 <bastypes.hxx>
22 #include <bastype2.hxx>
23 #include <strings.hrc>
24 #include <bitmaps.hlst>
25 #include <iderid.hxx>
26 #include <o3tl/make_unique.hxx>
27 #include <tools/urlobj.hxx>
28 #include <tools/diagnose_ex.h>
29 #include <svtools/imagemgr.hxx>
30 #include <svtools/treelistentry.hxx>
31 #include <com/sun/star/script/XLibraryContainerPassword.hpp>
32 #include <com/sun/star/frame/ModuleManager.hpp>
33 #include <comphelper/processfactory.hxx>
34 #include <sfx2/dispatch.hxx>
35 #include <vcl/builderfactory.hxx>
36 
37 #include <initializer_list>
38 #include <memory>
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 
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 
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 
86 Entry::~Entry()
87 { }
88 
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 
101 DocumentEntry::~DocumentEntry()
102 { }
103 
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 
113 LibEntry::~LibEntry()
114 { }
115 
116 EntryDescriptor::EntryDescriptor () :
117     m_aDocument(ScriptDocument::getApplicationScriptDocument()),
118     m_eLocation(LIBRARY_LOCATION_UNKNOWN),
119     m_eType(OBJ_TYPE_UNKNOWN)
120 { }
121 
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 
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 
160 TreeListBox::TreeListBox (vcl::Window* pParent, WinBits nStyle)
161     : SvTreeListBox(pParent, nStyle)
162     , m_aNotifier( *this )
163 {
164     SetNodeDefaultImages();
165     SetSelectionMode( SelectionMode::Single );
166     nMode = BrowseMode::All;   // everything
167 }
168 
169 VCL_BUILDER_FACTORY_CONSTRUCTOR(TreeListBox, WB_TABSTOP)
170 
171 TreeListBox::~TreeListBox ()
172 {
173     disposeOnce();
174 }
175 
176 void TreeListBox::dispose()
177 {
178     m_aNotifier.dispose();
179 
180     // destroy user data
181     SvTreeListEntry* pEntry = First();
182     while ( pEntry )
183     {
184         delete static_cast<Entry*>( pEntry->GetUserData() );
185         pEntry->SetUserData( nullptr );
186         pEntry = Next( pEntry );
187     }
188     SvTreeListBox::dispose();
189 }
190 
191 void TreeListBox::ScanEntry( const ScriptDocument& rDocument, LibraryLocation eLocation )
192 {
193     OSL_ENSURE( rDocument.isAlive(), "TreeListBox::ScanEntry: illegal document!" );
194     if ( !rDocument.isAlive() )
195         return;
196 
197     // can be called multiple times for updating!
198 
199     // actually test if basic's in the tree already?!
200     SetUpdateMode(false);
201 
202     // level 1: BasicManager (application, document, ...)
203     SvTreeListEntry* pDocumentRootEntry = FindRootEntry( rDocument, eLocation );
204     if ( pDocumentRootEntry && IsExpanded( pDocumentRootEntry ) )
205         ImpCreateLibEntries( pDocumentRootEntry, rDocument, eLocation );
206     if ( !pDocumentRootEntry )
207     {
208         OUString aRootName( GetRootEntryName( rDocument, eLocation ) );
209         Image aImage;
210         GetRootEntryBitmaps( rDocument, aImage );
211         AddEntry(
212             aRootName,
213             aImage,
214             nullptr, true, o3tl::make_unique<DocumentEntry>(rDocument, eLocation));
215     }
216 
217     SetUpdateMode(true);
218 }
219 
220 void TreeListBox::ImpCreateLibEntries( SvTreeListEntry* pDocumentRootEntry, const ScriptDocument& rDocument, LibraryLocation eLocation )
221 {
222     // get a sorted list of library names
223     Sequence< OUString > aLibNames( rDocument.getLibraryNames() );
224     sal_Int32 nLibCount = aLibNames.getLength();
225     const OUString* pLibNames = aLibNames.getConstArray();
226 
227     for ( sal_Int32 i = 0 ; i < nLibCount ; i++ )
228     {
229         OUString aLibName = pLibNames[ i ];
230 
231         if ( eLocation == rDocument.getLibraryLocation( aLibName ) )
232         {
233             // check, if the module library is loaded
234             bool bModLibLoaded = false;
235             Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
236             if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryLoaded( aLibName ) )
237                 bModLibLoaded = true;
238 
239             // check, if the dialog library is loaded
240             bool bDlgLibLoaded = false;
241             Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
242             if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryLoaded( aLibName ) )
243                 bDlgLibLoaded = true;
244 
245             bool bLoaded = bModLibLoaded || bDlgLibLoaded;
246 
247             // if only one of the libraries is loaded, load also the other
248             if ( bLoaded )
249             {
250                 if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) )
251                     xModLibContainer->loadLibrary( aLibName );
252 
253                 if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) )
254                     xDlgLibContainer->loadLibrary( aLibName );
255             }
256 
257             // create tree list box entry
258             OUString sId;
259             if ( ( nMode & BrowseMode::Dialogs ) && !( nMode & BrowseMode::Modules ) )
260                 sId = bLoaded ? OUStringLiteral(RID_BMP_DLGLIB) : OUStringLiteral(RID_BMP_DLGLIBNOTLOADED);
261             else
262                 sId = bLoaded ? OUStringLiteral(RID_BMP_MODLIB) : OUStringLiteral(RID_BMP_MODLIBNOTLOADED);
263             SvTreeListEntry* pLibRootEntry = FindEntry( pDocumentRootEntry, aLibName, OBJ_TYPE_LIBRARY );
264             if ( pLibRootEntry )
265             {
266                 SetEntryBitmaps(pLibRootEntry, Image(BitmapEx(sId)));
267                 if ( IsExpanded(pLibRootEntry))
268                     ImpCreateLibSubEntries( pLibRootEntry, rDocument, aLibName );
269             }
270             else
271             {
272                 AddEntry(
273                     aLibName,
274                     Image(BitmapEx(sId)),
275                     pDocumentRootEntry, true,
276                     o3tl::make_unique<Entry>(OBJ_TYPE_LIBRARY));
277             }
278         }
279     }
280 }
281 
282 void TreeListBox::ImpCreateLibSubEntries( SvTreeListEntry* pLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName )
283 {
284     // modules
285     if ( nMode & BrowseMode::Modules )
286     {
287         Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) );
288 
289         if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) && xModLibContainer->isLibraryLoaded( rLibName ) )
290         {
291             try
292             {
293                 if( rDocument.isInVBAMode() )
294                     ImpCreateLibSubEntriesInVBAMode( pLibRootEntry, rDocument, rLibName );
295                 else
296                 {
297                     // get a sorted list of module names
298                     Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName );
299                     sal_Int32 nModCount = aModNames.getLength();
300                     const OUString* pModNames = aModNames.getConstArray();
301 
302                     for ( sal_Int32 i = 0 ; i < nModCount ; i++ )
303                     {
304                         OUString aModName = pModNames[ i ];
305                         SvTreeListEntry* pModuleEntry = FindEntry( pLibRootEntry, aModName, OBJ_TYPE_MODULE );
306                         if ( !pModuleEntry )
307                         {
308                             pModuleEntry = AddEntry(
309                                 aModName,
310                                 Image(BitmapEx(RID_BMP_MODULE)),
311                                 pLibRootEntry, false,
312                                 o3tl::make_unique<Entry>(OBJ_TYPE_MODULE));
313                         }
314 
315                         // methods
316                         if ( nMode & BrowseMode::Subs )
317                         {
318                             Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName );
319                             sal_Int32 nCount = aNames.getLength();
320                             const OUString* pNames = aNames.getConstArray();
321 
322                             for ( sal_Int32 j = 0 ; j < nCount ; j++ )
323                             {
324                                 OUString aName = pNames[ j ];
325                                 SvTreeListEntry* pEntry = FindEntry( pModuleEntry, aName, OBJ_TYPE_METHOD );
326                                 if ( !pEntry )
327                                 {
328                                     AddEntry(
329                                         aName,
330                                         Image(BitmapEx(RID_BMP_MACRO)),
331                                         pModuleEntry, false,
332                                         o3tl::make_unique<Entry>(
333                                             OBJ_TYPE_METHOD));
334                                 }
335                             }
336                         }
337                     }
338                 }
339             }
340             catch ( const container::NoSuchElementException& )
341             {
342                 DBG_UNHANDLED_EXCEPTION("basctl.basicide");
343             }
344         }
345     }
346 
347     // dialogs
348     if ( nMode & BrowseMode::Dialogs )
349     {
350          Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) );
351 
352          if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( rLibName ) && xDlgLibContainer->isLibraryLoaded( rLibName ) )
353          {
354             try
355             {
356                 // get a sorted list of dialog names
357                 Sequence< OUString > aDlgNames( rDocument.getObjectNames( E_DIALOGS, rLibName ) );
358                 sal_Int32 nDlgCount = aDlgNames.getLength();
359                 const OUString* pDlgNames = aDlgNames.getConstArray();
360 
361                 for ( sal_Int32 i = 0 ; i < nDlgCount ; i++ )
362                 {
363                     OUString aDlgName = pDlgNames[ i ];
364                     SvTreeListEntry* pDialogEntry = FindEntry( pLibRootEntry, aDlgName, OBJ_TYPE_DIALOG );
365                     if ( !pDialogEntry )
366                     {
367                         AddEntry(
368                             aDlgName,
369                             Image(BitmapEx(RID_BMP_DIALOG)),
370                             pLibRootEntry, false,
371                             o3tl::make_unique<Entry>(OBJ_TYPE_DIALOG));
372                     }
373                 }
374             }
375             catch (const container::NoSuchElementException& )
376             {
377                 DBG_UNHANDLED_EXCEPTION("basctl.basicide");
378             }
379         }
380     }
381 }
382 
383 void TreeListBox::ImpCreateLibSubEntriesInVBAMode( SvTreeListEntry* pLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName )
384 {
385     auto const aEntries = {
386         std::make_pair( OBJ_TYPE_DOCUMENT_OBJECTS, IDEResId(RID_STR_DOCUMENT_OBJECTS) ),
387         std::make_pair( OBJ_TYPE_USERFORMS, IDEResId(RID_STR_USERFORMS) ),
388         std::make_pair( OBJ_TYPE_NORMAL_MODULES, IDEResId(RID_STR_NORMAL_MODULES) ),
389         std::make_pair( OBJ_TYPE_CLASS_MODULES, IDEResId(RID_STR_CLASS_MODULES) ) };
390     for( auto const & iter: aEntries )
391     {
392         EntryType eType = iter.first;
393         OUString const & aEntryName = iter.second;
394         SvTreeListEntry* pLibSubRootEntry = FindEntry( pLibRootEntry, aEntryName, eType );
395         if( pLibSubRootEntry )
396         {
397             SetEntryBitmaps(pLibSubRootEntry, Image(BitmapEx(RID_BMP_MODLIB)));
398             if ( IsExpanded( pLibSubRootEntry ) )
399                 ImpCreateLibSubSubEntriesInVBAMode( pLibSubRootEntry, rDocument, rLibName );
400         }
401         else
402         {
403             AddEntry(
404                 aEntryName,
405                 Image(BitmapEx(RID_BMP_MODLIB)),
406                 pLibRootEntry, true, o3tl::make_unique<Entry>(eType));
407         }
408     }
409 }
410 
411 void TreeListBox::ImpCreateLibSubSubEntriesInVBAMode( SvTreeListEntry* pLibSubRootEntry, const ScriptDocument& rDocument, const OUString& rLibName )
412 {
413     uno::Reference< container::XNameContainer > xLib = rDocument.getOrCreateLibrary( E_SCRIPTS, rLibName );
414     if( !xLib.is() )
415         return;
416 
417     try
418     {
419         // get a sorted list of module names
420         Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName );
421         sal_Int32 nModCount = aModNames.getLength();
422         const OUString* pModNames = aModNames.getConstArray();
423 
424         EntryDescriptor aDesc( GetEntryDescriptor( pLibSubRootEntry ) );
425         EntryType eCurrentType( aDesc.GetType() );
426 
427         for ( sal_Int32 i = 0 ; i < nModCount ; i++ )
428         {
429             OUString aModName = pModNames[ i ];
430             EntryType eType = OBJ_TYPE_UNKNOWN;
431             switch( ModuleInfoHelper::getModuleType( xLib, aModName ) )
432             {
433                 case script::ModuleType::DOCUMENT:
434                     eType = OBJ_TYPE_DOCUMENT_OBJECTS;
435                     break;
436                 case script::ModuleType::FORM:
437                     eType = OBJ_TYPE_USERFORMS;
438                     break;
439                 case script::ModuleType::NORMAL:
440                     eType = OBJ_TYPE_NORMAL_MODULES;
441                     break;
442                 case script::ModuleType::CLASS:
443                     eType = OBJ_TYPE_CLASS_MODULES;
444                     break;
445             }
446             if( eType != eCurrentType )
447                 continue;
448 
449             // display a nice friendly name in the ObjectModule tab,
450                // combining the objectname and module name, e.g. Sheet1 ( Financials )
451             OUString aEntryName = aModName;
452             if( eType == OBJ_TYPE_DOCUMENT_OBJECTS )
453             {
454                 OUString sObjName;
455                 ModuleInfoHelper::getObjectName( xLib, aModName, sObjName );
456                 if( !sObjName.isEmpty() )
457                 {
458                     aEntryName += " (" + sObjName + ")";
459                 }
460             }
461             SvTreeListEntry* pModuleEntry = FindEntry( pLibSubRootEntry, aEntryName, OBJ_TYPE_MODULE );
462             if ( !pModuleEntry )
463             {
464                 pModuleEntry = AddEntry(
465                     aEntryName,
466                     Image(BitmapEx(RID_BMP_MODULE)),
467                     pLibSubRootEntry, false,
468                     o3tl::make_unique<Entry>(OBJ_TYPE_MODULE));
469             }
470 
471             // methods
472             if ( nMode & BrowseMode::Subs )
473             {
474                 Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName );
475                 sal_Int32 nCount = aNames.getLength();
476                 const OUString* pNames = aNames.getConstArray();
477 
478                 for ( sal_Int32 j = 0 ; j < nCount ; j++ )
479                 {
480                     OUString aName = pNames[ j ];
481                     SvTreeListEntry* pEntry = FindEntry( pModuleEntry, aName, OBJ_TYPE_METHOD );
482                     if ( !pEntry )
483                     {
484                         AddEntry(
485                             aName,
486                             Image(BitmapEx(RID_BMP_MACRO)),
487                             pModuleEntry, false,
488                             o3tl::make_unique<Entry>(OBJ_TYPE_METHOD));
489                     }
490                 }
491             }
492         }
493     }
494     catch ( const container::NoSuchElementException& )
495     {
496         DBG_UNHANDLED_EXCEPTION("basctl.basicide");
497     }
498 }
499 
500 SvTreeListEntry* TreeListBox::ImpFindEntry( SvTreeListEntry* pParent, const OUString& rText )
501 {
502     sal_uLong nRootPos = 0;
503     SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : GetEntry( nRootPos );
504     while ( pEntry )
505     {
506         if (  rText == GetEntryText( pEntry ) )
507             return pEntry;
508 
509         pEntry = pParent ? pEntry->NextSibling() : GetEntry( ++nRootPos );
510     }
511     return nullptr;
512 }
513 
514 void TreeListBox::onDocumentCreated( const ScriptDocument& /*_rDocument*/ )
515 {
516     UpdateEntries();
517 }
518 
519 void TreeListBox::onDocumentOpened( const ScriptDocument& /*_rDocument*/ )
520 {
521     UpdateEntries();
522 }
523 
524 void TreeListBox::onDocumentSave( const ScriptDocument& /*_rDocument*/ )
525 {
526     // not interested in
527 }
528 
529 void TreeListBox::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ )
530 {
531     // not interested in
532 }
533 
534 void TreeListBox::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ )
535 {
536     // not interested in
537 }
538 
539 void TreeListBox::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ )
540 {
541     UpdateEntries();
542 }
543 
544 void TreeListBox::onDocumentClosed( const ScriptDocument& rDocument )
545 {
546     UpdateEntries();
547     // The document is not yet actually deleted, so we need to remove its entry
548     // manually.
549     RemoveEntry(rDocument);
550 }
551 
552 void TreeListBox::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ )
553 {
554     // not interested in
555 }
556 
557 void TreeListBox::onDocumentModeChanged( const ScriptDocument& /*_rDocument*/ )
558 {
559     // not interested in
560 }
561 
562 void TreeListBox::UpdateEntries()
563 {
564     EntryDescriptor aCurDesc( GetEntryDescriptor( FirstSelected() ) );
565 
566     // removing the invalid entries
567     SvTreeListEntry* pLastValid = nullptr;
568     SvTreeListEntry* pEntry = First();
569     while ( pEntry )
570     {
571         if ( IsValidEntry( pEntry ) )
572             pLastValid = pEntry;
573         else
574             RemoveEntry(pEntry);
575         pEntry = pLastValid ? Next( pLastValid ) : First();
576     }
577 
578     ScanAllEntries();
579 
580     SetCurrentEntry( aCurDesc );
581 }
582 
583 // Removes the entry from the tree.
584 void TreeListBox::RemoveEntry (SvTreeListEntry const * pEntry)
585 {
586     // removing the associated user data
587     delete static_cast<Entry*>(pEntry->GetUserData());
588     // removing the entry
589     GetModel()->Remove( pEntry );
590 }
591 
592 // Removes the entry of rDocument.
593 void TreeListBox::RemoveEntry (ScriptDocument const& rDocument)
594 {
595     // finding the entry of rDocument
596     for (SvTreeListEntry* pEntry = First(); pEntry; pEntry = Next(pEntry))
597         if (rDocument == GetEntryDescriptor(pEntry).GetDocument())
598         {
599             RemoveEntry(pEntry);
600             break;
601         }
602 }
603 
604 SvTreeListEntry* TreeListBox::CloneEntry( SvTreeListEntry* pSource )
605 {
606     SvTreeListEntry* pNew = SvTreeListBox::CloneEntry( pSource );
607     Entry* pUser = static_cast<Entry*>(pSource->GetUserData());
608 
609     assert(pUser && "User data?!");
610     DBG_ASSERT( pUser->GetType() != OBJ_TYPE_DOCUMENT, "TreeListBox::CloneEntry: document?!" );
611 
612     Entry* pNewUser = new Entry( *pUser );
613     pNew->SetUserData( pNewUser );
614     return pNew;
615 }
616 
617 SvTreeListEntry* TreeListBox::FindEntry( SvTreeListEntry* pParent, const OUString& rText, EntryType eType )
618 {
619     sal_uLong nRootPos = 0;
620     SvTreeListEntry* pEntry = pParent ? FirstChild( pParent ) : GetEntry( nRootPos );
621     while ( pEntry )
622     {
623         Entry* pBasicEntry = static_cast<Entry*>(pEntry->GetUserData());
624         assert(pBasicEntry && "FindEntry: no Entry ?!");
625         if ( ( pBasicEntry->GetType() == eType  ) && ( rText == GetEntryText( pEntry ) ) )
626             return pEntry;
627 
628         pEntry = pParent ? pEntry->NextSibling() : GetEntry( ++nRootPos );
629     }
630     return nullptr;
631 }
632 
633 bool TreeListBox::ExpandingHdl()
634 {
635     // expanding or collapsing?
636     bool bOK = true;
637     if ( GetModel()->GetDepth( GetHdlEntry() ) == 1 )
638     {
639         SvTreeListEntry* pCurEntry = GetCurEntry();
640         EntryDescriptor aDesc( GetEntryDescriptor( pCurEntry ) );
641         const ScriptDocument& aDocument( aDesc.GetDocument() );
642         OSL_ENSURE( aDocument.isAlive(), "TreeListBox::ExpandingHdl: no document, or document is dead!" );
643         if ( aDocument.isAlive() )
644         {
645             const OUString& aLibName( aDesc.GetLibName() );
646             const OUString& aLibSubName( aDesc.GetLibSubName() );
647             const OUString& aName( aDesc.GetName() );
648             const OUString& aMethodName( aDesc.GetMethodName() );
649 
650             if ( !aLibName.isEmpty() && aLibSubName.isEmpty() && aName.isEmpty() && aMethodName.isEmpty() )
651             {
652                 // check password, if library is password protected and not verified
653                 Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
654                 if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) )
655                 {
656                     Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
657                     if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) )
658                     {
659                         OUString aPassword;
660                         bOK = QueryPassword( xModLibContainer, aLibName, aPassword );
661                     }
662                 }
663             }
664         }
665     }
666     return bOK;
667 }
668 
669 bool TreeListBox::IsEntryProtected( SvTreeListEntry* pEntry )
670 {
671     bool bProtected = false;
672     if ( pEntry && ( GetModel()->GetDepth( pEntry ) == 1 ) )
673     {
674         EntryDescriptor aDesc( GetEntryDescriptor( pEntry ) );
675         const ScriptDocument& aDocument( aDesc.GetDocument() );
676         OSL_ENSURE( aDocument.isAlive(), "TreeListBox::IsEntryProtected: no document, or document is dead!" );
677         if ( aDocument.isAlive() )
678         {
679             const OUString& aOULibName( aDesc.GetLibName() );
680             Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
681             if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) )
682             {
683                 Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY );
684                 if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) )
685                 {
686                     bProtected = true;
687                 }
688             }
689         }
690     }
691     return bProtected;
692 }
693 
694 SvTreeListEntry* TreeListBox::AddEntry(
695     OUString const& rText,
696     const Image& rImage,
697     SvTreeListEntry* pParent,
698     bool bChildrenOnDemand,
699     std::unique_ptr<Entry> && aUserData
700 )
701 {
702     SvTreeListEntry* p = InsertEntry(
703         rText, rImage, rImage, pParent, bChildrenOnDemand, TREELIST_APPEND,
704         aUserData.get()
705     );
706     aUserData.release();
707     return p;
708 }
709 
710 void TreeListBox::SetEntryBitmaps( SvTreeListEntry * pEntry, const Image& rImage )
711 {
712     SetExpandedEntryBmp(  pEntry, rImage );
713     SetCollapsedEntryBmp( pEntry, rImage );
714 }
715 
716 LibraryType TreeListBox::GetLibraryType() const
717 {
718     LibraryType eType = LibraryType::All;
719     if ( ( nMode & BrowseMode::Modules ) && !( nMode & BrowseMode::Dialogs ) )
720         eType = LibraryType::Module;
721     else if ( !( nMode & BrowseMode::Modules ) && ( nMode & BrowseMode::Dialogs ) )
722         eType = LibraryType::Dialog;
723     return eType;
724 }
725 
726 OUString TreeListBox::GetRootEntryName( const ScriptDocument& rDocument, LibraryLocation eLocation ) const
727 {
728     return rDocument.getTitle( eLocation, GetLibraryType() );
729 }
730 
731 void TreeListBox::GetRootEntryBitmaps( const ScriptDocument& rDocument, Image& rImage )
732 {
733     OSL_ENSURE( rDocument.isValid(), "TreeListBox::GetRootEntryBitmaps: illegal document!" );
734     if ( !rDocument.isValid() )
735         return;
736 
737     if ( rDocument.isDocument() )
738     {
739         OUString sFactoryURL;
740         Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() );
741         Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xContext) );
742         try
743         {
744             OUString sModule( xModuleManager->identify( rDocument.getDocument() ) );
745             Reference< container::XNameAccess > xModuleConfig( xModuleManager, UNO_QUERY );
746             if ( xModuleConfig.is() )
747             {
748                 Sequence< beans::PropertyValue > aModuleDescr;
749                 xModuleConfig->getByName( sModule ) >>= aModuleDescr;
750                 sal_Int32 nCount = aModuleDescr.getLength();
751                 const beans::PropertyValue* pModuleDescr = aModuleDescr.getConstArray();
752                 for ( sal_Int32 i = 0; i < nCount; ++i )
753                 {
754                     if ( pModuleDescr[ i ].Name == "ooSetupFactoryEmptyDocumentURL" )
755                     {
756                         pModuleDescr[ i ].Value >>= sFactoryURL;
757                         break;
758                     }
759                 }
760             }
761         }
762         catch( const Exception& )
763         {
764             DBG_UNHANDLED_EXCEPTION("basctl.basicide");
765         }
766 
767         if ( !sFactoryURL.isEmpty() )
768         {
769             rImage = SvFileInformationManager::GetFileImage( INetURLObject( sFactoryURL ) );
770         }
771         else
772         {
773             // default icon
774             rImage = Image(BitmapEx(RID_BMP_DOCUMENT));
775         }
776     }
777     else
778     {
779         rImage = Image(BitmapEx(RID_BMP_INSTALLATION));
780     }
781 }
782 
783 void TreeListBox::SetCurrentEntry (EntryDescriptor const & rDesc)
784 {
785     SvTreeListEntry* pCurEntry = nullptr;
786     EntryDescriptor aDesc = rDesc;
787     if ( aDesc.GetType() == OBJ_TYPE_UNKNOWN )
788     {
789         aDesc = EntryDescriptor(
790             ScriptDocument::getApplicationScriptDocument(),
791             LIBRARY_LOCATION_USER, "Standard",
792             OUString(), ".", OBJ_TYPE_UNKNOWN
793         );
794     }
795     ScriptDocument aDocument = aDesc.GetDocument();
796     OSL_ENSURE( aDocument.isValid(), "TreeListBox::SetCurrentEntry: invalid document!" );
797     LibraryLocation eLocation = aDesc.GetLocation();
798     SvTreeListEntry* pRootEntry = FindRootEntry( aDocument, eLocation );
799     if ( pRootEntry )
800     {
801         pCurEntry = pRootEntry;
802         const OUString& aLibName( aDesc.GetLibName() );
803         if ( !aLibName.isEmpty() )
804         {
805             Expand( pRootEntry );
806             SvTreeListEntry* pLibEntry = FindEntry( pRootEntry, aLibName, OBJ_TYPE_LIBRARY );
807             if ( pLibEntry )
808             {
809                 pCurEntry = pLibEntry;
810                 const OUString& aLibSubName( aDesc.GetLibSubName() );
811                 if( !aLibSubName.isEmpty() )
812                 {
813                     Expand( pLibEntry );
814                     SvTreeListEntry* pLibSubEntry = ImpFindEntry( pLibEntry, aLibSubName );
815                     if( pLibSubEntry )
816                     {
817                         pCurEntry = pLibSubEntry;
818                     }
819                 }
820                 const OUString& aName( aDesc.GetName() );
821                 if ( !aName.isEmpty() )
822                 {
823                     Expand( pCurEntry );
824                     EntryType eType = OBJ_TYPE_MODULE;
825                     if ( aDesc.GetType() == OBJ_TYPE_DIALOG )
826                         eType = OBJ_TYPE_DIALOG;
827                     SvTreeListEntry* pEntry = FindEntry( pCurEntry, aName, eType );
828                     if ( pEntry )
829                     {
830                         pCurEntry = pEntry;
831                         const OUString& aMethodName( aDesc.GetMethodName() );
832                         if ( !aMethodName.isEmpty() )
833                         {
834                             Expand( pEntry );
835                             SvTreeListEntry* pSubEntry = FindEntry( pEntry, aMethodName, OBJ_TYPE_METHOD );
836                             if ( pSubEntry )
837                             {
838                                 pCurEntry = pSubEntry;
839                             }
840                             else
841                             {
842                                 pSubEntry = FirstChild( pEntry );
843                                 if ( pSubEntry )
844                                     pCurEntry = pSubEntry;
845                             }
846                         }
847                     }
848                     else
849                     {
850                         pEntry = FirstChild( pLibEntry );
851                         if ( pEntry )
852                             pCurEntry = pEntry;
853                     }
854                 }
855             }
856             else
857             {
858                 pLibEntry = FirstChild( pRootEntry );
859                 if ( pLibEntry )
860                     pCurEntry = pLibEntry;
861             }
862         }
863     }
864     else
865     {
866         pRootEntry = First();
867         if ( pRootEntry )
868             pCurEntry = pRootEntry;
869     }
870 
871     SetCurEntry( pCurEntry );
872 }
873 
874 void TreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
875 {
876     SvTreeListBox::MouseButtonDown( rMEvt );
877     if ( rMEvt.IsLeft() && ( rMEvt.GetClicks() == 2 ) )
878     {
879         OpenCurrent();
880     }
881 }
882 
883 void TreeListBox::KeyInput( const KeyEvent& rEvt )
884 {
885     if ( rEvt.GetKeyCode() == KEY_RETURN && OpenCurrent() )
886     {
887         return;
888     }
889     SvTreeListBox::KeyInput( rEvt );
890 }
891 
892 bool TreeListBox::OpenCurrent()
893 {
894     EntryDescriptor aDesc = GetEntryDescriptor(GetCurEntry());
895     switch (aDesc.GetType())
896     {
897         case OBJ_TYPE_METHOD:
898         case OBJ_TYPE_MODULE:
899         case OBJ_TYPE_DIALOG:
900             if (SfxDispatcher* pDispatcher = GetDispatcher())
901             {
902                 SbxItem aSbxItem(
903                     SID_BASICIDE_ARG_SBX, aDesc.GetDocument(),
904                     aDesc.GetLibName(), aDesc.GetName(), aDesc.GetMethodName(),
905                     ConvertType(aDesc.GetType())
906                 );
907                 pDispatcher->ExecuteList(
908                     SID_BASICIDE_SHOWSBX, SfxCallMode::SYNCHRON,
909                     { &aSbxItem }
910                 );
911                 return true;
912             }
913             break;
914 
915         default:
916             break;
917     }
918     return false;
919 }
920 
921 } // namespace basctl
922 
923 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
924