nss: upgrade to release 3.73
[LibreOffice.git] / basctl / source / basicide / basobj2.cxx
blobb302c8b9493c265b4e06c84ca28b925227b3b3ca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
25 #include <iderid.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>
43 #include <memory>
44 #include <vector>
45 #include <algorithm>
46 #include <basic/basmgr.hxx>
47 namespace basctl
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::container;
54 extern "C" {
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 );
63 return 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)
74 EnsureIde();
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];
85 bool bValid = (
86 ( c >= 'A' && c <= 'Z' ) ||
87 ( c >= 'a' && c <= 'z' ) ||
88 ( c >= '0' && c <= '9' && nChar ) ||
89 ( c == '_' )
91 if ( !bValid )
92 return false;
94 return true;
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 ] );
120 // sort list
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;
128 // remove duplicates
129 std::vector<OUString>::iterator aIterEnd = std::unique( aLibList.begin(), aLibList.end() );
130 aLibList.erase( aIterEnd, aLibList.end() );
132 return comphelper::containerToSequence(aLibList);
135 bool RenameModule (
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!" );
146 return false;
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)));
153 xError->run();
154 return false;
157 // #i74440
158 if ( rNewName.isEmpty() )
160 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent,
161 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
162 xError->run();
163 return false;
166 if ( !rDocument.renameModule( rLibName, rOldName, rNewName ) )
167 return false;
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 ) );
179 // update tabwriter
180 sal_uInt16 nId = pShell->GetWindowId( pWin );
181 SAL_WARN_IF( nId == 0 , "basctl.basicide", "No entry in Tabbar!");
182 if ( nId )
184 TabBar& rTabBar = pShell->GetTabBar();
185 rTabBar.SetPageText(nId, rNewName);
186 rTabBar.Sort();
187 rTabBar.MakeVisible(rTabBar.GetCurPageId());
191 return true;
194 namespace
196 struct MacroExecutionData
198 ScriptDocument aDocument;
199 SbMethodRef xMethod;
201 MacroExecutionData()
202 :aDocument( ScriptDocument::NoDocument )
207 class MacroExecution
209 public:
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
223 // flawed scripts
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,
235 bool bChooseOnly)
237 EnsureIde();
239 GetExtraData()->ChoosingMacro() = true;
241 OUString aScriptURL;
242 SbMethod* pMethod = nullptr;
244 MacroChooser aChooser(pParent, xDocFrame);
245 if ( bChooseOnly || !SvtModuleOptions::IsBasicIDE() )
246 aChooser.SetMode(MacroChooser::ChooseOnly);
248 if ( !bChooseOnly && rxLimitToDocument.is() )
250 // Hack!
251 aChooser.SetMode(MacroChooser::Recording);
254 short nRetValue = aChooser.run();
256 GetExtraData()->ChoosingMacro() = false;
258 switch ( nRetValue )
260 case Macro_OkRun:
262 bool bError = false;
264 pMethod = aChooser.GetMacro();
265 if ( !pMethod && aChooser.GetMode() == MacroChooser::Recording )
266 pMethod = aChooser.CreateMacro();
268 if ( !pMethod )
269 break;
271 SbModule* pModule = pMethod->GetModule();
272 if ( !pModule )
274 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Module found!" );
275 break;
278 StarBASIC* pBasic = dynamic_cast<StarBASIC*>(pModule->GetParent());
279 if ( !pBasic )
281 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Basic found!" );
282 break;
285 BasicManager* pBasMgr = FindBasicManager( pBasic );
286 if ( !pBasMgr )
288 SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No BasicManager found!" );
289 break;
292 // name
293 OUString aName = pBasic->GetName() + "." + pModule->GetName() + "." + pMethod->GetName();
295 // location
296 OUString aLocation;
297 ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
298 if ( aDocument.isDocument() )
300 // document basic
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 );
311 if ( xContext.is() )
312 xScripts = xContext->getScriptContainer();
313 if ( xScripts.is() )
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() )
326 // error
327 bError = true;
328 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(nullptr,
329 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_ERRORCHOOSEMACRO)));
330 xError->run();
334 else
336 // application basic
337 aLocation = "application" ;
340 // script URL
341 if ( !bError )
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 );
354 break;
357 return aScriptURL;
360 Sequence< OUString > GetMethodNames( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName )
362 Sequence< OUString > aSeqMethods;
364 // get module
365 OUString aOUSource;
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;
372 SbModuleRef xModule;
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() )
388 --nRealCount;
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() )
397 continue;
398 SAL_WARN_IF( !pMethod, "basctl.basicide","Method not found! (NULL)" );
399 aSeqMethods.getArray()[ iTarget++ ] = pMethod->GetName();
403 return aSeqMethods;
406 bool HasMethod (
407 ScriptDocument const& rDocument,
408 OUString const& rLibName,
409 OUString const& rModName,
410 OUString const& rMethName
413 bool bHasMethod = false;
415 OUString aOUSource;
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;
422 SbModuleRef xModule;
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();
432 if ( pMethods )
434 SbMethod* pMethod = static_cast<SbMethod*>(pMethods->Find( rMethName, SbxClassType::Method ));
435 if ( pMethod && !pMethod->IsHidden() )
436 bHasMethod = true;
440 return bHasMethod;
443 } // namespace basctl
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */