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 <tools/diagnose_ex.h>
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
, sal_Int16 nTabId
)
67 SAL_INFO("basctl.basicide","in basicide_macro_organizer");
68 basctl::Organize(static_cast<weld::Window
*>(pParent
), nTabId
);
72 void Organize(weld::Window
* pParent
, sal_Int16 tabId
)
76 auto xDlg(std::make_shared
<OrganizeDialog
>(pParent
, tabId
));
77 weld::DialogController::runAsync(xDlg
, [](int) {});
80 bool IsValidSbxName( const OUString
& rName
)
82 for ( sal_Int32 nChar
= 0; nChar
< rName
.getLength(); nChar
++ )
84 sal_Unicode c
= rName
[nChar
];
86 ( c
>= 'A' && c
<= 'Z' ) ||
87 ( c
>= 'a' && c
<= 'z' ) ||
88 ( c
>= '0' && c
<= '9' && nChar
) ||
97 Sequence
< OUString
> GetMergedLibraryNames( const Reference
< script::XLibraryContainer
>& xModLibContainer
, const Reference
< script::XLibraryContainer
>& xDlgLibContainer
)
99 // create a list of module library names
100 std::vector
<OUString
> aLibList
;
101 if ( xModLibContainer
.is() )
103 Sequence
< OUString
> aModLibNames
= xModLibContainer
->getElementNames();
104 sal_Int32 nModLibCount
= aModLibNames
.getLength();
105 const OUString
* pModLibNames
= aModLibNames
.getConstArray();
106 for ( sal_Int32 i
= 0 ; i
< nModLibCount
; i
++ )
107 aLibList
.push_back( pModLibNames
[ i
] );
110 // create a list of dialog library names
111 if ( xDlgLibContainer
.is() )
113 Sequence
< OUString
> aDlgLibNames
= xDlgLibContainer
->getElementNames();
114 sal_Int32 nDlgLibCount
= aDlgLibNames
.getLength();
115 const OUString
* pDlgLibNames
= aDlgLibNames
.getConstArray();
116 for ( sal_Int32 i
= 0 ; i
< nDlgLibCount
; i
++ )
117 aLibList
.push_back( pDlgLibNames
[ i
] );
121 auto const sort
= comphelper::string::NaturalStringSorter(
122 comphelper::getProcessComponentContext(),
123 Application::GetSettings().GetUILanguageTag().getLocale());
124 std::sort(aLibList
.begin(), aLibList
.end(),
125 [&sort
](const OUString
& rLHS
, const OUString
& rRHS
) {
126 return sort
.compare(rLHS
, rRHS
) < 0;
129 std::vector
<OUString
>::iterator aIterEnd
= std::unique( aLibList
.begin(), aLibList
.end() );
130 aLibList
.erase( aIterEnd
, aLibList
.end() );
132 return comphelper::containerToSequence(aLibList
);
136 weld::Widget
* pErrorParent
,
137 const ScriptDocument
& rDocument
,
138 const OUString
& rLibName
,
139 const OUString
& rOldName
,
140 const OUString
& rNewName
143 if ( !rDocument
.hasModule( rLibName
, rOldName
) )
145 SAL_WARN( "basctl.basicide","basctl::RenameModule: old module name is invalid!" );
149 if ( rDocument
.hasModule( rLibName
, rNewName
) )
151 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(pErrorParent
,
152 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_SBXNAMEALLREADYUSED2
)));
158 if ( rNewName
.isEmpty() )
160 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(pErrorParent
,
161 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_BADSBXNAME
)));
166 if ( !rDocument
.renameModule( rLibName
, rOldName
, rNewName
) )
169 if (Shell
* pShell
= GetShell())
171 if (VclPtr
<ModulWindow
> pWin
= pShell
->FindBasWin(rDocument
, rLibName
, rNewName
, false, true))
173 // set new name in window
174 pWin
->SetName( rNewName
);
176 // set new module in module window
177 pWin
->SetSbModule( pWin
->GetBasic()->FindModule( rNewName
) );
180 sal_uInt16 nId
= pShell
->GetWindowId( pWin
);
181 SAL_WARN_IF( nId
== 0 , "basctl.basicide", "No entry in Tabbar!");
184 TabBar
& rTabBar
= pShell
->GetTabBar();
185 rTabBar
.SetPageText(nId
, rNewName
);
187 rTabBar
.MakeVisible(rTabBar
.GetCurPageId());
196 struct MacroExecutionData
198 ScriptDocument aDocument
;
202 :aDocument( ScriptDocument::NoDocument
)
210 DECL_STATIC_LINK( MacroExecution
, ExecuteMacroEvent
, void*, void );
213 IMPL_STATIC_LINK( MacroExecution
, ExecuteMacroEvent
, void*, p
, void )
215 MacroExecutionData
* i_pData
= static_cast<MacroExecutionData
*>(p
);
216 ENSURE_OR_RETURN_VOID( i_pData
, "wrong MacroExecutionData" );
217 // take ownership of the data
218 std::unique_ptr
< MacroExecutionData
> pData( i_pData
);
220 SAL_WARN_IF( (pData
->xMethod
->GetParent()->GetFlags() & SbxFlagBits::ExtSearch
) == SbxFlagBits::NONE
, "basctl.basicide","No EXTSEARCH!" );
222 // in case this is a document-local macro, try to protect the document's Undo Manager from
224 std::unique_ptr
< ::framework::DocumentUndoGuard
> pUndoGuard
;
225 if ( pData
->aDocument
.isDocument() )
226 pUndoGuard
.reset( new ::framework::DocumentUndoGuard( pData
->aDocument
.getDocument() ) );
228 RunMethod( pData
->xMethod
.get() );
232 OUString
ChooseMacro(weld::Window
* pParent
,
233 const uno::Reference
< frame::XModel
>& rxLimitToDocument
,
234 const uno::Reference
< frame::XFrame
>& xDocFrame
,
239 GetExtraData()->ChoosingMacro() = true;
242 SbMethod
* pMethod
= nullptr;
244 MacroChooser
aChooser(pParent
, xDocFrame
);
245 if ( bChooseOnly
|| !SvtModuleOptions::IsBasicIDE() )
246 aChooser
.SetMode(MacroChooser::ChooseOnly
);
248 if ( !bChooseOnly
&& rxLimitToDocument
.is() )
251 aChooser
.SetMode(MacroChooser::Recording
);
254 short nRetValue
= aChooser
.run();
256 GetExtraData()->ChoosingMacro() = false;
264 pMethod
= aChooser
.GetMacro();
265 if ( !pMethod
&& aChooser
.GetMode() == MacroChooser::Recording
)
266 pMethod
= aChooser
.CreateMacro();
271 SbModule
* pModule
= pMethod
->GetModule();
274 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Module found!" );
278 StarBASIC
* pBasic
= dynamic_cast<StarBASIC
*>(pModule
->GetParent());
281 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Basic found!" );
285 BasicManager
* pBasMgr
= FindBasicManager( pBasic
);
288 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No BasicManager found!" );
293 OUString aName
= pBasic
->GetName() + "." + pModule
->GetName() + "." + pMethod
->GetName();
297 ScriptDocument
aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr
) );
298 if ( aDocument
.isDocument() )
301 aLocation
= "document" ;
303 if ( rxLimitToDocument
.is() )
305 uno::Reference
< frame::XModel
> xLimitToDocument( rxLimitToDocument
);
307 uno::Reference
< document::XEmbeddedScripts
> xScripts( rxLimitToDocument
, UNO_QUERY
);
308 if ( !xScripts
.is() )
309 { // the document itself does not support embedding scripts
310 uno::Reference
< document::XScriptInvocationContext
> xContext( rxLimitToDocument
, UNO_QUERY
);
312 xScripts
= xContext
->getScriptContainer();
314 { // but it is able to refer to a document which actually does support this
315 xLimitToDocument
.set( xScripts
, UNO_QUERY
);
316 if ( !xLimitToDocument
.is() )
318 SAL_WARN_IF(!xLimitToDocument
.is(), "basctl.basicide", "basctl::ChooseMacro: a script container which is no document!?" );
319 xLimitToDocument
= rxLimitToDocument
;
324 if ( xLimitToDocument
!= aDocument
.getDocument() )
328 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(nullptr,
329 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_ERRORCHOOSEMACRO
)));
337 aLocation
= "application" ;
343 aScriptURL
= "vnd.sun.star.script:" + aName
+ "?language=Basic&location=" + aLocation
;
346 if ( !rxLimitToDocument
.is() )
348 MacroExecutionData
* pExecData
= new MacroExecutionData
;
349 pExecData
->aDocument
= aDocument
;
350 pExecData
->xMethod
= pMethod
; // keep alive until the event has been processed
351 Application::PostUserEvent( LINK( nullptr, MacroExecution
, ExecuteMacroEvent
), pExecData
);
360 Sequence
< OUString
> GetMethodNames( const ScriptDocument
& rDocument
, const OUString
& rLibName
, const OUString
& rModName
)
362 Sequence
< OUString
> aSeqMethods
;
366 if ( rDocument
.getModule( rLibName
, rModName
, aOUSource
) )
368 BasicManager
* pBasMgr
= rDocument
.getBasicManager();
369 StarBASIC
* pSb
= pBasMgr
? pBasMgr
->GetLib( rLibName
) : nullptr;
370 SbModule
* pMod
= pSb
? pSb
->FindModule( rModName
) : nullptr;
373 // Only reparse modules if ScriptDocument source is out of sync
374 // with basic's Module
375 if ( !pMod
|| pMod
->GetSource32() != aOUSource
)
377 xModule
= new SbModule( rModName
);
378 xModule
->SetSource32( aOUSource
);
379 pMod
= xModule
.get();
382 sal_uInt32 nCount
= pMod
->GetMethods()->Count32();
383 sal_uInt32 nRealCount
= nCount
;
384 for ( sal_uInt32 i
= 0; i
< nCount
; i
++ )
386 SbMethod
* pMethod
= static_cast<SbMethod
*>(pMod
->GetMethods()->Get32( i
));
387 if( pMethod
->IsHidden() )
390 aSeqMethods
.realloc( nRealCount
);
392 sal_uInt32 iTarget
= 0;
393 for ( sal_uInt32 i
= 0 ; i
< nCount
; ++i
)
395 SbMethod
* pMethod
= static_cast<SbMethod
*>(pMod
->GetMethods()->Get32( i
));
396 if( pMethod
->IsHidden() )
398 SAL_WARN_IF( !pMethod
, "basctl.basicide","Method not found! (NULL)" );
399 aSeqMethods
.getArray()[ iTarget
++ ] = pMethod
->GetName();
407 ScriptDocument
const& rDocument
,
408 OUString
const& rLibName
,
409 OUString
const& rModName
,
410 OUString
const& rMethName
413 bool bHasMethod
= false;
416 if ( rDocument
.hasModule( rLibName
, rModName
) && rDocument
.getModule( rLibName
, rModName
, aOUSource
) )
418 // Check if we really need to scan the source ( again )
419 BasicManager
* pBasMgr
= rDocument
.getBasicManager();
420 StarBASIC
* pSb
= pBasMgr
? pBasMgr
->GetLib( rLibName
) : nullptr;
421 SbModule
* pMod
= pSb
? pSb
->FindModule( rModName
) : nullptr;
423 // Only reparse modules if ScriptDocument source is out of sync
424 // with basic's Module
425 if ( !pMod
|| pMod
->GetSource32() != aOUSource
)
427 xModule
= new SbModule( rModName
);
428 xModule
->SetSource32( aOUSource
);
429 pMod
= xModule
.get();
431 SbxArray
* pMethods
= pMod
->GetMethods().get();
434 SbMethod
* pMethod
= static_cast<SbMethod
*>(pMethods
->Find( rMethName
, SbxClassType::Method
));
435 if ( pMethod
&& !pMethod
->IsHidden() )
443 } // namespace basctl
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */