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