LibreOffice Module basctl (master) 1
basobj2.cxx
Go to the documentation of this file.
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#include <basidesh.hxx>
21#include <iderdll.hxx>
22#include "iderdll2.hxx"
23#include "macrodlg.hxx"
24#include "moduldlg.hxx"
25#include <iderid.hxx>
26#include <strings.hrc>
27#include "baside2.hxx"
28
29#include <com/sun/star/document/XScriptInvocationContext.hpp>
30
31#include <basic/sbmeth.hxx>
33#include <comphelper/string.hxx>
36#include <sal/log.hxx>
39#include <vcl/settings.hxx>
40#include <vcl/svapp.hxx>
41#include <vcl/weld.hxx>
42
43#include <memory>
44#include <vector>
45#include <algorithm>
46#include <basic/basmgr.hxx>
47namespace basctl
48{
49
50using namespace ::com::sun::star;
51using namespace ::com::sun::star::uno;
52using namespace ::com::sun::star::container;
53
54extern "C" {
55 SAL_DLLPUBLIC_EXPORT rtl_uString* basicide_choose_macro(void* pParent, void* pOnlyInDocument_AsXModel, void* pDocFrame_AsXFrame, sal_Bool bChooseOnly )
56 {
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 );
62
63 return pScriptURL;
64 }
65 SAL_DLLPUBLIC_EXPORT void basicide_macro_organizer(void *pParent, void* pDocFrame_AsXFrame, sal_Int16 nTabId)
66 {
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);
70 }
71}
72
73void Organize(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId)
74{
75 EnsureIde();
76
77 auto xDlg(std::make_shared<OrganizeDialog>(pParent, xDocFrame, tabId));
78 weld::DialogController::runAsync(xDlg, [](int) {});
79}
80
81bool IsValidSbxName( std::u16string_view rName )
82{
83 for ( size_t nChar = 0; nChar < rName.size(); nChar++ )
84 {
85 sal_Unicode c = rName[nChar];
86 bool bValid = (
87 ( c >= 'A' && c <= 'Z' ) ||
88 ( c >= 'a' && c <= 'z' ) ||
89 ( c >= '0' && c <= '9' && nChar ) ||
90 ( c == '_' )
91 );
92 if ( !bValid )
93 return false;
94 }
95 return true;
96}
97
99{
100 // create a list of module library names
101 std::vector<OUString> aLibList;
102 if ( xModLibContainer.is() )
103 {
104 const Sequence< OUString > aModLibNames = xModLibContainer->getElementNames();
105 aLibList.insert( aLibList.end(), aModLibNames.begin(), aModLibNames.end() );
106 }
107
108 // create a list of dialog library names
109 if ( xDlgLibContainer.is() )
110 {
111 const Sequence< OUString > aDlgLibNames = xDlgLibContainer->getElementNames();
112 aLibList.insert( aLibList.end(), aDlgLibNames.begin(), aDlgLibNames.end() );
113 }
114
115 // sort list
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;
122 });
123 // remove duplicates
124 std::vector<OUString>::iterator aIterEnd = std::unique( aLibList.begin(), aLibList.end() );
125 aLibList.erase( aIterEnd, aLibList.end() );
126
127 return comphelper::containerToSequence(aLibList);
128}
129
131 weld::Widget* pErrorParent,
132 const ScriptDocument& rDocument,
133 const OUString& rLibName,
134 const OUString& rOldName,
135 const OUString& rNewName
136)
137{
138 if ( !rDocument.hasModule( rLibName, rOldName ) )
139 {
140 SAL_WARN( "basctl.basicide","basctl::RenameModule: old module name is invalid!" );
141 return false;
142 }
143
144 if ( rDocument.hasModule( rLibName, rNewName ) )
145 {
146 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent,
147 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2)));
148 xError->run();
149 return false;
150 }
151
152 // #i74440
153 if ( rNewName.isEmpty() )
154 {
155 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent,
156 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
157 xError->run();
158 return false;
159 }
160
161 if ( !rDocument.renameModule( rLibName, rOldName, rNewName ) )
162 return false;
163
164 Shell* pShell = GetShell();
165 if (!pShell)
166 return true;
167 VclPtr<ModulWindow> pWin = pShell->FindBasWin(rDocument, rLibName, rNewName, false, true);
168 if (!pWin)
169 return true;
170
171 // set new name in window
172 pWin->SetName( rNewName );
173
174 // set new module in module window
175 pWin->SetSbModule( pWin->GetBasic()->FindModule( rNewName ) );
176
177 // update tabwriter
178 sal_uInt16 nId = pShell->GetWindowId( pWin );
179 SAL_WARN_IF( nId == 0 , "basctl.basicide", "No entry in Tabbar!");
180 if ( nId )
181 {
182 TabBar& rTabBar = pShell->GetTabBar();
183 rTabBar.SetPageText(nId, rNewName);
184 rTabBar.Sort();
185 rTabBar.MakeVisible(rTabBar.GetCurPageId());
186 }
187 return true;
188}
189
190namespace
191{
192 struct MacroExecutionData
193 {
194 ScriptDocument aDocument;
196
197 MacroExecutionData()
198 :aDocument( ScriptDocument::NoDocument )
199 {
200 }
201 };
202
203 class MacroExecution
204 {
205 public:
206 DECL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, void*, void );
207 };
208
209 IMPL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, void*, p, void )
210 {
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 );
215
216 SAL_WARN_IF( (pData->xMethod->GetParent()->GetFlags() & SbxFlagBits::ExtSearch) == SbxFlagBits::NONE, "basctl.basicide","No EXTSEARCH!" );
217
218 // in case this is a document-local macro, try to protect the document's Undo Manager from
219 // flawed scripts
220 std::optional< ::framework::DocumentUndoGuard > pUndoGuard;
221 if ( pData->aDocument.isDocument() )
222 pUndoGuard.emplace( pData->aDocument.getDocument() );
223
224 RunMethod( pData->xMethod.get() );
225 }
226}
227
228OUString ChooseMacro(weld::Window* pParent,
229 const uno::Reference< frame::XModel >& rxLimitToDocument,
230 const uno::Reference< frame::XFrame >& xDocFrame,
231 bool bChooseOnly)
232{
233 EnsureIde();
234
235 GetExtraData()->ChoosingMacro() = true;
236
237 OUString aScriptURL;
238 SbMethod* pMethod = nullptr;
239
240 MacroChooser aChooser(pParent, xDocFrame);
241 if ( bChooseOnly || !SvtModuleOptions::IsBasicIDE() )
243
244 if ( !bChooseOnly && rxLimitToDocument.is() )
245 {
246 // Hack!
248 }
249
250 short nRetValue = aChooser.run();
251
252 GetExtraData()->ChoosingMacro() = false;
253
254 switch ( nRetValue )
255 {
256 case Macro_OkRun:
257 {
258 bool bError = false;
259
260 pMethod = aChooser.GetMacro();
261 if ( !pMethod && aChooser.GetMode() == MacroChooser::Recording )
262 pMethod = aChooser.CreateMacro();
263
264 if ( !pMethod )
265 break;
266
267 SbModule* pModule = pMethod->GetModule();
268 if ( !pModule )
269 {
270 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Module found!" );
271 break;
272 }
273
274 StarBASIC* pBasic = dynamic_cast<StarBASIC*>(pModule->GetParent());
275 if ( !pBasic )
276 {
277 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Basic found!" );
278 break;
279 }
280
281 BasicManager* pBasMgr = FindBasicManager( pBasic );
282 if ( !pBasMgr )
283 {
284 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No BasicManager found!" );
285 break;
286 }
287
288 // name
289 OUString aName = pBasic->GetName() + "." + pModule->GetName() + "." + pMethod->GetName();
290
291 // location
292 OUString aLocation;
294 if ( aDocument.isDocument() )
295 {
296 // document basic
297 aLocation = "document" ;
298
299 if ( rxLimitToDocument.is() )
300 {
301 uno::Reference< frame::XModel > xLimitToDocument( rxLimitToDocument );
302
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 );
307 if ( xContext.is() )
308 xScripts = xContext->getScriptContainer();
309 if ( xScripts.is() )
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() )
313 {
314 SAL_WARN_IF(!xLimitToDocument.is(), "basctl.basicide", "basctl::ChooseMacro: a script container which is no document!?" );
315 xLimitToDocument = rxLimitToDocument;
316 }
317 }
318 }
319
320 if ( xLimitToDocument != aDocument.getDocument() )
321 {
322 // error
323 bError = true;
324 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(nullptr,
325 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_ERRORCHOOSEMACRO)));
326 xError->run();
327 }
328 }
329 }
330 else
331 {
332 // application basic
333 aLocation = "application" ;
334 }
335
336 // script URL
337 if ( !bError )
338 {
339 aScriptURL = "vnd.sun.star.script:" + aName + "?language=Basic&location=" + aLocation;
340 }
341
342 if ( !rxLimitToDocument.is() )
343 {
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 );
348 }
349 }
350 break;
351 }
352
353 return aScriptURL;
354}
355
356Sequence< OUString > GetMethodNames( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName )
357{
358 Sequence< OUString > aSeqMethods;
359
360 // get module
361 OUString aOUSource;
362 if ( rDocument.getModule( rLibName, rModName, aOUSource ) )
363 {
364 BasicManager* pBasMgr = rDocument.getBasicManager();
365 StarBASIC* pSb = pBasMgr ? pBasMgr->GetLib( rLibName ) : nullptr;
366 SbModule* pMod = pSb ? pSb->FindModule( rModName ) : nullptr;
367
368 SbModuleRef xModule;
369 // Only reparse modules if ScriptDocument source is out of sync
370 // with basic's Module
371 if ( !pMod || pMod->GetSource32() != aOUSource )
372 {
373 xModule = new SbModule( rModName );
374 xModule->SetSource32( aOUSource );
375 pMod = xModule.get();
376 }
377
378 sal_uInt32 nCount = pMod->GetMethods()->Count();
379 sal_uInt32 nRealCount = nCount;
380 for ( sal_uInt32 i = 0; i < nCount; i++ )
381 {
382 SbMethod* pMethod = static_cast<SbMethod*>(pMod->GetMethods()->Get(i));
383 if( pMethod->IsHidden() )
384 --nRealCount;
385 }
386 aSeqMethods.realloc( nRealCount );
387
388 sal_uInt32 iTarget = 0;
389 for ( sal_uInt32 i = 0 ; i < nCount; ++i )
390 {
391 SbMethod* pMethod = static_cast<SbMethod*>(pMod->GetMethods()->Get(i));
392 if( pMethod->IsHidden() )
393 continue;
394 SAL_WARN_IF( !pMethod, "basctl.basicide","Method not found! (NULL)" );
395 aSeqMethods.getArray()[ iTarget++ ] = pMethod->GetName();
396 }
397 }
398
399 return aSeqMethods;
400}
401
403 ScriptDocument const& rDocument,
404 OUString const& rLibName,
405 OUString const& rModName,
406 OUString const& rMethName
407)
408{
409 bool bHasMethod = false;
410
411 OUString aOUSource;
412 if ( rDocument.hasModule( rLibName, rModName ) && rDocument.getModule( rLibName, rModName, aOUSource ) )
413 {
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;
418 SbModuleRef xModule;
419 // Only reparse modules if ScriptDocument source is out of sync
420 // with basic's Module
421 if ( !pMod || pMod->GetSource32() != aOUSource )
422 {
423 xModule = new SbModule( rModName );
424 xModule->SetSource32( aOUSource );
425 pMod = xModule.get();
426 }
427 SbxArray* pMethods = pMod->GetMethods().get();
428 if ( pMethods )
429 {
430 SbMethod* pMethod = static_cast<SbMethod*>(pMethods->Find( rMethName, SbxClassType::Method ));
431 if ( pMethod && !pMethod->IsHidden() )
432 bHasMethod = true;
433 }
434 }
435
436 return bHasMethod;
437}
438
439} // namespace basctl
440
441/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ScriptDocument aDocument
Definition: basobj2.cxx:194
SbMethodRef xMethod
Definition: basobj2.cxx:195
static const AllSettings & GetSettings()
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, const ILibreOfficeKitNotifier *pNotifier=nullptr)
StarBASIC * GetLib(sal_uInt16 nLib) const
SbModule * GetModule()
const SbxArrayRef & GetMethods() const
const OUString & GetSource32() const
SbxVariable * Find(const OUString &, SbxClassType)
bool IsHidden() const
const SbxObject * GetParent() const
const OUString & GetName(SbxNameType=SbxNameType::NONE) const
SbModule * FindModule(std::u16string_view)
static bool IsBasicIDE()
virtual void SetPageText(sal_uInt16 nPageId, const OUString &rText)
void MakeVisible(sal_uInt16 nPageId)
sal_uInt16 GetCurPageId() const
bool & ChoosingMacro()
Definition: iderdll2.hxx:55
SbMethod * CreateMacro()
Definition: macrodlg.cxx:295
SbMethod * GetMacro()
Definition: macrodlg.cxx:239
Mode GetMode() const
Definition: macrodlg.hxx:103
virtual short run() override
Definition: macrodlg.cxx:178
void SetMode(Mode)
Definition: macrodlg.cxx:820
encapsulates a document which contains Basic scripts and dialogs
bool getModule(const OUString &_rLibName, const OUString &_rModName, OUString &_rModuleSource) const
retrieves a module's source
css::uno::Reference< css::frame::XModel > getDocument() const
returns the UNO component representing the document which the instance operates on
bool isDocument() const
determines whether the ScriptDocument instance operates on a real document, as opposed to the whole a...
BasicManager * getBasicManager() const
returns the BasicManager associated with this instance
static ScriptDocument getDocumentForBasicManager(const BasicManager *_pManager)
returns a (newly created) ScriptDocument instance for the document to which a given BasicManager belo...
bool renameModule(const OUString &_rLibName, const OUString &_rOldName, const OUString &_rNewName) const
renames a module
bool hasModule(const OUString &_rLibName, const OUString &_rModName) const
determines whether a module with the given name exists in the given library
VclPtr< ModulWindow > FindBasWin(const ScriptDocument &rDocument, const OUString &rLibName, const OUString &rModName, bool bCreateIfNotExist=false, bool bFindSuspended=false)
Definition: basides2.cxx:205
TabBar & GetTabBar()
Definition: basidesh.hxx:166
sal_uInt16 GetWindowId(BaseWindow const *pWin) const
Definition: basides3.cxx:125
T * get() const
static bool runAsync(const std::shared_ptr< DialogController > &rController, const std::function< void(sal_Int32)> &)
int nCount
#define ENSURE_OR_RETURN_VOID(c, m)
OUString aName
void * p
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
std::unique_ptr< sal_Int32[]> pData
void RunMethod(SbMethod const *pMethod)
Definition: basobj3.cxx:276
bool HasMethod(ScriptDocument const &rDocument, OUString const &rLibName, OUString const &rModName, OUString const &rMethName)
Definition: basobj2.cxx:402
bool IsValidSbxName(std::u16string_view rName)
Definition: basobj2.cxx:81
IMPL_STATIC_LINK(ExtraData, GlobalBasicBreakHdl, StarBASIC *, pBasic, BasicDebugFlags)
Definition: iderdll.cxx:165
@ Macro_OkRun
Definition: macrodlg.hxx:33
SAL_DLLPUBLIC_EXPORT rtl_uString * basicide_choose_macro(void *pParent, void *pOnlyInDocument_AsXModel, void *pDocFrame_AsXFrame, sal_Bool bChooseOnly)
Definition: basobj2.cxx:55
ExtraData * GetExtraData()
Definition: iderdll.cxx:101
OUString ChooseMacro(weld::Window *pParent, const uno::Reference< frame::XModel > &rxLimitToDocument, const uno::Reference< frame::XFrame > &xDocFrame, bool bChooseOnly)
Definition: basobj2.cxx:228
void Organize(weld::Window *pParent, const css::uno::Reference< css::frame::XFrame > &xDocFrame, sal_Int16 tabId)
Definition: basobj2.cxx:73
Shell * GetShell()
Definition: iderdll.cxx:80
void EnsureIde()
Definition: iderdll.cxx:74
BasicManager * FindBasicManager(StarBASIC const *pLib)
Definition: basobj3.cxx:225
SAL_DLLPUBLIC_EXPORT void basicide_macro_organizer(void *pParent, void *pDocFrame_AsXFrame, sal_Int16 nTabId)
Definition: basobj2.cxx:65
bool RenameModule(weld::Widget *pErrorParent, const ScriptDocument &rDocument, const OUString &rLibName, const OUString &rOldName, const OUString &rNewName)
renames a module
Definition: basobj2.cxx:130
Sequence< OUString > GetMethodNames(const ScriptDocument &rDocument, const OUString &rLibName, const OUString &rModName)
Definition: basobj2.cxx:356
Sequence< OUString > GetMergedLibraryNames(const Reference< script::XLibraryContainer > &xModLibContainer, const Reference< script::XLibraryContainer > &xDlgLibContainer)
Definition: basobj2.cxx:98
OUString IDEResId(TranslateId aId)
Definition: iderdll.cxx:108
const LanguageTag & getLocale()
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Reference< XComponentContext > getProcessComponentContext()
int i
sal_Int16 nId
unsigned char sal_Bool
sal_uInt16 sal_Unicode