xref: /core/basctl/source/basicide/macrodlg.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 "macrodlg.hxx"
22 #include <basidesh.hxx>
23 #include <strings.hrc>
24 
25 #include <iderdll.hxx>
26 #include "iderdll2.hxx"
27 
28 #include "moduldlg.hxx"
29 #include <basic/basmgr.hxx>
30 #include <basic/sbmeth.hxx>
31 #include <basic/sbmod.hxx>
32 
33 #include <sfx2/dispatch.hxx>
34 #include <sfx2/minfitem.hxx>
35 #include <sfx2/request.hxx>
36 #include <vcl/weld.hxx>
37 
38 #include <map>
39 
40 namespace basctl
41 {
42 
43 using std::map;
44 
45 using namespace ::com::sun::star;
46 using namespace ::com::sun::star::uno;
47 
48 MacroChooser::MacroChooser( vcl::Window* pParnt, const Reference< frame::XFrame >& xDocFrame, bool bCreateEntries )
49     : SfxModalDialog(pParnt, "BasicMacroDialog", "modules/BasicIDE/ui/basicmacrodialog.ui")
50     , m_xDocumentFrame(xDocFrame)
51     , bNewDelIsDel(true)
52     // the Sfx doesn't ask the BasicManager whether modified or not
53     // => start saving in case of a change without a into the BasicIDE.
54     , bForceStoreBasic(false)
55     , nMode(All)
56 {
57     get(m_pMacroNameEdit, "macronameedit");
58     get(m_pMacroFromTxT, "macrofromft");
59     get(m_pMacrosSaveInTxt, "macrotoft");
60     get(m_pBasicBox, "libraries");
61     get(m_pMacrosInTxt, "existingmacrosft");
62     m_aMacrosInTxtBaseStr = m_pMacrosInTxt->GetText();
63     get(m_pMacroBox, "macros");
64     get(m_pRunButton, "run");
65     get(m_pCloseButton, "close");
66     get(m_pAssignButton, "assign");
67     get(m_pEditButton, "edit");
68     get(m_pDelButton, "delete");
69     get(m_pOrganizeButton, "organize");
70     get(m_pNewLibButton, "newlibrary");
71     get(m_pNewModButton, "newmodule");
72 
73     m_pMacroBox->SetSelectionMode( SelectionMode::Single );
74     m_pMacroBox->SetHighlightRange(); // select over the whole width
75 
76     m_pRunButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
77     m_pCloseButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
78     m_pAssignButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
79     m_pEditButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
80     m_pDelButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
81     m_pOrganizeButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
82 
83     // Buttons only for MacroChooser::Recording
84     m_pNewLibButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
85     m_pNewModButton->SetClickHdl( LINK( this, MacroChooser, ButtonHdl ) );
86     m_pNewLibButton->Hide();       // default
87     m_pNewModButton->Hide();       // default
88     m_pMacrosSaveInTxt->Hide();    // default
89 
90     m_pMacrosInTxt->SetStyle( WB_NOMULTILINE | WB_PATHELLIPSIS );
91 
92     m_pMacroNameEdit->SetModifyHdl( LINK( this, MacroChooser, EditModifyHdl ) );
93 
94     m_pBasicBox->SetSelectHdl( LINK( this, MacroChooser, BasicSelectHdl ) );
95 
96     m_pMacroBox->SetDoubleClickHdl( LINK( this, MacroChooser, MacroDoubleClickHdl ) );
97     m_pMacroBox->SetSelectHdl( LINK( this, MacroChooser, MacroSelectHdl ) );
98 
99     m_pBasicBox->SetMode( BrowseMode::Modules );
100     m_pBasicBox->SetStyle( WB_TABSTOP | WB_BORDER |
101                         WB_HASLINES | WB_HASLINESATROOT |
102                         WB_HASBUTTONS | WB_HASBUTTONSATROOT |
103                         WB_HSCROLL );
104 
105     if (SfxDispatcher* pDispatcher = GetDispatcher())
106         pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
107 
108     if ( bCreateEntries )
109         m_pBasicBox->ScanAllEntries();
110 }
111 
112 MacroChooser::~MacroChooser()
113 {
114     disposeOnce();
115 }
116 
117 void MacroChooser::dispose()
118 {
119     if ( bForceStoreBasic )
120     {
121         SfxGetpApp()->SaveBasicAndDialogContainer();
122         bForceStoreBasic = false;
123     }
124     m_pMacroNameEdit.clear();
125     m_pMacroFromTxT.clear();
126     m_pMacrosSaveInTxt.clear();
127     m_pBasicBox.clear();
128     m_pMacrosInTxt.clear();
129     m_pMacroBox.clear();
130     m_pRunButton.clear();
131     m_pCloseButton.clear();
132     m_pAssignButton.clear();
133     m_pEditButton.clear();
134     m_pDelButton.clear();
135     m_pOrganizeButton.clear();
136     m_pNewLibButton.clear();
137     m_pNewModButton.clear();
138     SfxModalDialog::dispose();
139 }
140 
141 void MacroChooser::StoreMacroDescription()
142 {
143     EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(m_pBasicBox->FirstSelected());
144     OUString aMethodName;
145     SvTreeListEntry* pEntry = m_pMacroBox->FirstSelected();
146     if ( pEntry )
147         aMethodName = m_pMacroBox->GetEntryText( pEntry );
148     else
149         aMethodName = m_pMacroNameEdit->GetText();
150     if ( !aMethodName.isEmpty() )
151     {
152         aDesc.SetMethodName( aMethodName );
153         aDesc.SetType( OBJ_TYPE_METHOD );
154     }
155 
156     if (ExtraData* pData = basctl::GetExtraData())
157         pData->SetLastEntryDescriptor( aDesc );
158 }
159 
160 void MacroChooser::RestoreMacroDescription()
161 {
162     EntryDescriptor aDesc;
163     if (Shell* pShell = GetShell())
164     {
165         if (BaseWindow* pCurWin = pShell->GetCurWindow())
166             aDesc = pCurWin->CreateEntryDescriptor();
167     }
168     else
169     {
170         if (ExtraData* pData = basctl::GetExtraData())
171             aDesc = pData->GetLastEntryDescriptor();
172     }
173 
174     m_pBasicBox->SetCurrentEntry( aDesc );
175 
176     OUString aLastMacro( aDesc.GetMethodName() );
177     if ( !aLastMacro.isEmpty() )
178     {
179         // find entry in macro box
180         SvTreeListEntry* pEntry = nullptr;
181         sal_uLong nPos = 0;
182         SvTreeListEntry* pE = m_pMacroBox->GetEntry( nPos );
183         while ( pE )
184         {
185             if ( m_pMacroBox->GetEntryText( pE ) == aLastMacro )
186             {
187                 pEntry = pE;
188                 break;
189             }
190             pE = m_pMacroBox->GetEntry( ++nPos );
191         }
192 
193         if ( pEntry )
194             m_pMacroBox->SetCurEntry( pEntry );
195         else
196         {
197             m_pMacroNameEdit->SetText( aLastMacro );
198             m_pMacroNameEdit->SetSelection( Selection( 0, 0 ) );
199         }
200     }
201 }
202 
203 short MacroChooser::Execute()
204 {
205     RestoreMacroDescription();
206     m_pRunButton->GrabFocus();
207 
208     // #104198 Check if "wrong" document is active
209     SvTreeListEntry* pSelectedEntry = m_pBasicBox->GetCurEntry();
210     EntryDescriptor aDesc( m_pBasicBox->GetEntryDescriptor( pSelectedEntry ) );
211     const ScriptDocument& rSelectedDoc( aDesc.GetDocument() );
212 
213     // App Basic is always ok, so only check if shell was found
214     if( rSelectedDoc.isDocument() && !rSelectedDoc.isActive() )
215     {
216         // Search for the right entry
217         sal_uLong nRootPos = 0;
218         SvTreeListEntry* pRootEntry = m_pBasicBox->GetEntry( nRootPos );
219         while( pRootEntry )
220         {
221             EntryDescriptor aCmpDesc( m_pBasicBox->GetEntryDescriptor( pRootEntry ) );
222             const ScriptDocument& rCmpDoc( aCmpDesc.GetDocument() );
223             if ( rCmpDoc.isDocument() && rCmpDoc.isActive() )
224             {
225                 SvTreeListEntry* pEntry = pRootEntry;
226                 SvTreeListEntry* pLastValid = pEntry;
227                 while ( pEntry )
228                 {
229                     pLastValid = pEntry;
230                     pEntry = m_pBasicBox->FirstChild( pEntry );
231                 }
232                 if( pLastValid )
233                     m_pBasicBox->SetCurEntry( pLastValid );
234             }
235             pRootEntry = m_pBasicBox->GetEntry( ++nRootPos );
236         }
237     }
238 
239     CheckButtons();
240     UpdateFields();
241 
242     if ( StarBASIC::IsRunning() )
243         m_pCloseButton->GrabFocus();
244 
245     return ModalDialog::Execute();
246 }
247 
248 void MacroChooser::EnableButton( Button& rButton, bool bEnable )
249 {
250     if ( bEnable )
251     {
252         if (nMode == ChooseOnly || nMode == Recording)
253             rButton.Enable(&rButton == m_pRunButton);
254         else
255             rButton.Enable();
256     }
257     else
258         rButton.Disable();
259 }
260 
261 
262 SbMethod* MacroChooser::GetMacro()
263 {
264     SbMethod* pMethod = nullptr;
265     SbModule* pModule = m_pBasicBox->FindModule( m_pBasicBox->GetCurEntry() );
266     if ( pModule )
267     {
268         SvTreeListEntry* pEntry = m_pMacroBox->FirstSelected();
269         if ( pEntry )
270         {
271             OUString aMacroName( m_pMacroBox->GetEntryText( pEntry ) );
272             pMethod = pModule->FindMethod( aMacroName, SbxClassType::Method );
273         }
274     }
275     return pMethod;
276 }
277 
278 
279 void MacroChooser::DeleteMacro()
280 {
281     SbMethod* pMethod = GetMacro();
282     DBG_ASSERT( pMethod, "DeleteMacro: No Macro !" );
283     if (pMethod && QueryDelMacro(pMethod->GetName(), GetFrameWeld()))
284     {
285         if (SfxDispatcher* pDispatcher = GetDispatcher())
286             pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES );
287 
288         // mark current doc as modified:
289         StarBASIC* pBasic = FindBasic(pMethod);
290         assert(pBasic && "Basic?!");
291         BasicManager* pBasMgr = FindBasicManager( pBasic );
292         DBG_ASSERT( pBasMgr, "BasMgr?" );
293         ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
294         if ( aDocument.isDocument() )
295         {
296             aDocument.setDocumentModified();
297             if (SfxBindings* pBindings = GetBindingsPtr())
298                 pBindings->Invalidate( SID_SAVEDOC );
299         }
300 
301         SbModule* pModule = pMethod->GetModule();
302         assert(pModule && "DeleteMacro: No Module?!");
303         OUString aSource( pModule->GetSource32() );
304         sal_uInt16 nStart, nEnd;
305         pMethod->GetLineRange( nStart, nEnd );
306         pModule->GetMethods()->Remove( pMethod );
307         CutLines( aSource, nStart-1, nEnd-nStart+1 );
308         pModule->SetSource32( aSource );
309 
310         // update module in library
311         OUString aLibName = pBasic->GetName();
312         OUString aModName = pModule->GetName();
313         OSL_VERIFY( aDocument.updateModule( aLibName, aModName, aSource ) );
314 
315         SvTreeListEntry* pEntry = m_pMacroBox->FirstSelected();
316         DBG_ASSERT( pEntry, "DeleteMacro: Entry ?!" );
317         m_pMacroBox->GetModel()->Remove( pEntry );
318         bForceStoreBasic = true;
319     }
320 }
321 
322 SbMethod* MacroChooser::CreateMacro()
323 {
324     SbMethod* pMethod = nullptr;
325     SvTreeListEntry* pCurEntry = m_pBasicBox->GetCurEntry();
326     EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(pCurEntry);
327     const ScriptDocument& aDocument( aDesc.GetDocument() );
328     OSL_ENSURE( aDocument.isAlive(), "MacroChooser::CreateMacro: no document!" );
329     if ( !aDocument.isAlive() )
330         return nullptr;
331 
332     OUString aLibName( aDesc.GetLibName() );
333 
334     if ( aLibName.isEmpty() )
335         aLibName = "Standard" ;
336 
337     aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
338 
339     OUString aOULibName( aLibName );
340     Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
341     if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && !xModLibContainer->isLibraryLoaded( aOULibName ) )
342         xModLibContainer->loadLibrary( aOULibName );
343     Reference< script::XLibraryContainer > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ) );
344     if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && !xDlgLibContainer->isLibraryLoaded( aOULibName ) )
345         xDlgLibContainer->loadLibrary( aOULibName );
346 
347     BasicManager* pBasMgr = aDocument.getBasicManager();
348     StarBASIC* pBasic = pBasMgr ? pBasMgr->GetLib( aLibName ) : nullptr;
349     if ( pBasic )
350     {
351         SbModule* pModule = nullptr;
352         OUString aModName( aDesc.GetName() );
353         if ( !aModName.isEmpty() )
354         {
355             // extract the module name from the string like "Sheet1 (Example1)"
356             if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
357             {
358                 sal_Int32 nIndex = 0;
359                 aModName = aModName.getToken( 0, ' ', nIndex );
360             }
361             pModule = pBasic->FindModule( aModName );
362         }
363         else if ( !pBasic->GetModules().empty() )
364             pModule = pBasic->GetModules().front().get();
365 
366         // Retain the desired macro name before the macro dialog box is forced to close
367         // by opening the module name dialog window when no module exists in the current library.
368         OUString aSubName = m_pMacroNameEdit->GetText();
369 
370         if ( !pModule )
371         {
372             pModule = createModImpl(GetFrameWeld(), aDocument, *m_pBasicBox, aLibName, aModName, false);
373         }
374 
375         DBG_ASSERT( !pModule || !pModule->FindMethod( aSubName, SbxClassType::Method ), "Macro exists already!" );
376         pMethod = pModule ? basctl::CreateMacro( pModule, aSubName ) : nullptr;
377     }
378 
379     return pMethod;
380 }
381 
382 void MacroChooser::SaveSetCurEntry( SvTreeListBox& rBox, SvTreeListEntry* pEntry )
383 {
384     // the edit would be killed by the highlight otherwise:
385 
386     OUString aSaveText( m_pMacroNameEdit->GetText() );
387     Selection aCurSel( m_pMacroNameEdit->GetSelection() );
388 
389     rBox.SetCurEntry( pEntry );
390     m_pMacroNameEdit->SetText( aSaveText );
391     m_pMacroNameEdit->SetSelection( aCurSel );
392 }
393 
394 void MacroChooser::CheckButtons()
395 {
396     SvTreeListEntry* pCurEntry = m_pBasicBox->GetCurEntry();
397     EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(pCurEntry);
398     SvTreeListEntry* pMacroEntry = m_pMacroBox->FirstSelected();
399     SbMethod* pMethod = GetMacro();
400 
401     // check, if corresponding libraries are readonly
402     bool bReadOnly = false;
403     sal_uInt16 nDepth = pCurEntry ? m_pBasicBox->GetModel()->GetDepth( pCurEntry ) : 0;
404     if ( nDepth == 1 || nDepth == 2 )
405     {
406         const ScriptDocument& aDocument( aDesc.GetDocument() );
407         const OUString& aOULibName( aDesc.GetLibName() );
408         Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
409         Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY );
410         if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && xModLibContainer->isLibraryReadOnly( aOULibName ) ) ||
411                 ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && xDlgLibContainer->isLibraryReadOnly( aOULibName ) ) )
412         {
413             bReadOnly = true;
414         }
415     }
416 
417     if (nMode != Recording)
418     {
419         // Run...
420         bool bEnable = pMethod != nullptr;
421         if (nMode != ChooseOnly && StarBASIC::IsRunning())
422             bEnable = false;
423         EnableButton(*m_pRunButton, bEnable);
424     }
425 
426     // organising still possible?
427 
428     // Assign...
429     EnableButton(*m_pAssignButton, pMethod != nullptr);
430 
431     // Edit...
432     EnableButton(*m_pEditButton, pMacroEntry != nullptr);
433 
434     // Organizer...
435     EnableButton(*m_pOrganizeButton, !StarBASIC::IsRunning() && nMode == All);
436 
437     // m_pDelButton->...
438     bool bProtected = m_pBasicBox->IsEntryProtected( pCurEntry );
439     bool bShare = ( aDesc.GetLocation() == LIBRARY_LOCATION_SHARE );
440     EnableButton(*m_pDelButton, !StarBASIC::IsRunning() && nMode == All && !bProtected && !bReadOnly && !bShare);
441     bool bPrev = bNewDelIsDel;
442     bNewDelIsDel = pMethod != nullptr;
443     if (bPrev != bNewDelIsDel && nMode == All)
444     {
445         OUString aBtnText( bNewDelIsDel ? IDEResId(RID_STR_BTNDEL) : IDEResId(RID_STR_BTNNEW) );
446         m_pDelButton->SetText( aBtnText );
447     }
448 
449     if (nMode == Recording)
450     {
451         // save button
452         m_pRunButton->Enable(!bProtected && !bReadOnly && !bShare);
453         // new library button
454         m_pNewLibButton->Enable(!bShare);
455         // new module button
456         m_pNewModButton->Enable(!bProtected && !bReadOnly && !bShare);
457     }
458 }
459 
460 
461 IMPL_LINK_NOARG(MacroChooser, MacroDoubleClickHdl, SvTreeListBox*, bool)
462 {
463     SbMethod* pMethod = GetMacro();
464     SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
465     StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
466     BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
467     ScriptDocument aDocument(ScriptDocument::getDocumentForBasicManager(pBasMgr));
468     if (aDocument.isDocument() && !aDocument.allowMacros())
469     {
470         std::unique_ptr<weld::MessageDialog> xError(
471             Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Warning,
472                                              VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
473         xError->run();
474         return false;
475     }
476 
477     StoreMacroDescription();
478     if (nMode == Recording)
479     {
480         if (pMethod && !QueryReplaceMacro(pMethod->GetName(), GetFrameWeld()))
481             return false;
482     }
483 
484     EndDialog(Macro_OkRun);
485     return false;
486 }
487 
488 IMPL_LINK( MacroChooser, MacroSelectHdl, SvTreeListBox *, pBox, void )
489 {
490     // Is also called if deselected!
491     // Two function calls in every SelectHdl because
492     // there's no separate DeselectHDL.
493     // So find out if select or deselect:
494     if ( pBox->IsSelected( pBox->GetHdlEntry() ) )
495     {
496         UpdateFields();
497         CheckButtons();
498     }
499 }
500 
501 IMPL_LINK( MacroChooser, BasicSelectHdl, SvTreeListBox *, pBox, void )
502 {
503     // Is also called if deselected!
504     // Two function calls in every SelectHdl because
505     // there's no separate DeselectHDL.
506     // So find out if select or deselect:
507     if ( !pBox->IsSelected( pBox->GetHdlEntry() ) )
508         return;
509 
510     SbModule* pModule = m_pBasicBox->FindModule( m_pBasicBox->GetCurEntry() );
511 
512     m_pMacroBox->Clear();
513     if ( pModule )
514     {
515         m_pMacrosInTxt->SetText( m_aMacrosInTxtBaseStr + " " + pModule->GetName() );
516 
517         // The macros should be called in the same order that they
518         // are written down in the module.
519 
520         map< sal_uInt16, SbMethod* > aMacros;
521         size_t nMacroCount = pModule->GetMethods()->Count();
522         for ( size_t iMeth = 0; iMeth  < nMacroCount; iMeth++ )
523         {
524             SbMethod* pMethod = static_cast<SbMethod*>(pModule->GetMethods()->Get( iMeth ));
525             if( pMethod->IsHidden() )
526                 continue;
527             DBG_ASSERT( pMethod, "Method not found! (NULL)" );
528             sal_uInt16 nStart, nEnd;
529             pMethod->GetLineRange( nStart, nEnd );
530             aMacros.emplace( nStart, pMethod );
531         }
532 
533         m_pMacroBox->SetUpdateMode(false);
534         for (auto const& macro : aMacros)
535             m_pMacroBox->InsertEntry( macro.second->GetName() );
536         m_pMacroBox->SetUpdateMode(true);
537 
538         if ( m_pMacroBox->GetEntryCount() )
539         {
540             SvTreeListEntry* pEntry = m_pMacroBox->GetEntry( 0 );
541             DBG_ASSERT( pEntry, "Entry ?!" );
542             m_pMacroBox->SetCurEntry( pEntry );
543         }
544     }
545 
546     UpdateFields();
547     CheckButtons();
548 }
549 
550 
551 IMPL_LINK_NOARG( MacroChooser, EditModifyHdl, Edit&, void )
552 {
553     // select the module in which the macro is put at "new",
554     // if BasicManager or Lib is selecting
555     SvTreeListEntry* pCurEntry = m_pBasicBox->GetCurEntry();
556     if ( pCurEntry )
557     {
558         sal_uInt16 nDepth = m_pBasicBox->GetModel()->GetDepth( pCurEntry );
559         if ( ( nDepth == 1 ) && ( m_pBasicBox->IsEntryProtected( pCurEntry ) ) )
560         {
561             // then put to the respective Std-Lib...
562             SvTreeListEntry* pManagerEntry = m_pBasicBox->GetModel()->GetParent( pCurEntry );
563             pCurEntry = m_pBasicBox->GetModel()->FirstChild( pManagerEntry );
564         }
565         if ( nDepth < 2 )
566         {
567             SvTreeListEntry* pNewEntry = pCurEntry;
568             while ( pCurEntry && ( nDepth < 2 ) )
569             {
570                 pCurEntry = m_pBasicBox->FirstChild( pCurEntry );
571                 if ( pCurEntry )
572                 {
573                     pNewEntry = pCurEntry;
574                     nDepth = m_pBasicBox->GetModel()->GetDepth( pCurEntry );
575                 }
576             }
577             SaveSetCurEntry( *m_pBasicBox, pNewEntry );
578         }
579         if ( m_pMacroBox->GetEntryCount() )
580         {
581             OUString aEdtText( m_pMacroNameEdit->GetText() );
582             bool bFound = false;
583             for ( sal_uLong n = 0; n < m_pMacroBox->GetEntryCount(); n++ )
584             {
585                 SvTreeListEntry* pEntry = m_pMacroBox->GetEntry( n );
586                 DBG_ASSERT( pEntry, "Entry ?!" );
587                 if ( m_pMacroBox->GetEntryText( pEntry ).equalsIgnoreAsciiCase( aEdtText ) )
588                 {
589                     SaveSetCurEntry(*m_pMacroBox, pEntry);
590                     bFound = true;
591                     break;
592                 }
593             }
594             if ( !bFound )
595             {
596                 SvTreeListEntry* pEntry = m_pMacroBox->FirstSelected();
597                 // if the entry exists ->Select ->Description...
598                 if ( pEntry )
599                     m_pMacroBox->Select( pEntry, false );
600             }
601         }
602     }
603 
604     CheckButtons();
605 }
606 
607 
608 IMPL_LINK( MacroChooser, ButtonHdl, Button *, pButton, void )
609 {
610     // apart from New/Record the Description is done by LoseFocus
611     if (pButton == m_pRunButton)
612     {
613         StoreMacroDescription();
614 
615         // #116444# check security settings before macro execution
616         if (nMode == All)
617         {
618             SbMethod* pMethod = GetMacro();
619             SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr;
620             StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr;
621             BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr;
622             if ( pBasMgr )
623             {
624                 ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
625                 if ( aDocument.isDocument() && !aDocument.allowMacros() )
626                 {
627                     std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(GetFrameWeld(),
628                                                                 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
629                     xError->run();
630                     return;
631                 }
632             }
633         }
634         else if (nMode == Recording )
635         {
636             if ( !IsValidSbxName(m_pMacroNameEdit->GetText()) )
637             {
638                 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(GetFrameWeld(),
639                                                             VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
640                 xError->run();
641                 m_pMacroNameEdit->SetSelection( Selection( 0, m_pMacroNameEdit->GetText().getLength() ) );
642                 m_pMacroNameEdit->GrabFocus();
643                 return;
644             }
645 
646             SbMethod* pMethod = GetMacro();
647             if (pMethod && !QueryReplaceMacro(pMethod->GetName(), GetFrameWeld()))
648                 return;
649         }
650 
651         EndDialog(Macro_OkRun);
652     }
653     else if (pButton == m_pCloseButton)
654     {
655         StoreMacroDescription();
656         EndDialog(Macro_Close);
657     }
658     else if ((pButton == m_pEditButton) || (pButton == m_pDelButton))
659     {
660         SvTreeListEntry* pCurEntry = m_pBasicBox->GetCurEntry();
661         EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(pCurEntry);
662         const ScriptDocument& aDocument( aDesc.GetDocument() );
663         DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
664         if ( !aDocument.isAlive() )
665             return;
666         BasicManager* pBasMgr = aDocument.getBasicManager();
667         const OUString& aLib( aDesc.GetLibName() );
668         OUString aMod( aDesc.GetName() );
669         // extract the module name from the string like "Sheet1 (Example1)"
670         if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) )
671         {
672             sal_Int32 nIndex = 0;
673             aMod = aMod.getToken( 0, ' ', nIndex );
674         }
675         const OUString& aSub( aDesc.GetMethodName() );
676         SfxMacroInfoItem aInfoItem( SID_BASICIDE_ARG_MACROINFO, pBasMgr, aLib, aMod, aSub, OUString() );
677         if (pButton == m_pEditButton)
678         {
679             SvTreeListEntry* pEntry = m_pMacroBox->FirstSelected();
680             if ( pEntry )
681                 aInfoItem.SetMethod( m_pMacroBox->GetEntryText( pEntry ) );
682             StoreMacroDescription();
683             SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
684             SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
685             SfxGetpApp()->ExecuteSlot( aRequest );
686 
687             if (SfxDispatcher* pDispatcher = GetDispatcher())
688             {
689                 pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
690                         SfxCallMode::ASYNCHRON, { &aInfoItem });
691             }
692             EndDialog(Macro_Edit);
693         }
694         else
695         {
696             if ( bNewDelIsDel )
697             {
698                 DeleteMacro();
699                 if (SfxDispatcher* pDispatcher = GetDispatcher())
700                 {
701                     pDispatcher->ExecuteList( SID_BASICIDE_UPDATEMODULESOURCE,
702                                   SfxCallMode::SYNCHRON, { &aInfoItem });
703                 }
704                 CheckButtons();
705                 UpdateFields();
706                 //if ( m_pMacroBox->GetCurEntry() )    // OV-Bug ?
707                 //  m_pMacroBox->Select( m_pMacroBox->GetCurEntry() );
708             }
709             else
710             {
711                 if ( !IsValidSbxName(m_pMacroNameEdit->GetText()) )
712                 {
713                     std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(GetFrameWeld(),
714                                                                 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
715                     xError->run();
716                     m_pMacroNameEdit->SetSelection( Selection( 0, m_pMacroNameEdit->GetText().getLength() ) );
717                     m_pMacroNameEdit->GrabFocus();
718                     return;
719                 }
720                 SbMethod* pMethod = CreateMacro();
721                 if ( pMethod )
722                 {
723                     aInfoItem.SetMethod( pMethod->GetName() );
724                     aInfoItem.SetModule( pMethod->GetModule()->GetName() );
725                     aInfoItem.SetLib( pMethod->GetModule()->GetParent()->GetName() );
726                     SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
727                     SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs );
728                     SfxGetpApp()->ExecuteSlot( aRequest );
729 
730                     if (SfxDispatcher* pDispatcher = GetDispatcher())
731                     {
732                         pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO,
733                                 SfxCallMode::ASYNCHRON, { &aInfoItem });
734                     }
735                     StoreMacroDescription();
736                     EndDialog(Macro_New);
737                 }
738             }
739         }
740     }
741     else if (pButton == m_pAssignButton)
742     {
743         SvTreeListEntry* pCurEntry = m_pBasicBox->GetCurEntry();
744         EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(pCurEntry);
745         const ScriptDocument& aDocument( aDesc.GetDocument() );
746         DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" );
747         if ( !aDocument.isAlive() )
748             return;
749         BasicManager* pBasMgr = aDocument.getBasicManager();
750         const OUString& aLib( aDesc.GetLibName() );
751         const OUString& aMod( aDesc.GetName() );
752         OUString aSub( m_pMacroNameEdit->GetText() );
753         SbMethod* pMethod = GetMacro();
754         DBG_ASSERT( pBasMgr, "BasMgr?" );
755         DBG_ASSERT( pMethod, "Method?" );
756         OUString aComment( GetInfo( pMethod ) );
757         SfxMacroInfoItem aItem( SID_MACROINFO, pBasMgr, aLib, aMod, aSub, aComment );
758         SfxAllItemSet Args( SfxGetpApp()->GetPool() );
759 
760         SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool());
761         if (m_xDocumentFrame.is())
762             aInternalSet.Put(SfxUnoFrameItem(SID_FILLFRAME, m_xDocumentFrame));
763 
764         SfxRequest aRequest(SID_CONFIG, SfxCallMode::SYNCHRON, Args, aInternalSet);
765         aRequest.AppendItem( aItem );
766         SfxGetpApp()->ExecuteSlot( aRequest );
767     }
768     else if (pButton == m_pNewLibButton)
769     {
770         SvTreeListEntry* pCurEntry = m_pBasicBox->GetCurEntry();
771         EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(pCurEntry);
772         const ScriptDocument& aDocument( aDesc.GetDocument() );
773         createLibImpl(GetFrameWeld(), aDocument, nullptr, m_pBasicBox);
774     }
775     else if (pButton == m_pNewModButton)
776     {
777         SvTreeListEntry* pCurEntry = m_pBasicBox->GetCurEntry();
778         EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(pCurEntry);
779         const ScriptDocument& aDocument( aDesc.GetDocument() );
780         const OUString& aLibName( aDesc.GetLibName() );
781         createModImpl(GetFrameWeld(), aDocument, *m_pBasicBox, aLibName, OUString(), true);
782     }
783     else if (pButton == m_pOrganizeButton)
784     {
785         StoreMacroDescription();
786 
787         EntryDescriptor aDesc = m_pBasicBox->GetEntryDescriptor(m_pBasicBox->FirstSelected());
788         VclPtrInstance< OrganizeDialog > pDlg( this, 0, aDesc );
789         sal_uInt16 nRet = pDlg->Execute();
790         pDlg.reset();
791 
792         if ( nRet ) // not only closed
793         {
794             EndDialog(Macro_Edit);
795             return;
796         }
797 
798         Shell* pShell = GetShell();
799         if ( pShell && pShell->IsAppBasicModified() )
800             bForceStoreBasic = true;
801 
802         m_pBasicBox->UpdateEntries();
803     }
804 }
805 
806 
807 void MacroChooser::UpdateFields()
808 {
809     SvTreeListEntry*    pMacroEntry = m_pMacroBox->GetCurEntry();
810 
811     m_pMacroNameEdit->SetText( "" );
812     if ( pMacroEntry )
813         m_pMacroNameEdit->SetText( m_pMacroBox->GetEntryText( pMacroEntry ) );
814 }
815 
816 void MacroChooser::SetMode (Mode nM)
817 {
818     nMode = nM;
819     switch (nMode)
820     {
821         case All:
822         {
823             m_pRunButton->SetText(IDEResId(RID_STR_RUN));
824             EnableButton(*m_pDelButton, true);
825             EnableButton(*m_pOrganizeButton, true);
826             break;
827         }
828 
829         case ChooseOnly:
830         {
831             m_pRunButton->SetText(IDEResId(RID_STR_CHOOSE));
832             EnableButton(*m_pDelButton, false);
833             EnableButton(*m_pOrganizeButton, false);
834             break;
835         }
836 
837         case Recording:
838         {
839             m_pRunButton->SetText(IDEResId(RID_STR_RECORD));
840             EnableButton(*m_pDelButton, false);
841             EnableButton(*m_pOrganizeButton, false);
842 
843             m_pAssignButton->Hide();
844             m_pEditButton->Hide();
845             m_pDelButton->Hide();
846             m_pOrganizeButton->Hide();
847             m_pMacroFromTxT->Hide();
848 
849             m_pNewLibButton->Show();
850             m_pNewModButton->Show();
851             m_pMacrosSaveInTxt->Show();
852 
853             break;
854         }
855     }
856     CheckButtons();
857 }
858 
859 OUString MacroChooser::GetInfo( SbxVariable* pVar )
860 {
861     OUString aComment;
862     SbxInfoRef xInfo = pVar->GetInfo();
863     if ( xInfo.is() )
864         aComment = xInfo->GetComment();
865     return aComment;
866 }
867 
868 
869 } // namespace basctl
870 
871 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
872