1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <basidesh.hxx>
21 #include <iderdll.hxx>
22 #include "iderdll2.hxx"
23 #include "macrodlg.hxx"
24 #include "moduldlg.hxx"
26 #include <strings.hrc>
27 #include "baside2.hxx"
29 #include <com/sun/star/document/XScriptInvocationContext.hpp>
31 #include <basic/sbmeth.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/string.hxx>
34 #include <comphelper/sequence.hxx>
35 #include <framework/documentundoguard.hxx>
36 #include <sal/log.hxx>
37 #include <comphelper/diagnose_ex.hxx>
38 #include <unotools/moduleoptions.hxx>
39 #include <vcl/settings.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/weld.hxx>
46 #include <basic/basmgr.hxx>
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::uno
;
52 using namespace ::com::sun::star::container
;
55 SAL_DLLPUBLIC_EXPORT rtl_uString
* basicide_choose_macro(void* pParent
, void* pOnlyInDocument_AsXModel
, void* pDocFrame_AsXFrame
, sal_Bool bChooseOnly
)
57 Reference
< frame::XModel
> aDocument( static_cast< frame::XModel
* >( pOnlyInDocument_AsXModel
) );
58 Reference
< frame::XFrame
> aDocFrame( static_cast< frame::XFrame
* >( pDocFrame_AsXFrame
) );
59 OUString aScriptURL
= basctl::ChooseMacro(static_cast<weld::Window
*>(pParent
), aDocument
, aDocFrame
, bChooseOnly
);
60 rtl_uString
* pScriptURL
= aScriptURL
.pData
;
61 rtl_uString_acquire( pScriptURL
);
65 SAL_DLLPUBLIC_EXPORT
void basicide_macro_organizer(void *pParent
, void* pDocFrame_AsXFrame
, sal_Int16 nTabId
)
67 SAL_INFO("basctl.basicide","in basicide_macro_organizer");
68 Reference
< frame::XFrame
> aDocFrame( static_cast< frame::XFrame
* >( pDocFrame_AsXFrame
) );
69 basctl::Organize(static_cast<weld::Window
*>(pParent
), aDocFrame
, nTabId
);
73 void Organize(weld::Window
* pParent
, const css::uno::Reference
<css::frame::XFrame
>& xDocFrame
, sal_Int16 tabId
)
77 auto xDlg(std::make_shared
<OrganizeDialog
>(pParent
, xDocFrame
, tabId
));
78 weld::DialogController::runAsync(xDlg
, [](int) {});
81 bool IsValidSbxName( std::u16string_view rName
)
83 for ( size_t nChar
= 0; nChar
< rName
.size(); nChar
++ )
85 sal_Unicode c
= rName
[nChar
];
87 ( c
>= 'A' && c
<= 'Z' ) ||
88 ( c
>= 'a' && c
<= 'z' ) ||
89 ( c
>= '0' && c
<= '9' && nChar
) ||
98 Sequence
< OUString
> GetMergedLibraryNames( const Reference
< script::XLibraryContainer
>& xModLibContainer
, const Reference
< script::XLibraryContainer
>& xDlgLibContainer
)
100 // create a list of module library names
101 std::vector
<OUString
> aLibList
;
102 if ( xModLibContainer
.is() )
104 const Sequence
< OUString
> aModLibNames
= xModLibContainer
->getElementNames();
105 aLibList
.insert( aLibList
.end(), aModLibNames
.begin(), aModLibNames
.end() );
108 // create a list of dialog library names
109 if ( xDlgLibContainer
.is() )
111 const Sequence
< OUString
> aDlgLibNames
= xDlgLibContainer
->getElementNames();
112 aLibList
.insert( aLibList
.end(), aDlgLibNames
.begin(), aDlgLibNames
.end() );
116 auto const sort
= comphelper::string::NaturalStringSorter(
117 comphelper::getProcessComponentContext(),
118 Application::GetSettings().GetUILanguageTag().getLocale());
119 std::sort(aLibList
.begin(), aLibList
.end(),
120 [&sort
](const OUString
& rLHS
, const OUString
& rRHS
) {
121 return sort
.compare(rLHS
, rRHS
) < 0;
124 std::vector
<OUString
>::iterator aIterEnd
= std::unique( aLibList
.begin(), aLibList
.end() );
125 aLibList
.erase( aIterEnd
, aLibList
.end() );
127 return comphelper::containerToSequence(aLibList
);
131 weld::Widget
* pErrorParent
,
132 const ScriptDocument
& rDocument
,
133 const OUString
& rLibName
,
134 const OUString
& rOldName
,
135 const OUString
& rNewName
138 if ( !rDocument
.hasModule( rLibName
, rOldName
) )
140 SAL_WARN( "basctl.basicide","basctl::RenameModule: old module name is invalid!" );
144 if ( rDocument
.hasModule( rLibName
, rNewName
) )
146 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(pErrorParent
,
147 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_SBXNAMEALLREADYUSED2
)));
153 if ( rNewName
.isEmpty() )
155 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(pErrorParent
,
156 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_BADSBXNAME
)));
161 if ( !rDocument
.renameModule( rLibName
, rOldName
, rNewName
) )
164 Shell
* pShell
= GetShell();
167 VclPtr
<ModulWindow
> pWin
= pShell
->FindBasWin(rDocument
, rLibName
, rNewName
, false, true);
171 // set new name in window
172 pWin
->SetName( rNewName
);
174 // set new module in module window
175 pWin
->SetSbModule( pWin
->GetBasic()->FindModule( rNewName
) );
178 sal_uInt16 nId
= pShell
->GetWindowId( pWin
);
179 SAL_WARN_IF( nId
== 0 , "basctl.basicide", "No entry in Tabbar!");
182 TabBar
& rTabBar
= pShell
->GetTabBar();
183 rTabBar
.SetPageText(nId
, rNewName
);
185 rTabBar
.MakeVisible(rTabBar
.GetCurPageId());
192 struct MacroExecutionData
194 ScriptDocument aDocument
;
198 :aDocument( ScriptDocument::NoDocument
)
206 DECL_STATIC_LINK( MacroExecution
, ExecuteMacroEvent
, void*, void );
209 IMPL_STATIC_LINK( MacroExecution
, ExecuteMacroEvent
, void*, p
, void )
211 MacroExecutionData
* i_pData
= static_cast<MacroExecutionData
*>(p
);
212 ENSURE_OR_RETURN_VOID( i_pData
, "wrong MacroExecutionData" );
213 // take ownership of the data
214 std::unique_ptr
< MacroExecutionData
> pData( i_pData
);
216 SAL_WARN_IF( (pData
->xMethod
->GetParent()->GetFlags() & SbxFlagBits::ExtSearch
) == SbxFlagBits::NONE
, "basctl.basicide","No EXTSEARCH!" );
218 // in case this is a document-local macro, try to protect the document's Undo Manager from
220 std::optional
< ::framework::DocumentUndoGuard
> pUndoGuard
;
221 if ( pData
->aDocument
.isDocument() )
222 pUndoGuard
.emplace( pData
->aDocument
.getDocument() );
224 RunMethod( pData
->xMethod
.get() );
228 OUString
ChooseMacro(weld::Window
* pParent
,
229 const uno::Reference
< frame::XModel
>& rxLimitToDocument
,
230 const uno::Reference
< frame::XFrame
>& xDocFrame
,
235 GetExtraData()->ChoosingMacro() = true;
238 SbMethod
* pMethod
= nullptr;
240 MacroChooser
aChooser(pParent
, xDocFrame
);
241 if ( bChooseOnly
|| !SvtModuleOptions::IsBasicIDE() )
242 aChooser
.SetMode(MacroChooser::ChooseOnly
);
244 if ( !bChooseOnly
&& rxLimitToDocument
.is() )
247 aChooser
.SetMode(MacroChooser::Recording
);
250 short nRetValue
= aChooser
.run();
252 GetExtraData()->ChoosingMacro() = false;
260 pMethod
= aChooser
.GetMacro();
261 if ( !pMethod
&& aChooser
.GetMode() == MacroChooser::Recording
)
262 pMethod
= aChooser
.CreateMacro();
267 SbModule
* pModule
= pMethod
->GetModule();
270 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Module found!" );
274 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>(pModule
->GetParent());
277 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Basic found!" );
281 BasicManager
* pBasMgr
= FindBasicManager( pBasic
);
284 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No BasicManager found!" );
289 OUString aName
= pBasic
->GetName() + "." + pModule
->GetName() + "." + pMethod
->GetName();
293 ScriptDocument
aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr
) );
294 if ( aDocument
.isDocument() )
297 aLocation
= "document" ;
299 if ( rxLimitToDocument
.is() )
301 uno::Reference
< frame::XModel
> xLimitToDocument( rxLimitToDocument
);
303 uno::Reference
< document::XEmbeddedScripts
> xScripts( rxLimitToDocument
, UNO_QUERY
);
304 if ( !xScripts
.is() )
305 { // the document itself does not support embedding scripts
306 uno::Reference
< document::XScriptInvocationContext
> xContext( rxLimitToDocument
, UNO_QUERY
);
308 xScripts
= xContext
->getScriptContainer();
310 { // but it is able to refer to a document which actually does support this
311 xLimitToDocument
.set( xScripts
, UNO_QUERY
);
312 if ( !xLimitToDocument
.is() )
314 SAL_WARN_IF(!xLimitToDocument
.is(), "basctl.basicide", "basctl::ChooseMacro: a script container which is no document!?" );
315 xLimitToDocument
= rxLimitToDocument
;
320 if ( xLimitToDocument
!= aDocument
.getDocument() )
324 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(nullptr,
325 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_ERRORCHOOSEMACRO
)));
333 aLocation
= "application" ;
339 aScriptURL
= "vnd.sun.star.script:" + aName
+ "?language=Basic&location=" + aLocation
;
342 if ( !rxLimitToDocument
.is() )
344 MacroExecutionData
* pExecData
= new MacroExecutionData
;
345 pExecData
->aDocument
= aDocument
;
346 pExecData
->xMethod
= pMethod
; // keep alive until the event has been processed
347 Application::PostUserEvent( LINK( nullptr, MacroExecution
, ExecuteMacroEvent
), pExecData
);
356 Sequence
< OUString
> GetMethodNames( const ScriptDocument
& rDocument
, const OUString
& rLibName
, const OUString
& rModName
)
358 Sequence
< OUString
> aSeqMethods
;
362 if ( rDocument
.getModule( rLibName
, rModName
, aOUSource
) )
364 BasicManager
* pBasMgr
= rDocument
.getBasicManager();
365 StarBASIC
* pSb
= pBasMgr
? pBasMgr
->GetLib( rLibName
) : nullptr;
366 SbModule
* pMod
= pSb
? pSb
->FindModule( rModName
) : nullptr;
369 // Only reparse modules if ScriptDocument source is out of sync
370 // with basic's Module
371 if ( !pMod
|| pMod
->GetSource32() != aOUSource
)
373 xModule
= new SbModule( rModName
);
374 xModule
->SetSource32( aOUSource
);
375 pMod
= xModule
.get();
378 sal_uInt32 nCount
= pMod
->GetMethods()->Count();
379 sal_uInt32 nRealCount
= nCount
;
380 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
382 SbMethod
* pMethod
= static_cast<SbMethod
*>(pMod
->GetMethods()->Get(i
));
383 if( pMethod
->IsHidden() )
386 aSeqMethods
.realloc( nRealCount
);
388 sal_uInt32 iTarget
= 0;
389 for ( sal_uInt32 i
= 0 ; i
< nCount
; ++i
)
391 SbMethod
* pMethod
= static_cast<SbMethod
*>(pMod
->GetMethods()->Get(i
));
392 if( pMethod
->IsHidden() )
394 SAL_WARN_IF( !pMethod
, "basctl.basicide","Method not found! (NULL)" );
395 aSeqMethods
.getArray()[ iTarget
++ ] = pMethod
->GetName();
403 ScriptDocument
const& rDocument
,
404 OUString
const& rLibName
,
405 OUString
const& rModName
,
406 OUString
const& rMethName
409 bool bHasMethod
= false;
412 if ( rDocument
.hasModule( rLibName
, rModName
) && rDocument
.getModule( rLibName
, rModName
, aOUSource
) )
414 // Check if we really need to scan the source ( again )
415 BasicManager
* pBasMgr
= rDocument
.getBasicManager();
416 StarBASIC
* pSb
= pBasMgr
? pBasMgr
->GetLib( rLibName
) : nullptr;
417 SbModule
* pMod
= pSb
? pSb
->FindModule( rModName
) : nullptr;
419 // Only reparse modules if ScriptDocument source is out of sync
420 // with basic's Module
421 if ( !pMod
|| pMod
->GetSource32() != aOUSource
)
423 xModule
= new SbModule( rModName
);
424 xModule
->SetSource32( aOUSource
);
425 pMod
= xModule
.get();
427 SbxArray
* pMethods
= pMod
->GetMethods().get();
430 SbMethod
* pMethod
= static_cast<SbMethod
*>(pMethods
->Find( rMethName
, SbxClassType::Method
));
431 if ( pMethod
&& !pMethod
->IsHidden() )
439 } // namespace basctl
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */