/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: vbahelper.cxx,v $ * * $Revision: 1.3 $ * * last change: $Author: vg $ $Date: 2007-12-07 10:53:38 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. * * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2005 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vbahelper.hxx" #include "tabvwsh.hxx" #include "transobj.hxx" #include "scmod.hxx" using namespace ::com::sun::star; using namespace ::org::openoffice; #define POINTTO100THMILLIMETERFACTOR 35.27778 void unoToSbxValue( SbxVariable* pVar, const uno::Any& aValue ); uno::Any sbxToUnoValue( SbxVariable* pVar ); namespace org { namespace openoffice { const double Millimeter::factor = 35.27778; uno::Reference< script::XTypeConverter > getTypeConverter( const uno::Reference< uno::XComponentContext >& xContext ) throw (uno::RuntimeException) { static uno::Reference< script::XTypeConverter > xTypeConv( xContext->getServiceManager()->createInstanceWithContext( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.script.Converter") ), xContext ), uno::UNO_QUERY_THROW ); return xTypeConv; } // helper method to determine if the view ( calc ) is in print-preview mode bool isInPrintPreview( SfxViewFrame* pView ) { sal_uInt16 nViewNo = SID_VIEWSHELL1 - SID_VIEWSHELL0; if ( pView->GetObjectShell()->GetFactory().GetViewFactoryCount() > nViewNo && !pView->GetObjectShell()->IsInPlaceActive() ) { SfxViewFactory &rViewFactory = pView->GetObjectShell()->GetFactory().GetViewFactory(nViewNo); if ( pView->GetCurViewId() == rViewFactory.GetOrdinal() ) return true; } return false; } const ::rtl::OUString REPLACE_CELLS_WARNING( RTL_CONSTASCII_USTRINGPARAM( "ReplaceCellsWarning")); const uno::Any& aNULL() { static uno::Any aNULLL = uno::makeAny( uno::Reference< uno::XInterface >() ); return aNULLL; } class PasteCellsWarningReseter { private: bool bInitialWarningState; static uno::Reference< beans::XPropertySet > getGlobalSheetSettings() throw ( uno::RuntimeException ) { static uno::Reference< beans::XPropertySet > xTmpProps( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW ); static uno::Reference xContext( xTmpProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), uno::UNO_QUERY_THROW ); static uno::Reference xServiceManager( xContext->getServiceManager(), uno::UNO_QUERY_THROW ); static uno::Reference< beans::XPropertySet > xProps( xServiceManager->createInstanceWithContext( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.GlobalSheetSettings" ) ) ,xContext ), uno::UNO_QUERY_THROW ); return xProps; } bool getReplaceCellsWarning() throw ( uno::RuntimeException ) { sal_Bool res = sal_False; getGlobalSheetSettings()->getPropertyValue( REPLACE_CELLS_WARNING ) >>= res; return ( res == sal_True ); } void setReplaceCellsWarning( bool bState ) throw ( uno::RuntimeException ) { getGlobalSheetSettings()->setPropertyValue( REPLACE_CELLS_WARNING, uno::makeAny( bState ) ); } public: PasteCellsWarningReseter() throw ( uno::RuntimeException ) { bInitialWarningState = getReplaceCellsWarning(); if ( bInitialWarningState ) setReplaceCellsWarning( false ); } ~PasteCellsWarningReseter() { if ( bInitialWarningState ) { // don't allow dtor to throw try { setReplaceCellsWarning( true ); } catch ( uno::Exception& /*e*/ ){} } } }; void dispatchRequests (uno::Reference< frame::XModel>& xModel,rtl::OUString & aUrl, uno::Sequence< beans::PropertyValue >& sProps ) { util::URL url ; url.Complete = aUrl; rtl::OUString emptyString = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "" )); uno::Reference xController = xModel->getCurrentController(); uno::Reference xFrame = xController->getFrame(); uno::Reference xDispatchProvider (xFrame,uno::UNO_QUERY_THROW); try { uno::Reference< beans::XPropertySet > xProps( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW ); uno::Reference xContext( xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), uno::UNO_QUERY_THROW ); if ( !xContext.is() ) { return ; } uno::Reference xServiceManager( xContext->getServiceManager() ); if ( !xServiceManager.is() ) { return ; } uno::Reference xParser( xServiceManager->createInstanceWithContext( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.util.URLTransformer" ) ) ,xContext), uno::UNO_QUERY_THROW ); if (!xParser.is()) return; xParser->parseStrict (url); } catch ( uno::Exception & /*e*/ ) { return ; } uno::Reference xDispatcher = xDispatchProvider->queryDispatch(url,emptyString,0); uno::Sequence dispatchProps(1); sal_Int32 nProps = sProps.getLength(); beans::PropertyValue* pDest = dispatchProps.getArray(); if ( nProps ) { dispatchProps.realloc( nProps + 1 ); // need to reaccquire pDest after realloc pDest = dispatchProps.getArray(); beans::PropertyValue* pSrc = sProps.getArray(); for ( sal_Int32 index=0; indexdispatch( url, dispatchProps ); } void dispatchRequests (uno::Reference< frame::XModel>& xModel,rtl::OUString & aUrl) { uno::Sequence dispatchProps; dispatchRequests( xModel, aUrl, dispatchProps ); } void implnPaste() { PasteCellsWarningReseter resetWarningBox; ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell(); if ( pViewShell ) { pViewShell->PasteFromSystem(); pViewShell->CellContentChanged(); } } void implnCopy() { ScTabViewShell* pViewShell = getCurrentBestViewShell(); if ( pViewShell ) pViewShell->CopyToClip(NULL,false,false,true); } void implnCut() { ScTabViewShell* pViewShell = getCurrentBestViewShell(); if ( pViewShell ) pViewShell->CutToClip( NULL, TRUE ); } void implnPasteSpecial(USHORT nFlags,USHORT nFunction,sal_Bool bSkipEmpty, sal_Bool bTranspose) { PasteCellsWarningReseter resetWarningBox; sal_Bool bAsLink(sal_False), bOtherDoc(sal_False); InsCellCmd eMoveMode = INS_NONE; ScTabViewShell* pTabViewShell = ScTabViewShell::GetActiveViewShell(); if ( !pTabViewShell ) // none active, try next best pTabViewShell = getCurrentBestViewShell(); if ( pTabViewShell ) { ScViewData* pView = pTabViewShell->GetViewData(); Window* pWin = ( pView != NULL ) ? pView->GetActiveWin() : NULL; if ( pView && pWin ) { if ( bAsLink && bOtherDoc ) pTabViewShell->PasteFromSystem(0);//SOT_FORMATSTR_ID_LINK else { ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard( pWin ); ScDocument* pDoc = NULL; if ( pOwnClip ) pDoc = pOwnClip->GetDocument(); pTabViewShell->PasteFromClip( nFlags, pDoc, nFunction, bSkipEmpty, bTranspose, bAsLink, eMoveMode, IDF_NONE, TRUE ); pTabViewShell->CellContentChanged(); } } } } bool isRangeShortCut( const ::rtl::OUString& sParam ) { // for a ShortCutRange param, I'd expect the first letter to be //[A-Z] and the last letter to be a digit 0-9 e.g A10, [A1:A10] etc. ::rtl::OString sStr = rtl::OUStringToOString( sParam, RTL_TEXTENCODING_UTF8 ); const sal_Char* pFirst = (const sal_Char*)sStr; const sal_Char* pLast = pFirst + ( sStr.getLength() - 1 ); if ( (( *pFirst >= 'A' && *pFirst <= 'Z' ) || ( *pFirst >= 'a' && *pFirst <= 'Z' ) ) ) if ( ( *pLast >= '0' ) && ( *pLast <= '9' ) ) return true; return false; } uno::Reference< frame::XModel > getCurrentDocument() throw (uno::RuntimeException) { uno::Reference< frame::XModel > xModel; SbxObject* pBasic = dynamic_cast< SbxObject* > ( SFX_APP()->GetBasic() ); SbxObject* basicChosen = pBasic ; if ( basicChosen == NULL) { OSL_TRACE("getModelFromBasic() StarBASIC* is NULL" ); return xModel; } SbxObject* p = pBasic; SbxObject* pParent = p->GetParent(); SbxObject* pParentParent = pParent ? pParent->GetParent() : NULL; if( pParentParent ) { basicChosen = pParentParent; } else if( pParent ) { basicChosen = pParent; } uno::Any aModel; SbxVariable *pCompVar = basicChosen->Find( UniString(RTL_CONSTASCII_USTRINGPARAM("ThisComponent")), SbxCLASS_OBJECT ); if ( pCompVar ) { aModel = sbxToUnoValue( pCompVar ); if ( sal_False == ( aModel >>= xModel ) || !xModel.is() ) { // trying last gasp try the current component uno::Reference< beans::XPropertySet > xProps( ::comphelper::getProcessServiceFactory(), uno::UNO_QUERY_THROW ); // test if vba service is present uno::Reference< uno::XComponentContext > xCtx( xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DefaultContext" ))), uno::UNO_QUERY_THROW ); uno::Reference xSMgr( xCtx->getServiceManager(), uno::UNO_QUERY_THROW ); uno::Reference< frame::XDesktop > xDesktop (xSMgr->createInstanceWithContext(::rtl::OUString::createFromAscii("com.sun.star.frame.Desktop"), xCtx), uno::UNO_QUERY_THROW ); xModel.set( xDesktop->getCurrentComponent(), uno::UNO_QUERY ); if ( !xModel.is() ) { throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Can't extract model from basic ( its obviously not set yet ) therefore don't know the currently selected document") ), uno::Reference< uno::XInterface >() ); } return xModel; } else { OSL_TRACE("Have model ThisComponent points to url %s", ::rtl::OUStringToOString( xModel->getURL(), RTL_TEXTENCODING_ASCII_US ).pData->buffer ); } } else { OSL_TRACE("Failed to get ThisComponent"); throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Can't determine the currently selected document") ), uno::Reference< uno::XInterface >() ); } return xModel; } ScDocShell* getDocShell( css::uno::Reference< css::frame::XModel>& xModel ) { uno::Reference< uno::XInterface > xIf( xModel, uno::UNO_QUERY_THROW ); ScModelObj* pModel = dynamic_cast< ScModelObj* >( xIf.get() ); ScDocShell* pDocShell = NULL; if ( pModel ) pDocShell = (ScDocShell*)pModel->GetEmbeddedObject(); return pDocShell; } ScTabViewShell* getBestViewShell( css::uno::Reference< css::frame::XModel>& xModel ) { ScDocShell* pDocShell = getDocShell( xModel ); if ( pDocShell ) return pDocShell->GetBestViewShell(); return NULL; } ScTabViewShell* getCurrentBestViewShell() { uno::Reference< frame::XModel > xModel = getCurrentDocument(); return getBestViewShell( xModel ); } SfxViewFrame* getCurrentViewFrame() { ScTabViewShell* pViewShell = getCurrentBestViewShell(); if ( pViewShell ) return pViewShell->GetViewFrame(); return NULL; } sal_Int32 OORGBToXLRGB( sal_Int32 nCol ) { sal_Int32 nRed = nCol; nRed &= 0x00FF0000; nRed >>= 16; sal_Int32 nGreen = nCol; nGreen &= 0x0000FF00; nGreen >>= 8; sal_Int32 nBlue = nCol; nBlue &= 0x000000FF; sal_Int32 nRGB = ( (nBlue << 16) | (nGreen << 8) | nRed ); return nRGB; } sal_Int32 XLRGBToOORGB( sal_Int32 nCol ) { sal_Int32 nBlue = nCol; nBlue &= 0x00FF0000; nBlue >>= 16; sal_Int32 nGreen = nCol; nGreen &= 0x0000FF00; nGreen >>= 8; sal_Int32 nRed = nCol; nRed &= 0x000000FF; sal_Int32 nRGB = ( (nRed << 16) | (nGreen << 8) | nBlue ); return nRGB; } uno::Any OORGBToXLRGB( const uno::Any& aCol ) { sal_Int32 nCol; aCol >>= nCol; nCol = OORGBToXLRGB( nCol ); return uno::makeAny( nCol ); } uno::Any XLRGBToOORGB( const uno::Any& aCol ) { sal_Int32 nCol; aCol >>= nCol; nCol = XLRGBToOORGB( nCol ); return uno::makeAny( nCol ); } void PrintOutHelper( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& /*ActivePrinter*/, const uno::Any& /*PrintToFile*/, const uno::Any& Collate, const uno::Any& PrToFileName, css::uno::Reference< frame::XModel >& xModel, sal_Bool bUseSelection ) { sal_Int32 nTo = 0; sal_Int32 nFrom = 0; sal_Int16 nCopies = 1; sal_Bool bPreview = sal_False; sal_Bool bCollate = sal_False; sal_Bool bSelection = bUseSelection; From >>= nFrom; To >>= nTo; Copies >>= nCopies; Preview >>= bPreview; if ( nCopies > 1 ) // Collate only useful when more that 1 copy Collate >>= bCollate; rtl::OUString sRange( RTL_CONSTASCII_USTRINGPARAM( "-" ) ); rtl::OUString sFileName; if (( nFrom || nTo ) ) { if ( nFrom ) sRange = ( ::rtl::OUString::valueOf( nFrom ) + sRange ); if ( nTo ) sRange += ::rtl::OUString::valueOf( nTo ); } if ( PrToFileName.getValue() ) { PrToFileName >>= sFileName; } ScTabViewShell* pViewShell = getBestViewShell( xModel ); SfxViewFrame* pViewFrame = NULL; if ( pViewShell ) pViewFrame = pViewShell->GetViewFrame(); if ( pViewFrame ) { SfxAllItemSet aArgs( SFX_APP()->GetPool() ); SfxBoolItem sfxCollate( SID_PRINT_COLLATE, bCollate ); aArgs.Put( sfxCollate, sfxCollate.Which() ); SfxInt16Item sfxCopies( SID_PRINT_COPIES, nCopies ); aArgs.Put( sfxCopies, sfxCopies.Which() ); if ( sFileName.getLength() ) { SfxStringItem sfxFileName( SID_FILE_NAME, sFileName); aArgs.Put( sfxFileName, sfxFileName.Which() ); } if ( sRange.getLength() ) { SfxStringItem sfxRange( SID_PRINT_PAGES, sRange ); aArgs.Put( sfxRange, sfxRange.Which() ); } SfxBoolItem sfxSelection( SID_SELECTION, bSelection ); aArgs.Put( sfxSelection, sfxSelection.Which() ); SfxBoolItem sfxAsync( SID_ASYNCHRON, sal_False ); aArgs.Put( sfxAsync, sfxAsync.Which() ); SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher(); if ( pDispatcher ) { if ( bPreview ) { if ( !pViewFrame->GetFrame()->IsInPlace() ) { SC_MOD()->InputEnterHandler(); pViewFrame->GetDispatcher()->Execute( SID_VIEWSHELL1, SFX_CALLMODE_SYNCHRON ); while ( isInPrintPreview( pViewFrame ) ) Application::Yield(); } } else pDispatcher->Execute( (USHORT)SID_PRINTDOC, (SfxCallMode)SFX_CALLMODE_SYNCHRON, aArgs ); } } // #FIXME #TODO // 1 ActivePrinter ( how/can we switch a printer via API? ) // 2 PrintToFile ( ms behaviour if this option is specified but no // filename supplied 'PrToFileName' then the user will be prompted ) // 3 Need to check behaviour of Selected sheets with range ( e.g. From & To // values ) in oOO these options are mutually exclusive // 4 There is a pop up to do with transparent objects in the print source // should be able to disable that via configuration for the duration // of this method } rtl::OUString getAnyAsString( const uno::Any& pvargItem ) throw ( uno::RuntimeException ) { uno::Type aType = pvargItem.getValueType(); uno::TypeClass eTypeClass = aType.getTypeClass(); rtl::OUString sString; switch ( eTypeClass ) { case uno::TypeClass_BOOLEAN: { sal_Bool bBool = sal_False; pvargItem >>= bBool; sString = rtl::OUString::valueOf( bBool ); break; } case uno::TypeClass_STRING: pvargItem >>= sString; break; case uno::TypeClass_FLOAT: { float aFloat = 0; pvargItem >>= aFloat; sString = rtl::OUString::valueOf( aFloat ); break; } case uno::TypeClass_DOUBLE: { double aDouble = 0; pvargItem >>= aDouble; sString = rtl::OUString::valueOf( aDouble ); break; } case uno::TypeClass_SHORT: case uno::TypeClass_LONG: case uno::TypeClass_BYTE: { sal_Int32 aNum = 0; pvargItem >>= aNum; sString = rtl::OUString::valueOf( aNum ); break; } case uno::TypeClass_HYPER: { sal_Int64 aHyper = 0; pvargItem >>= aHyper; sString = rtl::OUString::valueOf( aHyper ); break; } default: throw uno::RuntimeException( rtl::OUString::createFromAscii( "Invalid type, can't convert" ), uno::Reference< uno::XInterface >() ); } return sString; } rtl::OUString ContainerUtilities::getUniqueName( const uno::Sequence< ::rtl::OUString >& _slist, const rtl::OUString& _sElementName, const ::rtl::OUString& _sSuffixSeparator) { return getUniqueName(_slist, _sElementName, _sSuffixSeparator, sal_Int32(2)); } rtl::OUString ContainerUtilities::getUniqueName( const uno::Sequence< rtl::OUString >& _slist, const rtl::OUString _sElementName, const rtl::OUString& _sSuffixSeparator, sal_Int32 _nStartSuffix) { sal_Int32 a = _nStartSuffix; rtl::OUString scompname = _sElementName; bool bElementexists = true; sal_Int32 nLen = _slist.getLength(); if ( nLen == 0 ) return _sElementName; while (bElementexists == true) { for (sal_Int32 i = 0; i < nLen; i++) { if (FieldInList(_slist, scompname) == -1) { return scompname; } } scompname = _sElementName + _sSuffixSeparator + rtl::OUString::valueOf( a++ ); } return rtl::OUString(); } sal_Int32 ContainerUtilities::FieldInList( const uno::Sequence< rtl::OUString >& SearchList, const rtl::OUString& SearchString ) { sal_Int32 FieldLen = SearchList.getLength(); sal_Int32 retvalue = -1; for (sal_Int32 i = 0; i < FieldLen; i++) { // I wonder why comparing lexicographically is done // when its a match is whats interesting? //if (SearchList[i].compareTo(SearchString) == 0) if ( SearchList[i].equals( SearchString ) ) { retvalue = i; break; } } return retvalue; } bool NeedEsc(sal_Unicode cCode) { String sEsc(RTL_CONSTASCII_USTRINGPARAM(".^$+\\|{}()")); return (STRING_NOTFOUND != sEsc.Search(cCode)); } rtl::OUString VBAToRegexp(const rtl::OUString &rIn, bool bForLike ) { rtl::OUStringBuffer sResult; const sal_Unicode *start = rIn.getStr(); const sal_Unicode *end = start + rIn.getLength(); int seenright = 0; if ( bForLike ) sResult.append(static_cast('^')); while (start < end) { switch (*start) { case '?': sResult.append(static_cast('.')); start++; break; case '*': sResult.append(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".*"))); start++; break; case '#': sResult.append(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("[0-9]"))); start++; break; case '~': sResult.append(static_cast('\\')); sResult.append(*(++start)); start++; break; // dump the ~ and escape the next characture case ']': sResult.append(static_cast('\\')); sResult.append(*start++); break; case '[': sResult.append(*start++); seenright = 0; while (start < end && !seenright) { switch (*start) { case '[': case '?': case '*': sResult.append(static_cast('\\')); sResult.append(*start); break; case ']': sResult.append(*start); seenright = 1; break; case '!': sResult.append(static_cast('^')); break; default: if (NeedEsc(*start)) sResult.append(static_cast('\\')); sResult.append(*start); break; } start++; } break; default: if (NeedEsc(*start)) sResult.append(static_cast('\\')); sResult.append(*start++); } } if ( bForLike ) sResult.append(static_cast('$')); return sResult.makeStringAndClear( ); } double getPixelTo100thMillimeterConversionFactor( css::uno::Reference< css::awt::XDevice >& xDevice, sal_Bool bVertical) { double fConvertFactor = 1.0; if( bVertical ) { fConvertFactor = xDevice->getInfo().PixelPerMeterY/100000; } else { fConvertFactor = xDevice->getInfo().PixelPerMeterX/100000; } return fConvertFactor; } double PointsToPixels( css::uno::Reference< css::awt::XDevice >& xDevice, double fPoints, sal_Bool bVertical) { double fConvertFactor = getPixelTo100thMillimeterConversionFactor( xDevice, bVertical ); return fPoints * POINTTO100THMILLIMETERFACTOR * fConvertFactor; } double PixelsToPoints( css::uno::Reference< css::awt::XDevice >& xDevice, double fPixels, sal_Bool bVertical) { double fConvertFactor = getPixelTo100thMillimeterConversionFactor( xDevice, bVertical ); return (fPixels/fConvertFactor)/POINTTO100THMILLIMETERFACTOR; } } // openoffice } //org