Line data Source code
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 "basobj.hxx"
21 : #include "iderdll.hxx"
22 : #include "iderdll2.hxx"
23 : #include "iderid.hxx"
24 : #include "macrodlg.hxx"
25 : #include "moduldlg.hxx"
26 : #include "basidesh.hxx"
27 : #include "basidesh.hrc"
28 : #include "baside2.hxx"
29 : #include "basicmod.hxx"
30 : #include "basdoc.hxx"
31 :
32 : #include <com/sun/star/document/XEmbeddedScripts.hpp>
33 : #include <com/sun/star/document/XScriptInvocationContext.hpp>
34 :
35 : #include <basic/sbmeth.hxx>
36 : #include <basic/sbx.hxx>
37 : #include <framework/documentundoguard.hxx>
38 : #include <tools/diagnose_ex.h>
39 : #include <unotools/moduleoptions.hxx>
40 : #include <vcl/msgbox.hxx>
41 :
42 : #include <vector>
43 : #include <algorithm>
44 : #include <memory>
45 :
46 : namespace basctl
47 : {
48 :
49 : using namespace ::com::sun::star;
50 : using namespace ::com::sun::star::uno;
51 : using namespace ::com::sun::star::container;
52 :
53 :
54 : //----------------------------------------------------------------------------
55 :
56 : extern "C" {
57 0 : SAL_DLLPUBLIC_EXPORT rtl_uString* basicide_choose_macro( void* pOnlyInDocument_AsXModel, sal_Bool bChooseOnly, rtl_uString* pMacroDesc )
58 : {
59 0 : OUString aMacroDesc( pMacroDesc );
60 0 : Reference< frame::XModel > aDocument( static_cast< frame::XModel* >( pOnlyInDocument_AsXModel ) );
61 0 : OUString aScriptURL = basctl::ChooseMacro( aDocument, bChooseOnly, aMacroDesc );
62 0 : rtl_uString* pScriptURL = aScriptURL.pData;
63 0 : rtl_uString_acquire( pScriptURL );
64 :
65 0 : return pScriptURL;
66 : }
67 0 : SAL_DLLPUBLIC_EXPORT void basicide_macro_organizer( sal_Int16 nTabId )
68 : {
69 : OSL_TRACE("in basicide_macro_organizer");
70 0 : basctl::Organize( nTabId );
71 0 : }
72 : }
73 :
74 : //----------------------------------------------------------------------------
75 :
76 0 : void Organize( sal_Int16 tabId )
77 : {
78 0 : EnsureIde();
79 :
80 0 : EntryDescriptor aDesc;
81 0 : if (Shell* pShell = GetShell())
82 0 : if (BaseWindow* pCurWin = pShell->GetCurWindow())
83 0 : aDesc = pCurWin->CreateEntryDescriptor();
84 :
85 0 : Window* pParent = Application::GetDefDialogParent();
86 0 : OrganizeDialog(pParent, tabId, aDesc).Execute();
87 0 : }
88 :
89 : //----------------------------------------------------------------------------
90 :
91 0 : bool IsValidSbxName( const String& rName )
92 : {
93 0 : for ( sal_uInt16 nChar = 0; nChar < rName.Len(); nChar++ )
94 : {
95 0 : sal_Unicode c = rName.GetChar(nChar);
96 : bool bValid = (
97 : ( c >= 'A' && c <= 'Z' ) ||
98 : ( c >= 'a' && c <= 'z' ) ||
99 : ( c >= '0' && c <= '9' && nChar ) ||
100 : ( c == '_' )
101 0 : );
102 0 : if ( !bValid )
103 0 : return false;
104 : }
105 0 : return true;
106 : }
107 :
108 0 : static bool StringCompareLessThan( const String& rStr1, const String& rStr2 )
109 : {
110 0 : return (rStr1.CompareIgnoreCaseToAscii( rStr2 ) == COMPARE_LESS);
111 : }
112 :
113 : //----------------------------------------------------------------------------
114 :
115 0 : Sequence< OUString > GetMergedLibraryNames( const Reference< script::XLibraryContainer >& xModLibContainer, const Reference< script::XLibraryContainer >& xDlgLibContainer )
116 : {
117 : // create a sorted list of module library names
118 0 : ::std::vector<String> aModLibList;
119 0 : if ( xModLibContainer.is() )
120 : {
121 0 : Sequence< OUString > aModLibNames = xModLibContainer->getElementNames();
122 0 : sal_Int32 nModLibCount = aModLibNames.getLength();
123 0 : const OUString* pModLibNames = aModLibNames.getConstArray();
124 0 : for ( sal_Int32 i = 0 ; i < nModLibCount ; i++ )
125 0 : aModLibList.push_back( pModLibNames[ i ] );
126 0 : ::std::sort( aModLibList.begin() , aModLibList.end() , StringCompareLessThan );
127 : }
128 :
129 : // create a sorted list of dialog library names
130 0 : ::std::vector<String> aDlgLibList;
131 0 : if ( xDlgLibContainer.is() )
132 : {
133 0 : Sequence< OUString > aDlgLibNames = xDlgLibContainer->getElementNames();
134 0 : sal_Int32 nDlgLibCount = aDlgLibNames.getLength();
135 0 : const OUString* pDlgLibNames = aDlgLibNames.getConstArray();
136 0 : for ( sal_Int32 i = 0 ; i < nDlgLibCount ; i++ )
137 0 : aDlgLibList.push_back( pDlgLibNames[ i ] );
138 0 : ::std::sort( aDlgLibList.begin() , aDlgLibList.end() , StringCompareLessThan );
139 : }
140 :
141 : // merge both lists
142 0 : ::std::vector<String> aLibList( aModLibList.size() + aDlgLibList.size() );
143 0 : ::std::merge( aModLibList.begin(), aModLibList.end(), aDlgLibList.begin(), aDlgLibList.end(), aLibList.begin(), StringCompareLessThan );
144 0 : ::std::vector<String>::iterator aIterEnd = ::std::unique( aLibList.begin(), aLibList.end() ); // move unique elements to the front
145 0 : aLibList.erase( aIterEnd, aLibList.end() ); // remove duplicates
146 :
147 : // copy to sequence
148 0 : sal_Int32 nLibCount = aLibList.size();
149 0 : Sequence< OUString > aSeqLibNames( nLibCount );
150 0 : for ( sal_Int32 i = 0 ; i < nLibCount ; i++ )
151 0 : aSeqLibNames.getArray()[ i ] = aLibList[ i ];
152 :
153 0 : return aSeqLibNames;
154 : }
155 :
156 : //----------------------------------------------------------------------------
157 :
158 0 : bool RenameModule (
159 : Window* pErrorParent,
160 : const ScriptDocument& rDocument,
161 : const OUString& rLibName,
162 : const OUString& rOldName,
163 : const OUString& rNewName
164 : )
165 : {
166 0 : if ( !rDocument.hasModule( rLibName, rOldName ) )
167 : {
168 : OSL_FAIL( "basctl::RenameModule: old module name is invalid!" );
169 0 : return false;
170 : }
171 :
172 0 : if ( rDocument.hasModule( rLibName, rNewName ) )
173 : {
174 0 : ErrorBox aError( pErrorParent, WB_OK | WB_DEF_OK, IDE_RESSTR(RID_STR_SBXNAMEALLREADYUSED2) );
175 0 : aError.Execute();
176 0 : return false;
177 : }
178 :
179 : // #i74440
180 0 : if ( rNewName.isEmpty() )
181 : {
182 0 : ErrorBox aError( pErrorParent, WB_OK | WB_DEF_OK, IDE_RESSTR(RID_STR_BADSBXNAME) );
183 0 : aError.Execute();
184 0 : return false;
185 : }
186 :
187 0 : if ( !rDocument.renameModule( rLibName, rOldName, rNewName ) )
188 0 : return false;
189 :
190 0 : if (Shell* pShell = GetShell())
191 : {
192 0 : if (ModulWindow* pWin = pShell->FindBasWin(rDocument, rLibName, rNewName, false, true))
193 : {
194 : // set new name in window
195 0 : pWin->SetName( rNewName );
196 :
197 : // set new module in module window
198 0 : pWin->SetSbModule( (SbModule*)pWin->GetBasic()->FindModule( rNewName ) );
199 :
200 : // update tabwriter
201 0 : sal_uInt16 nId = pShell->GetWindowId( pWin );
202 : DBG_ASSERT( nId, "No entry in Tabbar!" );
203 0 : if ( nId )
204 : {
205 0 : TabBar& rTabBar = pShell->GetTabBar();
206 0 : rTabBar.SetPageText(nId, rNewName);
207 0 : rTabBar.Sort();
208 0 : rTabBar.MakeVisible(rTabBar.GetCurPageId());
209 : }
210 : }
211 : }
212 0 : return true;
213 : }
214 :
215 :
216 : //----------------------------------------------------------------------------
217 :
218 : namespace
219 : {
220 0 : struct MacroExecutionData
221 : {
222 : ScriptDocument aDocument;
223 : SbMethodRef xMethod;
224 :
225 0 : MacroExecutionData()
226 : :aDocument( ScriptDocument::NoDocument )
227 0 : ,xMethod( NULL )
228 : {
229 0 : }
230 : };
231 :
232 : class MacroExecution
233 : {
234 : public:
235 : DECL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, MacroExecutionData* );
236 : };
237 :
238 :
239 0 : IMPL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, MacroExecutionData*, i_pData )
240 : {
241 : (void)pThis;
242 0 : ENSURE_OR_RETURN( i_pData, "wrong MacroExecutionData", 0L );
243 : // take ownership of the data
244 0 : ::std::auto_ptr< MacroExecutionData > pData( i_pData );
245 :
246 : DBG_ASSERT( pData->xMethod->GetParent()->GetFlags() & SBX_EXTSEARCH, "Kein EXTSEARCH!" );
247 :
248 : // in case this is a document-local macro, try to protect the document's Undo Manager from
249 : // flawed scripts
250 0 : ::std::auto_ptr< ::framework::DocumentUndoGuard > pUndoGuard;
251 0 : if ( pData->aDocument.isDocument() )
252 0 : pUndoGuard.reset( new ::framework::DocumentUndoGuard( pData->aDocument.getDocument() ) );
253 :
254 0 : RunMethod(pData->xMethod);
255 :
256 0 : return 1L;
257 : }
258 : }
259 :
260 : //----------------------------------------------------------------------------
261 :
262 0 : OUString ChooseMacro( const uno::Reference< frame::XModel >& rxLimitToDocument, bool bChooseOnly, const OUString& rMacroDesc )
263 : {
264 : (void)rMacroDesc;
265 :
266 0 : EnsureIde();
267 :
268 0 : GetExtraData()->ChoosingMacro() = true;
269 :
270 0 : String aScriptURL;
271 0 : bool bError = false;
272 0 : SbMethod* pMethod = NULL;
273 :
274 0 : ::std::auto_ptr< MacroChooser > pChooser( new MacroChooser( NULL, true ) );
275 0 : if ( bChooseOnly || !SvtModuleOptions().IsBasicIDE() )
276 0 : pChooser->SetMode(MacroChooser::ChooseOnly);
277 :
278 0 : if ( !bChooseOnly && rxLimitToDocument.is() )
279 : // Hack!
280 0 : pChooser->SetMode(MacroChooser::Recording);
281 :
282 0 : short nRetValue = pChooser->Execute();
283 :
284 0 : GetExtraData()->ChoosingMacro() = false;
285 :
286 0 : switch ( nRetValue )
287 : {
288 : case Macro_OkRun:
289 : {
290 0 : pMethod = pChooser->GetMacro();
291 0 : if ( !pMethod && pChooser->GetMode() == MacroChooser::Recording )
292 0 : pMethod = pChooser->CreateMacro();
293 :
294 0 : if ( !pMethod )
295 : break;
296 :
297 0 : SbModule* pModule = pMethod->GetModule();
298 0 : if ( !pModule )
299 : {
300 : SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Module found!" );
301 : break;
302 : }
303 :
304 0 : StarBASIC* pBasic = dynamic_cast<StarBASIC*>(pModule->GetParent());
305 0 : if ( !pBasic )
306 : {
307 : SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Basic found!" );
308 : break;
309 : }
310 :
311 0 : BasicManager* pBasMgr = FindBasicManager( pBasic );
312 0 : if ( !pBasMgr )
313 : {
314 : SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No BasicManager found!" );
315 : break;
316 : }
317 :
318 : // name
319 0 : String aName;
320 0 : aName += pBasic->GetName();
321 0 : aName += '.';
322 0 : aName += pModule->GetName();
323 0 : aName += '.';
324 0 : aName += pMethod->GetName();
325 :
326 : // language
327 0 : OUString aLanguage("Basic");
328 :
329 : // location
330 0 : OUString aLocation;
331 0 : ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) );
332 0 : if ( aDocument.isDocument() )
333 : {
334 : // document basic
335 0 : aLocation = "document" ;
336 :
337 0 : if ( rxLimitToDocument.is() )
338 : {
339 0 : uno::Reference< frame::XModel > xLimitToDocument( rxLimitToDocument );
340 :
341 0 : uno::Reference< document::XEmbeddedScripts > xScripts( rxLimitToDocument, UNO_QUERY );
342 0 : if ( !xScripts.is() )
343 : { // the document itself does not support embedding scripts
344 0 : uno::Reference< document::XScriptInvocationContext > xContext( rxLimitToDocument, UNO_QUERY );
345 0 : if ( xContext.is() )
346 0 : xScripts = xContext->getScriptContainer();
347 0 : if ( xScripts.is() )
348 : { // but it is able to refer to a document which actually does support this
349 0 : xLimitToDocument.set( xScripts, UNO_QUERY );
350 0 : if ( !xLimitToDocument.is() )
351 : {
352 : OSL_ENSURE( false, "basctl::ChooseMacro: a script container which is no document!?" );
353 0 : xLimitToDocument = rxLimitToDocument;
354 : }
355 0 : }
356 : }
357 :
358 0 : if ( xLimitToDocument != aDocument.getDocument() )
359 : {
360 : // error
361 0 : bError = true;
362 0 : ErrorBox( NULL, WB_OK | WB_DEF_OK, String( IDEResId( RID_STR_ERRORCHOOSEMACRO ) ) ).Execute();
363 0 : }
364 : }
365 : }
366 : else
367 : {
368 : // application basic
369 0 : aLocation = "application" ;
370 : }
371 :
372 : // script URL
373 0 : if ( !bError )
374 : {
375 0 : aScriptURL = "vnd.sun.star.script:" ;
376 0 : aScriptURL += aName;
377 0 : aScriptURL += "?language=" ;
378 0 : aScriptURL += aLanguage;
379 0 : aScriptURL += "&location=" ;
380 0 : aScriptURL += aLocation;
381 : }
382 :
383 0 : if ( !rxLimitToDocument.is() )
384 : {
385 0 : MacroExecutionData* pExecData = new MacroExecutionData;
386 0 : pExecData->aDocument = aDocument;
387 0 : pExecData->xMethod = pMethod; // keep alive until the event has been processed
388 0 : Application::PostUserEvent( STATIC_LINK( NULL, MacroExecution, ExecuteMacroEvent ), pExecData );
389 0 : }
390 : }
391 0 : break;
392 : }
393 :
394 0 : return aScriptURL;
395 : }
396 :
397 : //----------------------------------------------------------------------------
398 :
399 0 : Sequence< OUString > GetMethodNames( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName )
400 : throw(NoSuchElementException )
401 : {
402 0 : Sequence< OUString > aSeqMethods;
403 :
404 : // get module
405 0 : OUString aOUSource;
406 0 : if ( rDocument.getModule( rLibName, rModName, aOUSource ) )
407 : {
408 0 : SbModuleRef xModule = new SbModule( rModName );
409 0 : xModule->SetSource32( aOUSource );
410 0 : sal_uInt16 nCount = xModule->GetMethods()->Count();
411 0 : sal_uInt16 nRealCount = nCount;
412 0 : for ( sal_uInt16 i = 0; i < nCount; i++ )
413 : {
414 0 : SbMethod* pMethod = (SbMethod*)xModule->GetMethods()->Get( i );
415 0 : if( pMethod->IsHidden() )
416 0 : --nRealCount;
417 : }
418 0 : aSeqMethods.realloc( nRealCount );
419 :
420 0 : sal_uInt16 iTarget = 0;
421 0 : for ( sal_uInt16 i = 0 ; i < nCount; ++i )
422 : {
423 0 : SbMethod* pMethod = (SbMethod*)xModule->GetMethods()->Get( i );
424 0 : if( pMethod->IsHidden() )
425 0 : continue;
426 : DBG_ASSERT( pMethod, "Method not found! (NULL)" );
427 0 : aSeqMethods.getArray()[ iTarget++ ] = pMethod->GetName();
428 0 : }
429 : }
430 :
431 0 : return aSeqMethods;
432 : }
433 :
434 : //----------------------------------------------------------------------------
435 :
436 0 : bool HasMethod (
437 : ScriptDocument const& rDocument,
438 : OUString const& rLibName,
439 : OUString const& rModName,
440 : OUString const& rMethName
441 : )
442 : {
443 0 : bool bHasMethod = false;
444 :
445 0 : OUString aOUSource;
446 0 : if ( rDocument.hasModule( rLibName, rModName ) && rDocument.getModule( rLibName, rModName, aOUSource ) )
447 : {
448 0 : SbModuleRef xModule = new SbModule( rModName );
449 0 : xModule->SetSource32( aOUSource );
450 0 : SbxArray* pMethods = xModule->GetMethods();
451 0 : if ( pMethods )
452 : {
453 0 : SbMethod* pMethod = (SbMethod*)pMethods->Find( rMethName, SbxCLASS_METHOD );
454 0 : if ( pMethod && !pMethod->IsHidden() )
455 0 : bHasMethod = true;
456 0 : }
457 : }
458 :
459 0 : return bHasMethod;
460 : }
461 :
462 : //----------------------------------------------------------------------------
463 : } // namespace basctl
464 :
465 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|