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 #include "formoperations.hxx"
28 #include "frm_strings.hxx"
29 #include "frm_resource.hxx"
30 #include "frm_resource.hrc"
31 #include "frm_module.hxx"
32
33 /** === begin UNO includes === **/
34 #include <com/sun/star/ucb/AlreadyInitializedException.hpp>
35 #include <com/sun/star/util/XModifyBroadcaster.hpp>
36 #include <com/sun/star/form/runtime/FormFeature.hpp>
37 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <com/sun/star/lang/DisposedException.hpp>
39 #include <com/sun/star/awt/XControl.hpp>
40 #include <com/sun/star/form/XGrid.hpp>
41 #include <com/sun/star/form/XBoundControl.hpp>
42 #include <com/sun/star/form/XBoundComponent.hpp>
43 #include <com/sun/star/sdbcx/XRowLocate.hpp>
44 #include <com/sun/star/form/XConfirmDeleteListener.hpp>
45 #include <com/sun/star/sdb/RowChangeEvent.hpp>
46 #include <com/sun/star/sdb/RowChangeAction.hpp>
47 #include <com/sun/star/sdb/SQLFilterOperator.hpp>
48 #include <com/sun/star/sdbc/DataType.hpp>
49 #include <com/sun/star/form/XReset.hpp>
50 #include <com/sun/star/beans/XMultiPropertySet.hpp>
51 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
52 #include <com/sun/star/util/XRefreshable.hpp>
53 /** === end UNO includes === **/
54
55 #include <connectivity/dbtools.hxx>
56 #include <connectivity/dbexception.hxx>
57 #include <vcl/svapp.hxx>
58 #include <vcl/stdtext.hxx>
59 #include <vcl/msgbox.hxx>
60 #include <vcl/waitobj.hxx>
61 #include <tools/diagnose_ex.h>
62 #include <comphelper/container.hxx>
63 #include <comphelper/property.hxx>
64 #include <comphelper/namedvaluecollection.hxx>
65 #include <cppuhelper/exc_hlp.hxx>
66 #include <vos/mutex.hxx>
67
68 //--------------------------------------------------------------------------
createRegistryInfo_FormOperations()69 extern "C" void SAL_CALL createRegistryInfo_FormOperations()
70 {
71 static ::frm::OMultiInstanceAutoRegistration< ::frm::FormOperations > aAutoRegistration;
72 }
73
74 //........................................................................
75 namespace frm
76 {
77 //........................................................................
78
79 using ::dbtools::SQLExceptionInfo;
80 /** === begin UNO using === **/
81 using ::com::sun::star::uno::Reference;
82 using ::com::sun::star::uno::XComponentContext;
83 using ::com::sun::star::uno::RuntimeException;
84 using ::com::sun::star::uno::Sequence;
85 using ::com::sun::star::uno::Exception;
86 using ::com::sun::star::uno::Any;
87 using ::com::sun::star::uno::XInterface;
88 using ::com::sun::star::sdbc::XRowSet;
89 using ::com::sun::star::sdbc::XResultSetUpdate;
90 using ::com::sun::star::form::runtime::XFormController;
91 using ::com::sun::star::form::runtime::XFeatureInvalidation;
92 using ::com::sun::star::form::runtime::FeatureState;
93 using ::com::sun::star::lang::IllegalArgumentException;
94 using ::com::sun::star::sdbc::SQLException;
95 using namespace ::com::sun::star::sdbc;
96 using ::com::sun::star::form::XForm;
97 using ::com::sun::star::ucb::AlreadyInitializedException;
98 using ::com::sun::star::util::XModifyBroadcaster;
99 using ::com::sun::star::uno::UNO_QUERY;
100 using ::com::sun::star::lang::EventObject;
101 using ::com::sun::star::beans::PropertyChangeEvent;
102 using ::com::sun::star::lang::XMultiServiceFactory;
103 using ::com::sun::star::lang::DisposedException;
104 using ::com::sun::star::beans::XPropertySet;
105 using ::com::sun::star::awt::XControl;
106 using ::com::sun::star::form::XGrid;
107 using ::com::sun::star::container::XIndexAccess;
108 using ::com::sun::star::uno::UNO_QUERY_THROW;
109 using ::com::sun::star::form::XBoundControl;
110 using ::com::sun::star::form::XBoundComponent;
111 using ::com::sun::star::sdbcx::XRowLocate;
112 using ::com::sun::star::form::XConfirmDeleteListener;
113 using ::com::sun::star::sdb::RowChangeEvent;
114 using namespace ::com::sun::star::sdb;
115 using ::com::sun::star::form::XReset;
116 using ::com::sun::star::beans::XMultiPropertySet;
117 using ::com::sun::star::uno::makeAny;
118 using ::com::sun::star::lang::WrappedTargetException;
119 using ::com::sun::star::beans::PropertyValue;
120 using ::com::sun::star::ui::dialogs::XExecutableDialog;
121 using ::com::sun::star::beans::NamedValue;
122
123 using ::com::sun::star::util::XRefreshable;
124 using ::com::sun::star::awt::XControlModel;
125 /** === end UNO using === **/
126 namespace FormFeature = ::com::sun::star::form::runtime::FormFeature;
127 namespace RowChangeAction = ::com::sun::star::sdb::RowChangeAction;
128
129 //====================================================================
130 //= FormOperations
131 //====================================================================
132 //--------------------------------------------------------------------
FormOperations(const Reference<XMultiServiceFactory> & _rxContext)133 FormOperations::FormOperations( const Reference< XMultiServiceFactory >& _rxContext )
134 :FormOperations_Base( m_aMutex )
135 ,m_aContext( _rxContext )
136 ,m_bInitializedParser( false )
137 ,m_bActiveControlModified( false )
138 ,m_bConstructed( false )
139 #ifdef DBG_UTIL
140 ,m_nMethodNestingLevel( false )
141 #endif
142 {
143 }
144
145 //--------------------------------------------------------------------
~FormOperations()146 FormOperations::~FormOperations()
147 {
148 }
149
150 //--------------------------------------------------------------------
getImplementationName_Static()151 ::rtl::OUString FormOperations::getImplementationName_Static( ) throw(RuntimeException)
152 {
153 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.forms.FormOperations" ) );
154 }
155
156 //--------------------------------------------------------------------
getSupportedServiceNames_Static()157 Sequence< ::rtl::OUString > FormOperations::getSupportedServiceNames_Static( ) throw(RuntimeException)
158 {
159 Sequence< ::rtl::OUString > aNames(1);
160 aNames[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.runtime.FormOperations" ) );
161 return aNames;
162 }
163
164 //--------------------------------------------------------------------
Create(const Reference<XMultiServiceFactory> & _rxFactory)165 Reference< XInterface > SAL_CALL FormOperations::Create(const Reference< XMultiServiceFactory >& _rxFactory )
166 {
167 return *new FormOperations( _rxFactory );
168 }
169
170 //--------------------------------------------------------------------
initialize(const Sequence<Any> & _arguments)171 void SAL_CALL FormOperations::initialize( const Sequence< Any >& _arguments ) throw (Exception, RuntimeException)
172 {
173 if ( m_bConstructed )
174 throw AlreadyInitializedException();
175
176 if ( _arguments.getLength() == 1 )
177 {
178 Reference< XFormController > xController;
179 Reference< XForm > xForm;
180 if ( _arguments[0] >>= xController )
181 createWithFormController( xController );
182 else if ( _arguments[0] >>= xForm )
183 createWithForm( xForm );
184 else
185 throw IllegalArgumentException( ::rtl::OUString(), *this, 1 );
186 return;
187 }
188
189 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
190 }
191
192 //--------------------------------------------------------------------
getImplementationName()193 ::rtl::OUString SAL_CALL FormOperations::getImplementationName( ) throw (RuntimeException)
194 {
195 return getImplementationName_Static();
196 }
197
198 //--------------------------------------------------------------------
supportsService(const::rtl::OUString & _ServiceName)199 ::sal_Bool SAL_CALL FormOperations::supportsService( const ::rtl::OUString& _ServiceName ) throw (RuntimeException)
200 {
201 Sequence< ::rtl::OUString > aSupportedServiceNames( getSupportedServiceNames() );
202 const ::rtl::OUString* pBegin = aSupportedServiceNames.getConstArray();
203 const ::rtl::OUString* pEnd = aSupportedServiceNames.getConstArray() + aSupportedServiceNames.getLength();
204 return ::std::find( pBegin, pEnd, _ServiceName ) != pEnd;
205 }
206
207 //--------------------------------------------------------------------
getSupportedServiceNames()208 Sequence< ::rtl::OUString > SAL_CALL FormOperations::getSupportedServiceNames( ) throw (RuntimeException)
209 {
210 return getSupportedServiceNames_Static();
211 }
212
213 //--------------------------------------------------------------------
getCursor()214 Reference< XRowSet > SAL_CALL FormOperations::getCursor() throw (RuntimeException)
215 {
216 MethodGuard aGuard( *this );
217 return m_xCursor;
218 }
219
220 //--------------------------------------------------------------------
getUpdateCursor()221 Reference< XResultSetUpdate > SAL_CALL FormOperations::getUpdateCursor() throw (RuntimeException)
222 {
223 MethodGuard aGuard( *this );
224 return m_xUpdateCursor;
225 }
226
227 //--------------------------------------------------------------------
getController()228 Reference< XFormController > SAL_CALL FormOperations::getController() throw (RuntimeException)
229 {
230 MethodGuard aGuard( *this );
231 return m_xController;
232 }
233
234 //--------------------------------------------------------------------
getFeatureInvalidation()235 Reference< XFeatureInvalidation > SAL_CALL FormOperations::getFeatureInvalidation() throw (RuntimeException)
236 {
237 MethodGuard aGuard( *this );
238 return m_xFeatureInvalidation;
239 }
240
241 //--------------------------------------------------------------------
setFeatureInvalidation(const Reference<XFeatureInvalidation> & _rxFeatureInvalidation)242 void SAL_CALL FormOperations::setFeatureInvalidation( const Reference< XFeatureInvalidation > & _rxFeatureInvalidation ) throw (RuntimeException)
243 {
244 MethodGuard aGuard( *this );
245 m_xFeatureInvalidation = _rxFeatureInvalidation;
246 }
247
248 //--------------------------------------------------------------------
getState(::sal_Int16 _nFeature)249 FeatureState SAL_CALL FormOperations::getState( ::sal_Int16 _nFeature ) throw (RuntimeException)
250 {
251 MethodGuard aGuard( *this );
252
253 FeatureState aState;
254 aState.Enabled = sal_False;
255
256 try
257 {
258 // some checks for basic pre-requisites
259 if ( !m_xLoadableForm.is()
260 || !m_xLoadableForm->isLoaded()
261 || !m_xCursorProperties.is()
262 )
263 {
264 return aState;
265 }
266
267 switch ( _nFeature )
268 {
269 case FormFeature::MoveToFirst:
270 case FormFeature::MoveToPrevious:
271 aState.Enabled = impl_canMoveLeft_throw( );
272 break;
273
274 case FormFeature::MoveToNext:
275 aState.Enabled = impl_canMoveRight_throw();
276 break;
277
278 case FormFeature::MoveToLast:
279 aState.Enabled = impl_getRowCount_throw() && ( !m_xCursor->isLast() || impl_isInsertionRow_throw() );
280 break;
281
282 case FormFeature::DeleteRecord:
283 // already deleted ?
284 if ( m_xCursor->rowDeleted() )
285 aState.Enabled = sal_False;
286 else
287 {
288 // allowed to delete the row ?
289 aState.Enabled = !impl_isInsertionRow_throw() && ::dbtools::canDelete( m_xCursorProperties );
290 }
291 break;
292
293 case FormFeature::MoveToInsertRow:
294 // if we are inserting we can move to the next row if the current record or control is modified
295 aState.Enabled = impl_isInsertionRow_throw()
296 ? impl_isModifiedRow_throw() || m_bActiveControlModified
297 : ::dbtools::canInsert( m_xCursorProperties );
298 break;
299
300 case FormFeature::ReloadForm:
301 {
302 // there must be an active connection
303 Reference< XRowSet > xCursorRowSet( m_xCursor, UNO_QUERY );
304 aState.Enabled = ::dbtools::getConnection( xCursorRowSet ).is();
305
306 // and an active command
307 ::rtl::OUString sActiveCommand;
308 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sActiveCommand;
309 aState.Enabled &= sActiveCommand.getLength() > 0;
310 }
311 break;
312
313 case FormFeature::RefreshCurrentControl:
314 {
315 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
316 aState.Enabled = xControlModelRefresh.is();
317 }
318 break;
319
320 case FormFeature::SaveRecordChanges:
321 case FormFeature::UndoRecordChanges:
322 aState.Enabled = impl_isModifiedRow_throw() || m_bActiveControlModified;
323 break;
324
325 case FormFeature::RemoveFilterAndSort:
326 if ( impl_isParseable_throw() && impl_hasFilterOrOrder_throw() )
327 aState.Enabled = !impl_isInsertOnlyForm_throw();
328 break;
329
330 case FormFeature::SortAscending:
331 case FormFeature::SortDescending:
332 case FormFeature::AutoFilter:
333 if ( m_xController.is() && impl_isParseable_throw() )
334 {
335 sal_Bool bIsDeleted = m_xCursor->rowDeleted();
336
337 if ( !bIsDeleted && !impl_isInsertOnlyForm_throw() )
338 {
339 Reference< XPropertySet > xBoundField = impl_getCurrentBoundField_nothrow( );
340 if ( xBoundField.is() )
341 xBoundField->getPropertyValue( PROPERTY_SEARCHABLE ) >>= aState.Enabled;
342 }
343 }
344 break;
345
346 case FormFeature::InteractiveSort:
347 case FormFeature::InteractiveFilter:
348 if ( impl_isParseable_throw() )
349 aState.Enabled = !impl_isInsertOnlyForm_throw();
350 break;
351
352 case FormFeature::ToggleApplyFilter:
353 {
354 ::rtl::OUString sFilter;
355 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
356 if ( sFilter.getLength() )
357 {
358 aState.State = m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER );
359 aState.Enabled = !impl_isInsertOnlyForm_throw();
360 }
361 else
362 aState.State <<= (sal_Bool)sal_False;
363 }
364 break;
365
366 case FormFeature::MoveAbsolute:
367 {
368 sal_Int32 nPosition = m_xCursor->getRow();
369 sal_Bool bIsNew = impl_isInsertionRow_throw();
370 sal_Int32 nCount = impl_getRowCount_throw();
371 sal_Bool bFinalCount = impl_isRowCountFinal_throw();
372
373 if ( ( nPosition >= 0 ) || bIsNew )
374 {
375 if ( bFinalCount )
376 {
377 // special case: there are no records at all, and we
378 // can't insert records -> disabled
379 if ( !nCount && !::dbtools::canInsert( m_xCursorProperties ) )
380 {
381 aState.Enabled = sal_False;
382 }
383 else
384 {
385 if ( bIsNew )
386 nPosition = ++nCount;
387 aState.State <<= (sal_Int32)nPosition;
388 aState.Enabled = sal_True;
389 }
390 }
391 else
392 {
393 aState.State <<= (sal_Int32)nPosition;
394 aState.Enabled = sal_True;
395 }
396 }
397 }
398 break;
399
400 case FormFeature::TotalRecords:
401 {
402 sal_Bool bIsNew = impl_isInsertionRow_throw();
403 sal_Int32 nCount = impl_getRowCount_throw();
404 sal_Bool bFinalCount = impl_isRowCountFinal_throw();
405
406 if ( bIsNew )
407 ++nCount;
408
409 ::rtl::OUString sValue = ::rtl::OUString::valueOf( sal_Int32( nCount ) );
410 if ( !bFinalCount )
411 sValue += ::rtl::OUString::createFromAscii( " *" );
412
413 aState.State <<= sValue;
414 aState.Enabled = sal_True;
415 }
416 break;
417
418 default:
419 OSL_ENSURE( sal_False, "FormOperations::getState: unknown feature id!" );
420 break;
421 }
422 }
423 catch( const Exception& )
424 {
425 OSL_ENSURE( sal_False, "FormOperations::getState: caught an exception!" );
426 }
427
428 return aState;
429 }
430
431 //--------------------------------------------------------------------
isEnabled(::sal_Int16 _nFeature)432 ::sal_Bool SAL_CALL FormOperations::isEnabled( ::sal_Int16 _nFeature ) throw (RuntimeException)
433 {
434 MethodGuard aGuard( *this );
435
436 FeatureState aState( getState( _nFeature ) );
437 return aState.Enabled;
438 }
439
440 //--------------------------------------------------------------------
441 namespace
442 {
lcl_needConfirmCommit(sal_Int32 _nFeature)443 static bool lcl_needConfirmCommit( sal_Int32 _nFeature )
444 {
445 return ( ( _nFeature == FormFeature::ReloadForm )
446 || ( _nFeature == FormFeature::RemoveFilterAndSort )
447 || ( _nFeature == FormFeature::ToggleApplyFilter )
448 || ( _nFeature == FormFeature::SortAscending )
449 || ( _nFeature == FormFeature::SortDescending )
450 || ( _nFeature == FormFeature::AutoFilter )
451 || ( _nFeature == FormFeature::InteractiveSort )
452 || ( _nFeature == FormFeature::InteractiveFilter )
453 );
454 }
lcl_requiresArguments(sal_Int32 _nFeature)455 static bool lcl_requiresArguments( sal_Int32 _nFeature )
456 {
457 return ( _nFeature == FormFeature::MoveAbsolute );
458 }
lcl_isExecutableFeature(sal_Int32 _nFeature)459 static bool lcl_isExecutableFeature( sal_Int32 _nFeature )
460 {
461 return ( _nFeature != FormFeature::TotalRecords );
462 }
463 }
464
465 //--------------------------------------------------------------------
execute(::sal_Int16 _nFeature)466 void SAL_CALL FormOperations::execute( ::sal_Int16 _nFeature ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException)
467 {
468 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
469 MethodGuard aGuard( *this );
470
471 if ( ( _nFeature != FormFeature::DeleteRecord ) && ( _nFeature != FormFeature::UndoRecordChanges ) )
472 {
473 // if we have a controller, commit the current control
474 if ( m_xController.is() )
475 if ( !impl_commitCurrentControl_throw() )
476 return;
477
478 // commit the current record
479 bool bCommitCurrentRecord = true;
480 // (but before, let the user confirm if necessary)
481 if ( impl_isModifiedRow_throw() )
482 {
483 if ( lcl_needConfirmCommit( _nFeature ) )
484 {
485 // TODO: shouldn't this be done with an interaction handler?
486 QueryBox aQuery( NULL, WB_YES_NO_CANCEL | WB_DEF_YES, FRM_RES_STRING( RID_STR_QUERY_SAVE_MODIFIED_ROW ) );
487 switch ( aQuery.Execute() )
488 {
489 case RET_NO: bCommitCurrentRecord = false; break;
490 case RET_CANCEL: return;
491 }
492 }
493 }
494
495 if ( bCommitCurrentRecord && !impl_commitCurrentRecord_throw() )
496 return;
497 }
498
499 try
500 {
501 switch ( _nFeature )
502 {
503 case FormFeature::MoveToFirst:
504 m_xCursor->first();
505 break;
506
507 case FormFeature::MoveToNext:
508 impl_moveRight_throw( );
509 break;
510
511 case FormFeature::MoveToPrevious:
512 impl_moveLeft_throw( );
513 break;
514
515 case FormFeature::MoveToLast:
516 {
517 /*
518 // TODO: re-implement this .....
519 // run in an own thread if ...
520 // ... the data source is thread safe ...
521 sal_Bool bAllowOwnThread = sal_False;
522 if ( ::comphelper::hasProperty( PROPERTY_THREADSAFE, m_xCursorProperties ) )
523 m_xCursorProperties->getPropertyValue( PROPERTY_THREADSAFE ) >>= bAllowOwnThread;
524
525 // ... the record count is unknown
526 sal_Bool bNeedOwnThread sal_False;
527 if ( ::comphelper::hasProperty( PROPERTY_ROWCOUNTFINAL, m_xCursorProperties ) )
528 m_xCursorProperties->getPropertyValue( PROPERTY_ROWCOUNTFINAL ) >>= bNeedOwnThread;
529
530 if ( bNeedOwnThread && bAllowOwnThread )
531 ;
532 else
533 */
534 m_xCursor->last();
535 }
536 break;
537
538 case FormFeature::ReloadForm:
539 if ( m_xLoadableForm.is() )
540 {
541 WaitObject aWO( NULL );
542 m_xLoadableForm->reload();
543
544 // refresh all controls in the form (and sub forms) which can be refreshed
545 // #i90914# / 2008-07-02 / frank.schoenheit@sun.com
546 ::comphelper::IndexAccessIterator aIter( m_xLoadableForm );
547 Reference< XInterface > xElement( aIter.Next() );
548 while ( xElement.is() )
549 {
550 Reference< XRefreshable > xRefresh( xElement, UNO_QUERY );
551 if ( xRefresh.is() )
552 xRefresh->refresh();
553 xElement = aIter.Next();
554 }
555 }
556 break;
557
558 case FormFeature::RefreshCurrentControl:
559 {
560 Reference< XRefreshable > xControlModelRefresh( impl_getCurrentControlModel_throw(), UNO_QUERY );
561 OSL_ENSURE( xControlModelRefresh.is(), "FormOperations::execute: how did you reach this?" );
562 if ( xControlModelRefresh.is() )
563 xControlModelRefresh->refresh();
564 }
565 break;
566
567 case FormFeature::DeleteRecord:
568 {
569 sal_uInt32 nCount = impl_getRowCount_throw();
570
571 // next position
572 sal_Bool bLeft = m_xCursor->isLast() && ( nCount > 1 );
573 sal_Bool bRight= !m_xCursor->isLast();
574 sal_Bool bSuccess = sal_False;
575 try
576 {
577 // ask for confirmation
578 Reference< XConfirmDeleteListener > xConfirmDelete( m_xController, UNO_QUERY );
579
580 if ( xConfirmDelete.is() )
581 {
582 RowChangeEvent aEvent;
583 aEvent.Source = Reference< XInterface >( m_xCursor, UNO_QUERY );
584 aEvent.Action = RowChangeAction::DELETE;
585 aEvent.Rows = 1;
586 bSuccess = xConfirmDelete->confirmDelete( aEvent );
587 }
588
589 // delete it
590 if ( bSuccess )
591 m_xUpdateCursor->deleteRow();
592 }
593 catch( const Exception& )
594 {
595 bSuccess = sal_False;
596 }
597
598 if ( bSuccess )
599 {
600 if ( bLeft || bRight )
601 m_xCursor->relative( bRight ? 1 : -1 );
602 else
603 {
604 sal_Bool bCanInsert = ::dbtools::canInsert( m_xCursorProperties );
605 // is it possible to insert another record?
606 if ( bCanInsert )
607 m_xUpdateCursor->moveToInsertRow();
608 else
609 // move record to update stati
610 m_xCursor->first();
611 }
612 }
613 }
614 break;
615
616 case FormFeature::SaveRecordChanges:
617 case FormFeature::UndoRecordChanges:
618 {
619 sal_Bool bInserting = impl_isInsertionRow_throw();
620
621 if ( FormFeature::UndoRecordChanges == _nFeature )
622 {
623 if ( !bInserting )
624 m_xUpdateCursor->cancelRowUpdates();
625
626 // reset all controls for this form
627 impl_resetAllControls_nothrow( );
628
629 if ( bInserting ) // back to insertion mode for this form
630 m_xUpdateCursor->moveToInsertRow();
631 }
632 else
633 {
634 if ( bInserting )
635 {
636 m_xUpdateCursor->insertRow();
637 m_xCursor->last();
638 }
639 else
640 m_xUpdateCursor->updateRow();
641 }
642 }
643 break;
644
645 case FormFeature::MoveToInsertRow:
646 // move to the last row before moving to the insert row
647 // 21.01.2002 - 96480 - fs@openoffice.org
648 m_xCursor->last();
649 m_xUpdateCursor->moveToInsertRow();
650 break;
651
652 case FormFeature::RemoveFilterAndSort:
653 {
654 // simultaneously reset Filter and Order property
655 Reference< XMultiPropertySet > xProperties( m_xCursorProperties, UNO_QUERY );
656 OSL_ENSURE( xProperties.is(), "FormOperations::execute: no multi property access!" );
657 if ( xProperties.is() )
658 {
659 Sequence< ::rtl::OUString > aNames( 2 );
660 aNames[0] = PROPERTY_FILTER;
661 aNames[1] = PROPERTY_SORT;
662
663 Sequence< Any> aValues( 2 );
664 aValues[0] <<= ::rtl::OUString();
665 aValues[1] <<= ::rtl::OUString();
666
667 WaitObject aWO( NULL );
668 xProperties->setPropertyValues( aNames, aValues );
669
670 if ( m_xLoadableForm.is() )
671 m_xLoadableForm->reload();
672 }
673 }
674 break;
675
676 case FormFeature::ToggleApplyFilter:
677 if ( impl_commitCurrentControl_throw() && impl_commitCurrentRecord_throw() )
678 {
679 // simply toggle the value
680 sal_Bool bApplied = sal_False;
681 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
682 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( (sal_Bool)!bApplied ) );
683
684 // and reload
685 WaitObject aWO( NULL );
686 m_xLoadableForm->reload();
687 }
688 break;
689
690 case FormFeature::SortAscending:
691 impl_executeAutoSort_throw( true );
692 break;
693
694 case FormFeature::SortDescending:
695 impl_executeAutoSort_throw( false );
696 break;
697
698 case FormFeature::AutoFilter:
699 impl_executeAutoFilter_throw();
700 break;
701
702 case FormFeature::InteractiveSort:
703 impl_executeFilterOrSort_throw( false );
704 break;
705
706 case FormFeature::InteractiveFilter:
707 impl_executeFilterOrSort_throw( true );
708 break;
709
710 default:
711 {
712 sal_uInt16 nErrorResourceId = RID_STR_FEATURE_UNKNOWN;
713 if ( lcl_requiresArguments( _nFeature ) )
714 nErrorResourceId = RID_STR_FEATURE_REQUIRES_PARAMETERS;
715 else if ( !lcl_isExecutableFeature( _nFeature ) )
716 nErrorResourceId = RID_STR_FEATURE_NOT_EXECUTABLE;
717 throw IllegalArgumentException( FRM_RES_STRING( nErrorResourceId ), *this, 1 );
718 }
719 } // switch
720 }
721 catch( const RuntimeException& ) { throw; }
722 catch( const SQLException& ) { throw; }
723 catch( const IllegalArgumentException& ) { throw; }
724 catch( const Exception& )
725 {
726 throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
727 }
728
729 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
730 }
731
732 //--------------------------------------------------------------------
executeWithArguments(::sal_Int16 _nFeature,const Sequence<NamedValue> & _rArguments)733 void SAL_CALL FormOperations::executeWithArguments( ::sal_Int16 _nFeature, const Sequence< NamedValue >& _rArguments ) throw (RuntimeException, IllegalArgumentException, SQLException, WrappedTargetException)
734 {
735 if ( !lcl_requiresArguments( _nFeature ) )
736 {
737 execute( _nFeature );
738 return;
739 }
740
741 ::vos::OGuard aSolarGuard( Application::GetSolarMutex() );
742 MethodGuard aGuard( *this );
743
744 // at the moment we have only one feature which supports execution parameters
745 if ( !lcl_isExecutableFeature( _nFeature ) )
746 throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_NOT_EXECUTABLE ), *this, 1 );
747
748 switch ( _nFeature )
749 {
750 case FormFeature::MoveAbsolute:
751 {
752 sal_Int32 nPosition = -1;
753
754 ::comphelper::NamedValueCollection aArguments( _rArguments );
755 aArguments.get_ensureType( "Position", nPosition );
756
757 if ( nPosition < 1 )
758 nPosition = 1;
759
760 try
761 {
762 // commit before doing anything else
763 if ( m_xController.is() && !impl_commitCurrentControl_throw() )
764 return;
765 if ( !impl_commitCurrentRecord_throw() )
766 return;
767
768 sal_Int32 nCount = impl_getRowCount_throw();
769 sal_Bool bFinalCount = impl_isRowCountFinal_throw();
770
771 if ( bFinalCount && ( (sal_Int32)nPosition > nCount ) )
772 nPosition = nCount;
773
774 m_xCursor->absolute( nPosition );
775 }
776 catch( const RuntimeException& ) { throw; }
777 catch( const SQLException& ) { throw; }
778 catch( const Exception& )
779 {
780 throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
781 }
782 }
783 break;
784 default:
785 throw IllegalArgumentException( FRM_RES_STRING( RID_STR_FEATURE_UNKNOWN ), *this, 1 );
786 } // switch
787 }
788
789 //--------------------------------------------------------------------
commitCurrentRecord(::sal_Bool & _out_rRecordInserted)790 ::sal_Bool SAL_CALL FormOperations::commitCurrentRecord( ::sal_Bool& _out_rRecordInserted ) throw (RuntimeException, SQLException)
791 {
792 MethodGuard aGuard( *this );
793 _out_rRecordInserted = sal_False;
794
795 return impl_commitCurrentRecord_throw( &_out_rRecordInserted );
796 }
797
798 //--------------------------------------------------------------------
impl_commitCurrentRecord_throw(::sal_Bool * _pRecordInserted) const799 bool FormOperations::impl_commitCurrentRecord_throw( ::sal_Bool* _pRecordInserted ) const
800 {
801 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
802
803 if ( !impl_hasCursor_nothrow() )
804 return false;
805
806 // nothing to do if the record is not modified
807 sal_Bool bResult = !impl_isModifiedRow_throw();
808 if ( !bResult )
809 {
810 // insert respectively update the row
811 if ( impl_isInsertionRow_throw() )
812 {
813 m_xUpdateCursor->insertRow();
814 if ( _pRecordInserted )
815 *_pRecordInserted = sal_True;
816 }
817 else
818 m_xUpdateCursor->updateRow();
819 bResult = true;
820 }
821 return bResult;
822 }
823
824 //--------------------------------------------------------------------
commitCurrentControl()825 ::sal_Bool SAL_CALL FormOperations::commitCurrentControl() throw (RuntimeException, SQLException)
826 {
827 MethodGuard aGuard( *this );
828 return impl_commitCurrentControl_throw();
829 }
830
831 //--------------------------------------------------------------------
impl_commitCurrentControl_throw() const832 bool FormOperations::impl_commitCurrentControl_throw() const
833 {
834 DBG_ASSERT( m_nMethodNestingLevel, "FormOperations::impl_commitCurrentRecord_throw: to be called within a MethodGuard'ed section only!" );
835 OSL_PRECOND( m_xController.is(), "FormOperations::commitCurrentControl: no controller!" );
836 if ( !m_xController.is() )
837 return false;
838
839 bool bSuccess = false;
840 try
841 {
842 Reference< XControl > xCurrentControl( m_xController->getCurrentControl() );
843
844 // check whether the control is locked
845 Reference< XBoundControl > xCheckLock( xCurrentControl, UNO_QUERY );
846 sal_Bool bControlIsLocked = xCheckLock.is() && xCheckLock->getLock();
847
848 // commit if necessary
849 bSuccess = true;
850 if ( xCurrentControl.is() && !bControlIsLocked )
851 {
852 // both the control and it's model can be committable, so try both
853 Reference< XBoundComponent > xBound( xCurrentControl, UNO_QUERY );
854 if ( !xBound.is() )
855 xBound = xBound.query( xCurrentControl->getModel() );
856 // and now really commit
857 if ( xBound.is() )
858 bSuccess = xBound->commit();
859 }
860
861 }
862 catch( const RuntimeException& ) { throw; }
863 catch( const SQLException& ) { throw; }
864 catch( const Exception& )
865 {
866 DBG_UNHANDLED_EXCEPTION();
867 bSuccess = false;
868 }
869
870 return bSuccess;
871 }
872
873 //--------------------------------------------------------------------
isInsertionRow()874 ::sal_Bool SAL_CALL FormOperations::isInsertionRow() throw (RuntimeException, WrappedTargetException)
875 {
876 sal_Bool bIs = sal_False;
877 try
878 {
879 bIs = impl_isInsertionRow_throw();
880 }
881 catch( const RuntimeException& ) { throw; }
882 catch( const Exception& )
883 {
884 throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
885 }
886 return bIs;
887 }
888
889 //--------------------------------------------------------------------
isModifiedRow()890 ::sal_Bool SAL_CALL FormOperations::isModifiedRow() throw (RuntimeException, WrappedTargetException)
891 {
892 sal_Bool bIs = sal_False;
893 try
894 {
895 bIs = impl_isModifiedRow_throw();
896 }
897 catch( const RuntimeException& ) { throw; }
898 catch( const Exception& )
899 {
900 throw WrappedTargetException( ::rtl::OUString(), *this, ::cppu::getCaughtException() );
901 }
902 return bIs;
903 }
904
905 //--------------------------------------------------------------------
cursorMoved(const EventObject &)906 void SAL_CALL FormOperations::cursorMoved( const EventObject& /*_Event*/ ) throw (RuntimeException)
907 {
908 MethodGuard aGuard( *this );
909 m_bActiveControlModified = sal_False;
910
911 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
912 }
913
914 //--------------------------------------------------------------------
rowChanged(const EventObject &)915 void SAL_CALL FormOperations::rowChanged( const EventObject& /*_Event*/ ) throw (RuntimeException)
916 {
917 // not interested in
918 }
919
920 //--------------------------------------------------------------------
rowSetChanged(const EventObject &)921 void SAL_CALL FormOperations::rowSetChanged( const EventObject& /*_Event*/ ) throw (RuntimeException)
922 {
923 // not interested in
924 }
925
926 //--------------------------------------------------------------------
modified(const EventObject &)927 void SAL_CALL FormOperations::modified( const EventObject& /*_Source*/ ) throw( RuntimeException )
928 {
929 MethodGuard aGuard( *this );
930
931 OSL_ENSURE( m_xCursor.is(), "FormOperations::modified: already disposed!" );
932 if ( !m_bActiveControlModified )
933 {
934 m_bActiveControlModified = sal_True;
935 impl_invalidateModifyDependentFeatures_nothrow( aGuard );
936 }
937 }
938
939 //--------------------------------------------------------------------
propertyChange(const PropertyChangeEvent & _rEvent)940 void SAL_CALL FormOperations::propertyChange( const PropertyChangeEvent& _rEvent ) throw (RuntimeException)
941 {
942 MethodGuard aGuard( *this );
943
944 if ( m_xCursor.is() && ( m_xCursor == _rEvent.Source ) )
945 {
946 sal_Bool bIs = sal_False;
947 if ( ( _rEvent.PropertyName == PROPERTY_ISMODIFIED )
948 || ( _rEvent.PropertyName == PROPERTY_ISNEW )
949 )
950 {
951 if ( ( _rEvent.NewValue >>= bIs ) && !bIs )
952 m_bActiveControlModified = sal_False;
953 }
954 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
955 }
956
957 if ( m_xParser.is() && ( m_xCursor == _rEvent.Source ) )
958 {
959 try
960 {
961 ::rtl::OUString sNewValue;
962 _rEvent.NewValue >>= sNewValue;
963 if ( _rEvent.PropertyName == PROPERTY_ACTIVECOMMAND )
964 {
965 m_xParser->setElementaryQuery( sNewValue );
966 }
967 else if ( _rEvent.PropertyName == PROPERTY_FILTER )
968 {
969 if ( m_xParser->getFilter() != sNewValue )
970 m_xParser->setFilter( sNewValue );
971 }
972 else if ( _rEvent.PropertyName == PROPERTY_SORT )
973 {
974 _rEvent.NewValue >>= sNewValue;
975 if ( m_xParser->getOrder() != sNewValue )
976 m_xParser->setOrder( sNewValue );
977 }
978 }
979 catch( Exception& )
980 {
981 OSL_ENSURE( sal_False, "FormOperations::propertyChange: caught an exception while updating the parser!" );
982 }
983 impl_invalidateAllSupportedFeatures_nothrow( aGuard );
984 }
985 }
986
987 //--------------------------------------------------------------------
disposing(const EventObject &)988 void SAL_CALL FormOperations::disposing( const EventObject& /*_Source*/ ) throw (RuntimeException)
989 {
990 // TODO: should we react on this? Or is this the responsibility of our owner to dispose us?
991 }
992
993 //--------------------------------------------------------------------
disposing()994 void SAL_CALL FormOperations::disposing()
995 {
996 ::osl::MutexGuard aGuard( m_aMutex );
997
998 impl_disposeParser_nothrow();
999
1000 try
1001 {
1002 // revoke various listeners
1003 if ( m_xCursor.is() )
1004 m_xCursor->removeRowSetListener( this );
1005
1006 if ( m_xCursorProperties.is() )
1007 {
1008 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISMODIFIED,this );
1009 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ISNEW, this );
1010 }
1011
1012 Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1013 if ( xBroadcaster.is() )
1014 xBroadcaster->removeModifyListener( this );
1015 }
1016 catch( const Exception& )
1017 {
1018 DBG_UNHANDLED_EXCEPTION();
1019 }
1020
1021 m_xController.clear();
1022 m_xCursor.clear();
1023 m_xUpdateCursor.clear();
1024 m_xCursorProperties.clear();
1025 m_xLoadableForm.clear();
1026 m_xFeatureInvalidation.clear();
1027
1028 m_bActiveControlModified = true;
1029 }
1030
1031 //--------------------------------------------------------------------
impl_checkDisposed_throw() const1032 void FormOperations::impl_checkDisposed_throw() const
1033 {
1034 if ( impl_isDisposed_nothrow() )
1035 throw DisposedException( ::rtl::OUString(), *const_cast< FormOperations* >( this ) );
1036 }
1037
1038 //--------------------------------------------------------------------
impl_initFromController_throw()1039 void FormOperations::impl_initFromController_throw()
1040 {
1041 OSL_PRECOND( m_xController.is(), "FormOperations::impl_initFromController_throw: invalid controller!" );
1042 m_xCursor = m_xCursor.query( m_xController->getModel() );
1043 if ( !m_xCursor.is() )
1044 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1045
1046 impl_initFromForm_throw();
1047
1048 Reference< XModifyBroadcaster > xBroadcaster( m_xController, UNO_QUERY );
1049 if ( xBroadcaster.is() )
1050 xBroadcaster->addModifyListener( this );
1051 }
1052
1053 //--------------------------------------------------------------------
impl_initFromForm_throw()1054 void FormOperations::impl_initFromForm_throw()
1055 {
1056 OSL_PRECOND( m_xCursor.is(), "FormOperations::impl_initFromForm_throw: invalid form!" );
1057 m_xCursorProperties = m_xCursorProperties.query ( m_xCursor );
1058 m_xUpdateCursor = m_xUpdateCursor.query ( m_xCursor );
1059 m_xLoadableForm = m_xLoadableForm.query ( m_xCursor );
1060
1061 if ( !m_xCursor.is() || !m_xCursorProperties.is() || !m_xLoadableForm.is() )
1062 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1063
1064 m_xCursor->addRowSetListener( this );
1065 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISMODIFIED,this );
1066 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ISNEW, this );
1067 }
1068
1069 //--------------------------------------------------------------------
createWithFormController(const Reference<XFormController> & _rxController)1070 void FormOperations::createWithFormController( const Reference< XFormController >& _rxController )
1071 {
1072 m_xController = _rxController;
1073 if ( !m_xController.is() )
1074 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1075
1076 impl_initFromController_throw();
1077
1078 m_bConstructed = true;
1079 }
1080
1081 //--------------------------------------------------------------------
createWithForm(const Reference<XForm> & _rxForm)1082 void FormOperations::createWithForm( const Reference< XForm >& _rxForm )
1083 {
1084 m_xCursor = m_xCursor.query( _rxForm );
1085 if ( !m_xCursor.is() )
1086 throw IllegalArgumentException( ::rtl::OUString(), *this, 0 );
1087
1088 impl_initFromForm_throw();
1089
1090 m_bConstructed = true;
1091 }
1092
1093 //------------------------------------------------------------------------------
impl_invalidateAllSupportedFeatures_nothrow(MethodGuard & _rClearForCallback) const1094 void FormOperations::impl_invalidateAllSupportedFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1095 {
1096 if ( !m_xFeatureInvalidation.is() )
1097 // nobody's interested in ...
1098 return;
1099
1100 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1101 _rClearForCallback.clear();
1102 xInvalidation->invalidateAllFeatures();
1103 }
1104
1105 //------------------------------------------------------------------------------
impl_invalidateModifyDependentFeatures_nothrow(MethodGuard & _rClearForCallback) const1106 void FormOperations::impl_invalidateModifyDependentFeatures_nothrow( MethodGuard& _rClearForCallback ) const
1107 {
1108 if ( !m_xFeatureInvalidation.is() )
1109 // nobody's interested in ...
1110 return;
1111
1112 static Sequence< sal_Int16 > s_aModifyDependentFeatures;
1113 if ( s_aModifyDependentFeatures.getLength() == 0 )
1114 {
1115 sal_Int16 pModifyDependentFeatures[] =
1116 {
1117 FormFeature::MoveToNext,
1118 FormFeature::MoveToInsertRow,
1119 FormFeature::SaveRecordChanges,
1120 FormFeature::UndoRecordChanges
1121 };
1122 size_t nFeatureCount = sizeof( pModifyDependentFeatures ) / sizeof( pModifyDependentFeatures[ 0 ] );
1123 s_aModifyDependentFeatures = Sequence< sal_Int16 >( pModifyDependentFeatures, nFeatureCount );
1124 }
1125
1126 Reference< XFeatureInvalidation > xInvalidation = m_xFeatureInvalidation;
1127 _rClearForCallback.clear();
1128
1129 xInvalidation->invalidateFeatures( s_aModifyDependentFeatures );
1130 }
1131
1132 //--------------------------------------------------------------------
impl_ensureInitializedParser_nothrow()1133 void FormOperations::impl_ensureInitializedParser_nothrow()
1134 {
1135 OSL_PRECOND( m_xCursorProperties.is(), "FormOperations::impl_ensureInitializedParser_nothrow: we're disposed!" );
1136 if ( m_bInitializedParser )
1137 return;
1138
1139 try
1140 {
1141 sal_Bool bUseEscapeProcessing = sal_False;
1142 m_xCursorProperties->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bUseEscapeProcessing;
1143 if ( bUseEscapeProcessing )
1144 {
1145 Reference< XMultiServiceFactory > xFactory( ::dbtools::getConnection( m_xCursor ), UNO_QUERY );
1146 if ( xFactory.is() )
1147 {
1148 m_xParser.set( xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.SingleSelectQueryComposer" ) ) ), UNO_QUERY );
1149 OSL_ENSURE( m_xParser.is(), "FormOperations::impl_ensureInitializedParser_nothrow: factory did not create a parser for us!" );
1150 }
1151 }
1152
1153 if ( m_xParser.is() )
1154 {
1155 if ( m_xLoadableForm.is() && m_xLoadableForm->isLoaded() )
1156 {
1157 ::rtl::OUString sStatement;
1158 ::rtl::OUString sFilter;
1159 ::rtl::OUString sSort;
1160
1161 m_xCursorProperties->getPropertyValue( PROPERTY_ACTIVECOMMAND ) >>= sStatement;
1162 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sFilter;
1163 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sSort;
1164
1165 m_xParser->setElementaryQuery( sStatement );
1166 m_xParser->setFilter ( sFilter );
1167 m_xParser->setOrder ( sSort );
1168 }
1169
1170 // start listening at the order/sort properties at the form, so
1171 // we can keep our parser in sync
1172 m_xCursorProperties->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1173 m_xCursorProperties->addPropertyChangeListener( PROPERTY_FILTER, this );
1174 m_xCursorProperties->addPropertyChangeListener( PROPERTY_SORT, this );
1175 }
1176 }
1177 catch( const Exception& )
1178 {
1179 OSL_ENSURE( sal_False, "FormOperations::impl_ensureInitializedParser_nothrow: caught an exception!" );
1180 }
1181
1182 m_bInitializedParser = true;
1183 }
1184
1185 //--------------------------------------------------------------------
impl_disposeParser_nothrow()1186 void FormOperations::impl_disposeParser_nothrow()
1187 {
1188 try
1189 {
1190 // if we have a parser (and a cursor), then we're listening at the cursor's
1191 // properties to keep the parser in sync with the cursor
1192 if ( m_xParser.is() && m_xCursorProperties.is() )
1193 {
1194 m_xCursorProperties->removePropertyChangeListener( PROPERTY_FILTER, this );
1195 m_xCursorProperties->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this );
1196 m_xCursorProperties->removePropertyChangeListener( PROPERTY_SORT, this );
1197 }
1198
1199 Reference< XComponent > xParserComp( m_xParser, UNO_QUERY );
1200 if ( xParserComp.is() )
1201 xParserComp->dispose();
1202 m_xParser.clear();
1203
1204 m_bInitializedParser = false;
1205 }
1206 catch( const Exception& )
1207 {
1208 OSL_ENSURE( sal_False, "FormOperations::impl_disposeParser_nothrow: caught an exception!" );
1209 }
1210 }
1211
1212 //--------------------------------------------------------------------
impl_canMoveLeft_throw() const1213 bool FormOperations::impl_canMoveLeft_throw( ) const
1214 {
1215 if ( !impl_hasCursor_nothrow() )
1216 return false;
1217
1218 return impl_getRowCount_throw() && ( !m_xCursor->isFirst() || impl_isInsertionRow_throw() );
1219 }
1220
1221 //--------------------------------------------------------------------
impl_canMoveRight_throw() const1222 bool FormOperations::impl_canMoveRight_throw( ) const
1223 {
1224 if ( !impl_hasCursor_nothrow() )
1225 return false;
1226
1227 bool bIsNew = impl_isInsertionRow_throw();
1228
1229 if ( impl_getRowCount_throw() && !m_xCursor->isLast() && !bIsNew )
1230 return true;
1231
1232 if ( ::dbtools::canInsert( m_xCursorProperties ) )
1233 if ( !bIsNew || impl_isModifiedRow_throw() )
1234 return true;
1235
1236 if ( bIsNew && m_bActiveControlModified )
1237 return true;
1238
1239 return false;
1240 }
1241
1242 //--------------------------------------------------------------------
1243 namespace
1244 {
1245 template < typename TYPE >
lcl_safeGetPropertyValue_throw(const Reference<XPropertySet> & _rxProperties,const::rtl::OUString & _rPropertyName,TYPE _Default)1246 TYPE lcl_safeGetPropertyValue_throw( const Reference< XPropertySet >& _rxProperties, const ::rtl::OUString& _rPropertyName, TYPE _Default )
1247 {
1248 TYPE value( _Default );
1249 OSL_PRECOND( _rxProperties.is(), "FormOperations::<foo>: no cursor (already disposed?)!" );
1250 if ( _rxProperties.is() )
1251 OSL_VERIFY( _rxProperties->getPropertyValue( _rPropertyName ) >>= value );
1252 return value;
1253 }
1254 }
1255
1256 //--------------------------------------------------------------------
impl_isInsertionRow_throw() const1257 bool FormOperations::impl_isInsertionRow_throw() const
1258 {
1259 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISNEW, false );
1260 }
1261
1262 //--------------------------------------------------------------------
impl_getRowCount_throw() const1263 sal_Int32 FormOperations::impl_getRowCount_throw() const
1264 {
1265 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNT, (sal_Int32)0 );
1266 }
1267 //--------------------------------------------------------------------
impl_isRowCountFinal_throw() const1268 bool FormOperations::impl_isRowCountFinal_throw() const
1269 {
1270 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ROWCOUNTFINAL, false );
1271 }
1272
1273 //--------------------------------------------------------------------
impl_isModifiedRow_throw() const1274 bool FormOperations::impl_isModifiedRow_throw() const
1275 {
1276 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_ISMODIFIED, false );
1277 }
1278
1279 //--------------------------------------------------------------------
impl_isParseable_throw() const1280 bool FormOperations::impl_isParseable_throw() const
1281 {
1282 const_cast< FormOperations* >( this )->impl_ensureInitializedParser_nothrow();
1283 return m_xParser.is() && m_xParser->getQuery().getLength();
1284 }
1285
1286 //--------------------------------------------------------------------
impl_hasFilterOrOrder_throw() const1287 bool FormOperations::impl_hasFilterOrOrder_throw() const
1288 {
1289 return impl_isParseable_throw() && ( m_xParser->getFilter().getLength() || m_xParser->getOrder().getLength() );
1290 }
1291
1292 //--------------------------------------------------------------------
impl_isInsertOnlyForm_throw() const1293 bool FormOperations::impl_isInsertOnlyForm_throw() const
1294 {
1295 return lcl_safeGetPropertyValue_throw( m_xCursorProperties, PROPERTY_INSERTONLY, true );
1296 }
1297
1298 //------------------------------------------------------------------------------
impl_getCurrentControlModel_throw() const1299 Reference< XControlModel > FormOperations::impl_getCurrentControlModel_throw() const
1300 {
1301 Reference< XControl > xControl( m_xController->getCurrentControl() );
1302
1303 // special handling for grid controls
1304 Reference< XGrid > xGrid( xControl, UNO_QUERY );
1305 Reference< XControlModel > xControlModel;
1306
1307 if ( xGrid.is() )
1308 {
1309 Reference< XIndexAccess > xColumns( xControl->getModel(), UNO_QUERY_THROW );
1310 sal_Int16 nCurrentPos = xGrid->getCurrentColumnPosition();
1311 nCurrentPos = impl_gridView2ModelPos_nothrow( xColumns, nCurrentPos );
1312
1313 if ( nCurrentPos != (sal_Int16)-1 )
1314 xColumns->getByIndex( nCurrentPos ) >>= xControlModel;
1315 }
1316 else if ( xControl.is() )
1317 {
1318 xControlModel = xControl->getModel();
1319 }
1320 return xControlModel;
1321 }
1322
1323 //------------------------------------------------------------------------------
impl_getCurrentBoundField_nothrow() const1324 Reference< XPropertySet > FormOperations::impl_getCurrentBoundField_nothrow( ) const
1325 {
1326 OSL_PRECOND( m_xController.is(), "FormOperations::impl_getCurrentBoundField_nothrow: no controller -> no control!" );
1327 if ( !m_xController.is() )
1328 return NULL;
1329
1330 Reference< XPropertySet > xField;
1331 try
1332 {
1333 Reference< XPropertySet > xControlModel( impl_getCurrentControlModel_throw(), UNO_QUERY );
1334
1335 if ( xControlModel.is() && ::comphelper::hasProperty( PROPERTY_BOUNDFIELD, xControlModel ) )
1336 xControlModel->getPropertyValue( PROPERTY_BOUNDFIELD ) >>= xField;
1337
1338 }
1339 catch( const Exception& )
1340 {
1341 DBG_UNHANDLED_EXCEPTION();
1342 }
1343
1344 return xField;
1345 }
1346
1347 //------------------------------------------------------------------------------
impl_gridView2ModelPos_nothrow(const Reference<XIndexAccess> & _rxColumns,sal_Int16 _nViewPos) const1348 sal_Int16 FormOperations::impl_gridView2ModelPos_nothrow( const Reference< XIndexAccess >& _rxColumns, sal_Int16 _nViewPos ) const
1349 {
1350 OSL_PRECOND( _rxColumns.is(), "FormOperations::impl_gridView2ModelPos_nothrow: invalid columns container!" );
1351 try
1352 {
1353 // loop through all columns
1354 sal_Int16 col = 0;
1355 Reference< XPropertySet > xCol;
1356 bool bHidden( false );
1357 for ( col = 0; col < _rxColumns->getCount(); ++col )
1358 {
1359 _rxColumns->getByIndex( col ) >>= xCol;
1360 OSL_VERIFY( xCol->getPropertyValue( PROPERTY_HIDDEN ) >>= bHidden );
1361 if ( bHidden )
1362 continue;
1363
1364 // for every visible col : if nViewPos is greater zero, decrement it, else we
1365 // have found the model position
1366 if ( !_nViewPos )
1367 break;
1368 else
1369 --_nViewPos;
1370 }
1371 if ( col < _rxColumns->getCount() )
1372 return col;
1373 }
1374 catch( const Exception& )
1375 {
1376 DBG_UNHANDLED_EXCEPTION();
1377 }
1378 return (sal_Int16)-1;
1379 }
1380
1381 //------------------------------------------------------------------------------
impl_moveLeft_throw() const1382 bool FormOperations::impl_moveLeft_throw( ) const
1383 {
1384 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveLeft_throw: no cursor!" );
1385 if ( !impl_hasCursor_nothrow() )
1386 return false;
1387
1388 sal_Bool bRecordInserted = sal_False;
1389 sal_Bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1390
1391 if ( !bSuccess )
1392 return false;
1393
1394 if ( bRecordInserted )
1395 {
1396 // retrieve the bookmark of the new record and move to the record preceding this bookmark
1397 Reference< XRowLocate > xLocate( m_xCursor, UNO_QUERY );
1398 OSL_ENSURE( xLocate.is(), "FormOperations::impl_moveLeft_throw: no XRowLocate!" );
1399 if ( xLocate.is() )
1400 xLocate->moveRelativeToBookmark( xLocate->getBookmark(), -1 );
1401 }
1402 else
1403 {
1404 if ( impl_isInsertionRow_throw() )
1405 {
1406 // we assume that the inserted record is now the last record in the
1407 // result set
1408 m_xCursor->last();
1409 }
1410 else
1411 m_xCursor->previous();
1412 }
1413
1414 return true;
1415 }
1416
1417 //--------------------------------------------------------------------
impl_moveRight_throw() const1418 bool FormOperations::impl_moveRight_throw( ) const
1419 {
1420 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_moveRight_throw: no cursor!" );
1421 if ( !impl_hasCursor_nothrow() )
1422 return false;
1423
1424 sal_Bool bRecordInserted = sal_False;
1425 sal_Bool bSuccess = impl_commitCurrentRecord_throw( &bRecordInserted );
1426
1427 if ( !bSuccess )
1428 return false;
1429
1430 if ( bRecordInserted )
1431 {
1432 // go to insert row
1433 m_xUpdateCursor->moveToInsertRow();
1434 }
1435 else
1436 {
1437 if ( m_xCursor->isLast() )
1438 m_xUpdateCursor->moveToInsertRow();
1439 else
1440 m_xCursor->next();
1441 }
1442
1443 return true;
1444 }
1445
1446 //--------------------------------------------------------------------
impl_resetAllControls_nothrow() const1447 void FormOperations::impl_resetAllControls_nothrow() const
1448 {
1449 Reference< XIndexAccess > xContainer( m_xCursor, UNO_QUERY );
1450 if ( !xContainer.is() )
1451 return;
1452
1453 try
1454 {
1455 Reference< XReset > xReset;
1456 sal_Int32 nCount( xContainer->getCount() );
1457 for ( sal_Int32 i = 0; i < nCount; ++i )
1458 {
1459 if ( xContainer->getByIndex( i ) >>= xReset )
1460 {
1461 // no resets on sub forms
1462 Reference< XForm > xAsForm( xReset, UNO_QUERY );
1463 if ( !xAsForm.is() )
1464 xReset->reset();
1465 }
1466 }
1467 }
1468 catch( const Exception& )
1469 {
1470 DBG_UNHANDLED_EXCEPTION();
1471 }
1472 }
1473
1474 //------------------------------------------------------------------------------
impl_executeAutoSort_throw(bool _bUp) const1475 void FormOperations::impl_executeAutoSort_throw( bool _bUp ) const
1476 {
1477 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoSort_throw: need a controller for this!" );
1478 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoSort_throw: need a cursor for this!" );
1479 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoSort_throw: need a parseable statement for this!" );
1480 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1481 return;
1482
1483 try
1484 {
1485 Reference< XControl > xControl = m_xController->getCurrentControl();
1486 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1487 return;
1488
1489 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1490 if ( !xBoundField.is() )
1491 return;
1492
1493 ::rtl::OUString sOriginalSort;
1494 m_xCursorProperties->getPropertyValue( PROPERTY_SORT ) >>= sOriginalSort;
1495
1496 // automatic sort by field is expected to always resets the previous sort order
1497 m_xParser->setOrder( ::rtl::OUString() );
1498
1499 param_appendOrderByColumn aParam;
1500 aParam.xField = xBoundField;
1501 aParam.bUp = _bUp;
1502 impl_doActionInSQLContext_throw(
1503 (Action)&FormOperations::impl_appendOrderByColumn_throw,
1504 static_cast< const void* >( &aParam ),
1505 (sal_uInt16)RID_STR_COULD_NOT_SET_ORDER
1506 );
1507
1508 WaitObject aWO( NULL );
1509 try
1510 {
1511 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1512 m_xLoadableForm->reload();
1513 }
1514 catch( const Exception& )
1515 {
1516 OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoSort_throw: caught an exception while setting the parser properties!" );
1517 }
1518
1519
1520 if ( !m_xLoadableForm->isLoaded() )
1521 { // something went wrong -> restore the original state
1522 try
1523 {
1524 m_xParser->setOrder( sOriginalSort );
1525 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1526 m_xLoadableForm->reload();
1527 }
1528 catch( const Exception& )
1529 {
1530 OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoSort_throw: could not reset the form to it's original state!" );
1531 }
1532
1533 }
1534 }
1535 catch( const RuntimeException& ) { throw; }
1536 catch( const SQLException& ) { throw; }
1537 catch( const Exception& )
1538 {
1539 throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1540 }
1541 }
1542
1543 //------------------------------------------------------------------------------
impl_executeAutoFilter_throw() const1544 void FormOperations::impl_executeAutoFilter_throw( ) const
1545 {
1546 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeAutoFilter_throw: need a controller for this!" );
1547 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeAutoFilter_throw: need a cursor for this!" );
1548 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeAutoFilter_throw: need a parseable statement for this!" );
1549 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1550 return;
1551
1552 try
1553 {
1554 Reference< XControl > xControl = m_xController->getCurrentControl();
1555 if ( !xControl.is() || !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1556 return;
1557
1558 Reference< XPropertySet > xBoundField( impl_getCurrentBoundField_nothrow() );
1559 if ( !xBoundField.is() )
1560 return;
1561
1562 ::rtl::OUString sOriginalFilter;
1563 m_xCursorProperties->getPropertyValue( PROPERTY_FILTER ) >>= sOriginalFilter;
1564 sal_Bool bApplied = sal_True;
1565 m_xCursorProperties->getPropertyValue( PROPERTY_APPLYFILTER ) >>= bApplied;
1566
1567 // if we have a filter, but it's not applied, then we have to overwrite it, else append one
1568 if ( !bApplied )
1569 m_xParser->setFilter( ::rtl::OUString() );
1570
1571 param_appendFilterByColumn aParam;
1572 aParam.xField = xBoundField;
1573 impl_doActionInSQLContext_throw(
1574 (Action)&FormOperations::impl_appendFilterByColumn_throw,
1575 static_cast< const void* >( &aParam ),
1576 (sal_uInt16)RID_STR_COULD_NOT_SET_FILTER
1577 );
1578
1579 WaitObject aWO( NULL );
1580 try
1581 {
1582 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1583 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( (sal_Bool)sal_True ) );
1584
1585 m_xLoadableForm->reload();
1586 }
1587 catch( const Exception& )
1588 {
1589 OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoFilter_throw: caught an exception while setting the parser properties!" );
1590 }
1591
1592
1593 if ( !m_xLoadableForm->isLoaded() )
1594 { // something went wrong -> restore the original state
1595 try
1596 {
1597 m_xParser->setOrder( sOriginalFilter );
1598 m_xCursorProperties->setPropertyValue( PROPERTY_APPLYFILTER, makeAny( (sal_Bool)bApplied ) );
1599 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1600 m_xLoadableForm->reload();
1601 }
1602 catch( const Exception& )
1603 {
1604 OSL_ENSURE( sal_False, "FormOperations::impl_executeAutoFilter_throw: could not reset the form to it's original state!" );
1605 }
1606
1607 }
1608 }
1609 catch( const RuntimeException& ) { throw; }
1610 catch( const SQLException& ) { throw; }
1611 catch( const Exception& )
1612 {
1613 throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1614 }
1615 }
1616
1617 //--------------------------------------------------------------------
impl_executeFilterOrSort_throw(bool _bFilter) const1618 void FormOperations::impl_executeFilterOrSort_throw( bool _bFilter ) const
1619 {
1620 OSL_PRECOND( m_xController.is(), "FormOperations::impl_executeFilterOrSort_throw: need a controller for this!" );
1621 OSL_PRECOND( impl_hasCursor_nothrow(), "FormOperations::impl_executeFilterOrSort_throw: need a cursor for this!" );
1622 OSL_PRECOND( impl_isParseable_throw(), "FormOperations::impl_executeFilterOrSort_throw: need a parseable statement for this!" );
1623 if ( !m_xController.is() || !impl_hasCursor_nothrow() || !impl_isParseable_throw() )
1624 return;
1625
1626 if ( !impl_commitCurrentControl_throw() || !impl_commitCurrentRecord_throw() )
1627 return;
1628 try
1629 {
1630 PropertyValue aFirst;
1631 aFirst.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "QueryComposer" ) );
1632 aFirst.Value <<= m_xParser;
1633
1634 PropertyValue aSecond;
1635 aSecond.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "RowSet" ) );
1636 aSecond.Value <<= m_xCursorProperties;
1637
1638 Sequence<Any> aInit(2);
1639 aInit[0] <<= aFirst;
1640 aInit[1] <<= aSecond;
1641
1642 ::rtl::OUString sDialogServiceName;
1643 if ( _bFilter )
1644 sDialogServiceName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.FilterDialog" ) );
1645 else
1646 sDialogServiceName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sdb.OrderDialog" ) );
1647
1648 Reference< XExecutableDialog> xDialog;
1649 m_aContext.createComponentWithArguments( sDialogServiceName, aInit, xDialog );
1650
1651 if ( !xDialog.is() )
1652 {
1653 ShowServiceNotAvailableError( NULL, sDialogServiceName, sal_True );
1654 return;
1655 }
1656
1657 if ( RET_OK == xDialog->execute() )
1658 {
1659 WaitObject aWO( NULL );
1660 if ( _bFilter )
1661 m_xCursorProperties->setPropertyValue( PROPERTY_FILTER, makeAny( m_xParser->getFilter() ) );
1662 else
1663 m_xCursorProperties->setPropertyValue( PROPERTY_SORT, makeAny( m_xParser->getOrder() ) );
1664 m_xLoadableForm->reload();
1665 }
1666
1667 }
1668 catch( const RuntimeException& ) { throw; }
1669 catch( const SQLException& ) { throw; }
1670 catch( const Exception& )
1671 {
1672 throw WrappedTargetException( ::rtl::OUString(), *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1673 }
1674 }
1675
1676 //------------------------------------------------------------------------------
impl_appendOrderByColumn_throw(const void * _pActionParam) const1677 void FormOperations::impl_appendOrderByColumn_throw( const void* _pActionParam ) const
1678 {
1679 const param_appendOrderByColumn* pParam = static_cast< const param_appendOrderByColumn* >( _pActionParam );
1680 m_xParser->appendOrderByColumn( pParam->xField, pParam->bUp );
1681 }
1682
1683 //------------------------------------------------------------------------------
impl_appendFilterByColumn_throw(const void * _pActionParam) const1684 void FormOperations::impl_appendFilterByColumn_throw( const void* _pActionParam ) const
1685 {
1686 const param_appendFilterByColumn* pParam = static_cast< const param_appendFilterByColumn* >( _pActionParam );
1687 sal_Int32 nOp = SQLFilterOperator::EQUAL;
1688 if ( pParam->xField.is() )
1689 {
1690 sal_Int32 nType = 0;
1691 pParam->xField->getPropertyValue(PROPERTY_FIELDTYPE) >>= nType;
1692 switch(nType)
1693 {
1694 case DataType::VARCHAR:
1695 case DataType::CHAR:
1696 case DataType::LONGVARCHAR:
1697 nOp = SQLFilterOperator::LIKE;
1698 break;
1699 default:
1700 nOp = SQLFilterOperator::EQUAL;
1701 }
1702 }
1703 m_xParser->appendFilterByColumn( pParam->xField, sal_True,nOp );
1704 }
1705
1706 //------------------------------------------------------------------------------
impl_doActionInSQLContext_throw(Action _pAction,const void * _pParam,sal_uInt16 _nErrorResourceId) const1707 void FormOperations::impl_doActionInSQLContext_throw( Action _pAction, const void* _pParam, sal_uInt16 _nErrorResourceId ) const
1708 {
1709 try
1710 {
1711 (this->*_pAction)( _pParam );
1712 }
1713 catch( const SQLException& e )
1714 {
1715 (void)e;
1716 if ( !_nErrorResourceId )
1717 // no information to prepend
1718 throw;
1719
1720 SQLExceptionInfo aInfo( ::cppu::getCaughtException() );
1721 ::rtl::OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1722 aInfo.prepend( sAdditionalError );
1723 aInfo.doThrow();
1724 }
1725 catch( const RuntimeException& ) { throw; }
1726 catch( const Exception& )
1727 {
1728 ::rtl::OUString sAdditionalError( FRM_RES_STRING( _nErrorResourceId ) );
1729 throw WrappedTargetException( sAdditionalError, *const_cast< FormOperations* >( this ), ::cppu::getCaughtException() );
1730 }
1731 }
1732
1733 //........................................................................
1734 } // namespace frm
1735 //........................................................................
1736