LibreOffice Module forms (master) 1
Filter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <config_features.h>
23#include <config_fuzzers.h>
24
25#include "Filter.hxx"
26#include <strings.hrc>
27#include <frm_resource.hxx>
28#include <frm_strings.hxx>
29
30#include <com/sun/star/awt/VclWindowPeerAttribute.hpp>
31#include <com/sun/star/awt/XCheckBox.hpp>
32#include <com/sun/star/awt/XComboBox.hpp>
33#include <com/sun/star/awt/XListBox.hpp>
34#include <com/sun/star/awt/XRadioButton.hpp>
35#include <com/sun/star/awt/XVclWindowPeer.hpp>
36#include <com/sun/star/beans/NamedValue.hpp>
37#include <com/sun/star/beans/PropertyValue.hpp>
38#include <com/sun/star/container/XChild.hpp>
39#include <com/sun/star/container/XIndexAccess.hpp>
40#include <com/sun/star/container/XNamed.hpp>
41#include <com/sun/star/form/FormComponentType.hpp>
42#include <com/sun/star/sdb/ErrorMessageDialog.hpp>
43#include <com/sun/star/sdbc/XConnection.hpp>
44#include <com/sun/star/sdbc/XRowSet.hpp>
45#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
46#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
47#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
48#include <com/sun/star/util/NumberFormatter.hpp>
49#include <com/sun/star/awt/XItemList.hpp>
50
52#include <comphelper/types.hxx>
57#include <o3tl/safeint.hxx>
58#include <rtl/ustrbuf.hxx>
60#include <tools/gen.hxx>
61
62
63namespace frm
64{
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::awt;
67 using namespace ::com::sun::star::lang;
68 using namespace ::com::sun::star::beans;
69 using namespace ::com::sun::star::sdb;
70 using namespace ::com::sun::star::sdbc;
71 using namespace ::com::sun::star::sdbcx;
72 using namespace ::com::sun::star::util;
73 using namespace ::com::sun::star::form;
74 using namespace ::com::sun::star::container;
75 using namespace ::com::sun::star::ui::dialogs;
76
77 using namespace ::connectivity;
78
79 OFilterControl::OFilterControl( const Reference< XComponentContext >& _rxORB )
80 :m_aTextListeners( *this )
81 ,m_xContext( _rxORB )
82 ,m_nControlClass( FormComponentType::TEXTFIELD )
83 ,m_bFilterList( false )
84 ,m_bMultiLine( false )
85 ,m_bFilterListFilled( false )
86 {
87 }
88
89
91 {
92#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
93 if ( !m_xField.is() )
94 {
95 OSL_FAIL( "OFilterControl::ensureInitialized: improperly initialized: no field!" );
96 return false;
97 }
98
99 if ( !m_xConnection.is() )
100 {
101 OSL_FAIL( "OFilterControl::ensureInitialized: improperly initialized: no connection!" );
102 return false;
103 }
104
105 if ( !m_xFormatter.is() )
106 {
107 // we can create one from the connection, if it's an SDB connection
108
109 Reference< XNumberFormatsSupplier > xFormatSupplier = ::dbtools::getNumberFormats( m_xConnection, true, m_xContext );
110
111 if ( xFormatSupplier.is() )
112 {
113 m_xFormatter.set(NumberFormatter::create(m_xContext), UNO_QUERY_THROW );
114 m_xFormatter->attachNumberFormatsSupplier( xFormatSupplier );
115 }
116 }
117 if ( !m_xFormatter.is() )
118 {
119 OSL_FAIL( "OFilterControl::ensureInitialized: no number formatter!" );
120 // no fallback anymore
121 return false;
122 }
123#endif
124 return true;
125 }
126
127
128 Any SAL_CALL OFilterControl::queryAggregation( const Type & rType )
129 {
130 Any aRet = UnoControl::queryAggregation( rType);
131 if(!aRet.hasValue())
133
134 return aRet;
135 }
136
137
139 {
140 OUString aServiceName;
141 switch (m_nControlClass)
142 {
143 case FormComponentType::RADIOBUTTON:
144 aServiceName = "radiobutton";
145 break;
146 case FormComponentType::CHECKBOX:
147 aServiceName = "checkbox";
148 break;
149 case FormComponentType::COMBOBOX:
150 aServiceName = "combobox";
151 break;
152 case FormComponentType::LISTBOX:
153 aServiceName = "listbox";
154 break;
155 default:
156 if (m_bMultiLine)
157 aServiceName = "MultiLineEdit";
158 else
159 aServiceName = "Edit";
160 }
161 return aServiceName;
162 }
163
164 // XComponent
165
167 {
168 EventObject aEvt(*this);
169 m_aTextListeners.disposeAndClear( aEvt );
171 }
172
173
174 void OFilterControl::createPeer( const Reference< XToolkit > & rxToolkit, const Reference< XWindowPeer > & rParentPeer )
175 {
176 UnoControl::createPeer( rxToolkit, rParentPeer );
177
178 try
179 {
180 Reference< XVclWindowPeer > xVclWindow( getPeer(), UNO_QUERY_THROW );
181 switch ( m_nControlClass )
182 {
183 case FormComponentType::CHECKBOX:
184 {
185 // checkboxes always have a tristate-mode
186 xVclWindow->setProperty( PROPERTY_TRISTATE, Any( true ) );
187 xVclWindow->setProperty( PROPERTY_STATE, Any( sal_Int32( TRISTATE_INDET ) ) );
188
189 Reference< XCheckBox > xBox( getPeer(), UNO_QUERY_THROW );
190 xBox->addItemListener( this );
191
192 }
193 break;
194
195 case FormComponentType::RADIOBUTTON:
196 {
197 xVclWindow->setProperty( PROPERTY_STATE, Any( sal_Int32( TRISTATE_FALSE ) ) );
198
199 Reference< XRadioButton > xRadio( getPeer(), UNO_QUERY_THROW );
200 xRadio->addItemListener( this );
201 }
202 break;
203
204 case FormComponentType::LISTBOX:
205 {
206 Reference< XListBox > xListBox( getPeer(), UNO_QUERY_THROW );
207 xListBox->addItemListener( this );
208 [[fallthrough]];
209 }
210
211 case FormComponentType::COMBOBOX:
212 {
213 xVclWindow->setProperty(PROPERTY_AUTOCOMPLETE, Any( true ) );
214 [[fallthrough]];
215 }
216
217 default:
218 {
219 Reference< XWindow > xWindow( getPeer(), UNO_QUERY );
220 xWindow->addFocusListener( this );
221
222 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
223 if (xText.is())
224 xText->setMaxTextLen(0);
225 }
226 break;
227 }
228
229 // filter controls are _never_ readonly
230 Reference< XPropertySet > xModel( getModel(), UNO_QUERY_THROW );
231 Reference< XPropertySetInfo > xModelPSI( xModel->getPropertySetInfo(), UNO_SET_THROW );
232 if ( xModelPSI->hasPropertyByName( PROPERTY_READONLY ) )
233 xVclWindow->setProperty( PROPERTY_READONLY, Any( false ) );
234 }
235 catch( const Exception& )
236 {
237 DBG_UNHANDLED_EXCEPTION("forms.component");
238 }
239
240 if (m_bFilterList)
241 m_bFilterListFilled = false;
242 }
243
244
245 void OFilterControl::PrepareWindowDescriptor( WindowDescriptor& rDescr )
246 {
247 if (m_bFilterList)
248 rDescr.WindowAttributes |= VclWindowPeerAttribute::DROPDOWN;
249 }
250
251
252 void OFilterControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal )
253 {
254 // these properties are ignored
255 if (rPropName == PROPERTY_TEXT ||
256 rPropName == PROPERTY_STATE)
257 return;
258
259 UnoControl::ImplSetPeerProperty( rPropName, rVal );
260 }
261
262 // XEventListener
263
264 void SAL_CALL OFilterControl::disposing(const EventObject& Source)
265 {
267 }
268
269 // XItemListener
270
271 void SAL_CALL OFilterControl::itemStateChanged( const ItemEvent& rEvent )
272 {
273#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
274 (void) rEvent;
275#else
276 OUStringBuffer aText;
277 switch (m_nControlClass)
278 {
279 case FormComponentType::CHECKBOX:
280 {
281 if ( ( rEvent.Selected == TRISTATE_TRUE ) || ( rEvent.Selected == TRISTATE_FALSE ) )
282 {
283 sal_Int32 nBooleanComparisonMode = ::dbtools::DatabaseMetaData( m_xConnection ).getBooleanComparisonMode();
284
285 bool bSelected = ( rEvent.Selected == TRISTATE_TRUE );
286
287 OUString sExpressionMarker( "$expression$" );
288 ::dbtools::getBooleanComparisonPredicate(
289 sExpressionMarker,
290 bSelected,
291 nBooleanComparisonMode,
292 aText
293 );
294
295 OUString sText( aText.makeStringAndClear() );
296 sal_Int32 nMarkerPos( sText.indexOf( sExpressionMarker ) );
297 OSL_ENSURE( nMarkerPos == 0, "OFilterControl::itemStateChanged: unsupported boolean comparison mode!" );
298 // If this assertion fails, then getBooleanComparisonPredicate created a predicate which
299 // does not start with the expression we gave it. The only known case is when
300 // the comparison mode is ACCESS_COMPAT, and the value is TRUE. In this case,
301 // the expression is rather complex.
302 // Well, so this is a known issue - the filter controls (and thus the form based filter)
303 // do not work with boolean MS Access fields.
304 // To fix this, we would probably have to revert here to always return "1" or "0" as normalized
305 // filter, and change our client code to properly translate this (which could be some effort).
306 if ( nMarkerPos == 0 )
307 aText.append( sText.subView(sExpressionMarker.getLength()) );
308 else
309 {
310 // fallback
311 aText.appendAscii( bSelected ? "1" : "0" );
312 }
313 }
314 }
315 break;
316
317 case FormComponentType::LISTBOX:
318 {
319 try
320 {
321 const Reference< XItemList > xItemList( getModel(), UNO_QUERY_THROW );
322 OUString sItemText( xItemList->getItemText( rEvent.Selected ) );
323
324 const MapString2String::const_iterator itemPos = m_aDisplayItemToValueItem.find( sItemText );
325 if ( itemPos != m_aDisplayItemToValueItem.end() )
326 {
327 sItemText = itemPos->second;
328 if ( !sItemText.isEmpty() )
329 {
331 OUString sErrorMessage;
332 OSL_VERIFY( aPredicateInput.normalizePredicateString( sItemText, m_xField, &sErrorMessage ) );
333 }
334 }
335 aText.append( sItemText );
336 }
337 catch( const Exception& )
338 {
339 DBG_UNHANDLED_EXCEPTION("forms.component");
340 }
341 }
342 break;
343
344 case FormComponentType::RADIOBUTTON:
345 {
346 if ( rEvent.Selected == TRISTATE_TRUE )
347 aText.append( ::comphelper::getString( Reference< XPropertySet >( getModel(), UNO_QUERY_THROW )->getPropertyValue( PROPERTY_REFVALUE ) ) );
348 }
349 break;
350 }
351
352 OUString sText( aText.makeStringAndClear() );
353 if ( m_aText != sText )
354 {
355 m_aText = sText;
356 TextEvent aEvt;
357 aEvt.Source = *this;
358 m_aTextListeners.notifyEach(&css::awt::XTextListener::textChanged, aEvt);
359 }
360#endif
361 }
362
363
365 {
366#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
367 if ( !ensureInitialized( ) )
368 // already asserted in ensureInitialized
369 return;
370
371 // ensure the cursor and the statement are disposed as soon as we leave
374
375 try
376 {
377 m_bFilterListFilled = true;
378
379 if ( !m_xField.is() )
380 return;
381
382 OUString sFieldName;
383 m_xField->getPropertyValue( PROPERTY_NAME ) >>= sFieldName;
384
385 // here we need a table to which the field belongs to
386 const Reference< XChild > xModelAsChild( getModel(), UNO_QUERY_THROW );
387 const Reference< XRowSet > xForm( xModelAsChild->getParent(), UNO_QUERY_THROW );
388 const Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW );
389
390 // create a query composer
391 Reference< XColumnsSupplier > xSuppColumns;
392 xFormProps->getPropertyValue("SingleSelectQueryComposer") >>= xSuppColumns;
393
394 const Reference< XConnection > xConnection( ::dbtools::getConnection( xForm ), UNO_SET_THROW );
395 const Reference< XNameAccess > xFieldNames( xSuppColumns->getColumns(), UNO_SET_THROW );
396 if ( !xFieldNames->hasByName( sFieldName ) )
397 return;
398 OUString sRealFieldName, sTableName;
399 const Reference< XPropertySet > xComposerFieldProps( xFieldNames->getByName( sFieldName ), UNO_QUERY_THROW );
400 xComposerFieldProps->getPropertyValue( PROPERTY_REALNAME ) >>= sRealFieldName;
401 xComposerFieldProps->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName;
402
403 // obtain the table of the field
404 const Reference< XTablesSupplier > xSuppTables( xSuppColumns, UNO_QUERY_THROW );
405 const Reference< XNameAccess > xTablesNames( xSuppTables->getTables(), UNO_SET_THROW );
406 const Reference< XNamed > xNamedTable( xTablesNames->getByName( sTableName ), UNO_QUERY_THROW );
407 sTableName = xNamedTable->getName();
408
409 // create a statement selecting all values for the given field
410 OUStringBuffer aStatement;
411
412 const Reference< XDatabaseMetaData > xMeta( xConnection->getMetaData(), UNO_SET_THROW );
413 const OUString sQuoteChar = xMeta->getIdentifierQuoteString();
414
415 aStatement.append(
416 "SELECT DISTINCT "
417 + sQuoteChar
418 + sRealFieldName
419 + sQuoteChar );
420
421 // if the field had an alias in our form's statement, give it this alias in the new statement, too
422 if ( !sFieldName.isEmpty() && ( sFieldName != sRealFieldName ) )
423 {
424 aStatement.append(" AS "+ sQuoteChar + sFieldName + sQuoteChar );
425 }
426
427 aStatement.append( " FROM " );
428
429 OUString sCatalog, sSchema, sTable;
430 ::dbtools::qualifiedNameComponents( xMeta, sTableName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
431 aStatement.append( ::dbtools::composeTableNameForSelect( xConnection, sCatalog, sSchema, sTable ) );
432
433 // execute the statement
434 xStatement.reset( xConnection->createStatement() );
435 const OUString sSelectStatement( aStatement.makeStringAndClear( ) );
436 xListCursor.reset( xStatement->executeQuery( sSelectStatement ) );
437
438 // retrieve the one column which we take the values from
439 const Reference< XColumnsSupplier > xSupplyCols( xListCursor, UNO_QUERY_THROW );
440 const Reference< XIndexAccess > xFields( xSupplyCols->getColumns(), UNO_QUERY_THROW );
441 const Reference< XPropertySet > xDataField( xFields->getByIndex(0), UNO_QUERY_THROW );
442
443 // ensure the values will be formatted according to the field format
444 const ::dbtools::FormattedColumnValue aFormatter( m_xFormatter, xDataField );
445
446 ::std::vector< OUString > aProposals;
447 aProposals.reserve(16);
448
449 while ( xListCursor->next() && ( aProposals.size() < o3tl::make_unsigned( SHRT_MAX ) ) )
450 {
451 const OUString sCurrentValue = aFormatter.getFormattedValue();
452 aProposals.push_back( sCurrentValue );
453 }
454
455 // fill the list items into our peer
456 Sequence< OUString> aStringSeq( comphelper::containerToSequence(aProposals) );
457
458 const Reference< XComboBox > xComboBox( getPeer(), UNO_QUERY_THROW );
459 xComboBox->addItems( aStringSeq, 0 );
460
461 // set the drop down line count to something reasonable
462 const sal_Int16 nLineCount = ::std::min( sal_Int16( 16 ), sal_Int16( aStringSeq.getLength() ) );
463 xComboBox->setDropDownLineCount( nLineCount );
464 }
465 catch( const Exception& )
466 {
467 DBG_UNHANDLED_EXCEPTION("forms.component");
468 }
469#endif
470 }
471
472 // XFocusListener
473
474 void SAL_CALL OFilterControl::focusGained(const FocusEvent& /*e*/)
475 {
476 // should we fill the combobox?
479 }
480
481
482 void SAL_CALL OFilterControl::focusLost(const FocusEvent& /*e*/)
483 {
484 }
485
486
488 {
489#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
490 if ( !ensureInitialized( ) )
491 // already asserted in ensureInitialized
492 return true;
493
494 OUString aText;
495 switch (m_nControlClass)
496 {
497 case FormComponentType::TEXTFIELD:
498 case FormComponentType::COMBOBOX:
499 {
500 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
501 if (xText.is())
502 aText = xText->getText();
503 } break;
504 default:
505 return true;
506 }
507 if ( m_aText == aText )
508 return true;
509 // check the text with the SQL-Parser
510 OUString aNewText = aText.trim();
511 if ( !aNewText.isEmpty() )
512 {
514 OUString sErrorMessage;
515 if ( !aPredicateInput.normalizePredicateString( aNewText, m_xField, &sErrorMessage ) )
516 {
517 // display the error and outta here
518 SQLContext aError;
519 aError.Message = ResourceManager::loadString(RID_STR_SYNTAXERROR);
520 aError.Details = sErrorMessage;
521 displayException( aError );
522 return false;
523 }
524 }
525
526 setText(aNewText);
527 TextEvent aEvt;
528 aEvt.Source = *this;
529 m_aTextListeners.notifyEach(&css::awt::XTextListener::textChanged, aEvt);
530#endif
531 return true;
532 }
533
534 // XTextComponent
535
536 void SAL_CALL OFilterControl::addTextListener(const Reference< XTextListener > & l)
537 {
538 m_aTextListeners.addInterface( l );
539 }
540
541
542 void SAL_CALL OFilterControl::removeTextListener(const Reference< XTextListener > & l)
543 {
544 m_aTextListeners.removeInterface( l );
545 }
546
547
548 void SAL_CALL OFilterControl::setText( const OUString& aText )
549 {
550 if ( !ensureInitialized( ) )
551 // already asserted in ensureInitialized
552 return;
553
554 switch (m_nControlClass)
555 {
556 case FormComponentType::CHECKBOX:
557 {
558 Reference< XVclWindowPeer > xVclWindow( getPeer(), UNO_QUERY );
559 if (xVclWindow.is())
560 {
561 Any aValue;
562 if ( aText == "1"
563 || aText.equalsIgnoreAsciiCase("TRUE")
564 || aText.equalsIgnoreAsciiCase("IS TRUE")
565 )
566 {
567 aValue <<= sal_Int32(TRISTATE_TRUE);
568 }
569 else if ( aText == "0" || aText.equalsIgnoreAsciiCase("FALSE") )
570 {
571 aValue <<= sal_Int32(TRISTATE_FALSE);
572 }
573 else
574 aValue <<= sal_Int32(TRISTATE_INDET);
575
576 m_aText = aText;
577 xVclWindow->setProperty( PROPERTY_STATE, aValue );
578 }
579 } break;
580 case FormComponentType::RADIOBUTTON:
581 {
582 Reference< XVclWindowPeer > xVclWindow( getPeer(), UNO_QUERY );
583 if (xVclWindow.is())
584 {
585 OUString aRefText = ::comphelper::getString(css::uno::Reference< XPropertySet > (getModel(), UNO_QUERY_THROW)->getPropertyValue(PROPERTY_REFVALUE));
586 Any aValue;
587 if (aText == aRefText)
588 aValue <<= sal_Int32(TRISTATE_TRUE);
589 else
590 aValue <<= sal_Int32(TRISTATE_FALSE);
591 m_aText = aText;
592 xVclWindow->setProperty(PROPERTY_STATE, aValue);
593 }
594 } break;
595 case FormComponentType::LISTBOX:
596 {
597 Reference< XListBox > xListBox( getPeer(), UNO_QUERY );
598 if (xListBox.is())
599 {
600 m_aText = aText;
601 MapString2String::const_iterator itemPos = m_aDisplayItemToValueItem.find( m_aText );
602 if ( itemPos == m_aDisplayItemToValueItem.end() )
603 {
604 const bool isQuoted = ( m_aText.getLength() > 1 )
605 && ( m_aText[0] == '\'' )
606 && ( m_aText[ m_aText.getLength() - 1 ] == '\'' );
607 if ( isQuoted )
608 {
609 m_aText = m_aText.copy( 1, m_aText.getLength() - 2 );
610 itemPos = m_aDisplayItemToValueItem.find( m_aText );
611 }
612 }
613
614 OSL_ENSURE( ( itemPos != m_aDisplayItemToValueItem.end() ) || m_aText.isEmpty(),
615 "OFilterControl::setText: this text is not in my display list!" );
616 if ( itemPos == m_aDisplayItemToValueItem.end() )
617 m_aText.clear();
618
619 if ( m_aText.isEmpty() )
620 {
621 while ( xListBox->getSelectedItemPos() >= 0 )
622 {
623 xListBox->selectItemPos( xListBox->getSelectedItemPos(), false );
624 }
625 }
626 else
627 {
628 xListBox->selectItem( m_aText, true );
629 }
630 }
631 }
632 break;
633
634 default:
635 {
636 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
637 if (xText.is())
638 {
639 m_aText = aText;
640 xText->setText(aText);
641 }
642 }
643 }
644 }
645
646
647 void SAL_CALL OFilterControl::insertText( const css::awt::Selection& rSel, const OUString& aText )
648 {
649 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
650 if (xText.is())
651 {
652 xText->insertText(rSel, aText);
653 m_aText = xText->getText();
654 }
655 }
656
657
658 OUString SAL_CALL OFilterControl::getText()
659 {
660 return m_aText;
661 }
662
663
665 {
666 OUString aSelected;
667 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
668 if (xText.is())
669 aSelected = xText->getSelectedText();
670
671 return aSelected;
672 }
673
674
675 void SAL_CALL OFilterControl::setSelection( const css::awt::Selection& aSelection )
676 {
677 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
678 if (xText.is())
679 xText->setSelection( aSelection );
680 }
681
682
683 css::awt::Selection SAL_CALL OFilterControl::getSelection()
684 {
685 css::awt::Selection aSel;
686 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
687 if (xText.is())
688 aSel = xText->getSelection();
689 return aSel;
690 }
691
692
694 {
695 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
696 return xText.is() && xText->isEditable();
697 }
698
699
700 void SAL_CALL OFilterControl::setEditable( sal_Bool bEditable )
701 {
702 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
703 if (xText.is())
704 xText->setEditable(bEditable);
705 }
706
707
708 sal_Int16 SAL_CALL OFilterControl::getMaxTextLen()
709 {
710 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
711 return xText.is() ? xText->getMaxTextLen() : 0;
712 }
713
714
715 void SAL_CALL OFilterControl::setMaxTextLen( sal_Int16 nLength )
716 {
717 Reference< XTextComponent > xText( getPeer(), UNO_QUERY );
718 if (xText.is())
719 xText->setMaxTextLen(nLength);
720 }
721
722
723 void OFilterControl::displayException( const css::sdb::SQLContext& _rExcept )
724 {
725 try
726 {
727 Reference< XExecutableDialog > xErrorDialog = ErrorMessageDialog::create( m_xContext, "", m_xMessageParent, Any(_rExcept));
728 xErrorDialog->execute();
729 }
730 catch( const Exception& )
731 {
732 DBG_UNHANDLED_EXCEPTION("forms.component");
733 }
734 }
735
736
737 void SAL_CALL OFilterControl::initialize( const Sequence< Any >& aArguments )
738 {
739 const Any* pArguments = aArguments.getConstArray();
740 const Any* pArgumentsEnd = pArguments + aArguments.getLength();
741
742 PropertyValue aProp;
743 NamedValue aValue;
744 const OUString* pName = nullptr;
745 const Any* pValue = nullptr;
746 Reference< XPropertySet > xControlModel;
747
748 if (aArguments.getLength() == 3
749 && (aArguments[0] >>= m_xMessageParent)
750 && (aArguments[1] >>= m_xFormatter)
751 && (aArguments[2] >>= xControlModel))
752 {
753 initControlModel(xControlModel);
754 }
755 else for ( ; pArguments != pArgumentsEnd; ++pArguments )
756 {
757 // we recognize PropertyValues and NamedValues
758 if ( *pArguments >>= aProp )
759 {
760 pName = &aProp.Name;
761 pValue = &aProp.Value;
762 }
763 else if ( *pArguments >>= aValue )
764 {
765 pName = &aValue.Name;
766 pValue = &aValue.Value;
767 }
768 else
769 {
770 OSL_FAIL( "OFilterControl::initialize: unrecognized argument!" );
771 continue;
772 }
773
774 if ( *pName == "MessageParent" )
775 {
776 // the message parent
777 *pValue >>= m_xMessageParent;
778 OSL_ENSURE( m_xMessageParent.is(), "OFilterControl::initialize: invalid MessageParent!" );
779 }
780 else if ( *pName == "NumberFormatter" )
781 {
782 // the number format. This argument is optional.
783 *pValue >>= m_xFormatter;
784 OSL_ENSURE( m_xFormatter.is(), "OFilterControl::initialize: invalid NumberFormatter!" );
785 }
786 else if ( *pName == "ControlModel" )
787 {
788 // the control model for which we act as filter control
789 if ( !(*pValue >>= xControlModel ) )
790 {
791 OSL_FAIL( "OFilterControl::initialize: invalid control model argument!" );
792 continue;
793 }
794 initControlModel(xControlModel);
795 }
796 }
797 }
798
799 void OFilterControl::initControlModel(Reference< XPropertySet > const & xControlModel)
800 {
801#if !HAVE_FEATURE_DBCONNECTIVITY || ENABLE_FUZZERS
802 (void) xControlModel;
803#else
804 if ( !xControlModel.is() )
805 {
806 OSL_FAIL( "OFilterControl::initialize: invalid control model argument!" );
807 return;
808 }
809 // some properties which are "derived" from the control model we're working for
810
811 // the field
812 m_xField.clear();
813 OSL_ENSURE( ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ), "OFilterControl::initialize: control model needs a bound field property!" );
814 xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= m_xField;
815
816
817 // filter list and control class
818 m_bFilterList = ::comphelper::hasProperty( PROPERTY_FILTERPROPOSAL, xControlModel ) && ::comphelper::getBOOL( xControlModel->getPropertyValue( PROPERTY_FILTERPROPOSAL ) );
819 if ( m_bFilterList )
820 m_nControlClass = FormComponentType::COMBOBOX;
821 else
822 {
823 sal_Int16 nClassId = ::comphelper::getINT16( xControlModel->getPropertyValue( PROPERTY_CLASSID ) );
824 switch (nClassId)
825 {
826 case FormComponentType::CHECKBOX:
827 case FormComponentType::RADIOBUTTON:
828 case FormComponentType::LISTBOX:
829 case FormComponentType::COMBOBOX:
830 m_nControlClass = nClassId;
831 if ( FormComponentType::LISTBOX == nClassId )
832 {
833 Sequence< OUString > aDisplayItems;
834 OSL_VERIFY( xControlModel->getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aDisplayItems );
835 Sequence< OUString > aValueItems;
836 OSL_VERIFY( xControlModel->getPropertyValue( PROPERTY_VALUE_SEQ ) >>= aValueItems );
837 OSL_ENSURE( aDisplayItems.getLength() == aValueItems.getLength(), "OFilterControl::initialize: inconsistent item lists!" );
838 for ( sal_Int32 i=0; i < ::std::min( aDisplayItems.getLength(), aValueItems.getLength() ); ++i )
839 m_aDisplayItemToValueItem[ aDisplayItems[i] ] = aValueItems[i];
840 }
841 break;
842 default:
843 m_bMultiLine = ::comphelper::hasProperty( PROPERTY_MULTILINE, xControlModel ) && ::comphelper::getBOOL( xControlModel->getPropertyValue( PROPERTY_MULTILINE ) );
844 m_nControlClass = FormComponentType::TEXTFIELD;
845 break;
846 }
847 }
848
849
850 // the connection meta data for the form which we're working for
851 Reference< XChild > xModel( xControlModel, UNO_QUERY );
852 Reference< XRowSet > xForm;
853 if ( xModel.is() )
854 xForm.set(xModel->getParent(), css::uno::UNO_QUERY);
855 m_xConnection = ::dbtools::getConnection( xForm );
856 OSL_ENSURE( m_xConnection.is(), "OFilterControl::initialize: unable to determine the form's connection!" );
857#endif
858 }
859
861 {
862 return "com.sun.star.comp.forms.OFilterControl";
863 }
864
865 sal_Bool SAL_CALL OFilterControl::supportsService( const OUString& ServiceName )
866 {
868 }
869
870 Sequence< OUString > SAL_CALL OFilterControl::getSupportedServiceNames( )
871 {
872 return { "com.sun.star.form.control.FilterControl",
873 "com.sun.star.awt.UnoControl" };
874 }
875} // namespace frm
876
877extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
879 css::uno::Sequence<css::uno::Any> const &)
880{
881 return cppu::acquire(new frm::OFilterControl(context));
882}
883
884/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_forms_OFilterControl_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
Definition: Filter.cxx:878
OptionalString sSchema
OptionalString sCatalog
Reference< XComponentContext > m_xContext
const char * pName
css::uno::Reference< css::awt::XControlModel > SAL_CALL getModel() override
void SAL_CALL dispose() override
virtual void ImplSetPeerProperty(const OUString &rPropName, const css::uno::Any &rVal)
void SAL_CALL disposing(const css::lang::EventObject &Source) override
css::uno::Reference< css::awt::XWindowPeer > SAL_CALL getPeer() override
void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit > &Toolkit, const css::uno::Reference< css::awt::XWindowPeer > &Parent) override
virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const &rType) SAL_OVERRIDE
sal_Int32 getBooleanComparisonMode() const
bool normalizePredicateString(OUString &_rPredicateValue, const css::uno::Reference< css::beans::XPropertySet > &_rxField, OUString *_pErrorMessage=nullptr) const
virtual void SAL_CALL setEditable(sal_Bool bEditable) override
Definition: Filter.cxx:700
void displayException(const css::sdb::SQLContext &_rExcept)
Definition: Filter.cxx:723
virtual void SAL_CALL setSelection(const css::awt::Selection &aSelection) override
Definition: Filter.cxx:675
MapString2String m_aDisplayItemToValueItem
Definition: Filter.hxx:66
virtual void SAL_CALL itemStateChanged(const css::awt::ItemEvent &rEvent) override
Definition: Filter.cxx:271
css::uno::Any SAL_CALL queryAggregation(const css::uno::Type &rType) override
Definition: Filter.cxx:128
virtual void SAL_CALL insertText(const css::awt::Selection &rSel, const OUString &aText) override
Definition: Filter.cxx:647
css::uno::Reference< css::beans::XPropertySet > m_xField
Definition: Filter.hxx:60
virtual void SAL_CALL removeTextListener(const css::uno::Reference< css::awt::XTextListener > &l) override
Definition: Filter.cxx:542
virtual void PrepareWindowDescriptor(css::awt::WindowDescriptor &rDesc) override
Definition: Filter.cxx:245
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: Filter.cxx:870
sal_Int16 m_nControlClass
Definition: Filter.hxx:69
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
Definition: Filter.cxx:865
bool ensureInitialized()
Definition: Filter.cxx:90
void initControlModel(css::uno::Reference< css::beans::XPropertySet > const &xControlModel)
Definition: Filter.cxx:799
virtual OUString SAL_CALL getImplementationName() override
Definition: Filter.cxx:860
virtual void SAL_CALL addTextListener(const css::uno::Reference< css::awt::XTextListener > &l) override
Definition: Filter.cxx:536
virtual OUString GetComponentServiceName() const override
Definition: Filter.cxx:138
void implInitFilterList()
Definition: Filter.cxx:364
virtual void SAL_CALL focusLost(const css::awt::FocusEvent &e) override
Definition: Filter.cxx:482
bool m_bFilterListFilled
Definition: Filter.hxx:72
virtual OUString SAL_CALL getSelectedText() override
Definition: Filter.cxx:664
virtual sal_Bool SAL_CALL isEditable() override
Definition: Filter.cxx:693
virtual void SAL_CALL focusGained(const css::awt::FocusEvent &e) override
Definition: Filter.cxx:474
css::uno::Reference< css::util::XNumberFormatter > m_xFormatter
Definition: Filter.hxx:61
virtual sal_Bool SAL_CALL commit() override
Definition: Filter.cxx:487
OUString m_aText
Definition: Filter.hxx:68
css::uno::Reference< css::awt::XWindow > m_xMessageParent
Definition: Filter.hxx:63
virtual void SAL_CALL dispose() override
Definition: Filter.cxx:166
virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > &aArguments) override
Definition: Filter.cxx:737
virtual void SAL_CALL setMaxTextLen(sal_Int16 nLength) override
Definition: Filter.cxx:715
css::uno::Reference< css::uno::XComponentContext > m_xContext
Definition: Filter.hxx:59
TextListenerMultiplexer m_aTextListeners
Definition: Filter.hxx:57
virtual css::awt::Selection SAL_CALL getSelection() override
Definition: Filter.cxx:683
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: Filter.cxx:264
virtual void ImplSetPeerProperty(const OUString &rPropName, const css::uno::Any &rVal) override
Definition: Filter.cxx:252
virtual void SAL_CALL setText(const OUString &aText) override
Definition: Filter.cxx:548
virtual OUString SAL_CALL getText() override
Definition: Filter.cxx:658
css::uno::Reference< css::sdbc::XConnection > m_xConnection
Definition: Filter.hxx:62
virtual sal_Int16 SAL_CALL getMaxTextLen() override
Definition: Filter.cxx:708
virtual void SAL_CALL createPeer(const css::uno::Reference< css::awt::XToolkit > &rxToolkit, const css::uno::Reference< css::awt::XWindowPeer > &rParentPeer) override
Definition: Filter.cxx:174
OFilterControl(const css::uno::Reference< css::uno::XComponentContext > &_rxORB)
Definition: Filter.cxx:79
const OSystemParseContext * getParseContext() const
void reset(const css::uno::Reference< INTERFACE > &_rxComponent, AssignmentMode _eMode=TakeOwnership)
#define DBG_UNHANDLED_EXCEPTION(...)
constexpr OUStringLiteral PROPERTY_NAME
Definition: frm_strings.hxx:28
constexpr OUStringLiteral PROPERTY_FILTERPROPOSAL
constexpr OUStringLiteral PROPERTY_BOUNDFIELD
constexpr OUStringLiteral PROPERTY_AUTOCOMPLETE
constexpr OUStringLiteral PROPERTY_READONLY
Definition: frm_strings.hxx:41
constexpr OUStringLiteral PROPERTY_TEXT
Definition: frm_strings.hxx:33
constexpr OUStringLiteral PROPERTY_REFVALUE
Definition: frm_strings.hxx:92
constexpr OUStringLiteral PROPERTY_STATE
Definition: frm_strings.hxx:58
constexpr OUStringLiteral PROPERTY_CLASSID
Definition: frm_strings.hxx:30
constexpr OUStringLiteral PROPERTY_VALUE_SEQ
Definition: frm_strings.hxx:79
constexpr OUStringLiteral PROPERTY_TABLENAME
constexpr OUStringLiteral PROPERTY_TRISTATE
Definition: frm_strings.hxx:59
constexpr OUStringLiteral PROPERTY_REALNAME
constexpr OUStringLiteral PROPERTY_STRINGITEMLIST
Definition: frm_strings.hxx:62
constexpr OUStringLiteral PROPERTY_MULTILINE
Definition: frm_strings.hxx:48
Sequence< PropertyValue > aArguments
@ Exception
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
Type
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
OUString loadString(TranslateId aResId)
loads the string with the specified resource id from the FormLayer mo file
ListBox is a bit confusing / different from other form components, so here are a few notes:
Definition: BaseListBox.hxx:25
@ TRISTATE_INDET
Definition: togglestate.hxx:27
@ TRISTATE_FALSE
Definition: togglestate.hxx:27
@ TRISTATE_TRUE
Definition: togglestate.hxx:27
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
bool getPropertyValue(ValueType &rValue, css::uno::Reference< css::beans::XPropertySet > const &xPropSet, OUString const &propName)
Reference< XModel > xModel
unsigned char sal_Bool
sal_Int32 nLength