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