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