/* -*- 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 .
*/
// submitting and resetting html-forms asynchronously class OFormSubmitResetThread: public OComponentEventThread
{ protected:
// process an event. while processing the mutex isn't locked, and pCompImpl // is made sure to remain valid virtualvoid processEvent( ::cppu::OComponentHelper* _pCompImpl, const EventObject* _pEvt, const Reference<XControl>& _rControl, bool _bSubmit) override;
Any SAL_CALL ODatabaseForm::queryAggregation(const Type& _rType)
{
Any aReturn = ODatabaseForm_BASE1::queryInterface(_rType); // our own interfaces if (!aReturn.hasValue())
{
aReturn = ODatabaseForm_BASE2::queryInterface(_rType); // property set related interfaces if (!aReturn.hasValue())
{
aReturn = OPropertySetAggregationHelper::queryInterface(_rType);
// form component collection related interfaces if (!aReturn.hasValue())
{
aReturn = OFormComponents::queryAggregation(_rType);
// interfaces already present in the aggregate which we want to reroute // only available if we could create the aggregate if (!aReturn.hasValue() && m_xAggregateAsRowSet.is())
aReturn = ODatabaseForm_BASE3::queryInterface(_rType);
// aggregate interfaces // (ask the aggregated object _after_ the OComponentHelper (base of OFormComponents), // so calls to the XComponent interface reach us and not the aggregation) if (!aReturn.hasValue() && m_xAggregate.is())
aReturn = m_xAggregate->queryAggregation(_rType);
}
}
}
osl_atomic_increment( &m_refCount );
{ // our aggregated rowset itself is not cloneable, so simply copy the properties
::comphelper::copyProperties( _cloneSource.m_xAggregateSet, m_xAggregateSet );
// also care for the dynamic properties: If the clone source has properties which we do not have, // then add them try
{
Reference< XPropertySet > xSourceProps( const_cast< ODatabaseForm& >( _cloneSource ).queryAggregation(
cppu::UnoType<XPropertySet>::get() ), UNO_QUERY_THROW );
Reference< XPropertySetInfo > xSourcePSI( xSourceProps->getPropertySetInfo(), UNO_SET_THROW );
Reference< XPropertyState > xSourcePropState( xSourceProps, UNO_QUERY );
// the initial value passed to XPropertyContainer is also used as default, usually. So, try // to retrieve the default of the source property
Any aInitialValue; if ( xSourcePropState.is() )
{
aInitialValue = xSourcePropState->getPropertyDefault( sourceProperty.Name );
} else
{
aInitialValue = xSourceProps->getPropertyValue( sourceProperty.Name );
}
addProperty( sourceProperty.Name, sourceProperty.Attributes, aInitialValue );
setPropertyValue( sourceProperty.Name, xSourceProps->getPropertyValue( sourceProperty.Name ) );
}
} catch(const RuntimeException&)
{ throw;
} catch(const Exception&)
{
css::uno::Any a(cppu::getCaughtException()); throw WrappedTargetRuntimeException(
u"Could not clone the given database form."_ustr,
*const_cast< ODatabaseForm* >( &_cloneSource ),
a
);
}
}
osl_atomic_decrement( &m_refCount );
}
// listen for the properties, important for Parameters if ( m_xAggregateSet.is() )
{
m_xAggregatePropertyMultiplexer = new OPropertyChangeMultiplexer(this, m_xAggregateSet, false);
m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_COMMAND);
m_xAggregatePropertyMultiplexer->addProperty(PROPERTY_ACTIVE_CONNECTION);
}
if (m_xAggregate.is())
m_xAggregate->setDelegator( nullptr );
m_aWarnings.setExternalWarnings( nullptr );
if (m_xAggregatePropertyMultiplexer.is())
{
m_xAggregatePropertyMultiplexer->dispose();
m_xAggregatePropertyMultiplexer.clear();
}
}
// html tools
OUString ODatabaseForm::GetDataEncoded(bool _bURLEncoded,const Reference<XControl>& SubmitButton, const css::awt::MouseEvent& MouseEvt)
{ // Fill List of successful Controls
HtmlSuccessfulObjList aSuccObjList;
FillSuccessfulList( aSuccObjList, SubmitButton, MouseEvt );
// Aggregate the list to OUString
OUStringBuffer aResult;
OUString aName;
OUString aValue;
for ( HtmlSuccessfulObjList::iterator pSuccObj = aSuccObjList.begin();
pSuccObj < aSuccObjList.end();
++pSuccObj
)
{
aName = pSuccObj->aName;
aValue = pSuccObj->aValue; if( pSuccObj->nRepresentation == SUCCESSFUL_REPRESENT_FILE && !aValue.isEmpty() )
{ // For File URLs we transfer the file name and not a URL, because Netscape does it like that
INetURLObject aURL;
aURL.SetSmartProtocol(INetProtocol::File);
aURL.SetSmartURL(aValue); if( INetProtocol::File == aURL.GetProtocol() )
aValue = INetURLObject::decode(aURL.PathToFileName(), INetURLObject::DecodeMechanism::Unambiguous);
}
Encode( aName );
Encode( aValue );
aResult.append(aName + "=" + aValue);
if (pSuccObj < aSuccObjList.end() - 1)
{ if ( _bURLEncoded )
aResult.append('&'); else
aResult.append("\r\n");
}
}
switch( nClassId )
{ // Buttons case FormComponentType::COMMANDBUTTON:
{ // We only evaluate the pressed Submit button // If one is passed at all if( rxSubmitButton.is() )
{
Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY); if (xSubmitButtonComponent == xComponentSet && hasProperty(PROPERTY_LABEL, xComponentSet))
{ // <name>=<label>
OUString aLabel;
xComponentSet->getPropertyValue( PROPERTY_LABEL ) >>= aLabel;
rList.emplace_back(aName, aLabel );
}
}
} break;
// ImageButtons case FormComponentType::IMAGEBUTTON:
{ // We only evaluate the pressed Submit button // If one is passed at all if( rxSubmitButton.is() )
{
Reference<XPropertySet> xSubmitButtonComponent(rxSubmitButton->getModel(), UNO_QUERY); if (xSubmitButtonComponent == xComponentSet)
{ // <name>.x=<pos.X>&<name>.y=<pos.Y>
OUString aRhs = OUString::number( MouseEvt.X );
// Only if a name is available we have a name.x
OUStringBuffer aLhs(aName); if (!aName.isEmpty())
aLhs.append(".x"); else
aLhs.append("x");
rList.emplace_back(aLhs.makeStringAndClear(), aRhs );
// Special treatment for multiline edit only if we have a control for it
Any aTmp = xComponentSet->getPropertyValue( PROPERTY_MULTILINE ); bool bMulti = rxSubmitButton.is()
&& (aTmp.getValueTypeClass() == TypeClass_BOOLEAN)
&& getBOOL(aTmp);
OUString sText; if ( bMulti ) // For multiline edit, get the text at the control
{
// Find the right control bool bFound = false; const Sequence<Reference<XControl>> aControls = xControlContainer->getControls(); for( autoconst& xControl : aControls )
{
Reference<XPropertySet> xModel(xControl->getModel(), UNO_QUERY); if ((bFound = xModel == xComponentSet))
{
Reference<XTextComponent> xTextComponent(xControl, UNO_QUERY); if( xTextComponent.is() )
sText = xTextComponent->getText(); break;
}
} // Couldn't find control or it does not exist (edit in the grid) if (!bFound)
xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
} else
xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= sText;
rList.emplace_back(aName, sText );
} break;
// ComboBox, Patternfield case FormComponentType::COMBOBOX: case FormComponentType::PATTERNFIELD:
{ // <name>=<text> if( hasProperty(PROPERTY_TEXT, xComponentSet) )
{
OUString aText;
xComponentSet->getPropertyValue( PROPERTY_TEXT ) >>= aText;
rList.emplace_back(aName, aText );
}
} break; case FormComponentType::CURRENCYFIELD: case FormComponentType::NUMERICFIELD:
{ // <name>=<value> // Value is a double with dot as decimal delimiter // no value (NULL) means empty value if( hasProperty(PROPERTY_VALUE, xComponentSet) )
{
OUString aText;
Any aVal = xComponentSet->getPropertyValue( PROPERTY_VALUE );
double aDoubleVal = 0; if (aVal >>= aDoubleVal)
{
sal_Int16 nScale = 0;
xComponentSet->getPropertyValue( PROPERTY_DECIMAL_ACCURACY ) >>= nScale;
aText = ::rtl::math::doubleToUString(aDoubleVal, rtl_math_StringFormat_F, nScale, '.', true);
}
rList.emplace_back(aName, aText );
}
} break; case FormComponentType::DATEFIELD:
{ // <name>=<value> // Value is a Date with the format MM-DD-YYYY // no value (NULL) means empty value if( hasProperty(PROPERTY_DATE, xComponentSet) )
{
OUString aText;
Any aVal = xComponentSet->getPropertyValue( PROPERTY_DATE );
sal_Int32 nInt32Val = 0; if (aVal >>= nInt32Val)
{
::Date aDate( nInt32Val );
OUStringBuffer aBuffer;
appendDigits( aDate.GetMonth(), 2, aBuffer );
aBuffer.append( '-' );
appendDigits( aDate.GetDay(), 2, aBuffer );
aBuffer.append( '-' );
appendDigits( aDate.GetYear(), 4, aBuffer );
aText = aBuffer.makeStringAndClear();
}
rList.emplace_back(aName, aText );
}
} break; case FormComponentType::TIMEFIELD:
{ // <name>=<value> // Value is a Time with the format HH:MM:SS // no value (NULL) means empty value if( hasProperty(PROPERTY_TIME, xComponentSet) )
{
OUString aText;
Any aVal = xComponentSet->getPropertyValue( PROPERTY_TIME );
sal_Int32 nInt32Val = 0; if (aVal >>= nInt32Val)
{ // Is this 32-bit number actually encoded time? Or should rather // Time::MakeTimeFromNS be used here?
::tools::Time aTime(tools::Time::fromEncodedTime(nInt32Val));
OUStringBuffer aBuffer;
appendDigits( aTime.GetHour(), 2, aBuffer );
aBuffer.append( '-' );
appendDigits( aTime.GetMin(), 2, aBuffer );
aBuffer.append( '-' );
appendDigits( aTime.GetSec(), 2, aBuffer );
aText = aBuffer.makeStringAndClear();
}
rList.emplace_back(aName, aText );
}
} break;
// starform case FormComponentType::HIDDENCONTROL:
{
// Simple or multiple selection // For simple selections MT only accounts for the list's first entry. if (nSelCount > 1 && !getBOOL(xComponentSet->getPropertyValue(PROPERTY_MULTISELECTION)))
nSelCount = 1;
// The indices in the selection list can also be invalid, so we first have to // find the valid ones to determine the length of the new list.
sal_Int32 nCurCnt = 0;
sal_Int32 i; for( i=0; i<nSelCount; ++i )
{ if( pSels[i] < nStringCnt )
++nCurCnt;
}
OUString aSubValue; for(i=0; i<nCurCnt; ++i )
{
sal_Int16 nSelPos = pSels[i]; if (nSelPos < nValCnt && !pVals[nSelPos].isEmpty())
{
aSubValue = pVals[nSelPos];
} else
{
aSubValue = pStrings[nSelPos];
}
rList.emplace_back(aName, aSubValue );
}
} break; case FormComponentType::GRIDCONTROL:
{ // Each of the column values is sent; // the name is extended by the grid's prefix.
Reference<XIndexAccess> xContainer(xComponentSet, UNO_QUERY); if (!xContainer.is()) break;
aName += ".";
Reference<XPropertySet> xSet;
sal_Int32 nCount = xContainer->getCount(); // we know already how many objects should be appended, // so why not allocate the space for them
rList.reserve( nCount + rList.capacity() ); // not size() for (sal_Int32 i = 0; i < nCount; ++i)
{
xContainer->getByIndex(i) >>= xSet; if (xSet.is())
AppendComponent(rList, xSet, aName, rxSubmitButton, MouseEvt);
}
}
}
}
// we know already how many objects should be appended, // so why not allocate the space for them
rList.reserve( getCount() ); for( sal_Int32 nIndex=0; nIndex < getCount(); nIndex++ )
{
getByIndex( nIndex ) >>= xComponentSet;
AppendComponent(rList, xComponentSet, std::u16string_view(), rxSubmitButton, MouseEvt);
}
}
// Handle chars, which are not an alphanumeric character and character codes > 127 if( (!rtl::isAsciiAlphanumeric(nCharCode) && nCharCode != ' ')
|| nCharCode > 127 )
{ switch( nCharCode )
{ case 13: // CR
aResult.append("%0D%0A"); // CR LF in hex break;
// Special treatment for Netscape case 42: // '*' case 45: // '-' case 46: // '.' case 64: // '@' case 95: // '_'
aResult.append(nCharCode); break;
bool ODatabaseForm::hasValidParent() const
{ // do we have to fill the parameters again? if (!m_bSubForm) returntrue;
Reference<XResultSet> xResultSet(m_xParent, UNO_QUERY); if (!xResultSet.is())
{
OSL_FAIL("ODatabaseForm::hasValidParent() : no parent resultset !"); returnfalse;
} try
{
Reference< XPropertySet > xSet( m_xParent, UNO_QUERY );
Reference< XLoadable > xLoad( m_xParent, UNO_QUERY ); if ( xLoad->isLoaded()
&& ( xResultSet->isBeforeFirst()
|| xResultSet->isAfterLast()
|| getBOOL( xSet->getPropertyValue( PROPERTY_ISNEW ) )
)
) // the parent form is loaded and on a "virtual" row -> not valid returnfalse;
} catch(const Exception&)
{ // parent could be forwardonly? returnfalse;
} returntrue;
}
bool ODatabaseForm::fillParameters( ::osl::ResettableMutexGuard& _rClearForNotifies, const Reference< XInteractionHandler >& _rxCompletionHandler )
{ // do we have to fill the parameters again? if ( !m_aParameterManager.isUpToDate() )
updateParameterInfo();
// is there a valid parent? if ( m_bSubForm && !hasValidParent() ) returntrue;
// ensure we're connected if ( !implEnsureConnection() ) returnfalse;
if ( m_aParameterManager.isUpToDate() ) return m_aParameterManager.fillParameterValues( _rxCompletionHandler, _rClearForNotifies );
if (!fillParameters(_rClearForNotifies, _rxCompletionHandler)) returnfalse;
restoreInsertOnlyState( );
// ensure the aggregated row set has the correct properties
sal_Int32 nConcurrency = ResultSetConcurrency::READ_ONLY;
// if we have a parent, who is not positioned on a valid row // we can't be updatable! if (m_bSubForm && !hasValidParent())
{ // don't use any parameters if we don't have a valid parent
m_aParameterManager.setAllParametersNull();
if (bSuccess)
{ // adjust the privilege property // m_nPrivileges;
m_xAggregateSet->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges; if (!m_bAllowInsert)
m_nPrivileges &= ~Privilege::INSERT; if (!m_bAllowUpdate)
m_nPrivileges &= ~Privilege::UPDATE; if (!m_bAllowDelete)
m_nPrivileges &= ~Privilege::DELETE;
if (bMoveToFirst)
{ // the row set is positioned _before_ the first row (per definitionem), so move the set ... try
{ // if we have an insert only rowset we move to the insert row
next(); if (((m_nPrivileges & Privilege::INSERT) == Privilege::INSERT)
&& isAfterLast())
{ // move on the insert row of set // resetting must be done later, after the load events have been posted // see: moveToInsertRow and load , reload if (auto xUpdate = query_aggregation<XResultSetUpdate>(m_xAggregate))
xUpdate->moveToInsertRow();
}
} catch(const SQLException& eDB)
{
_rClearForNotifies.clear(); if (!m_sCurrentErrorContext.isEmpty())
onError(eDB, m_sCurrentErrorContext); else
onError(eDB, ResourceManager::loadString(RID_STR_READERROR));
_rClearForNotifies.reset();
bSuccess = false;
}
}
} return bSuccess;
}
void ODatabaseForm::disposing()
{ if (m_xAggregatePropertyMultiplexer.is())
m_xAggregatePropertyMultiplexer->dispose();
if (m_xAggregateSet.is())
_rAggregateProps = m_xAggregateSet->getPropertySetInfo()->getProperties();
// we want to "override" the privileges, since we have additional "AllowInsert" etc. properties
RemoveProperty( _rAggregateProps, PROPERTY_PRIVILEGES );
// InsertOnly is also to be overridden, since we sometimes change it ourself
RemoveProperty( _rAggregateProps, PROPERTY_INSERTONLY );
// we remove and re-declare the DataSourceName property, 'cause we want it to be constrained, and the // original property of our aggregate isn't
RemoveProperty( _rAggregateProps, PROPERTY_DATASOURCENAME );
// for connection sharing, we need to override the ActiveConnection property, too
RemoveProperty( _rAggregateProps, PROPERTY_ACTIVE_CONNECTION );
// the Filter property is also overwritten, since we have some implicit filters // (e.g. the ones which result from linking master fields to detail fields // via column names instead of parameters)
RemoveProperty( _rAggregateProps, PROPERTY_FILTER );
RemoveProperty( _rAggregateProps, PROPERTY_HAVINGCLAUSE );
RemoveProperty( _rAggregateProps, PROPERTY_APPLYFILTER );
void ODatabaseForm::fire( sal_Int32* pnHandles, const Any* pNewValues, const Any* pOldValues, sal_Int32 nCount )
{ // same as in getFastPropertyValue(sal_Int32) : if we're resetting currently don't fire any changes of the // IsModified property from sal_False to sal_True, as this is only temporary 'til the reset is done if (m_nResetsPending > 0)
{ // look for the PROPERTY_ID_ISMODIFIED
sal_Int32 nPos = 0; for (nPos=0; nPos<nCount; ++nPos) if (pnHandles[nPos] == PROPERTY_ID_ISMODIFIED) break;
if ((nPos < nCount) && (pNewValues[nPos].getValueTypeClass() == TypeClass_BOOLEAN) && getBOOL(pNewValues[nPos]))
{ // yeah, we found it, and it changed to TRUE if (nPos == 0)
{ // just cut the first element
++pnHandles;
++pNewValues;
++pOldValues;
--nCount;
} elseif (nPos == nCount - 1) // just cut the last element
--nCount; else
{ // split into two base class calls
OPropertySetAggregationHelper::fire(pnHandles, pNewValues, pOldValues, nPos, false/*bVetoable*/);
++nPos;
OPropertySetAggregationHelper::fire(pnHandles + nPos, pNewValues + nPos, pOldValues + nPos, nCount - nPos, false/*bVetoable*/); return;
}
}
}
Any SAL_CALL ODatabaseForm::getFastPropertyValue( sal_Int32 nHandle )
{ if ((nHandle == PROPERTY_ID_ISMODIFIED) && (m_nResetsPending > 0)) return css::uno::Any(false); // don't allow the aggregate which is currently being reset to return a (temporary) "yes" else return OPropertySetAggregationHelper::getFastPropertyValue(nHandle);
}
case PROPERTY_ID_DATASOURCE:
{
css::uno::Reference<XInterface> xParent = getParent();
{ // prevent ABBA deadlock between this mutex and the SolarMutex
comphelper::MutexRelease aReleaser(m_aMutex);
Reference< XConnection > xSomeConnection; if ( ::dbtools::isEmbeddedInDatabase( xParent, xSomeConnection ) ) throw PropertyVetoException();
} try
{
m_xAggregateSet->setPropertyValue(PROPERTY_DATASOURCENAME, rValue);
} catch(const Exception&)
{
}
} break; case PROPERTY_ID_TARGET_URL:
rValue >>= m_aTargetURL; break; case PROPERTY_ID_TARGET_FRAME:
rValue >>= m_aTargetFrame; break; case PROPERTY_ID_SUBMIT_METHOD:
rValue >>= m_eSubmitMethod; break; case PROPERTY_ID_SUBMIT_ENCODING:
rValue >>= m_eSubmitEncoding; break; case PROPERTY_ID_NAME:
rValue >>= m_sName; break; case PROPERTY_ID_MASTERFIELDS:
rValue >>= m_aMasterFields;
invalidateParameters(); break; case PROPERTY_ID_DETAILFIELDS:
rValue >>= m_aDetailFields;
invalidateParameters(); break; case PROPERTY_ID_CYCLE:
m_aCycle = rValue; break; case PROPERTY_ID_NAVIGATION:
rValue >>= m_eNavigation; break; case PROPERTY_ID_ALLOWADDITIONS:
m_bAllowInsert = getBOOL(rValue); break; case PROPERTY_ID_ALLOWEDITS:
m_bAllowUpdate = getBOOL(rValue); break; case PROPERTY_ID_ALLOWDELETIONS:
m_bAllowDelete = getBOOL(rValue); break; case PROPERTY_ID_DYNAMIC_CONTROL_BORDER:
m_aDynamicControlBorder = rValue; break; case PROPERTY_ID_CONTROL_BORDER_COLOR_FOCUS:
m_aControlBorderColorFocus = rValue; break; case PROPERTY_ID_CONTROL_BORDER_COLOR_MOUSE:
m_aControlBorderColorMouse = rValue; break; case PROPERTY_ID_CONTROL_BORDER_COLOR_INVALID:
m_aControlBorderColorInvalid = rValue; break;
case PROPERTY_ID_ACTIVE_CONNECTION:
{ bool bIsEmbeddedInDatabase;
Reference< XConnection > xOuterConnection;
css::uno::Reference<XInterface> xParent = getParent();
{ // prevent ABBA deadlock between this mutex and the SolarMutex
comphelper::MutexRelease aReleaser(m_aMutex);
bIsEmbeddedInDatabase = ::dbtools::isEmbeddedInDatabase( xParent, xOuterConnection );
} if (bIsEmbeddedInDatabase)
{ if ( xOuterConnection != Reference< XConnection >( rValue, UNO_QUERY ) ) // somebody's trying to set a connection which is not equal the connection // implied by the database we're embedded in throw PropertyVetoException();
}
OPropertySetAggregationHelper::setFastPropertyValue_NoBroadcast( nHandle, rValue ); break;
}
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 ist noch experimentell.