/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
usingnamespace ::ooo::vba; usingnamespace ::com::sun::star; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::uno::UNO_QUERY;
/** Global application settings shared by all open workbooks. */ struct ScVbaAppSettings
{ bool mbDisplayAlerts; bool mbEnableEvents; bool mbExcel4Menus; bool mbDisplayNoteIndicator; bool mbShowWindowsInTaskbar; bool mbEnableCancelKey; explicit ScVbaAppSettings();
};
// Check, if the implementation of XFileDialogSelectedItems is what we expect if (!pItems) throw uno::RuntimeException(u"Unexpected XFileDialogSelectedItems implementation"_ustr);
autoconst & rItemVector = pItems->getItems();
if (!bMultiSelect) // only 1 selection allowed - return path
{
OUString aPath; if (!rItemVector.empty())
aPath = rItemVector.at(0); return uno::Any(aPath);
} else
{ // convert to sequence return uno::Any(comphelper::containerToSequence(rItemVector));
}
}
uno::Any SAL_CALL
ScVbaApplication::International( sal_Int32 /*Index*/ )
{ // complete stub for now // #TODO flesh out some of the Indices we could handle
uno::Any aRet; return aRet;
}
uno::Any SAL_CALL
ScVbaApplication::Evaluate( const OUString& Name )
{ // #TODO Evaluate allows other things to be evaluated, e.g. functions // I think ( like SIN(3) etc. ) need to investigate that // named Ranges also? e.g. [MyRange] if so need a list of named ranges
uno::Any aVoid; return uno::Any( getActiveWorkbook()->getActiveSheet()->Range( uno::Any( Name ), aVoid ) );
}
void SAL_CALL
ScVbaApplication::setStatusBar( const uno::Any& _statusbar )
{
OUString sText; bool bDefault = false;
uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
uno::Reference< task::XStatusIndicatorSupplier > xStatusIndicatorSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
uno::Reference< task::XStatusIndicator > xStatusIndicator( xStatusIndicatorSupplier->getStatusIndicator(), uno::UNO_SET_THROW ); if( _statusbar >>= sText )
{
setDisplayStatusBar( true ); if ( !sText.isEmpty() )
xStatusIndicator->start( sText, 100 ); else
xStatusIndicator->end(); // restore normal state for empty text
} elseif( _statusbar >>= bDefault )
{ if( !bDefault )
{
xStatusIndicator->end();
setDisplayStatusBar( true );
}
} else throw uno::RuntimeException(u"Invalid parameter. It should be a string or False"_ustr );
}
::sal_Int32 SAL_CALL
ScVbaApplication::getCalculation()
{ // TODO: in Excel, this is an application-wide setting
uno::Reference<sheet::XCalculatable> xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW); if(xCalc->isAutomaticCalculationEnabled()) return excel::XlCalculation::xlCalculationAutomatic; else return excel::XlCalculation::xlCalculationManual;
}
void SAL_CALL
ScVbaApplication::setCalculation( ::sal_Int32 _calculation )
{ // TODO: in Excel, this is an application-wide setting
uno::Reference< sheet::XCalculatable > xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW); switch(_calculation)
{ case excel::XlCalculation::xlCalculationManual:
xCalc->enableAutomaticCalculation(false); break; case excel::XlCalculation::xlCalculationAutomatic: case excel::XlCalculation::xlCalculationSemiautomatic:
xCalc->enableAutomaticCalculation(true); break;
}
}
if ( !result.is() )
{ // Fixme - check if this is reasonable/desired behavior throw uno::RuntimeException(u"No activeSheet available"_ustr );
} return result;
}
/******************************************************************************* * In msdn: * Reference Optional Variant. The destination. Can be a Range * object, a string that contains a cell reference in R1C1-style notation, * or a string that contains a Visual Basic procedure name. * Scroll Optional Variant. True to scroll, False to not scroll through * the window. The default is False. * Parser is split to three parts, Range, R1C1 string and procedure name. * by test excel, it seems Scroll no effect. ???
*******************************************************************************/ void SAL_CALL
ScVbaApplication::GoTo( const uno::Any& Reference, const uno::Any& Scroll )
{ //test Scroll is a boolean bool bScroll = false; //R1C1-style string or a string of procedure name.
if( Scroll.hasValue() )
{ bool aScroll = false; if( !(Scroll >>= aScroll) ) throw uno::RuntimeException(u"second parameter should be boolean"_ustr );
switch( nPointerStyle )
{ case PointerStyle::Arrow: return excel::XlMousePointer::xlNorthwestArrow; case PointerStyle::Null: return excel::XlMousePointer::xlDefault; case PointerStyle::Wait: return excel::XlMousePointer::xlWait; case PointerStyle::Text: return excel::XlMousePointer::xlIBeam; default: return excel::XlMousePointer::xlDefault;
}
}
void SAL_CALL
ScVbaApplication::setCursor( sal_Int32 _cursor )
{ try
{
uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW ); switch( _cursor )
{ case excel::XlMousePointer::xlNorthwestArrow:
{
setCursorHelper( xModel, PointerStyle::Arrow, false ); break;
} case excel::XlMousePointer::xlWait: case excel::XlMousePointer::xlIBeam:
{
PointerStyle nPointer( static_cast< PointerStyle >( _cursor ) ); //It will set the edit window, toobar and statusbar's mouse pointer.
setCursorHelper( xModel, nPointer, true ); break;
} case excel::XlMousePointer::xlDefault:
{
setCursorHelper( xModel, PointerStyle::Null, false ); break;
} default: throw uno::RuntimeException(u"Unknown value for Cursor pointer"_ustr ); // TODO: isn't this a flaw in the API? It should be allowed to throw an // IllegalArgumentException, or so
}
} catch (const uno::Exception&)
{
DBG_UNHANDLED_EXCEPTION("sc.ui");
}
}
// #TODO perhaps we should switch the return type depending of the filter // type, e.g. return Calc for Calc and Excel if it's an imported doc
OUString SAL_CALL
ScVbaApplication::getName()
{ return u"Microsoft Excel"_ustr;
}
// #TODO #FIXME get/setDisplayAlerts are just stub impl // here just the status of the switch is set // the function that throws an error message needs to // evaluate this switch in order to know whether it has to disable the // error message thrown by OpenOffice
void SAL_CALL
ScVbaApplication::setDisplayScrollBars( sal_Bool bSet )
{ // use uno here as it does all he repainting etc. magic
uno::Reference< sheet::XSpreadsheetView > xView( getCurrentDocument()->getCurrentController(), uno::UNO_QUERY_THROW );
uno::Reference< beans::XPropertySet > xProps( xView, uno::UNO_QUERY );
xProps->setPropertyValue(u"HasVerticalScrollBar"_ustr, uno::Any( bSet ) );
xProps->setPropertyValue(u"HasHorizontalScrollBar"_ustr, uno::Any( bSet ) );
}
// if it's a list of paths then use the last one
sal_Int32 nIndex = sUrl.lastIndexOf( ';' ) ; if ( nIndex > 0 )
sUrl = sUrl.copy( nIndex + 1 );
::osl::File::getSystemPathFromFileURL( sUrl, sRetPath );
} catch (const uno::Exception&)
{
DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED);
} return sRetPath;
}
OUString SAL_CALL
ScVbaApplication::getOperatingSystem()
{ // TODO Solution should contain the version number of the operating system // too. #ifdefined(_WIN32) return"Windows"; #elifdefined(MACOSX) return"Macintosh"; #elifdefined(UNX) // M. Office is not available on Unix systems, so it is not documented. return u"Unix"_ustr; #else return OUString("Unknown"); #endif
}
// Helpers for Intersect and Union
namespace {
typedef ::std::list< ScRange > ListOfScRange;
/** Appends all ranges of a VBA Range object in the passed Any to the list of ranges.
/** Returns true, if the passed ranges can be expressed by a single range. The
new range will be contained in r1 then, the range r2 can be removed. */ bool lclTryJoin( ScRange& r1, const ScRange& r2 )
{ // 1) r2 is completely inside r1 if( r1.Contains( r2 ) ) returntrue;
// 4) r1 and r2 have equal left and right border if( (n1L == n2L) && (n1R == n2R) )
{ // check that r1 overlaps or touches r2 if( ((n1T < n2T) && (n2T + 1 <= n1B)) || ((n2T < n1T) && (n1T + 1 <= n2B)) )
{
r1.aStart.SetRow( ::std::min( n1T, n2T ) );
r1.aEnd.SetRow( ::std::max( n1B, n2B ) ); returntrue;
} returnfalse;
}
// 5) cannot join these ranges returnfalse;
}
/** Strips out ranges that are contained by other ranges, joins ranges that can be joined
together (aligned borders, e.g. A4:D10 and B4:E10 would be combined to A4:E10. */ void lclJoinRanges( ListOfScRange& rList )
{
ListOfScRange::iterator aOuterIt = rList.begin(); while( aOuterIt != rList.end() )
{ bool bAnyErased = false; // true = any range erased from rList
ListOfScRange::iterator aInnerIt = rList.begin(); while( aInnerIt != rList.end() )
{ bool bInnerErased = false; // true = aInnerIt erased from rList // do not compare a range with itself if( (aOuterIt != aInnerIt) && lclTryJoin( *aOuterIt, *aInnerIt ) )
{ // aOuterIt points to joined range, aInnerIt will be removed
aInnerIt = rList.erase( aInnerIt );
bInnerErased = bAnyErased = true;
} /* If aInnerIt has been erased from rList, it already points to
the next element (return value of list::erase()). */ if( !bInnerErased )
++aInnerIt;
} // if any range has been erased, repeat outer loop with the same range if( !bAnyErased )
++aOuterIt;
}
}
/** Intersects the passed list with all ranges of a VBA Range object in the passed Any.
@throws script::BasicErrorException @throws uno::RuntimeException
*/ void lclIntersectRanges( ListOfScRange& rList, const uno::Any& rArg )
{ // extract the ranges from the passed argument, will throw on invalid data
ListOfScRange aList2;
lclAddToListOfScRange( aList2, rArg ); // do nothing, if the passed list is already empty if( rList.empty() || aList2.empty() ) return;
// save original list in a local
ListOfScRange aList1;
aList1.swap( rList ); // join ranges from passed argument
lclJoinRanges( aList2 ); // calculate intersection of the ranges in both lists for( constauto& rOuterItem : aList1 )
{ for( constauto& rInnerItem : aList2 )
{ if( rOuterItem.Intersects( rInnerItem ) )
{
ScRange aIsectRange(
std::max( rOuterItem.aStart.Col(), rInnerItem.aStart.Col() ),
std::max( rOuterItem.aStart.Row(), rInnerItem.aStart.Row() ),
std::max( rOuterItem.aStart.Tab(), rInnerItem.aStart.Tab() ),
std::min( rOuterItem.aEnd.Col(), rInnerItem.aEnd.Col() ),
std::min( rOuterItem.aEnd.Row(), rInnerItem.aEnd.Row() ),
std::min( rOuterItem.aEnd.Tab(), rInnerItem.aEnd.Tab() ) );
rList.push_back( aIsectRange );
}
}
} // again, join the result ranges
lclJoinRanges( rList );
}
/** Creates a VBA Range object from the passed list of ranges.
// initialize the result list with 1st parameter, join its ranges together
ListOfScRange aList;
lclAddToListOfScRange( aList, uno::Any( rArg1 ) );
lclJoinRanges( aList );
if( bUpdate )
{ // Since setting ScreenUpdating from user code might be unpaired, avoid calling function, // that asserts correct lock/unlock order and number, when not locked. if(rDoc.IsAdjustHeightLocked())
rDoc.UnlockAdjustHeight(); if( !rDoc.IsAdjustHeightLocked() )
pDocShell->UpdateAllRowHeights();
} else
{
rDoc.LockAdjustHeight();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.