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