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