| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_basctl.hxx" |
| |
| #include <ide_pch.hxx> |
| |
| #include "basobj.hxx" |
| #include "iderdll.hxx" |
| #include "iderdll2.hxx" |
| #include "iderid.hxx" |
| #include "macrodlg.hxx" |
| #include "moduldlg.hxx" |
| #include "basidesh.hxx" |
| #include "basidesh.hrc" |
| #include "baside2.hxx" |
| #include "basicmod.hxx" |
| #include "basdoc.hxx" |
| |
| #include <com/sun/star/document/XEmbeddedScripts.hpp> |
| #include <com/sun/star/document/XScriptInvocationContext.hpp> |
| |
| #include <basic/sbx.hxx> |
| #include <framework/documentundoguard.hxx> |
| #include <tools/diagnose_ex.h> |
| #include <unotools/moduleoptions.hxx> |
| |
| #include <vector> |
| #include <algorithm> |
| #include <memory> |
| |
| using namespace ::com::sun::star; |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::container; |
| |
| |
| //---------------------------------------------------------------------------- |
| |
| extern "C" { |
| SAL_DLLPUBLIC_EXPORT rtl_uString* basicide_choose_macro( void* pOnlyInDocument_AsXModel, sal_Bool bChooseOnly, rtl_uString* pMacroDesc ) |
| { |
| ::rtl::OUString aMacroDesc( pMacroDesc ); |
| Reference< frame::XModel > aDocument( static_cast< frame::XModel* >( pOnlyInDocument_AsXModel ) ); |
| ::rtl::OUString aScriptURL = BasicIDE::ChooseMacro( aDocument, bChooseOnly, aMacroDesc ); |
| rtl_uString* pScriptURL = aScriptURL.pData; |
| rtl_uString_acquire( pScriptURL ); |
| |
| return pScriptURL; |
| } |
| SAL_DLLPUBLIC_EXPORT void basicide_macro_organizer( sal_Int16 nTabId ) |
| { |
| OSL_TRACE("in basicide_macro_organizer"); |
| BasicIDE::Organize( nTabId ); |
| } |
| } |
| |
| namespace BasicIDE |
| { |
| //---------------------------------------------------------------------------- |
| |
| void Organize( sal_Int16 tabId ) |
| { |
| BasicIDEDLL::Init(); |
| |
| BasicEntryDescriptor aDesc; |
| BasicIDEShell* pIDEShell = IDE_DLL()->GetShell(); |
| if ( pIDEShell ) |
| { |
| IDEBaseWindow* pCurWin = pIDEShell->GetCurWindow(); |
| if ( pCurWin ) |
| aDesc = pCurWin->CreateEntryDescriptor(); |
| } |
| |
| Window* pParent = Application::GetDefDialogParent(); |
| OrganizeDialog* pDlg = new OrganizeDialog( pParent, tabId, aDesc ); |
| pDlg->Execute(); |
| delete pDlg; |
| } |
| |
| //---------------------------------------------------------------------------- |
| |
| sal_Bool IsValidSbxName( const String& rName ) |
| { |
| for ( sal_uInt16 nChar = 0; nChar < rName.Len(); nChar++ ) |
| { |
| sal_Bool bValid = ( ( rName.GetChar(nChar) >= 'A' && rName.GetChar(nChar) <= 'Z' ) || |
| ( rName.GetChar(nChar) >= 'a' && rName.GetChar(nChar) <= 'z' ) || |
| ( rName.GetChar(nChar) >= '0' && rName.GetChar(nChar) <= '9' && nChar ) || |
| ( rName.GetChar(nChar) == '_' ) ); |
| if ( !bValid ) |
| return sal_False; |
| } |
| return sal_True; |
| } |
| |
| static sal_Bool StringCompareLessThan( const String& rStr1, const String& rStr2 ) |
| { |
| return (rStr1.CompareIgnoreCaseToAscii( rStr2 ) == COMPARE_LESS); |
| } |
| |
| //---------------------------------------------------------------------------- |
| |
| Sequence< ::rtl::OUString > GetMergedLibraryNames( const Reference< script::XLibraryContainer >& xModLibContainer, const Reference< script::XLibraryContainer >& xDlgLibContainer ) |
| { |
| // create a sorted list of module library names |
| ::std::vector<String> aModLibList; |
| if ( xModLibContainer.is() ) |
| { |
| Sequence< ::rtl::OUString > aModLibNames = xModLibContainer->getElementNames(); |
| sal_Int32 nModLibCount = aModLibNames.getLength(); |
| const ::rtl::OUString* pModLibNames = aModLibNames.getConstArray(); |
| for ( sal_Int32 i = 0 ; i < nModLibCount ; i++ ) |
| aModLibList.push_back( pModLibNames[ i ] ); |
| ::std::sort( aModLibList.begin() , aModLibList.end() , StringCompareLessThan ); |
| } |
| |
| // create a sorted list of dialog library names |
| ::std::vector<String> aDlgLibList; |
| if ( xDlgLibContainer.is() ) |
| { |
| Sequence< ::rtl::OUString > aDlgLibNames = xDlgLibContainer->getElementNames(); |
| sal_Int32 nDlgLibCount = aDlgLibNames.getLength(); |
| const ::rtl::OUString* pDlgLibNames = aDlgLibNames.getConstArray(); |
| for ( sal_Int32 i = 0 ; i < nDlgLibCount ; i++ ) |
| aDlgLibList.push_back( pDlgLibNames[ i ] ); |
| ::std::sort( aDlgLibList.begin() , aDlgLibList.end() , StringCompareLessThan ); |
| } |
| |
| // merge both lists |
| ::std::vector<String> aLibList( aModLibList.size() + aDlgLibList.size() ); |
| ::std::merge( aModLibList.begin(), aModLibList.end(), aDlgLibList.begin(), aDlgLibList.end(), aLibList.begin(), StringCompareLessThan ); |
| ::std::vector<String>::iterator aIterEnd = ::std::unique( aLibList.begin(), aLibList.end() ); // move unique elements to the front |
| aLibList.erase( aIterEnd, aLibList.end() ); // remove duplicates |
| |
| // copy to sequence |
| sal_Int32 nLibCount = aLibList.size(); |
| Sequence< ::rtl::OUString > aSeqLibNames( nLibCount ); |
| for ( sal_Int32 i = 0 ; i < nLibCount ; i++ ) |
| aSeqLibNames.getArray()[ i ] = aLibList[ i ]; |
| |
| return aSeqLibNames; |
| } |
| |
| //---------------------------------------------------------------------------- |
| |
| bool RenameModule( Window* pErrorParent, const ScriptDocument& rDocument, const String& rLibName, const String& rOldName, const String& rNewName ) |
| { |
| if ( !rDocument.hasModule( rLibName, rOldName ) ) |
| { |
| OSL_ENSURE( false, "BasicIDE::RenameModule: old module name is invalid!" ); |
| return false; |
| } |
| |
| if ( rDocument.hasModule( rLibName, rNewName ) ) |
| { |
| ErrorBox aError( pErrorParent, WB_OK | WB_DEF_OK, String( IDEResId( RID_STR_SBXNAMEALLREADYUSED2 ) ) ); |
| aError.Execute(); |
| return false; |
| } |
| |
| // #i74440 |
| if ( rNewName.Len() == 0 ) |
| { |
| ErrorBox aError( pErrorParent, WB_OK | WB_DEF_OK, String( IDEResId( RID_STR_BADSBXNAME ) ) ); |
| aError.Execute(); |
| return false; |
| } |
| |
| if ( !rDocument.renameModule( rLibName, rOldName, rNewName ) ) |
| return false; |
| |
| BasicIDEShell* pIDEShell = IDE_DLL()->GetShell(); |
| if ( pIDEShell ) |
| { |
| IDEBaseWindow* pWin = pIDEShell->FindWindow( rDocument, rLibName, rNewName, BASICIDE_TYPE_MODULE, sal_True ); |
| if ( pWin ) |
| { |
| // set new name in window |
| pWin->SetName( rNewName ); |
| |
| // set new module in module window |
| ModulWindow* pModWin = (ModulWindow*)pWin; |
| pModWin->SetSbModule( (SbModule*)pModWin->GetBasic()->FindModule( rNewName ) ); |
| |
| // update tabwriter |
| sal_uInt16 nId = (sal_uInt16)(pIDEShell->GetIDEWindowTable()).GetKey( pWin ); |
| DBG_ASSERT( nId, "No entry in Tabbar!" ); |
| if ( nId ) |
| { |
| BasicIDETabBar* pTabBar = (BasicIDETabBar*)pIDEShell->GetTabBar(); |
| pTabBar->SetPageText( nId, rNewName ); |
| pTabBar->Sort(); |
| pTabBar->MakeVisible( pTabBar->GetCurPageId() ); |
| } |
| } |
| } |
| return true; |
| } |
| |
| |
| //---------------------------------------------------------------------------- |
| |
| namespace |
| { |
| struct MacroExecutionData |
| { |
| ScriptDocument aDocument; |
| SbMethodRef xMethod; |
| |
| MacroExecutionData() |
| :aDocument( ScriptDocument::NoDocument ) |
| ,xMethod( NULL ) |
| { |
| } |
| }; |
| |
| class MacroExecution |
| { |
| public: |
| DECL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, MacroExecutionData* ); |
| }; |
| |
| |
| IMPL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, MacroExecutionData*, i_pData ) |
| { |
| (void)pThis; |
| ENSURE_OR_RETURN( i_pData, "wrong MacroExecutionData", 0L ); |
| // take ownership of the data |
| ::std::auto_ptr< MacroExecutionData > pData( i_pData ); |
| |
| DBG_ASSERT( pData->xMethod->GetParent()->GetFlags() & SBX_EXTSEARCH, "Kein EXTSEARCH!" ); |
| |
| // in case this is a document-local macro, try to protect the document's Undo Manager from |
| // flawed scripts |
| ::std::auto_ptr< ::framework::DocumentUndoGuard > pUndoGuard; |
| if ( pData->aDocument.isDocument() ) |
| pUndoGuard.reset( new ::framework::DocumentUndoGuard( pData->aDocument.getDocument() ) ); |
| |
| BasicIDE::RunMethod( pData->xMethod ); |
| |
| return 1L; |
| } |
| } |
| |
| //---------------------------------------------------------------------------- |
| |
| ::rtl::OUString ChooseMacro( const uno::Reference< frame::XModel >& rxLimitToDocument, sal_Bool bChooseOnly, const ::rtl::OUString& rMacroDesc ) |
| { |
| (void)rMacroDesc; |
| |
| BasicIDEDLL::Init(); |
| |
| IDE_DLL()->GetExtraData()->ChoosingMacro() = sal_True; |
| |
| String aScriptURL; |
| sal_Bool bError = sal_False; |
| SbMethod* pMethod = NULL; |
| |
| ::std::auto_ptr< MacroChooser > pChooser( new MacroChooser( NULL, sal_True ) ); |
| if ( bChooseOnly || !SvtModuleOptions().IsBasicIDE() ) |
| pChooser->SetMode( MACROCHOOSER_CHOOSEONLY ); |
| |
| if ( !bChooseOnly && rxLimitToDocument.is() ) |
| // Hack! |
| pChooser->SetMode( MACROCHOOSER_RECORDING ); |
| |
| short nRetValue = pChooser->Execute(); |
| |
| IDE_DLL()->GetExtraData()->ChoosingMacro() = sal_False; |
| |
| switch ( nRetValue ) |
| { |
| case MACRO_OK_RUN: |
| { |
| pMethod = pChooser->GetMacro(); |
| if ( !pMethod && pChooser->GetMode() == MACROCHOOSER_RECORDING ) |
| pMethod = pChooser->CreateMacro(); |
| |
| if ( !pMethod ) |
| break; |
| |
| SbModule* pModule = pMethod->GetModule(); |
| ENSURE_OR_BREAK( pModule, "BasicIDE::ChooseMacro: No Module found!" ); |
| |
| StarBASIC* pBasic = (StarBASIC*)pModule->GetParent(); |
| ENSURE_OR_BREAK( pBasic, "BasicIDE::ChooseMacro: No Basic found!" ); |
| |
| BasicManager* pBasMgr = BasicIDE::FindBasicManager( pBasic ); |
| ENSURE_OR_BREAK( pBasMgr, "BasicIDE::ChooseMacro: No BasicManager found!" ); |
| |
| // name |
| String aName; |
| aName += pBasic->GetName(); |
| aName += '.'; |
| aName += pModule->GetName(); |
| aName += '.'; |
| aName += pMethod->GetName(); |
| |
| // language |
| String aLanguage = String::CreateFromAscii("Basic"); |
| |
| // location |
| String aLocation; |
| ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); |
| if ( aDocument.isDocument() ) |
| { |
| // document basic |
| aLocation = String::CreateFromAscii("document"); |
| |
| if ( rxLimitToDocument.is() ) |
| { |
| uno::Reference< frame::XModel > xLimitToDocument( rxLimitToDocument ); |
| |
| uno::Reference< document::XEmbeddedScripts > xScripts( rxLimitToDocument, UNO_QUERY ); |
| if ( !xScripts.is() ) |
| { // the document itself does not support embedding scripts |
| uno::Reference< document::XScriptInvocationContext > xContext( rxLimitToDocument, UNO_QUERY ); |
| if ( xContext.is() ) |
| xScripts = xContext->getScriptContainer(); |
| if ( xScripts.is() ) |
| { // but it is able to refer to a document which actually does support this |
| xLimitToDocument.set( xScripts, UNO_QUERY ); |
| if ( !xLimitToDocument.is() ) |
| { |
| OSL_ENSURE( false, "BasicIDE::ChooseMacro: a script container which is no document!?" ); |
| xLimitToDocument = rxLimitToDocument; |
| } |
| } |
| } |
| |
| if ( xLimitToDocument != aDocument.getDocument() ) |
| { |
| // error |
| bError = sal_True; |
| ErrorBox( NULL, WB_OK | WB_DEF_OK, String( IDEResId( RID_STR_ERRORCHOOSEMACRO ) ) ).Execute(); |
| } |
| } |
| } |
| else |
| { |
| // application basic |
| aLocation = String::CreateFromAscii("application"); |
| } |
| |
| // script URL |
| if ( !bError ) |
| { |
| aScriptURL = String::CreateFromAscii("vnd.sun.star.script:"); |
| aScriptURL += aName; |
| aScriptURL += String::CreateFromAscii("?language="); |
| aScriptURL += aLanguage; |
| aScriptURL += String::CreateFromAscii("&location="); |
| aScriptURL += aLocation; |
| } |
| |
| if ( !rxLimitToDocument.is() ) |
| { |
| MacroExecutionData* pExecData = new MacroExecutionData; |
| pExecData->aDocument = aDocument; |
| pExecData->xMethod = pMethod; // keep alive until the event has been processed |
| Application::PostUserEvent( STATIC_LINK( NULL, MacroExecution, ExecuteMacroEvent ), pExecData ); |
| } |
| } |
| break; |
| } |
| |
| return aScriptURL; |
| } |
| |
| //---------------------------------------------------------------------------- |
| |
| Sequence< ::rtl::OUString > GetMethodNames( const ScriptDocument& rDocument, const String& rLibName, const String& rModName ) |
| throw(NoSuchElementException ) |
| { |
| Sequence< ::rtl::OUString > aSeqMethods; |
| |
| // get module |
| ::rtl::OUString aOUSource; |
| if ( rDocument.getModule( rLibName, rModName, aOUSource ) ) |
| { |
| SbModuleRef xModule = new SbModule( rModName ); |
| xModule->SetSource32( aOUSource ); |
| sal_uInt16 nCount = xModule->GetMethods()->Count(); |
| sal_uInt16 nRealCount = nCount; |
| for ( sal_uInt16 i = 0; i < nCount; i++ ) |
| { |
| SbMethod* pMethod = (SbMethod*)xModule->GetMethods()->Get( i ); |
| if( pMethod->IsHidden() ) |
| --nRealCount; |
| } |
| aSeqMethods.realloc( nRealCount ); |
| |
| sal_uInt16 iTarget = 0; |
| for ( sal_uInt16 i = 0 ; i < nCount; ++i ) |
| { |
| SbMethod* pMethod = (SbMethod*)xModule->GetMethods()->Get( i ); |
| if( pMethod->IsHidden() ) |
| continue; |
| DBG_ASSERT( pMethod, "Method not found! (NULL)" ); |
| aSeqMethods.getArray()[ iTarget++ ] = pMethod->GetName(); |
| } |
| } |
| |
| return aSeqMethods; |
| } |
| |
| //---------------------------------------------------------------------------- |
| |
| sal_Bool HasMethod( const ScriptDocument& rDocument, const String& rLibName, const String& rModName, const String& rMethName ) |
| { |
| sal_Bool bHasMethod = sal_False; |
| |
| ::rtl::OUString aOUSource; |
| if ( rDocument.hasModule( rLibName, rModName ) && rDocument.getModule( rLibName, rModName, aOUSource ) ) |
| { |
| SbModuleRef xModule = new SbModule( rModName ); |
| xModule->SetSource32( aOUSource ); |
| SbxArray* pMethods = xModule->GetMethods(); |
| if ( pMethods ) |
| { |
| SbMethod* pMethod = (SbMethod*)pMethods->Find( rMethName, SbxCLASS_METHOD ); |
| if ( pMethod && !pMethod->IsHidden() ) |
| bHasMethod = sal_True; |
| } |
| } |
| |
| return bHasMethod; |
| } |
| } //namespace BasicIDE |
| //---------------------------------------------------------------------------- |