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