/* -*- 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 .
*/
switch (m_nFieldType)
{ case DataType::DATE: case DataType::TIME: case DataType::TIMESTAMP: case DataType::BIT: case DataType::BOOLEAN: case DataType::TINYINT: case DataType::SMALLINT: case DataType::INTEGER: case DataType::BIGINT: case DataType::FLOAT: case DataType::REAL: case DataType::DOUBLE: case DataType::NUMERIC: case DataType::DECIMAL:
m_nAlign = css::awt::TextAlign::RIGHT;
m_bNumeric = true; break; default:
m_nAlign = css::awt::TextAlign::LEFT; break;
}
}
std::unique_ptr<DbCellControl> pCellControl; if (m_rParent.IsFilterMode())
{
pCellControl.reset(new DbFilterField(m_rParent.getContext(),*this));
} else
{
switch (nTypeId)
{ case TYPE_CHECKBOX: pCellControl.reset(new DbCheckBox(*this)); break; case TYPE_COMBOBOX: pCellControl.reset(new DbComboBox(*this)); break; case TYPE_CURRENCYFIELD: pCellControl.reset(new DbCurrencyField(*this)); break; case TYPE_DATEFIELD: pCellControl.reset(new DbDateField(*this)); break; case TYPE_LISTBOX: pCellControl.reset(new DbListBox(*this)); break; case TYPE_NUMERICFIELD: pCellControl.reset(new DbNumericField(*this)); break; case TYPE_PATTERNFIELD: pCellControl.reset(new DbPatternField( *this, m_rParent.getContext() )); break; case TYPE_TEXTFIELD: pCellControl.reset(new DbTextField(*this)); break; case TYPE_TIMEFIELD: pCellControl.reset(new DbTimeField(*this)); break; case TYPE_FORMATTEDFIELD: pCellControl.reset(new DbFormattedField(*this)); break; default:
OSL_FAIL("DbGridColumn::CreateControl: Unknown Column"); return;
}
}
Reference< XRowSet > xCur; if (m_rParent.getDataSource())
xCur.set(Reference< XInterface >(*m_rParent.getDataSource()), UNO_QUERY); // TODO : the cursor wrapper should use an XRowSet interface, too
// now create the control wrapper auto pTempCellControl = pCellControl.get(); if (m_rParent.IsFilterMode())
m_pCell = new FmXFilterCell(this, std::unique_ptr<DbFilterField>(static_cast<DbFilterField*>(pCellControl.release()))); else
{ switch (nTypeId)
{ case TYPE_CHECKBOX: m_pCell = new FmXCheckBoxCell( this, std::move(pCellControl) ); break; case TYPE_LISTBOX: m_pCell = new FmXListBoxCell( this, std::move(pCellControl) ); break; case TYPE_COMBOBOX: m_pCell = new FmXComboBoxCell( this, std::move(pCellControl) ); break; default:
m_pCell = new FmXEditCell( this, std::move(pCellControl) );
}
}
m_pCell->init();
impl_toggleScriptManager_nothrow( true );
// only if we use have a bound field, we use a controller for displaying the // window in the grid if (m_xField.is())
m_xController = pTempCellControl->CreateController();
}
// store the data into the model
FmXDataCell* pDataCell = dynamic_cast<FmXDataCell*>( m_pCell.get() ); if (bResult && pDataCell)
{
Reference< css::form::XBoundComponent > xComp(m_xModel, UNO_QUERY); if (xComp.is())
bResult = xComp->commit();
}
m_bInSave = false;
} return bResult;
}
switch (nType)
{ case DataType::NUMERIC: case DataType::DECIMAL: case DataType::DOUBLE: case DataType::REAL: case DataType::BIGINT: case DataType::INTEGER: case DataType::SMALLINT: case DataType::TINYINT: case DataType::DATE: case DataType::TIME: case DataType::TIMESTAMP:
_nAlign = css::awt::TextAlign::RIGHT; break; case DataType::BIT: case DataType::BOOLEAN:
_nAlign = css::awt::TextAlign::CENTER; break; default:
_nAlign = css::awt::TextAlign::LEFT; break;
}
} else
_nAlign = css::awt::TextAlign::LEFT;
}
m_nAlign = _nAlign; if (m_pCell.is() && m_pCell->isAlignedController())
m_pCell->AlignControl(m_nAlign);
return m_nAlign;
}
sal_Int16 DbGridColumn::SetAlignmentFromModel(sal_Int16 nStandardAlign)
{
Any aAlign( m_xModel->getPropertyValue(FM_PROP_ALIGN)); if (aAlign.hasValue())
{
sal_Int16 nTest = sal_Int16(); if (aAlign >>= nTest)
nStandardAlign = nTest;
} return SetAlignment(nStandardAlign);
}
// if our model's format key changes we want to propagate the new value to our windows
m_pModelChangeBroadcaster = new ::comphelper::OPropertyChangeMultiplexer(this, _rColumn.getModel());
// be listener for some common properties
implDoPropertyListening( FM_PROP_READONLY, false );
implDoPropertyListening( FM_PROP_ENABLED, false );
// add as listener for all known "value" properties
implDoPropertyListening( FM_PROP_VALUE, false );
implDoPropertyListening( FM_PROP_STATE, false );
implDoPropertyListening( FM_PROP_TEXT, false );
implDoPropertyListening( FM_PROP_EFFECTIVE_VALUE, false );
implDoPropertyListening( FM_PROP_SELECT_SEQ, false );
implDoPropertyListening( FM_PROP_DATE, false );
implDoPropertyListening( FM_PROP_TIME, false );
// be listener at the bound field as well try
{
Reference< XPropertySetInfo > xPSI( xColModelProps->getPropertySetInfo(), UNO_SET_THROW ); if ( xPSI->hasPropertyByName( FM_PROP_BOUNDFIELD ) )
{
Reference< XPropertySet > xField;
xColModelProps->getPropertyValue( FM_PROP_BOUNDFIELD ) >>= xField; if ( xField.is() )
{
m_pFieldChangeBroadcaster = new ::comphelper::OPropertyChangeMultiplexer(this, xField);
m_pFieldChangeBroadcaster->addProperty( FM_PROP_ISREADONLY );
}
}
} catch( const Exception& )
{
TOOLS_WARN_EXCEPTION( "svx", "DbCellControl::doPropertyListening" );
}
}
DBG_ASSERT( !_bWarnIfNotExistent || ( xPSI.is() && xPSI->hasPropertyByName( _rPropertyName ) ), "DbCellControl::doPropertyListening: no property set info or non-existent property!" );
staticvoid lcl_clearBroadCaster(rtl::Reference<::comphelper::OPropertyChangeMultiplexer>& _pBroadcaster)
{ if ( _pBroadcaster.is() )
{
_pBroadcaster->dispose();
_pBroadcaster.clear(); // no delete, this is done implicitly
}
}
void DbCellControl::implValuePropertyChanged( )
{
OSL_ENSURE( !isValuePropertyLocked(), "DbCellControl::implValuePropertyChanged: not to be called with the value property locked!" );
if ( m_pWindow )
{ if ( m_rColumn.getModel().is() )
updateFromModel( m_rColumn.getModel() );
}
}
void DbCellControl::implAdjustGenericFieldSetting( const Reference< XPropertySet >& /*_rxModel*/ )
{ // nothing to do here
}
bool DbCellControl::Commit()
{ // lock the listening for value property changes
lockValueProperty(); // commit the content of the control into the model's value property bool bReturn = false; try
{
bReturn = commitControl();
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("svx");
} // unlock the listening for value property changes
unlockValueProperty(); // outta here return bReturn;
}
if ((_eInitWhat & InitWindowFacet::Font) || (_eInitWhat & InitWindowFacet::Foreground))
{
Color aTextColor(rParent.IsControlForeground() ? rParent.GetControlForeground() : rParent.GetTextColor());
bool bTextLineColor = rParent.IsTextLineColor();
Color aTextLineColor(rParent.GetTextLineColor());
for (svt::ControlBase* pWindow : pWindows)
{ if (pWindow)
{
pWindow->SetTextColor(aTextColor); if (rParent.IsControlForeground())
pWindow->SetControlForeground(aTextColor);
if (bTextLineColor)
pWindow->SetTextLineColor(); else
pWindow->SetTextLineColor(aTextLineColor);
}
}
}
if (!(_eInitWhat & InitWindowFacet::Background)) return;
if (rParent.IsControlBackground())
{
Color aColor(rParent.GetControlBackground()); for (svt::ControlBase* pWindow : pWindows)
{ if (pWindow)
{ if (isTransparent())
pWindow->SetBackground(); else
{
pWindow->SetBackground(aColor);
pWindow->SetControlBackground(aColor);
}
pWindow->GetOutDev()->SetFillColor(aColor);
}
}
} else
{ if (m_pPainter)
{ if (isTransparent())
m_pPainter->SetBackground(); else
m_pPainter->SetBackground(rParent.GetBackground());
m_pPainter->GetOutDev()->SetFillColor(rParent.GetOutDev()->GetFillColor());
}
if (m_pWindow)
{ if (isTransparent())
m_pWindow->SetBackground(rParent.GetBackground()); else
m_pWindow->GetOutDev()->SetFillColor(rParent.GetOutDev()->GetFillColor());
}
}
}
void DbCellControl::implAdjustReadOnly( const Reference< XPropertySet >& _rxModel,bool i_bReadOnly )
{
DBG_ASSERT( m_pWindow, "DbCellControl::implAdjustReadOnly: not to be called without window!" );
DBG_ASSERT( _rxModel.is(), "DbCellControl::implAdjustReadOnly: invalid model!" ); if ( !(m_pWindow && _rxModel.is()) ) return;
if (bLeftAlign)
{ // this is so that when getting the focus, the selection is oriented left-to-right
AllSettings aSettings = m_pWindow->GetSettings();
StyleSettings aStyleSettings = aSettings.GetStyleSettings();
aStyleSettings.SetSelectionOptions(
aStyleSettings.GetSelectionOptions() | SelectionOptions::ShowFirst);
aSettings.SetStyleSettings(aStyleSettings);
m_pWindow->SetSettings(aSettings);
}
bool DbTextField::commitControl()
{
OUString aText( m_pEdit->GetText( getModelLineEndSetting( m_rColumn.getModel() ) ) ); // we have to check if the length before we can decide if the value was modified
sal_Int32 nMaxTextLen = m_pEdit->GetMaxTextLen(); if (nMaxTextLen > 0)
{
OUString sOldValue;
m_rColumn.getModel()->getPropertyValue( FM_PROP_TEXT ) >>= sOldValue; // if the new value didn't change we must set the old long value again if ( sOldValue.getLength() > nMaxTextLen && sOldValue.compareTo(aText,nMaxTextLen) == 0 )
aText = sOldValue;
}
m_rColumn.getModel()->setPropertyValue( FM_PROP_TEXT, Any( aText ) ); returntrue;
}
DbFormattedField::DbFormattedField(DbGridColumn& _rColumn)
:DbLimitedLengthField(_rColumn)
{ // if our model's format key changes we want to propagate the new value to our windows
doPropertyListening( FM_PROP_FORMATKEY );
}
switch (nAlignment)
{ case awt::TextAlign::RIGHT:
xEditControl->get_widget().set_alignment(TxtAlign::Right);
xEditPainter->get_widget().set_alignment(TxtAlign::Right); break; case awt::TextAlign::CENTER:
xEditControl->get_widget().set_alignment(TxtAlign::Center);
xEditPainter->get_widget().set_alignment(TxtAlign::Center); break; default:
{ // Everything just so that the selection goes from right to left when getting focus
SelectionOptions eOptions = rControlFormatter.GetEntrySelectionOptions();
rControlFormatter.SetEntrySelectionOptions(eOptions | SelectionOptions::ShowFirst); break;
}
}
implAdjustGenericFieldSetting( xUnoModel );
rControlFormatter.SetStrictFormat(false);
rPainterFormatter.SetStrictFormat(false); // if one allows any formatting, one cannot make an entry check anyway // (the FormattedField does not support that anyway, only derived classes)
// get the formatter from the uno model // (I could theoretically also go via the css::util::NumberFormatter, which the cursor would // surely give me. The problem is that I can not really rely on the fact that the two // formatters are the same. Clean is the whole thing if I go via the UNO model.)
sal_Int32 nFormatKey = -1;
// let's see if the model has one ...
DBG_ASSERT(::comphelper::hasProperty(FM_PROP_FORMATSSUPPLIER, xUnoModel), "DbFormattedField::Init : invalid UNO model !");
Any aSupplier( xUnoModel->getPropertyValue(FM_PROP_FORMATSSUPPLIER)); if (aSupplier.hasValue())
{
m_xSupplier.set(aSupplier, css::uno::UNO_QUERY); if (m_xSupplier.is())
{ // if we take the supplier from the model, then also the key
Any aFmtKey( xUnoModel->getPropertyValue(FM_PROP_FORMATKEY)); if (aFmtKey.hasValue())
{
DBG_ASSERT(aFmtKey.getValueTypeClass() == TypeClass_LONG, "DbFormattedField::Init : invalid format key property (no sal_Int32) !");
nFormatKey = ::comphelper::getINT32(aFmtKey);
} else
{
SAL_INFO("svx.fmcomp", "DbFormattedField::Init : my uno-model has no format-key, but a formats supplier !"); // the OFormattedModel which we usually are working with ensures that the model has a format key // as soon as the form is loaded. Unfortunally this method here is called from within loaded, too. // So if our LoadListener is called before the LoadListener of the model, this "else case" is // allowed. // Of course our property listener for the FormatKey property will notify us if the prop is changed, // so this here isn't really bad...
nFormatKey = 0;
}
}
}
// No? Maybe the css::form::component::Form behind the cursor? if (!m_xSupplier.is())
{ if (xCursor.is())
{ // If we take the formatter from the cursor, then also the key from the field to which we are bound
m_xSupplier = getNumberFormats(getConnection(xCursor));
if (m_rColumn.GetField().is())
nFormatKey = ::comphelper::getINT32(m_rColumn.GetField()->getPropertyValue(FM_PROP_FORMATKEY));
}
}
SvNumberFormatter* pFormatterUsed = nullptr; if (m_xSupplier.is())
{
SvNumberFormatsSupplierObj* pImplementation = comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(m_xSupplier); if (pImplementation)
pFormatterUsed = pImplementation->GetNumberFormatter(); else // Everything is invalid: the supplier is of the wrong type, then we can not // rely on a standard formatter to know the (possibly non-standard) key.
nFormatKey = -1;
}
// a standard formatter ... if (pFormatterUsed == nullptr)
{
pFormatterUsed = rControlFormatter.StandardFormatter();
DBG_ASSERT(pFormatterUsed != nullptr, "DbFormattedField::Init : no standard formatter given by the numeric field !");
} // ... and a standard key if (nFormatKey == -1)
nFormatKey = 0;
// min and max values if (m_rColumn.IsNumeric())
{ bool bClearMin = true; if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MIN, xUnoModel))
{
Any aMin( xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_MIN)); if (aMin.getValueTypeClass() != TypeClass_VOID)
{
DBG_ASSERT(aMin.getValueTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid min value !"); double dMin = ::comphelper::getDouble(aMin);
rControlFormatter.SetMinValue(dMin);
rPainterFormatter.SetMinValue(dMin);
bClearMin = false;
}
} if (bClearMin)
{
rControlFormatter.ClearMinValue();
rPainterFormatter.ClearMinValue();
} bool bClearMax = true; if (::comphelper::hasProperty(FM_PROP_EFFECTIVE_MAX, xUnoModel))
{
Any aMax(xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_MAX)); if (aMax.getValueTypeClass() != TypeClass_VOID)
{
DBG_ASSERT(aMax.getValueTypeClass() == TypeClass_DOUBLE, "DbFormattedField::Init : the model has an invalid max value !"); double dMax = ::comphelper::getDouble(aMax);
rControlFormatter.SetMaxValue(dMax);
rPainterFormatter.SetMaxValue(dMax);
bClearMax = false;
}
} if (bClearMax)
{
rControlFormatter.ClearMaxValue();
rPainterFormatter.ClearMaxValue();
}
}
// the default value
Any aDefault( xUnoModel->getPropertyValue(FM_PROP_EFFECTIVE_DEFAULT)); if (aDefault.hasValue())
{ // the thing can be a double or a string switch (aDefault.getValueTypeClass())
{ case TypeClass_DOUBLE: if (m_rColumn.IsNumeric())
{
rControlFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
rPainterFormatter.SetDefaultValue(::comphelper::getDouble(aDefault));
} else
{
OUString sConverted; const Color* pDummy;
pFormatterUsed->GetOutputString(::comphelper::getDouble(aDefault), 0, sConverted, &pDummy);
rControlFormatter.SetDefaultText(sConverted);
rPainterFormatter.SetDefaultText(sConverted);
} break; case TypeClass_STRING:
{
OUString sDefault( ::comphelper::getString(aDefault) ); if (m_rColumn.IsNumeric())
{ double dVal;
sal_uInt32 nTestFormat(0); if (pFormatterUsed->IsNumberFormat(sDefault, nTestFormat, dVal))
{
rControlFormatter.SetDefaultValue(dVal);
rPainterFormatter.SetDefaultValue(dVal);
}
} else
{
rControlFormatter.SetDefaultText(sDefault);
rPainterFormatter.SetDefaultText(sDefault);
}
} break; default:
OSL_FAIL( "DbFormattedField::Init: unexpected value type!" ); break;
}
}
DbLimitedLengthField::Init( rParent, xCursor );
}
DBG_ASSERT(m_pWindow && m_pPainter, "DbFormattedField::_propertyChanged : where are my windows ?"); if (m_pWindow) static_cast<FormattedControlBase*>(m_pWindow.get())->get_formatter().SetFormatKey(nNewKey); if (m_pPainter) static_cast<FormattedControlBase*>(m_pPainter.get())->get_formatter().SetFormatKey(nNewKey);
} else
{
DbLimitedLengthField::_propertyChanged( _rEvent );
}
}
OUString DbFormattedField::GetFormatText(const Reference< css::sdb::XColumn >& _rxField, const Reference< XNumberFormatter >& /*xFormatter*/, const Color** ppColor)
{ // no color specification by default if (ppColor != nullptr)
*ppColor = nullptr;
// NULL value -> empty text if (!_rxField.is()) return OUString();
OUString aText; try
{ if (m_rColumn.IsNumeric())
{ // The IsNumeric at the column says nothing about the class of the used format, but // about the class of the field bound to the column. So when you bind a FormattedField // column to a double field and format it as text, m_rColumn.IsNumeric() returns // sal_True. So that simply means that I can query the contents of the variant using // getDouble, and then I can leave the rest (the formatting) to the FormattedField. double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() ); if (_rxField->wasNull()) return aText;
rPainterFormatter.SetValue(dValue);
} else
{ // Here I can not work with a double, since the field can not provide it to me. // So simply bind the text from the css::util::NumberFormatter to the correct css::form::component::Form.
aText = _rxField->getString(); if (_rxField->wasNull()) return aText;
rPainterFormatter.SetTextFormatted(aText);
}
} catch( const Exception& )
{
DBG_UNHANDLED_EXCEPTION("svx");
}
aText = pControl->get_widget().get_text(); if (ppColor != nullptr)
*ppColor = rPainterFormatter.GetLastOutputColor();
if (!_rxField.is())
{ // NULL value -> empty text
rEntry.set_text(OUString());
} elseif (m_rColumn.IsNumeric())
{ // The IsNumeric at the column says nothing about the class of the used format, but // about the class of the field bound to the column. So when you bind a FormattedField // column to a double field and format it as text, m_rColumn.IsNumeric() returns // sal_True. So that simply means that I can query the contents of the variant using // getDouble, and then I can leave the rest (the formatting) to the FormattedField. double dValue = getValue( _rxField, m_rColumn.GetParent().getNullDate() ); if (_rxField->wasNull())
rEntry.set_text(OUString()); else
rEditFormatter.SetValue(dValue);
} else
{ // Here I can not work with a double, since the field can not provide it to me. // So simply bind the text from the css::util::NumberFormatter to the correct css::form::component::Form.
OUString sText( _rxField->getString());
if (m_rColumn.IsNumeric())
{ if (!rEntry.get_text().isEmpty())
aNewVal <<= rEditFormatter.GetValue(); // an empty string is passed on as void by default, to start with
} else
aNewVal <<= rEditFormatter.GetTextValue();
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.