diff options
Diffstat (limited to 'svx/source/form/fmshimp.cxx')
-rw-r--r-- | svx/source/form/fmshimp.cxx | 4338 |
1 files changed, 4338 insertions, 0 deletions
diff --git a/svx/source/form/fmshimp.cxx b/svx/source/form/fmshimp.cxx new file mode 100644 index 000000000000..52ad139543c5 --- /dev/null +++ b/svx/source/form/fmshimp.cxx @@ -0,0 +1,4338 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" + +#include "fmitems.hxx" +#include "fmobj.hxx" +#include "fmpgeimp.hxx" +#include "svx/fmtools.hxx" +#include "fmprop.hrc" +#include "fmresids.hrc" +#include "fmservs.hxx" +#include "fmshimp.hxx" +#include "fmtextcontrolshell.hxx" +#include "fmundo.hxx" +#include "fmurl.hxx" +#include "fmvwimp.hxx" +#include "formtoolbars.hxx" +#include "gridcols.hxx" +#include "svditer.hxx" +#include "svx/dialmgr.hxx" +#include "svx/dialogs.hrc" +#include "svx/fmglob.hxx" +#include "svx/fmmodel.hxx" +#include "svx/fmpage.hxx" +#include "svx/fmshell.hxx" +#include "svx/obj3d.hxx" +#include "svx/sdrpagewindow.hxx" +#include "svx/svdpagv.hxx" +#include "svx/svxdlg.hxx" +#include "svx/svxids.hrc" + +/** === begin UNO includes === **/ +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/awt/XCheckBox.hpp> +#include <com/sun/star/awt/XListBox.hpp> +#include <com/sun/star/awt/XTextComponent.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/form/ListSourceType.hpp> +#include <com/sun/star/form/XBoundComponent.hpp> +#include <com/sun/star/form/XBoundControl.hpp> +#include <com/sun/star/form/XGrid.hpp> +#include <com/sun/star/form/XGridPeer.hpp> +#include <com/sun/star/form/XLoadable.hpp> +#include <com/sun/star/form/XReset.hpp> +#include <com/sun/star/form/binding/XBindableValue.hpp> +#include <com/sun/star/form/binding/XListEntrySink.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> +#include <com/sun/star/util/XCancellable.hpp> +#include <com/sun/star/util/XModeSelector.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/util/XNumberFormatter.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/beans/XIntrospection.hpp> +/** === end UNO includes === **/ + +#include <comphelper/extract.hxx> +#include <comphelper/evtmethodhelper.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/property.hxx> +#include <comphelper/stl_types.hxx> +#include <connectivity/dbtools.hxx> +#include <cppuhelper/servicefactory.hxx> +#include <osl/mutex.hxx> +#include <rtl/logfile.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/viewsh.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/color.hxx> +#include <tools/diagnose_ex.h> +#include <tools/shl.hxx> +#include <tools/urlobj.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/waitobj.hxx> +#include <vos/mutex.hxx> + +#include <algorithm> +#include <functional> + +// wird fuer Invalidate verwendet -> mitpflegen +sal_uInt16 DatabaseSlotMap[] = +{ + SID_FM_RECORD_FIRST, + SID_FM_RECORD_NEXT, + SID_FM_RECORD_PREV, + SID_FM_RECORD_LAST, + SID_FM_RECORD_NEW, + SID_FM_RECORD_DELETE, + SID_FM_RECORD_ABSOLUTE, + SID_FM_RECORD_TOTAL, + SID_FM_RECORD_SAVE, + SID_FM_RECORD_UNDO, + SID_FM_REMOVE_FILTER_SORT, + SID_FM_SORTUP, + SID_FM_SORTDOWN, + SID_FM_ORDERCRIT, + SID_FM_AUTOFILTER, + SID_FM_FORM_FILTERED, + SID_FM_REFRESH, + SID_FM_REFRESH_FORM_CONTROL, + SID_FM_SEARCH, + SID_FM_FILTER_START, + SID_FM_VIEW_AS_GRID, + 0 +}; + +// wird fuer Invalidate verwendet -> mitpflegen +// aufsteigend sortieren !!!!!! +sal_Int16 DlgSlotMap[] = // slots des Controllers +{ + SID_FM_CTL_PROPERTIES, + SID_FM_PROPERTIES, + SID_FM_TAB_DIALOG, + SID_FM_ADD_FIELD, + SID_FM_SHOW_FMEXPLORER, + SID_FM_FIELDS_CONTROL, + SID_FM_SHOW_PROPERTIES, + SID_FM_PROPERTY_CONTROL, + SID_FM_FMEXPLORER_CONTROL, + SID_FM_SHOW_DATANAVIGATOR, + SID_FM_DATANAVIGATOR_CONTROL, + 0 +}; + +sal_Int16 SelObjectSlotMap[] = // vom SelObject abhaengige Slots +{ + SID_FM_CONVERTTO_EDIT, + SID_FM_CONVERTTO_BUTTON, + SID_FM_CONVERTTO_FIXEDTEXT, + SID_FM_CONVERTTO_LISTBOX, + SID_FM_CONVERTTO_CHECKBOX, + SID_FM_CONVERTTO_RADIOBUTTON, + SID_FM_CONVERTTO_GROUPBOX, + SID_FM_CONVERTTO_COMBOBOX, + SID_FM_CONVERTTO_IMAGEBUTTON, + SID_FM_CONVERTTO_FILECONTROL, + SID_FM_CONVERTTO_DATE, + SID_FM_CONVERTTO_TIME, + SID_FM_CONVERTTO_NUMERIC, + SID_FM_CONVERTTO_CURRENCY, + SID_FM_CONVERTTO_PATTERN, + SID_FM_CONVERTTO_IMAGECONTROL, + SID_FM_CONVERTTO_FORMATTED, + SID_FM_CONVERTTO_SCROLLBAR, + SID_FM_CONVERTTO_SPINBUTTON, + SID_FM_CONVERTTO_NAVIGATIONBAR, + + SID_FM_FMEXPLORER_CONTROL, + SID_FM_DATANAVIGATOR_CONTROL, + + 0 +}; + +// die folgenden Arrays muessen kosistent sein, also einander entsprechende Eintraege an der selben relativen Position +// innerhalb ihres jeweiligen Arrays stehen +sal_Int16 nConvertSlots[] = +{ + SID_FM_CONVERTTO_EDIT, + SID_FM_CONVERTTO_BUTTON, + SID_FM_CONVERTTO_FIXEDTEXT, + SID_FM_CONVERTTO_LISTBOX, + SID_FM_CONVERTTO_CHECKBOX, + SID_FM_CONVERTTO_RADIOBUTTON, + SID_FM_CONVERTTO_GROUPBOX, + SID_FM_CONVERTTO_COMBOBOX, + SID_FM_CONVERTTO_IMAGEBUTTON, + SID_FM_CONVERTTO_FILECONTROL, + SID_FM_CONVERTTO_DATE, + SID_FM_CONVERTTO_TIME, + SID_FM_CONVERTTO_NUMERIC, + SID_FM_CONVERTTO_CURRENCY, + SID_FM_CONVERTTO_PATTERN, + SID_FM_CONVERTTO_IMAGECONTROL, + SID_FM_CONVERTTO_FORMATTED, + SID_FM_CONVERTTO_SCROLLBAR, + SID_FM_CONVERTTO_SPINBUTTON, + SID_FM_CONVERTTO_NAVIGATIONBAR +}; + +sal_Int16 nCreateSlots[] = +{ + SID_FM_EDIT, + SID_FM_PUSHBUTTON, + SID_FM_FIXEDTEXT, + SID_FM_LISTBOX, + SID_FM_CHECKBOX, + SID_FM_RADIOBUTTON, + SID_FM_GROUPBOX, + SID_FM_COMBOBOX, + SID_FM_IMAGEBUTTON, + SID_FM_FILECONTROL, + SID_FM_DATEFIELD, + SID_FM_TIMEFIELD, + SID_FM_NUMERICFIELD, + SID_FM_CURRENCYFIELD, + SID_FM_PATTERNFIELD, + SID_FM_IMAGECONTROL, + SID_FM_FORMATTEDFIELD, + SID_FM_SCROLLBAR, + SID_FM_SPINBUTTON, + SID_FM_NAVIGATIONBAR +}; + +sal_Int16 nObjectTypes[] = +{ + OBJ_FM_EDIT, + OBJ_FM_BUTTON, + OBJ_FM_FIXEDTEXT, + OBJ_FM_LISTBOX, + OBJ_FM_CHECKBOX, + OBJ_FM_RADIOBUTTON, + OBJ_FM_GROUPBOX, + OBJ_FM_COMBOBOX, + OBJ_FM_IMAGEBUTTON, + OBJ_FM_FILECONTROL, + OBJ_FM_DATEFIELD, + OBJ_FM_TIMEFIELD, + OBJ_FM_NUMERICFIELD, + OBJ_FM_CURRENCYFIELD, + OBJ_FM_PATTERNFIELD, + OBJ_FM_IMAGECONTROL, + OBJ_FM_FORMATTEDFIELD, + OBJ_FM_SCROLLBAR, + OBJ_FM_SPINBUTTON, + OBJ_FM_NAVIGATIONBAR +}; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::ui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::form::binding; +using namespace ::com::sun::star::form::runtime; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::script; +using namespace ::svxform; +using namespace ::svx; + +//============================================================================== +//= helper +//============================================================================== +namespace +{ + //.......................................................................... + void collectInterfacesFromMarkList( const SdrMarkList& _rMarkList, InterfaceBag& /* [out] */ _rInterfaces ) + { + _rInterfaces.clear(); + + sal_uInt32 nMarkCount = _rMarkList.GetMarkCount(); + for ( sal_uInt32 i = 0; i < nMarkCount; ++i) + { + SdrObject* pCurrent = _rMarkList.GetMark( i )->GetMarkedSdrObj(); + + SdrObjListIter* pGroupIterator = NULL; + if ( pCurrent->IsGroupObject() ) + { + pGroupIterator = new SdrObjListIter( *pCurrent->GetSubList() ); + pCurrent = pGroupIterator->IsMore() ? pGroupIterator->Next() : NULL; + } + + while ( pCurrent ) + { + FmFormObj* pAsFormObject = FmFormObj::GetFormObject( pCurrent ); + // note this will de-reference virtual objects, if necessary/possible + if ( pAsFormObject ) + { + Reference< XInterface > xControlModel( pAsFormObject->GetUnoControlModel(), UNO_QUERY ); + // the UNO_QUERY is important for normalization + if ( xControlModel.is() ) + _rInterfaces.insert( xControlModel ); + } + + // next element + pCurrent = pGroupIterator && pGroupIterator->IsMore() ? pGroupIterator->Next() : NULL; + } + + if ( pGroupIterator ) + delete pGroupIterator; + } + } + + //.......................................................................... + sal_Int16 GridView2ModelPos(const Reference< XIndexAccess>& rColumns, sal_Int16 nViewPos) + { + try + { + if (rColumns.is()) + { + // loop through all columns + sal_Int16 i; + Reference< XPropertySet> xCur; + for (i=0; i<rColumns->getCount(); ++i) + { + rColumns->getByIndex(i) >>= xCur; + if (!::comphelper::getBOOL(xCur->getPropertyValue(FM_PROP_HIDDEN))) + { + // for every visible col : if nViewPos is greater zero, decrement it, else we + // have found the model position + if (!nViewPos) + break; + else + --nViewPos; + } + } + if (i<rColumns->getCount()) + return i; + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + return (sal_Int16)-1; + } + + //.......................................................................... + void TransferEventScripts(const Reference< XControlModel>& xModel, const Reference< XControl>& xControl, + const Sequence< ScriptEventDescriptor>& rTransferIfAvailable) + { + // first check if we have a XEventAttacherManager for the model + Reference< XChild> xModelChild(xModel, UNO_QUERY); + if (!xModelChild.is()) + return; // nothing to do + + Reference< XEventAttacherManager> xEventManager(xModelChild->getParent(), UNO_QUERY); + if (!xEventManager.is()) + return; // nothing to do + + if (!rTransferIfAvailable.getLength()) + return; // nothing to do + + // check for the index of the model within it's parent + Reference< XIndexAccess> xParentIndex(xModelChild->getParent(), UNO_QUERY); + if (!xParentIndex.is()) + return; // nothing to do + sal_Int32 nIndex = getElementPos(xParentIndex, xModel); + if (nIndex<0 || nIndex>=xParentIndex->getCount()) + return; // nothing to do + + // then we need informations about the listeners supported by the control and the model + Sequence< Type> aModelListeners; + Sequence< Type> aControlListeners; + + Reference< XIntrospection> xModelIntrospection(::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.beans.Introspection")), UNO_QUERY); + Reference< XIntrospection> xControlIntrospection(::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.beans.Introspection")), UNO_QUERY); + + if (xModelIntrospection.is() && xModel.is()) + { + Any aModel(makeAny(xModel)); + aModelListeners = xModelIntrospection->inspect(aModel)->getSupportedListeners(); + } + + if (xControlIntrospection.is() && xControl.is()) + { + Any aControl(makeAny(xControl)); + aControlListeners = xControlIntrospection->inspect(aControl)->getSupportedListeners(); + } + + sal_Int32 nMaxNewLen = aModelListeners.getLength() + aControlListeners.getLength(); + if (!nMaxNewLen) + return; // the model and the listener don't support any listeners (or we were unable to retrieve these infos) + + Sequence< ScriptEventDescriptor> aTransferable(nMaxNewLen); + ScriptEventDescriptor* pTransferable = aTransferable.getArray(); + + const ScriptEventDescriptor* pCurrent = rTransferIfAvailable.getConstArray(); + sal_Int32 i,j,k; + for (i=0; i<rTransferIfAvailable.getLength(); ++i, ++pCurrent) + { + // search the model/control idl classes for the event described by pCurrent + for ( Sequence< Type>* pCurrentArray = &aModelListeners; + pCurrentArray; + pCurrentArray = (pCurrentArray == &aModelListeners) ? &aControlListeners : NULL + ) + { + const Type* pCurrentListeners = pCurrentArray->getConstArray(); + for (j=0; j<pCurrentArray->getLength(); ++j, ++pCurrentListeners) + { + UniString aListener = (*pCurrentListeners).getTypeName(); + xub_StrLen nTokens = aListener.GetTokenCount('.'); + if (nTokens) + aListener = aListener.GetToken(nTokens - 1, '.'); + + if (aListener == pCurrent->ListenerType.getStr()) + // the current ScriptEventDescriptor doesn't match the current listeners class + continue; + + // now check the methods + Sequence< ::rtl::OUString> aMethodsNames = ::comphelper::getEventMethodsForType(*pCurrentListeners); + + const ::rtl::OUString* pMethodsNames = aMethodsNames.getConstArray(); + for (k=0; k<aMethodsNames.getLength(); ++k, ++pMethodsNames) + { + if ((*pMethodsNames).compareTo(pCurrent->EventMethod) != COMPARE_EQUAL) + // the current ScriptEventDescriptor doesn't match the current listeners current method + continue; + + // we can transfer the script event : the model (control) supports it + *pTransferable = *pCurrent; + ++pTransferable; + break; + } + if (k<aMethodsNames.getLength()) + break; + } + } + } + + sal_Int32 nRealNewLen = pTransferable - aTransferable.getArray(); + aTransferable.realloc(nRealNewLen); + + xEventManager->registerScriptEvents(nIndex, aTransferable); + } + + //------------------------------------------------------------------------------ + ::rtl::OUString getServiceNameByControlType(sal_Int16 nType) + { + switch (nType) + { + case OBJ_FM_EDIT : return FM_COMPONENT_TEXTFIELD; + case OBJ_FM_BUTTON : return FM_COMPONENT_COMMANDBUTTON; + case OBJ_FM_FIXEDTEXT : return FM_COMPONENT_FIXEDTEXT; + case OBJ_FM_LISTBOX : return FM_COMPONENT_LISTBOX; + case OBJ_FM_CHECKBOX : return FM_COMPONENT_CHECKBOX; + case OBJ_FM_RADIOBUTTON : return FM_COMPONENT_RADIOBUTTON; + case OBJ_FM_GROUPBOX : return FM_COMPONENT_GROUPBOX; + case OBJ_FM_COMBOBOX : return FM_COMPONENT_COMBOBOX; + case OBJ_FM_GRID : return FM_COMPONENT_GRIDCONTROL; + case OBJ_FM_IMAGEBUTTON : return FM_COMPONENT_IMAGEBUTTON; + case OBJ_FM_FILECONTROL : return FM_COMPONENT_FILECONTROL; + case OBJ_FM_DATEFIELD : return FM_COMPONENT_DATEFIELD; + case OBJ_FM_TIMEFIELD : return FM_COMPONENT_TIMEFIELD; + case OBJ_FM_NUMERICFIELD : return FM_COMPONENT_NUMERICFIELD; + case OBJ_FM_CURRENCYFIELD : return FM_COMPONENT_CURRENCYFIELD; + case OBJ_FM_PATTERNFIELD : return FM_COMPONENT_PATTERNFIELD; + case OBJ_FM_HIDDEN : return FM_COMPONENT_HIDDENCONTROL; + case OBJ_FM_IMAGECONTROL : return FM_COMPONENT_IMAGECONTROL; + case OBJ_FM_FORMATTEDFIELD : return FM_COMPONENT_FORMATTEDFIELD; + case OBJ_FM_SCROLLBAR : return FM_SUN_COMPONENT_SCROLLBAR; + case OBJ_FM_SPINBUTTON : return FM_SUN_COMPONENT_SPINBUTTON; + case OBJ_FM_NAVIGATIONBAR : return FM_SUN_COMPONENT_NAVIGATIONBAR; + } + return ::rtl::OUString(); + } + +} + +//------------------------------------------------------------------------------ +// check if the control has one of the interfaces we can use for searching +// *_pCurrentText will be filled with the current text of the control (as used when searching this control) +sal_Bool IsSearchableControl( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& _rxControl, + ::rtl::OUString* _pCurrentText ) +{ + if ( !_rxControl.is() ) + return sal_False; + + Reference< XTextComponent > xAsText( _rxControl, UNO_QUERY ); + if ( xAsText.is() ) + { + if ( _pCurrentText ) + *_pCurrentText = xAsText->getText(); + return sal_True; + } + + Reference< XListBox > xListBox( _rxControl, UNO_QUERY ); + if ( xListBox.is() ) + { + if ( _pCurrentText ) + *_pCurrentText = xListBox->getSelectedItem(); + return sal_True; + } + + Reference< XCheckBox > xCheckBox( _rxControl, UNO_QUERY ); + if ( xCheckBox.is() ) + { + if ( _pCurrentText ) + { + switch ( (TriState)xCheckBox->getState() ) + { + case STATE_NOCHECK: *_pCurrentText = ::rtl::OUString::createFromAscii( "0" ); break; + case STATE_CHECK: *_pCurrentText = ::rtl::OUString::createFromAscii( "1" ); break; + default: *_pCurrentText = ::rtl::OUString(); break; + } + } + return sal_True; + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +sal_Bool FmXBoundFormFieldIterator::ShouldStepInto(const Reference< XInterface>& _rContainer) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXBoundFormFieldIterator::ShouldStepInto" ); + if (_rContainer == m_xStartingPoint) + // would be quite stupid to step over the root .... + return sal_True; + + return Reference< XControlModel>(_rContainer, UNO_QUERY).is(); +} + +//------------------------------------------------------------------------------ +sal_Bool FmXBoundFormFieldIterator::ShouldHandleElement(const Reference< XInterface>& _rElement) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXBoundFormFieldIterator::ShouldHandleElement" ); + if (!_rElement.is()) + // NULL element + return sal_False; + + if (Reference< XForm>(_rElement, UNO_QUERY).is() || Reference< XGrid>(_rElement, UNO_QUERY).is()) + // a forms or a grid + return sal_False; + + Reference< XPropertySet> xSet(_rElement, UNO_QUERY); + if (!xSet.is() || !::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) + // no "BoundField" property + return sal_False; + + Any aVal( xSet->getPropertyValue(FM_PROP_BOUNDFIELD) ); + if (aVal.getValueTypeClass() != TypeClass_INTERFACE) + // void or invalid property value + return sal_False; + + return aVal.hasValue(); +} + +//------------------------------------------------------------------------------ +sal_Bool isControlList(const SdrMarkList& rMarkList) +{ + // enthaelt die liste nur Controls und mindestens ein control + sal_uInt32 nMarkCount = rMarkList.GetMarkCount(); + sal_Bool bControlList = nMarkCount != 0; + + sal_Bool bHadAnyLeafs = sal_False; + + for (sal_uInt32 i = 0; i < nMarkCount && bControlList; i++) + { + SdrObject *pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); + E3dObject* pAs3DObject = PTR_CAST(E3dObject, pObj); + // E3dObject's do not contain any 2D-objects (by definition) + // we need this extra check here : an E3dObject->IsGroupObject says "YES", but an SdrObjListIter working + // with an E3dObject doesn't give me any Nodes (E3dObject has a sub list, but no members in that list, + // cause there implementation differs from the one of "normal" SdrObject's. Unfortunally SdrObject::IsGroupObject + // doesn't check the element count of the sub list, which is simply a bug in IsGroupObject we can't fix at the moment). + // So at the end of this function bControlList would have the same value it was initialized with above : sal_True + // And this would be wrong :) + // 03.02.00 - 72529 - FS + if (!pAs3DObject) + { + if (pObj->IsGroupObject()) + { + SdrObjListIter aIter(*pObj->GetSubList()); + while (aIter.IsMore() && bControlList) + { + bControlList = FmFormInventor == aIter.Next()->GetObjInventor(); + bHadAnyLeafs = sal_True; + } + } + else + { + bHadAnyLeafs = sal_True; + bControlList = FmFormInventor == pObj->GetObjInventor(); + } + } + } + + return bControlList && bHadAnyLeafs; +} + +//------------------------------------------------------------------------ +Reference< XForm > GetForm(const Reference< XInterface>& _rxElement) +{ + Reference< XForm > xForm( _rxElement, UNO_QUERY ); + if ( xForm.is() ) + return xForm; + + Reference< XChild > xChild( _rxElement, UNO_QUERY ); + if ( xChild.is() ) + return GetForm( xChild->getParent() ); + + return Reference< XForm >(); +} + +//======================================================================== +// class FmXFormShell_Base_Disambiguation +//======================================================================== +FmXFormShell_Base_Disambiguation::FmXFormShell_Base_Disambiguation( ::osl::Mutex& _rMutex ) + :FmXFormShell_BD_BASE( _rMutex ) +{ +} + +void SAL_CALL FmXFormShell_Base_Disambiguation::disposing() +{ + WeakComponentImplHelperBase::disposing(); + // Note: + // This is a HACK. + // Normally it should be sufficient to call the "disposing" of our direct + // base class, but SUN PRO 5 does not like this and claims there is a conflict + // with the XEventListener::disposing(EventObject) of our various listener + // base classes. +} + +//======================================================================== +// class FmXFormShell +//======================================================================== +DBG_NAME(FmXFormShell); +//------------------------------------------------------------------------ +FmXFormShell::FmXFormShell( FmFormShell& _rShell, SfxViewFrame* _pViewFrame ) + :FmXFormShell_BASE(m_aMutex) + ,FmXFormShell_CFGBASE(::rtl::OUString::createFromAscii("Office.Common/Misc"), CONFIG_MODE_DELAYED_UPDATE) + ,m_eNavigate( NavigationBarMode_NONE ) + ,m_nInvalidationEvent( 0 ) + ,m_nActivationEvent( 0 ) + ,m_pShell( &_rShell ) + ,m_pTextShell( new ::svx::FmTextControlShell( _pViewFrame ) ) + ,m_aActiveControllerFeatures( ::comphelper::getProcessServiceFactory(), this ) + ,m_aNavControllerFeatures( ::comphelper::getProcessServiceFactory(), this ) + ,m_eDocumentType( eUnknownDocumentType ) + ,m_nLockSlotInvalidation( 0 ) + ,m_bHadPropertyBrowserInDesignMode( sal_False ) + ,m_bTrackProperties( sal_True ) + ,m_bUseWizards( sal_True ) + ,m_bDatabaseBar( sal_False ) + ,m_bInActivate( sal_False ) + ,m_bSetFocus( sal_False ) + ,m_bFilterMode( sal_False ) + ,m_bChangingDesignMode( sal_False ) + ,m_bPreparedClose( sal_False ) + ,m_bFirstActivation( sal_True ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::FmXFormShell" ); + DBG_CTOR(FmXFormShell,NULL); + m_aMarkTimer.SetTimeout(100); + m_aMarkTimer.SetTimeoutHdl(LINK(this,FmXFormShell,OnTimeOut)); + + if ( _pViewFrame ) + m_xAttachedFrame = _pViewFrame->GetFrame().GetFrameInterface(); + + // to prevent deletion of this we acquire our refcounter once + ::comphelper::increment(FmXFormShell_BASE::m_refCount); + + // correct the refcounter + ::comphelper::decrement(FmXFormShell_BASE::m_refCount); + + // cache the current configuration settings we're interested in + implAdjustConfigCache(); + // and register for changes on this settings + Sequence< ::rtl::OUString > aNames(1); + aNames[0] = ::rtl::OUString::createFromAscii("FormControlPilotsEnabled"); + EnableNotification(aNames); +} + +//------------------------------------------------------------------------ +FmXFormShell::~FmXFormShell() +{ + delete m_pTextShell; + DBG_DTOR(FmXFormShell,NULL); +} + +//------------------------------------------------------------------ +Reference< XModel > FmXFormShell::getContextDocument() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getContextDocument" ); + Reference< XModel > xModel; + + // determine the type of document we live in + try + { + Reference< XController > xController; + if ( m_xAttachedFrame.is() ) + xController = m_xAttachedFrame->getController(); + if ( xController.is() ) + xModel = xController->getModel(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + return xModel; +} + +//------------------------------------------------------------------ +bool FmXFormShell::isEnhancedForm() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isEnhancedForm" ); + return getDocumentType() == eEnhancedForm; +} + +//------------------------------------------------------------------ +bool FmXFormShell::impl_checkDisposed() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_checkDisposed" ); + if ( !m_pShell ) + { + OSL_ENSURE( false, "FmXFormShell::impl_checkDisposed: already disposed!" ); + return true; + } + return false; +} + +//------------------------------------------------------------------ +::svxform::DocumentType FmXFormShell::getDocumentType() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getDocumentType" ); + if ( m_eDocumentType != eUnknownDocumentType ) + return m_eDocumentType; + + // determine the type of document we live in + Reference< XModel > xModel = getContextDocument(); + if ( xModel.is() ) + m_eDocumentType = DocumentClassification::classifyDocument( xModel ); + else + { + OSL_ENSURE( sal_False, "FmXFormShell::getDocumentType: can't determine the document type!" ); + m_eDocumentType = eTextDocument; + // fallback, just to have a defined state + } + + return m_eDocumentType; +} + +//------------------------------------------------------------------ +bool FmXFormShell::IsReadonlyDoc() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsReadonlyDoc" ); + if ( impl_checkDisposed() ) + return true; + + FmFormModel* pModel = m_pShell->GetFormModel(); + if ( pModel && pModel->GetObjectShell() ) + return pModel->GetObjectShell()->IsReadOnly() || pModel->GetObjectShell()->IsReadOnlyUI(); + return true; +} + +//------------------------------------------------------------------ +Any SAL_CALL FmXFormShell::queryInterface( const Type& type) throw ( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::queryInterface" ); + return FmXFormShell_BASE::queryInterface(type); +} +//------------------------------------------------------------------------------ +Sequence< Type > SAL_CALL FmXFormShell::getTypes( ) throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getTypes" ); + return FmXFormShell_BASE::getTypes(); +} +//------------------------------------------------------------------------------ +Sequence< sal_Int8 > SAL_CALL FmXFormShell::getImplementationId() throw(RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getImplementationId" ); + static ::cppu::OImplementationId* pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} +// EventListener +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::disposing(const EventObject& e) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::disposing" ); + impl_checkDisposed(); + + if (m_xActiveController == e.Source) + { + // wird der Controller freigeben dann alles loslassen + stopListening(); + m_xActiveForm = NULL; + m_xActiveController = NULL; + m_xNavigationController = NULL; + + m_aActiveControllerFeatures.dispose(); + m_aNavControllerFeatures.dispose(); + + if ( m_pShell ) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); + } + + if (e.Source == m_xExternalViewController) + { + Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY ); + OSL_ENSURE( xFormController.is(), "FmXFormShell::disposing: invalid external view controller!" ); + if (xFormController.is()) + xFormController->removeActivateListener((XFormControllerListener*)this); + + Reference< ::com::sun::star::lang::XComponent> xComp(m_xExternalViewController, UNO_QUERY); + if (xComp.is()) + xComp->removeEventListener((XEventListener*)(XPropertyChangeListener*)this); + + m_xExternalViewController = NULL; + m_xExternalDisplayedForm = NULL; + m_xExtViewTriggerController = NULL; + + InvalidateSlot( SID_FM_VIEW_AS_GRID, sal_False ); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::propertyChange(const PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::propertyChange" ); + if ( impl_checkDisposed() ) + return; + + if (evt.PropertyName == FM_PROP_ROWCOUNT) + { + // Das gleich folgenden Update erzwingt ein Neu-Painten der entsprechenden Slots. Wenn ich mich aber hier nicht + // in dem HauptThread der Applikation befinde (weil zum Beispiel ein Cursor gerade Datensaetze zaehlt und mir dabei + // immer diese PropertyChanges beschert), kann sich das mit en normalen Paints im HauptThread der Applikation beissen. + // (Solche Paints passieren zum Beispiel, wenn man einfach nur eine andere Applikation ueber das Office legt und wieder + // zurueckschaltet). + // Deshalb die Benutzung des SolarMutex, der sichert das ab. + ::vos::IMutex& rSolarSafety = Application::GetSolarMutex(); + if (rSolarSafety.tryToAcquire()) + { + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_RECORD_TOTAL , sal_True, sal_False); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(SID_FM_RECORD_TOTAL); + rSolarSafety.release(); + } + else + { + // with the following the slot is invalidated asynchron + LockSlotInvalidation(sal_True); + InvalidateSlot(SID_FM_RECORD_TOTAL, sal_False); + LockSlotInvalidation(sal_False); + } + } + + // this may be called from a non-main-thread so invalidate the shell asynchronously + LockSlotInvalidation(sal_True); + InvalidateSlot(0, 0); // special meaning : invalidate m_pShell + LockSlotInvalidation(sal_False); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::invalidateFeatures( const ::std::vector< sal_Int32 >& _rFeatures ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::invalidateFeatures" ); + if ( impl_checkDisposed() ) + return; + + OSL_ENSURE( _rFeatures.size() > 0, "FmXFormShell::invalidateFeatures: invalid arguments!" ); + + if ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() ) + { + // unfortunately, SFX requires sal_uInt16 + ::std::vector< sal_uInt16 > aSlotIds; + aSlotIds.reserve( _rFeatures.size() ); + ::std::copy( _rFeatures.begin(), + _rFeatures.end(), + ::std::insert_iterator< ::std::vector< sal_uInt16 > >( aSlotIds, aSlotIds.begin() ) + ); + + // furthermore, SFX wants a terminating 0 + aSlotIds.push_back( 0 ); + + // and, last but not least, SFX wants the ids to be sorted + ::std::sort( aSlotIds.begin(), aSlotIds.end() - 1 ); + + sal_uInt16 *pSlotIds = aSlotIds.empty() ? 0 : &(aSlotIds[0]); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( pSlotIds ); + } +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::formActivated(const EventObject& rEvent) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::formActivated" ); + if ( impl_checkDisposed() ) + return; + + Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW ); + m_pTextShell->formActivated( xController ); + setActiveController( xController ); +} + +//------------------------------------------------------------------------------ +void SAL_CALL FmXFormShell::formDeactivated(const EventObject& rEvent) throw( RuntimeException ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::formDeactivated" ); + if ( impl_checkDisposed() ) + return; + + Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW ); + m_pTextShell->formDeactivated( xController ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::disposing() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::disposing" ); + impl_checkDisposed(); + + FmXFormShell_BASE::disposing(); + + if ( m_pShell && !m_pShell->IsDesignMode() ) + setActiveController( NULL, sal_True ); + // do NOT save the content of the old form (the second parameter tells this) + // if we're here, then we expect that PrepareClose has been called, and thus the user + // got a chance to commit or reject any changes. So in case we're here and there + // are still uncommitted changes, the user explicitly wanted this. + // 2002-11-11 - 104702 - fs@openoffice.org + + m_pTextShell->dispose(); + + m_xAttachedFrame = NULL; + + CloseExternalFormViewer(); + + while ( m_aLoadingPages.size() ) + { + Application::RemoveUserEvent( m_aLoadingPages.front().nEventId ); + m_aLoadingPages.pop(); + } + + { + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + if (m_nInvalidationEvent) + { + Application::RemoveUserEvent(m_nInvalidationEvent); + m_nInvalidationEvent = 0; + } + if ( m_nActivationEvent ) + { + Application::RemoveUserEvent( m_nActivationEvent ); + m_nActivationEvent = 0; + } + } + + { + ::osl::ClearableMutexGuard aGuard(m_aAsyncSafety); + aGuard.clear(); + + DBG_ASSERT(!m_nInvalidationEvent, "FmXFormShell::~FmXFormShell : still have an invalidation event !"); + // should habe been deleted while beeing disposed + + m_aMarkTimer.Stop(); + } + + DisableNotification(); + + RemoveElement( m_xForms ); + m_xForms.clear(); + + impl_switchActiveControllerListening( false ); + m_xActiveController = NULL; + m_xActiveForm = NULL; + + m_pShell = NULL; + m_xNavigationController = NULL; + m_xCurrentForm = NULL; + m_xLastGridFound = NULL; + m_xAttachedFrame = NULL; + m_xExternalViewController = NULL; + m_xExtViewTriggerController = NULL; + m_xExternalDisplayedForm = NULL; + m_xLastGridFound = NULL; + + InterfaceBag aEmpty; + m_aCurrentSelection.swap( aEmpty ); + + m_aActiveControllerFeatures.dispose(); + m_aNavControllerFeatures.dispose(); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::UpdateSlot( sal_Int16 _nId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::UpdateSlot" ); + if ( impl_checkDisposed() ) + return; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + + if ( m_nLockSlotInvalidation ) + { + OSL_ENSURE( sal_False, "FmXFormShell::UpdateSlot: cannot update if invalidation is currently locked!" ); + InvalidateSlot( _nId, sal_False ); + } + else + { + OSL_ENSURE( _nId, "FmXFormShell::UpdateSlot: can't update the complete shell!" ); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( _nId, sal_True, sal_True ); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update( _nId ); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::InvalidateSlot( sal_Int16 nId, sal_Bool bWithId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::InvalidateSlot" ); + if ( impl_checkDisposed() ) + return; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + if (m_nLockSlotInvalidation) + { + m_arrInvalidSlots.Insert(nId, m_arrInvalidSlots.Count()); + BYTE nFlags = ( bWithId ? 0x01 : 0 ); + m_arrInvalidSlots_Flags.Insert(nFlags, m_arrInvalidSlots_Flags.Count()); + } + else + if (nId) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(nId, sal_True, bWithId); + else + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::LockSlotInvalidation(sal_Bool bLock) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::LockSlotInvalidation" ); + if ( impl_checkDisposed() ) + return; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + DBG_ASSERT(bLock || m_nLockSlotInvalidation>0, "FmXFormShell::LockSlotInvalidation : invalid call !"); + + if (bLock) + ++m_nLockSlotInvalidation; + else if (!--m_nLockSlotInvalidation) + { + // alles, was sich waehrend der gelockten Phase angesammelt hat, (asynchron) invalidieren + if (!m_nInvalidationEvent) + m_nInvalidationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnInvalidateSlots)); + } +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnInvalidateSlots, void*, EMPTYARG) +{ + if ( impl_checkDisposed() ) + return 0L; + + ::osl::MutexGuard aGuard(m_aInvalidationSafety); + m_nInvalidationEvent = 0; + + DBG_ASSERT(m_arrInvalidSlots.Count() == m_arrInvalidSlots_Flags.Count(), + "FmXFormShell::OnInvalidateSlots : inconsistent slot arrays !"); + BYTE nFlags; + for (sal_Int16 i=0; i<m_arrInvalidSlots.Count(); ++i) + { + nFlags = m_arrInvalidSlots_Flags[i]; + + if (m_arrInvalidSlots[i]) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(m_arrInvalidSlots[i], sal_True, (nFlags & 0x01)); + else + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); + } + + m_arrInvalidSlots.Remove(0, m_arrInvalidSlots.Count()); + m_arrInvalidSlots_Flags.Remove(0, m_arrInvalidSlots_Flags.Count()); + return 0L; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ForceUpdateSelection(sal_Bool bAllowInvalidation) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ForceUpdateSelection" ); + if ( impl_checkDisposed() ) + return; + + if (IsSelectionUpdatePending()) + { + m_aMarkTimer.Stop(); + + // die Invalidierung der Slots, die implizit von SetSelection besorgt wird, eventuell abschalten + if (!bAllowInvalidation) + LockSlotInvalidation(sal_True); + + SetSelection(m_pShell->GetFormView()->GetMarkedObjectList()); + + if (!bAllowInvalidation) + LockSlotInvalidation(sal_False); + } +} + +//------------------------------------------------------------------------------ +PopupMenu* FmXFormShell::GetConversionMenu() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetConversionMenu" ); + const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); + BOOL bIsHiContrastMode = rSettings.GetHighContrastMode(); + + PopupMenu* pNewMenu = new PopupMenu(SVX_RES( RID_FMSHELL_CONVERSIONMENU )); + + ImageList aImageList( SVX_RES( bIsHiContrastMode ? RID_SVXIMGLIST_FMEXPL_HC : RID_SVXIMGLIST_FMEXPL) ); + for ( size_t i = 0; i < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++i ) + { + // das entsprechende Image dran + pNewMenu->SetItemImage(nConvertSlots[i], aImageList.GetImage(nCreateSlots[i])); + } + + return pNewMenu; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::isControlConversionSlot( sal_uInt16 nSlotId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isControlConversionSlot" ); + for ( size_t i = 0; i < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++i ) + if (nConvertSlots[i] == nSlotId) + return true; + return false; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::executeControlConversionSlot( sal_uInt16 _nSlotId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::executeControlConversionSlot" ); + OSL_PRECOND( canConvertCurrentSelectionToControl( _nSlotId ), "FmXFormShell::executeControlConversionSlot: illegal call!" ); + InterfaceBag::const_iterator aSelectedElement = m_aCurrentSelection.begin(); + if ( aSelectedElement == m_aCurrentSelection.end() ) + return false; + + return executeControlConversionSlot( Reference< XFormComponent >( *aSelectedElement, UNO_QUERY ), _nSlotId ); +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::executeControlConversionSlot( const Reference< XFormComponent >& _rxObject, sal_uInt16 _nSlotId ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::executeControlConversionSlot" ); + if ( impl_checkDisposed() ) + return false; + + OSL_ENSURE( _rxObject.is(), "FmXFormShell::executeControlConversionSlot: invalid object!" ); + if ( !_rxObject.is() ) + return false; + + SdrPage* pPage = m_pShell->GetCurPage(); + FmFormPage* pFormPage = pPage ? dynamic_cast< FmFormPage* >( pPage ) : NULL; + OSL_ENSURE( pFormPage, "FmXFormShell::executeControlConversionSlot: no current (form) page!" ); + if ( !pFormPage ) + return false; + + OSL_ENSURE( isSolelySelected( _rxObject ), + "FmXFormShell::executeControlConversionSlot: hmm ... shouldn't this parameter be redundant?" ); + + for ( size_t lookupSlot = 0; lookupSlot < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++lookupSlot ) + { + if (nConvertSlots[lookupSlot] == _nSlotId) + { + Reference< XInterface > xNormalizedObject( _rxObject, UNO_QUERY ); + + FmFormObj* pFormObject = NULL; + SdrObjListIter aPageIter( *pFormPage ); + while ( aPageIter.IsMore() ) + { + SdrObject* pCurrent = aPageIter.Next(); + pFormObject = FmFormObj::GetFormObject( pCurrent ); + if ( !pFormObject ) + continue; + + Reference< XInterface > xCurrentNormalized( pFormObject->GetUnoControlModel(), UNO_QUERY ); + if ( xCurrentNormalized.get() == xNormalizedObject.get() ) + break; + + pFormObject = NULL; + } + + if ( !pFormObject ) + return false; + + ::rtl::OUString sNewName( getServiceNameByControlType( nObjectTypes[ lookupSlot ] ) ); + Reference< XControlModel> xNewModel( ::comphelper::getProcessServiceFactory()->createInstance( sNewName ), UNO_QUERY ); + if (!xNewModel.is()) + return false; + + Reference< XControlModel> xOldModel( pFormObject->GetUnoControlModel() ); + Reference< XServiceInfo> xModelInfo(xOldModel, UNO_QUERY); + + // Properties uebertragen + Reference< XPropertySet> xOldSet(xOldModel, UNO_QUERY); + Reference< XPropertySet> xNewSet(xNewModel, UNO_QUERY); + + + Locale aNewLanguage = Application::GetSettings().GetUILocale(); + TransferFormComponentProperties(xOldSet, xNewSet, aNewLanguage); + + Sequence< ::com::sun::star::script::ScriptEventDescriptor> aOldScripts; + Reference< XChild> xChild(xOldModel, UNO_QUERY); + if (xChild.is()) + { + Reference< XIndexAccess> xParent(xChild->getParent(), UNO_QUERY); + + // remember old script events + Reference< ::com::sun::star::script::XEventAttacherManager> xEvManager(xChild->getParent(), UNO_QUERY); + if (xParent.is() && xEvManager.is()) + { + sal_Int32 nIndex = getElementPos(xParent, xOldModel); + if (nIndex>=0 && nIndex<xParent->getCount()) + aOldScripts = xEvManager->getScriptEvents(nIndex); + } + + // replace the mdoel within the parent container + Reference< XIndexContainer> xIndexParent(xChild->getParent(), UNO_QUERY); //Modified by BerryJia for fixing Bug102516 Time(China):2002-9-5 16:00 + if (xIndexParent.is()) + { + // the form container works with FormComponents + Reference< XFormComponent> xComponent(xNewModel, UNO_QUERY); + DBG_ASSERT(xComponent.is(), "FmXFormShell::executeControlConversionSlot: the new model is no form component !"); + Any aNewModel(makeAny(xComponent)); + try + { + //Modified by BerryJia for fixing Bug102516 Time(China):2002-9-5 16:00 + sal_Int32 nIndex = getElementPos(xParent, xOldModel); + if (nIndex>=0 && nIndex<xParent->getCount()) + xIndexParent->replaceByIndex(nIndex, aNewModel); + else + { + DBG_ERROR("FmXFormShell::executeControlConversionSlot: could not replace the model !"); + Reference< ::com::sun::star::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY); + if (xNewComponent.is()) + xNewComponent->dispose(); + return false; + } + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::executeControlConversionSlot: could not replace the model !"); + Reference< ::com::sun::star::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY); + if (xNewComponent.is()) + xNewComponent->dispose(); + return false; + } + + } + } + + // special handling for the LabelControl-property : can only be set when the model is placed + // within the forms hierarchy + if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xOldSet) && ::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xNewSet)) + { + try + { + xNewSet->setPropertyValue(FM_PROP_CONTROLLABEL, xOldSet->getPropertyValue(FM_PROP_CONTROLLABEL)); + } + catch(Exception&) + { + } + + } + + // neues Model setzen + pFormObject->SetChanged(); + pFormObject->SetUnoControlModel(xNewModel); + + // transfer script events + // (do this _after_ SetUnoControlModel as we need the new (implicitly created) control) + if (aOldScripts.getLength()) + { + // das Control zum Model suchen + Reference< XControlContainer > xControlContainer( getControlContainerForView() ); + + Sequence< Reference< XControl> > aControls( xControlContainer->getControls() ); + const Reference< XControl>* pControls = aControls.getConstArray(); + + sal_uInt32 nLen = aControls.getLength(); + Reference< XControl> xControl; + for (sal_uInt32 i=0 ; i<nLen; ++i) + { + if (pControls[i]->getModel() == xNewModel) + { + xControl = pControls[i]; + break; + } + } + TransferEventScripts(xNewModel, xControl, aOldScripts); + } + + // transfer value bindings, if possible + { + Reference< XBindableValue > xOldBindable( xOldModel, UNO_QUERY ); + Reference< XBindableValue > xNewBindable( xNewModel, UNO_QUERY ); + if ( xOldBindable.is() ) + { + try + { + if ( xNewBindable.is() ) + xNewBindable->setValueBinding( xOldBindable->getValueBinding() ); + xOldBindable->setValueBinding( NULL ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + // same for list entry sources + { + Reference< XListEntrySink > xOldSink( xOldModel, UNO_QUERY ); + Reference< XListEntrySink > xNewSink( xNewModel, UNO_QUERY ); + if ( xOldSink.is() ) + { + try + { + if ( xNewSink.is() ) + xNewSink->setListEntrySource( xOldSink->getListEntrySource() ); + xOldSink->setListEntrySource( NULL ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + + // create an undo action + FmFormModel* pModel = m_pShell->GetFormModel(); + DBG_ASSERT(pModel != NULL, "FmXFormShell::executeControlConversionSlot: my shell has no model !"); + if (pModel && pModel->IsUndoEnabled() ) + { + pModel->AddUndo(new FmUndoModelReplaceAction(*pModel, pFormObject, xOldModel)); + } + else + { + FmUndoModelReplaceAction::DisposeElement( xOldModel ); + } + + return true; + } + } + return false; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::canConvertCurrentSelectionToControl( sal_Int16 nConversionSlot ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::canConvertCurrentSelectionToControl" ); + if ( m_aCurrentSelection.empty() ) + return false; + + InterfaceBag::const_iterator aCheck = m_aCurrentSelection.begin(); + Reference< XServiceInfo > xElementInfo( *aCheck, UNO_QUERY ); + if ( !xElementInfo.is() ) + // no service info -> cannot determine this + return false; + + if ( ++aCheck != m_aCurrentSelection.end() ) + // more than one element + return false; + + if ( Reference< XForm >::query( xElementInfo ).is() ) + // it's a form + return false; + + sal_Int16 nObjectType = getControlTypeByObject( xElementInfo ); + + if ( ( OBJ_FM_HIDDEN == nObjectType ) + || ( OBJ_FM_CONTROL == nObjectType ) + || ( OBJ_FM_GRID == nObjectType ) + ) + return false; // those types cannot be converted + + DBG_ASSERT(sizeof(nConvertSlots)/sizeof(nConvertSlots[0]) == sizeof(nObjectTypes)/sizeof(nObjectTypes[0]), + "FmXFormShell::canConvertCurrentSelectionToControl: nConvertSlots & nObjectTypes must have the same size !"); + + for ( size_t i = 0; i < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++i ) + if (nConvertSlots[i] == nConversionSlot) + return nObjectTypes[i] != nObjectType; + + return sal_True; // all other slots: assume "yes" +} + +//------------------------------------------------------------------------------ +void FmXFormShell::checkControlConversionSlotsForCurrentSelection( Menu& rMenu ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::checkControlConversionSlotsForCurrentSelection" ); + for (sal_Int16 i=0; i<rMenu.GetItemCount(); ++i) + // der Context ist schon von einem Typ, der dem Eitnrag entspricht -> disable + rMenu.EnableItem( rMenu.GetItemId(i), canConvertCurrentSelectionToControl( rMenu.GetItemId( i ) ) ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::LoopGrids(sal_Int16 nWhat) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::LoopGrids" ); + if ( impl_checkDisposed() ) + return; + + Reference< XIndexContainer> xControlModels(m_xActiveForm, UNO_QUERY); + if (xControlModels.is()) + { + for (sal_Int16 i=0; i<xControlModels->getCount(); ++i) + { + Reference< XPropertySet> xModelSet; + xControlModels->getByIndex(i) >>= xModelSet; + if (!xModelSet.is()) + continue; + + if (!::comphelper::hasProperty(FM_PROP_CLASSID, xModelSet)) + continue; + sal_Int16 nClassId = ::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_CLASSID)); + if (FormComponentType::GRIDCONTROL != nClassId) + continue; + + if (!::comphelper::hasProperty(FM_PROP_CURSORCOLOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_ALWAYSSHOWCURSOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_DISPLAYSYNCHRON, xModelSet)) + continue; + + switch (nWhat & GA_SYNC_MASK) + { + case GA_DISABLE_SYNC: + { + sal_Bool bB(sal_False); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType())); + } + break; + case GA_FORCE_SYNC: + { + Any aOldVal( xModelSet->getPropertyValue(FM_PROP_DISPLAYSYNCHRON) ); + sal_Bool bB(sal_True); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType())); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, aOldVal); + } + break; + case GA_ENABLE_SYNC: + { + sal_Bool bB(sal_True); + xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType())); + } + break; + } + + if (nWhat & GA_DISABLE_ROCTRLR) + { + sal_Bool bB(sal_False); + xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(&bB,getBooleanCppuType())); + Reference< XPropertyState> xModelPropState(xModelSet, UNO_QUERY); + if (xModelPropState.is()) + xModelPropState->setPropertyToDefault(FM_PROP_CURSORCOLOR); + else + xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); // this should be the default + } + else if (nWhat & GA_ENABLE_ROCTRLR) + { + sal_Bool bB(sal_True); + xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(&bB,getBooleanCppuType())); + xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, makeAny(sal_Int32(COL_LIGHTRED))); + } + } + } +} + +//------------------------------------------------------------------------------ +Reference< XControlContainer > FmXFormShell::getControlContainerForView() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getControlContainerForView" ); + if ( impl_checkDisposed() ) + return NULL; + + SdrPageView* pPageView = NULL; + if ( m_pShell && m_pShell->GetFormView() ) + pPageView = m_pShell->GetFormView()->GetSdrPageView(); + + Reference< XControlContainer> xControlContainer; + if ( pPageView ) + xControlContainer = pPageView->GetPageWindow(0)->GetControlContainer(); + + return xControlContainer; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ExecuteTabOrderDialog( const Reference< XTabControllerModel >& _rxForForm ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteTabOrderDialog" ); + if ( impl_checkDisposed() ) + return; + + OSL_PRECOND( _rxForForm.is(), "FmXFormShell::ExecuteTabOrderDialog: invalid tabbing model!" ); + if ( !_rxForForm.is() ) + return; + + try + { + Sequence< Any > aDialogArgs( 3 ); + aDialogArgs[0] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TabbingModel" ) ), + makeAny( _rxForForm ) + ); + aDialogArgs[1] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlContext" ) ), + makeAny( getControlContainerForView() ) + ); + + Reference< XWindow > xParentWindow; + if ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() ) + xParentWindow = VCLUnoHelper::GetInterface ( &m_pShell->GetViewShell()->GetViewFrame()->GetWindow() ); + aDialogArgs[2] <<= NamedValue( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ParentWindow" ) ), + makeAny( xParentWindow ) + ); + + Reference< dialogs::XExecutableDialog > xDialog( + ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.ui.TabOrderDialog" ) ), + aDialogArgs + ), + UNO_QUERY + ); + OSL_ENSURE( xDialog.is(), "FmXFormShell::ExecuteTabOrderDialog: could not create the dialog!" ); + + if ( xDialog.is() ) + xDialog->execute(); + } + catch( const Exception& ) + { + OSL_ENSURE( sal_False, "FmXFormShell::ExecuteTabOrderDialog: caught an exception!" ); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ExecuteSearch() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteSearch" ); + if ( impl_checkDisposed() ) + return; + + // eine Sammlung aller (logischen) Formulare + FmFormArray aEmpty; + m_aSearchForms.swap( aEmpty ); + ::std::vector< String > aContextNames; + impl_collectFormSearchContexts_nothrow( m_pShell->GetCurPage()->GetForms(), ::rtl::OUString(), m_aSearchForms, aContextNames ); + OSL_POSTCOND( m_aSearchForms.size() == aContextNames.size(), + "FmXFormShell::ExecuteSearch: nonsense!" ); + if ( m_aSearchForms.size() != aContextNames.size() ) + return; + + // filter out the forms which do not contain valid controls at all + { + FmFormArray aValidForms; + ::std::vector< String > aValidContexts; + FmFormArray::const_iterator form = m_aSearchForms.begin(); + ::std::vector< String >::const_iterator contextName = aContextNames.begin(); + for ( ; form != m_aSearchForms.end(); ++form, ++contextName ) + { + FmSearchContext aTestContext; + aTestContext.nContext = static_cast< sal_Int16 >( form - m_aSearchForms.begin() ); + sal_uInt32 nValidControls = OnSearchContextRequest( &aTestContext ); + if ( nValidControls > 0 ) + { + aValidForms.push_back( *form ); + aValidContexts.push_back( *contextName ); + } + } + + m_aSearchForms.swap( aValidForms ); + aContextNames.swap( aValidContexts ); + } + + if (m_aSearchForms.size() == 0) + { // es gibt keine Controls, die alle Bedingungen fuer eine Suche erfuellen + ErrorBox(NULL, WB_OK, SVX_RESSTR(RID_STR_NODATACONTROLS)).Execute(); + return; + } + + // jetzt brauche ich noch einen 'initial context' + sal_Int16 nInitialContext = 0; + Reference< XForm> xActiveForm( getActiveForm()); + for ( size_t i=0; i<m_aSearchForms.size(); ++i ) + { + if (m_aSearchForms.at(i) == xActiveForm) + { + nInitialContext = (sal_Int16)i; + break; + } + } + + // wenn der Dialog initial den Text des aktiven Controls anbieten soll, muss dieses ein XTextComponent-Interface habe, + // ausserdem macht das nur Sinn, wenn das aktuelle Feld auch an ein Tabellen- (oder was-auch-immer-)Feld gebunden ist + UniString strActiveField; + UniString strInitialText; + // ... das bekomme ich von meinem FormController + DBG_ASSERT(m_xActiveController.is(), "FmXFormShell::ExecuteSearch : no active controller !"); + Reference< XControl> xActiveControl( m_xActiveController->getCurrentControl()); + if (xActiveControl.is()) + { + // das Control kann mir sein Model sagen ... + Reference< XControlModel> xActiveModel( xActiveControl->getModel()); + DBG_ASSERT(xActiveModel.is(), "FmXFormShell::ExecuteSearch : active control has no model !"); + + // das Model frage ich nach der ControlSource-Eigenschaft ... + Reference< XPropertySet> xProperties(xActiveControl->getModel(), UNO_QUERY); + if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties)) + { + Reference< XPropertySet> xField; + xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + if (xField.is()) // (nur wenn das Ding wirklich gebunden ist) + { + // und das Control selber nach einem TextComponent-Interface (damit ich mir dort den Text abholen kann) + Reference< XTextComponent> xText(xActiveControl, UNO_QUERY); + if (xText.is()) + { + strActiveField = getLabelName(xProperties).getStr(); + strInitialText = xText->getText().getStr(); + } + } + } + else + { + // das Control selber hat keine ControlSource, aber vielleicht ist es ein GridControl + Reference< XGrid> xGrid(xActiveControl, UNO_QUERY); + if (xGrid.is()) + { + // fuer strActiveField brauche ich die die ControlSource der Column, dafuer den Columns-Container, dafuer die + // GridPeer + Reference< XGridPeer> xGridPeer(xActiveControl->getPeer(), UNO_QUERY); + Reference< XIndexAccess> xColumns; + if (xGridPeer.is()) + xColumns = Reference< XIndexAccess>(xGridPeer->getColumns(),UNO_QUERY); + + sal_Int16 nViewCol = xGrid->getCurrentColumnPosition(); + sal_Int16 nModelCol = GridView2ModelPos(xColumns, nViewCol); + Reference< XPropertySet> xCurrentCol; + if(xColumns.is()) + xColumns->getByIndex(nModelCol) >>= xCurrentCol; + if (xCurrentCol.is()) + strActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(FM_PROP_LABEL)).getStr(); + + // the text fo the current column + Reference< XIndexAccess> xColControls(xGridPeer, UNO_QUERY); + Reference< XInterface> xCurControl; + xColControls->getByIndex(nViewCol) >>= xCurControl; + ::rtl::OUString sInitialText; + if (IsSearchableControl(xCurControl, &sInitialText)) + strInitialText = sInitialText.getStr(); + } + } + } + + // um eventuelle GridControls, die ich kenne, kuemmern + LoopGrids(GA_DISABLE_SYNC /*| GA_ENABLE_ROCTRLR*/); + + // jetzt bin ich reif fuer den Dialog + // wenn die potentiellen Deadlocks, die durch die Benutzung des Solar-Mutex in MTs VCLX...-Klasen entstehen, irgendwann mal + // ausgeraeumt sind, sollte hier ein SM_USETHREAD rein, denn die Suche in einem eigenen Thread ist doch etwas fluessiger + // sollte allerdings irgendwie von dem unterliegenden Cursor abhaengig gemacht werden, DAO zum Beispiel ist nicht thread-sicher + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + AbstractFmSearchDialog* pDialog = NULL; + if ( pFact ) + pDialog = pFact->CreateFmSearchDialog( &m_pShell->GetViewShell()->GetViewFrame()->GetWindow(), strInitialText, aContextNames, nInitialContext, LINK( this, FmXFormShell, OnSearchContextRequest ) ); + DBG_ASSERT( pDialog, "FmXFormShell::ExecuteSearch: could not create the search dialog!" ); + if ( pDialog ) + { + pDialog->SetActiveField( strActiveField ); + pDialog->SetFoundHandler( LINK( this, FmXFormShell, OnFoundData ) ); + pDialog->SetCanceledNotFoundHdl( LINK( this, FmXFormShell, OnCanceledNotFound ) ); + pDialog->Execute(); + delete pDialog; + } + + // GridControls wieder restaurieren + LoopGrids(GA_ENABLE_SYNC | GA_DISABLE_ROCTRLR); + + m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); + // da ich in OnFoundData (fals ich dort war) Controls markiert habe +} + +//------------------------------------------------------------------------------ +sal_Bool FmXFormShell::GetY2KState(sal_uInt16& n) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetY2KState" ); + if ( impl_checkDisposed() ) + return sal_False; + + if (m_pShell->IsDesignMode()) + // im Design-Modus (ohne aktive Controls) soll sich das Haupt-Dokument darum kuemmern + return sal_False; + + Reference< XForm> xForm( getActiveForm()); + if (!xForm.is()) + // kein aktuelles Formular (also insbesondere kein aktuelles Control) -> das Haupt-Dokument soll sich kuemmern + return sal_False; + + Reference< XRowSet> xDB(xForm, UNO_QUERY); + DBG_ASSERT(xDB.is(), "FmXFormShell::GetY2KState : current form has no dbform-interface !"); + + Reference< XNumberFormatsSupplier> xSupplier( getNumberFormats(OStaticDataAccessTools().getRowSetConnection(xDB), sal_False)); + if (xSupplier.is()) + { + Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); + if (xSet.is()) + { + try + { + Any aVal( xSet->getPropertyValue(::rtl::OUString::createFromAscii("TwoDigitDateStart")) ); + aVal >>= n; + return sal_True; + } + catch(Exception&) + { + } + + } + } + return sal_False; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::SetY2KState(sal_uInt16 n) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetY2KState" ); + if ( impl_checkDisposed() ) + return; + + Reference< XForm > xActiveForm( getActiveForm()); + Reference< XRowSet > xActiveRowSet( xActiveForm, UNO_QUERY ); + if ( xActiveRowSet.is() ) + { + Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getRowSetConnection( xActiveRowSet ), sal_False ) ); + if (xSupplier.is()) + { + Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); + if (xSet.is()) + { + try + { + Any aVal; + aVal <<= n; + xSet->setPropertyValue(::rtl::OUString::createFromAscii("TwoDigitDateStart"), aVal); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::SetY2KState: Exception occured!"); + } + + } + return; + } + } + + // kein aktives Formular gefunden -> alle aktuell vorhandenen Formulare durchiterieren + Reference< XIndexAccess> xCurrentForms( m_xForms); + if (!xCurrentForms.is()) + { // im alive-Modus sind meine Forms nicht gesetzt, wohl aber die an der Page + if (m_pShell->GetCurPage()) + xCurrentForms = Reference< XIndexAccess>( m_pShell->GetCurPage()->GetForms( false ), UNO_QUERY ); + } + if (!xCurrentForms.is()) + return; + + ::comphelper::IndexAccessIterator aIter(xCurrentForms); + Reference< XInterface> xCurrentElement( aIter.Next()); + while (xCurrentElement.is()) + { + // ist das aktuelle Element eine DatabaseForm ? + Reference< XRowSet> xElementAsRowSet( xCurrentElement, UNO_QUERY ); + if ( xElementAsRowSet.is() ) + { + Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getRowSetConnection( xElementAsRowSet ), sal_False ) ); + if (!xSupplier.is()) + continue; + + Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); + if (xSet.is()) + { + try + { + Any aVal; + aVal <<= n; + xSet->setPropertyValue(::rtl::OUString::createFromAscii("TwoDigitDateStart"), aVal); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::SetY2KState: Exception occured!"); + } + + } + } + xCurrentElement = aIter.Next(); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::CloseExternalFormViewer() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::CloseExternalFormViewer" ); + if ( impl_checkDisposed() ) + return; + + if (!m_xExternalViewController.is()) + return; + + Reference< ::com::sun::star::frame::XFrame> xExternalViewFrame( m_xExternalViewController->getFrame()); + Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); + if (!xCommLink.is()) + return; + + xExternalViewFrame->setComponent(NULL,NULL); + ::comphelper::disposeComponent(xExternalViewFrame); + m_xExternalViewController = NULL; + m_xExtViewTriggerController = NULL; + m_xExternalDisplayedForm = NULL; +} + +//------------------------------------------------------------------------------ +Reference< XResultSet> FmXFormShell::getInternalForm(const Reference< XResultSet>& _xForm) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getInternalForm" ); + if ( impl_checkDisposed() ) + return NULL; + + Reference< runtime::XFormController> xExternalCtrlr(m_xExternalViewController, UNO_QUERY); + if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel())) + { + DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !"); + return m_xExternalDisplayedForm; + } + return _xForm; +} + +//------------------------------------------------------------------------------ +Reference< XForm> FmXFormShell::getInternalForm(const Reference< XForm>& _xForm) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getInternalForm" ); + if ( impl_checkDisposed() ) + return NULL; + + Reference< runtime::XFormController > xExternalCtrlr(m_xExternalViewController, UNO_QUERY); + if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel())) + { + DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !"); + return Reference< XForm>(m_xExternalDisplayedForm, UNO_QUERY); + } + return _xForm; +} + +//------------------------------------------------------------------------ +namespace +{ + static bool lcl_isNavigationRelevant( sal_Int32 _nWhich ) + { + return ( _nWhich == SID_FM_RECORD_FIRST ) + || ( _nWhich == SID_FM_RECORD_PREV ) + || ( _nWhich == SID_FM_RECORD_NEXT ) + || ( _nWhich == SID_FM_RECORD_LAST ) + || ( _nWhich == SID_FM_RECORD_NEW ); + } +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::IsFormSlotEnabled( sal_Int32 _nSlot, FeatureState* _pCompleteState ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsFormSlotEnabled" ); + const ::svx::ControllerFeatures& rController = + lcl_isNavigationRelevant( _nSlot ) + ? getNavControllerFeatures() + : getActiveControllerFeatures(); + + if ( !_pCompleteState ) + return rController->isEnabled( _nSlot ); + + rController->getState( _nSlot, *_pCompleteState ); + return _pCompleteState->Enabled; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ExecuteFormSlot( sal_Int32 _nSlot ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteFormSlot" ); + const ::svx::ControllerFeatures& rController = + lcl_isNavigationRelevant( _nSlot ) + ? getNavControllerFeatures() + : getActiveControllerFeatures(); + + rController->execute( _nSlot ); + + if ( _nSlot == SID_FM_RECORD_UNDO ) + { + // if we're doing an UNDO, *and* if the affected form is the form which we also display + // as external view, then we need to reset the controls of the external form, too + if ( getInternalForm( getActiveForm() ) == m_xExternalDisplayedForm ) + { + Reference< XIndexAccess > xContainer( m_xExternalDisplayedForm, UNO_QUERY ); + if ( xContainer.is() ) + { + Reference< XReset > xReset; + for ( sal_Int32 i = 0; i < xContainer->getCount(); ++i ) + { + if ( ( xContainer->getByIndex( i ) >>= xReset ) && xReset.is() ) + { + // no resets on sub forms + Reference< XForm > xAsForm( xReset, UNO_QUERY ); + if ( !xAsForm.is() ) + xReset->reset(); + } + } + } + } + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_switchActiveControllerListening( const bool _bListen ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_switchActiveControllerListening" ); + Reference< XComponent> xComp( m_xActiveController, UNO_QUERY ); + if ( !xComp.is() ) + return; + + if ( _bListen ) + xComp->addEventListener( (XFormControllerListener*)this ); + else + xComp->removeEventListener( (XFormControllerListener*)this ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::setActiveController( const Reference< runtime::XFormController >& xController, sal_Bool _bNoSaveOldContent ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setActiveController" ); + if ( impl_checkDisposed() ) + return; + + if (m_bChangingDesignMode) + return; + DBG_ASSERT(!m_pShell->IsDesignMode(), "nur im alive mode verwenden"); + + // Ist die Routine ein zweites Mal gerufen worden, + // dann sollte der Focus nicht mehr umgesetzt werden + if (m_bInActivate) + { + m_bSetFocus = xController != m_xActiveController; + return; + } + + if (xController != m_xActiveController) + { + ::osl::ClearableMutexGuard aGuard(m_aAsyncSafety); + // switch all nav dispatchers belonging to the form of the current nav controller to 'non active' + Reference< XResultSet> xNavigationForm; + if (m_xNavigationController.is()) + xNavigationForm = Reference< XResultSet>(m_xNavigationController->getModel(), UNO_QUERY); + aGuard.clear(); + + m_bInActivate = sal_True; + + // check if the 2 controllers serve different forms + Reference< XResultSet> xOldForm; + if (m_xActiveController.is()) + xOldForm = Reference< XResultSet>(m_xActiveController->getModel(), UNO_QUERY); + Reference< XResultSet> xNewForm; + if (xController.is()) + xNewForm = Reference< XResultSet>(xController->getModel(), UNO_QUERY); + xOldForm = getInternalForm(xOldForm); + xNewForm = getInternalForm(xNewForm); + + sal_Bool bDifferentForm = ( xOldForm.get() != xNewForm.get() ); + sal_Bool bNeedSave = bDifferentForm && !_bNoSaveOldContent; + // we save the content of the old form if we move to a new form, and saving old content is allowed + + if ( m_xActiveController.is() && bNeedSave ) + { + // beim Wechsel des Controllers den Inhalt speichern, ein Commit + // wurde bereits ausgefuehrt + if ( m_aActiveControllerFeatures->commitCurrentControl() ) + { + m_bSetFocus = sal_True; + if ( m_aActiveControllerFeatures->isModifiedRow() ) + { + sal_Bool bIsNew = m_aActiveControllerFeatures->isInsertionRow(); + sal_Bool bResult = m_aActiveControllerFeatures->commitCurrentRecord(); + if ( !bResult && m_bSetFocus ) + { + // if we couldn't save the current record, set the focus back to the + // current control + Reference< XWindow > xWindow( m_xActiveController->getCurrentControl(), UNO_QUERY ); + if ( xWindow.is() ) + xWindow->setFocus(); + m_bInActivate = sal_False; + return; + } + else if ( bResult && bIsNew ) + { + Reference< XResultSet > xCursor( m_aActiveControllerFeatures->getCursor().get() ); + if ( xCursor.is() ) + { + DO_SAFE( xCursor->last(); ); + } + } + } + } + } + + stopListening(); + + impl_switchActiveControllerListening( false ); + + m_aActiveControllerFeatures.dispose(); + m_xActiveController = xController; + if ( m_xActiveController.is() ) + m_aActiveControllerFeatures.assign( m_xActiveController ); + + impl_switchActiveControllerListening( true ); + + if ( m_xActiveController.is() ) + m_xActiveForm = getInternalForm( Reference< XForm >( m_xActiveController->getModel(), UNO_QUERY ) ); + else + m_xActiveForm = NULL; + + startListening(); + + // activate all dispatchers belonging to form of the new navigation controller + xNavigationForm = NULL; + if (m_xNavigationController.is()) + xNavigationForm = Reference< XResultSet>(m_xNavigationController->getModel(), UNO_QUERY); + + m_bInActivate = sal_False; + + m_pShell->UIFeatureChanged(); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); + + InvalidateSlot(SID_FM_FILTER_NAVIGATOR_CONTROL, sal_True); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::getCurrentSelection( InterfaceBag& /* [out] */ _rSelection ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getCurrentSelection" ); + _rSelection = m_aCurrentSelection; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::setCurrentSelectionFromMark( const SdrMarkList& _rMarkList ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setCurrentSelectionFromMark" ); + m_aLastKnownMarkedControls.clear(); + + if ( ( _rMarkList.GetMarkCount() > 0 ) && isControlList( _rMarkList ) ) + collectInterfacesFromMarkList( _rMarkList, m_aLastKnownMarkedControls ); + + return setCurrentSelection( m_aLastKnownMarkedControls ); +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::selectLastMarkedControls() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::selectLastMarkedControls" ); + return setCurrentSelection( m_aLastKnownMarkedControls ); +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::setCurrentSelection( const InterfaceBag& _rSelection ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setCurrentSelection" ); + if ( impl_checkDisposed() ) + return false; + + DBG_ASSERT( m_pShell->IsDesignMode(), "FmXFormShell::setCurrentSelection: only to be used in design mode!" ); + + if ( _rSelection.empty() && m_aCurrentSelection.empty() ) + // nothing to do + return false; + + if ( _rSelection.size() == m_aCurrentSelection.size() ) + { + InterfaceBag::const_iterator aNew = _rSelection.begin(); + InterfaceBag::const_iterator aOld = m_aCurrentSelection.begin(); + for ( ; aNew != _rSelection.end(); ++aNew, ++aOld ) + { + OSL_ENSURE( Reference< XInterface >( *aNew, UNO_QUERY ).get() == aNew->get(), "FmXFormShell::setCurrentSelection: new interface not normalized!" ); + OSL_ENSURE( Reference< XInterface >( *aOld, UNO_QUERY ).get() == aOld->get(), "FmXFormShell::setCurrentSelection: old interface not normalized!" ); + + if ( aNew->get() != aOld->get() ) + break; + } + + if ( aNew == _rSelection.end() ) + // both bags equal + return false; + } + + // the following is some strange code to ensure that when you have two grid controls in a document, + // only one of them can have a selected column. + // TODO: this should happen elsewhere, but not here - shouldn't it? + if ( !m_aCurrentSelection.empty() ) + { + Reference< XChild > xCur; if ( m_aCurrentSelection.size() == 1 ) xCur = xCur.query( *m_aCurrentSelection.begin() ); + Reference< XChild > xNew; if ( _rSelection.size() == 1 ) xNew = xNew.query( *_rSelection.begin() ); + + // is there nothing to be selected, or the parents differ, and the parent of the current object + // is a selection supplier, then deselect + if ( xCur.is() && ( !xNew.is() || ( xCur->getParent() != xNew->getParent() ) ) ) + { + Reference< XSelectionSupplier > xSel( xCur->getParent(), UNO_QUERY ); + if ( xSel.is() ) + xSel->select( Any() ); + } + } + + m_aCurrentSelection = _rSelection; + + // determine the form which all the selected obj�cts belong to, if any + Reference< XForm > xNewCurrentForm; + for ( InterfaceBag::const_iterator loop = m_aCurrentSelection.begin(); + loop != m_aCurrentSelection.end(); + ++loop + ) + { + Reference< XForm > xThisRoundsForm( GetForm( *loop ) ); + OSL_ENSURE( xThisRoundsForm.is(), "FmXFormShell::setCurrentSelection: *everything* should belong to a form!" ); + + if ( !xNewCurrentForm.is() ) + { // the first form we encounterd + xNewCurrentForm = xThisRoundsForm; + } + else if ( xNewCurrentForm != xThisRoundsForm ) + { // different forms -> no "current form" at all + xNewCurrentForm.clear(); + break; + } + } + + if ( !m_aCurrentSelection.empty() ) + impl_updateCurrentForm( xNewCurrentForm ); + + // ensure some slots are updated + for ( size_t i = 0; i < sizeof( SelObjectSlotMap ) / sizeof( SelObjectSlotMap[0] ); ++i ) + InvalidateSlot( SelObjectSlotMap[i], sal_False); + + return true; +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::isSolelySelected( const Reference< XInterface >& _rxObject ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isSolelySelected" ); + return ( m_aCurrentSelection.size() == 1 ) && ( *m_aCurrentSelection.begin() == _rxObject ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::forgetCurrentForm() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::forgetCurrentForm" ); + if ( !m_xCurrentForm.is() ) + return; + + // reset ... + impl_updateCurrentForm( NULL ); + + // ... and try finding a new current form + // #i88186# / 2008-04-12 / frank.schoenheit@sun.com + impl_defaultCurrentForm_nothrow(); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_updateCurrentForm( const Reference< XForm >& _rxNewCurForm ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_updateCurrentForm" ); + if ( impl_checkDisposed() ) + return; + + m_xCurrentForm = _rxNewCurForm; + + // propagate to the FormPage(Impl) + FmFormPage* pPage = m_pShell->GetCurPage(); + if ( pPage ) + pPage->GetImpl().setCurForm( m_xCurrentForm ); + + // ensure the UI which depends on the current form is up-to-date + for ( size_t i = 0; i < sizeof( DlgSlotMap ) / sizeof( DlgSlotMap[0] ); ++i ) + InvalidateSlot( DlgSlotMap[i], sal_False ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::startListening() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::startListening" ); + if ( impl_checkDisposed() ) + return; + + Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY); + if (xDatabaseForm.is() && getRowSetConnection(xDatabaseForm).is()) + { + Reference< XPropertySet> xActiveFormSet(m_xActiveForm, UNO_QUERY); + if (xActiveFormSet.is()) + { + // wenn es eine Datenquelle gibt, dann den Listener aufbauen + // TODO: this is strange - shouldn't this depend on a isLoaded instead of + // a "has command value"? Finally, the command value only means that it was + // intended to be loaded, not that it actually *is* loaded + ::rtl::OUString aSource = ::comphelper::getString(xActiveFormSet->getPropertyValue(FM_PROP_COMMAND)); + if (aSource.getLength()) + { + m_bDatabaseBar = sal_True; + + xActiveFormSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate; + + switch (m_eNavigate) + { + case NavigationBarMode_PARENT: + { + // suchen des Controllers, ueber den eine Navigation moeglich ist + Reference< XChild> xChild(m_xActiveController, UNO_QUERY); + Reference< runtime::XFormController > xParent; + while (xChild.is()) + { + xChild = Reference< XChild>(xChild->getParent(), UNO_QUERY); + xParent = Reference< runtime::XFormController >(xChild, UNO_QUERY); + Reference< XPropertySet> xParentSet; + if (xParent.is()) + xParentSet = Reference< XPropertySet>(xParent->getModel(), UNO_QUERY); + if (xParentSet.is()) + { + xParentSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate; + if (m_eNavigate == NavigationBarMode_CURRENT) + break; + } + } + m_xNavigationController = xParent; + } + break; + + case NavigationBarMode_CURRENT: + m_xNavigationController = m_xActiveController; + break; + + default: + m_xNavigationController = NULL; + m_bDatabaseBar = sal_False; + } + + m_aNavControllerFeatures.dispose(); + if ( m_xNavigationController.is() && ( m_xNavigationController != m_xActiveController ) ) + m_aNavControllerFeatures.assign( m_xNavigationController ); + + // an dem Controller, der die Navigation regelt, wg. RecordCount lauschen + Reference< XPropertySet> xNavigationSet; + if (m_xNavigationController.is()) + { + xNavigationSet = Reference< XPropertySet>(m_xNavigationController->getModel(), UNO_QUERY); + if (xNavigationSet.is()) + xNavigationSet->addPropertyChangeListener(FM_PROP_ROWCOUNT,this); + } + return; + } + } + } + + m_eNavigate = NavigationBarMode_NONE; + m_bDatabaseBar = sal_False; + m_xNavigationController = NULL; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::stopListening() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::stopListening" ); + if ( impl_checkDisposed() ) + return; + + Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY); + if ( xDatabaseForm.is() ) + { + if (m_xNavigationController.is()) + { + Reference< XPropertySet> xSet(m_xNavigationController->getModel(), UNO_QUERY); + if (xSet.is()) + xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this); + + } + } + + m_bDatabaseBar = sal_False; + m_eNavigate = NavigationBarMode_NONE; + m_xNavigationController = NULL; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::ShowSelectionProperties( sal_Bool bShow ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ShowSelectionProperties" ); + if ( impl_checkDisposed() ) + return; + + // if the window is already visible, only update the state + sal_Bool bHasChild = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_PROPERTIES ); + if ( bHasChild && bShow ) + UpdateSlot( SID_FM_PROPERTY_CONTROL ); + + // else toggle state + else + m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES); + + InvalidateSlot( SID_FM_PROPERTIES, sal_False ); + InvalidateSlot( SID_FM_CTL_PROPERTIES, sal_False ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnFoundData, FmFoundRecordInformation*, pfriWhere) +{ + if ( impl_checkDisposed() ) + return 0; + + DBG_ASSERT((pfriWhere->nContext >= 0) && (pfriWhere->nContext < (sal_Int16)m_aSearchForms.size()), + "FmXFormShell::OnFoundData : ungueltiger Kontext !"); + Reference< XForm> xForm( m_aSearchForms.at(pfriWhere->nContext)); + DBG_ASSERT(xForm.is(), "FmXFormShell::OnFoundData : ungueltige Form !"); + + Reference< XRowLocate> xCursor(xForm, UNO_QUERY); + if (!xCursor.is()) + return 0; // was soll ich da machen ? + + // zum Datensatz + try + { + xCursor->moveToBookmark(pfriWhere->aPosition); + } + catch(const SQLException&) + { + OSL_ENSURE(0,"Can position on bookmark!"); + } + + LoopGrids(GA_FORCE_SYNC); + + // und zum Feld (dazu habe ich vor dem Start des Suchens die XVclComponent-Interfaces eingesammelt) + DBG_ASSERT(pfriWhere->nFieldPos < m_arrSearchedControls.Count(), "FmXFormShell::OnFoundData : ungueltige Daten uebergeben !"); + SdrObject* pObject = m_arrSearchedControls.GetObject(pfriWhere->nFieldPos); + DBG_ASSERT(pObject != NULL, "FmXFormShell::OnFoundData : unerwartet : ungueltiges VclControl-Interface"); + + m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); + m_pShell->GetFormView()->MarkObj(pObject, m_pShell->GetFormView()->GetSdrPageView()); + + FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject ); + Reference< XControlModel > xControlModel( pFormObject ? pFormObject->GetUnoControlModel() : Reference< XControlModel >() ); + DBG_ASSERT( xControlModel.is(), "FmXFormShell::OnFoundData: invalid control!" ); + if ( !xControlModel.is() ) + return 0; + + // disable the permanent cursor for the last grid we found a record + if (m_xLastGridFound.is() && (m_xLastGridFound != xControlModel)) + { + Reference< XPropertySet> xOldSet(m_xLastGridFound, UNO_QUERY); + xOldSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, makeAny( (sal_Bool)sal_False ) ); + Reference< XPropertyState> xOldSetState(xOldSet, UNO_QUERY); + if (xOldSetState.is()) + xOldSetState->setPropertyToDefault(FM_PROP_CURSORCOLOR); + else + xOldSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); + } + + // wenn das Feld sich in einem GridControl befindet, muss ich dort noch in die entsprechende Spalte gehen + sal_Int32 nGridColumn = m_arrRelativeGridColumn.GetObject(pfriWhere->nFieldPos); + if (nGridColumn != -1) + { // dummer weise muss ich mir das Control erst wieder besorgen + Reference< XControl> xControl( impl_getControl( xControlModel, *pFormObject ) ); + Reference< XGrid> xGrid(xControl, UNO_QUERY); + DBG_ASSERT(xGrid.is(), "FmXFormShell::OnFoundData : ungueltiges Control !"); + // wenn eine der Asserts anschlaegt, habe ich beim Aufbauen von m_arrSearchedControls wohl was falsch gemacht + + // enable a permanent cursor for the grid so we can see the found text + Reference< XPropertySet> xModelSet(xControlModel, UNO_QUERY); + DBG_ASSERT(xModelSet.is(), "FmXFormShell::OnFoundData : invalid control model (no property set) !"); + xModelSet->setPropertyValue( FM_PROP_ALWAYSSHOWCURSOR, makeAny( (sal_Bool)sal_True ) ); + xModelSet->setPropertyValue( FM_PROP_CURSORCOLOR, makeAny( sal_Int32( COL_LIGHTRED ) ) ); + m_xLastGridFound = xControlModel; + + if ( xGrid.is() ) + xGrid->setCurrentColumnPosition((sal_Int16)nGridColumn); + } + + // als der Cursor neu positioniert wurde, habe ich (in positioned) meine Formularleisten-Slots invalidiert, aber das greift + // hier dummerweise nicht, da i.A. ja der (modale) Suchdialog oben ist ... also Gewalt ... + sal_uInt16 nPos = 0; + while (DatabaseSlotMap[nPos]) + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(DatabaseSlotMap[nPos++]); + // leider geht das Update im Gegensatz zum Invalidate nur mit einzelnen Slots) + + return 0; +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnCanceledNotFound, FmFoundRecordInformation*, pfriWhere) +{ + if ( impl_checkDisposed() ) + return 0; + + DBG_ASSERT((pfriWhere->nContext >= 0) && (pfriWhere->nContext < (sal_Int16)m_aSearchForms.size()), + "FmXFormShell::OnCanceledNotFound : ungueltiger Kontext !"); + Reference< XForm> xForm( m_aSearchForms.at(pfriWhere->nContext)); + DBG_ASSERT(xForm.is(), "FmXFormShell::OnCanceledNotFound : ungueltige Form !"); + + Reference< XRowLocate> xCursor(xForm, UNO_QUERY); + if (!xCursor.is()) + return 0; // was soll ich da machen ? + + // zum Datensatz + try + { + xCursor->moveToBookmark(pfriWhere->aPosition); + } + catch(const SQLException&) + { + OSL_ENSURE(0,"Can position on bookmark!"); + } + + + m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); + return 0L; +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnSearchContextRequest, FmSearchContext*, pfmscContextInfo) +{ + if ( impl_checkDisposed() ) + return 0; + + DBG_ASSERT(pfmscContextInfo->nContext < (sal_Int16)m_aSearchForms.size(), "FmXFormShell::OnSearchContextRequest : invalid parameter !"); + Reference< XForm> xForm( m_aSearchForms.at(pfmscContextInfo->nContext)); + DBG_ASSERT(xForm.is(), "FmXFormShell::OnSearchContextRequest : unexpected : invalid context !"); + + Reference< XResultSet> xIter(xForm, UNO_QUERY); + DBG_ASSERT(xIter.is(), "FmXFormShell::OnSearchContextRequest : unexpected : context has no iterator !"); + + // -------------------------------------------------------------------------------------------- + // die Liste der zu involvierenden Felder zusammenstellen (sind die ControlSources aller Felder, die eine solche Eigenschaft habe) + UniString strFieldList, sFieldDisplayNames; + m_arrSearchedControls.Remove(0, m_arrSearchedControls.Count()); + m_arrRelativeGridColumn.Remove(0, m_arrRelativeGridColumn.Count()); + + // folgendes kleines Problem : Ich brauche, um gefundene Felder zu markieren, SdrObjekte. Um hier festzustellen, welche Controls + // ich in die Suche einbeziehen soll, brauche ich Controls (also XControl-Interfaces). Ich muss also ueber eines von beiden + // iterieren und mir das jeweils andere besorgen. Dummerweise gibt es keine direkte Verbindung zwischen beiden Welten (abgesehen + // von einem GetUnoControl an SdrUnoObject, das aber ein OutputDevice verlangt, womit ich nichts anfangen kann). + // Allerdings komme ich sowohl von einem Control als auch von einem SdrObject zum Model, und damit ist mir mit einer doppelten + // Schleife die Zuordnung SdrObject<->Control moeglich. + // Die Alternative zu dieser (unschoenen und sicher auch nicht ganz fixen) Loesung waere, auf das Cachen der SdrObjects zu + // verzichten, was dann aber in OnFoundData zu wesentlicher Mehrarbeit fuehren wuerde (da ich mir dort jedesmal das SdrObject + // erst besorgen muesste). Da aber OnFoundData i.d.R. oefter aufgerufen wird als ExecuteSearch, erledige ich das hier. + + Reference< XNameAccess> xValidFormFields; + Reference< XColumnsSupplier> xSupplyCols(xIter, UNO_QUERY); + DBG_ASSERT(xSupplyCols.is(), "FmXFormShell::OnSearchContextRequest : invalid cursor : no columns supplier !"); + if (xSupplyCols.is()) + xValidFormFields = xSupplyCols->getColumns(); + DBG_ASSERT(xValidFormFields.is(), "FmXFormShell::OnSearchContextRequest : form has no fields !"); + + // aktuelle(r) Page/Controller + FmFormPage* pCurrentPage = m_pShell->GetCurPage(); + DBG_ASSERT(pCurrentPage!=NULL, "FmXFormShell::OnSearchContextRequest : no page !"); + // alle Sdr-Controls dieser Seite durchsuchen ... + ::rtl::OUString sControlSource, aName; + + SdrObjListIter aPageIter( *pCurrentPage ); + while ( aPageIter.IsMore() ) + { + SdrObject* pCurrent = aPageIter.Next(); + FmFormObj* pFormObject = FmFormObj::GetFormObject( pCurrent ); + // note that in case pCurrent is a virtual object, pFormObject points to the referenced object + + if ( !pFormObject ) + continue; + + // the current object's model, in different tastes + Reference< XControlModel> xControlModel( pFormObject->GetUnoControlModel() ); + Reference< XFormComponent > xCurrentFormComponent( xControlModel, UNO_QUERY ); + DBG_ASSERT( xCurrentFormComponent.is(), "FmXFormShell::OnSearchContextRequest: invalid objects!" ); + if ( !xCurrentFormComponent.is() ) + continue; + + // does the component belong to the form which we're interested in? + if ( xCurrentFormComponent->getParent() != xForm ) + continue; + + // ... nach der ControlSource-Eigenschaft fragen + SearchableControlIterator iter( xCurrentFormComponent ); + Reference< XControl> xControl; + // das Control, das als Model xControlModel hat + // (das folgende while kann mehrmals durchlaufen werden, ohne dass das Control sich aendert, dann muss + // ich nicht jedesmal neu suchen) + + Reference< XInterface > xSearchable( iter.Next() ); + while ( xSearchable.is() ) + { + sControlSource = iter.getCurrentValue(); + if ( sControlSource.getLength() == 0 ) + { // das aktuelle Element hat keine ControlSource, also ist es ein GridControl (das ist das einzige, was + // der SearchableControlIterator noch zulaesst) + xControl = impl_getControl( xControlModel, *pFormObject ); + DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !"); + + Reference< XGridPeer> xGridPeer; + if ( xControl.is() ) + xGridPeer.set( xControl->getPeer(), UNO_QUERY ); + do + { + if (!xGridPeer.is()) + break; + + Reference< XIndexAccess> xPeerContainer(xGridPeer, UNO_QUERY); + if (!xPeerContainer.is()) + break; + + Reference< XIndexAccess> xModelColumns(xGridPeer->getColumns(), UNO_QUERY); + DBG_ASSERT(xModelColumns.is(), "FmXFormShell::OnSearchContextRequest : there is a grid control without columns !"); + // the case 'no columns' should be indicated with an empty container, I think ... + DBG_ASSERT(xModelColumns->getCount() >= xPeerContainer->getCount(), "FmXFormShell::OnSearchContextRequest : impossible : have more view than model columns !"); + + Reference< XInterface> xCurrentColumn; + for (sal_Int16 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos) + { + xPeerContainer->getByIndex(nViewPos) >>= xCurrentColumn; + if (!xCurrentColumn.is()) + continue; + + // can we use this column control fo searching ? + if (!IsSearchableControl(xCurrentColumn)) + continue; + + sal_Int16 nModelPos = GridView2ModelPos(xModelColumns, nViewPos); + Reference< XPropertySet> xCurrentColModel; + xModelColumns->getByIndex(nModelPos) >>= xCurrentColModel; + aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_CONTROLSOURCE)); + // the cursor has a field matching the control source ? + if (xValidFormFields->hasByName(aName)) + { + strFieldList += aName.getStr(); + strFieldList += ';'; + + sFieldDisplayNames += ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_LABEL)).getStr(); + sFieldDisplayNames += ';'; + + pfmscContextInfo->arrFields.push_back(xCurrentColumn); + + // und das SdrObjekt zum Feld + m_arrSearchedControls.C40_INSERT(SdrObject, pCurrent, m_arrSearchedControls.Count()); + // die Nummer der Spalte + m_arrRelativeGridColumn.Insert(nViewPos, m_arrRelativeGridColumn.Count()); + } + } + } while (sal_False); + } + else + { + if (sControlSource.getLength() && xValidFormFields->hasByName(sControlSource)) + { + // jetzt brauche ich das Control zum SdrObject + if (!xControl.is()) + { + xControl = impl_getControl( xControlModel, *pFormObject ); + DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !"); + } + + if (IsSearchableControl(xControl)) + { // alle Tests ueberstanden -> in die Liste mit aufnehmen + strFieldList += sControlSource.getStr(); + strFieldList += ';'; + + // the label which should appear for the control : + sFieldDisplayNames += getLabelName(Reference< XPropertySet>(xControlModel, UNO_QUERY)).getStr(); + sFieldDisplayNames += ';'; + + // das SdrObjekt merken (beschleunigt die Behandlung in OnFoundData) + m_arrSearchedControls.C40_INSERT(SdrObject, pCurrent, m_arrSearchedControls.Count()); + + // die Nummer der Spalte (hier ein Dummy, nur fuer GridControls interesant) + m_arrRelativeGridColumn.Insert(-1, m_arrRelativeGridColumn.Count()); + + // und fuer die formatierte Suche ... + pfmscContextInfo->arrFields.push_back(Reference< XInterface>(xControl, UNO_QUERY)); + } + } + } + + xSearchable = iter.Next(); + } + } + + strFieldList.EraseTrailingChars(';'); + sFieldDisplayNames.EraseTrailingChars(';'); + + if (!pfmscContextInfo->arrFields.size()) + { + pfmscContextInfo->arrFields.clear(); + pfmscContextInfo->xCursor = NULL; + pfmscContextInfo->strUsedFields.Erase(); + return 0L; + } + + pfmscContextInfo->xCursor = xIter; + pfmscContextInfo->strUsedFields = strFieldList; + pfmscContextInfo->sFieldDisplayNames = sFieldDisplayNames; + + // 66463 - 31.05.99 - FS + // wenn der Cursor sich in einem anderen RecordMode als STANDARD befindet, ruecksetzen + Reference< XPropertySet> xCursorSet(pfmscContextInfo->xCursor, UNO_QUERY); + Reference< XResultSetUpdate> xUpdateCursor(pfmscContextInfo->xCursor, UNO_QUERY); + if (xUpdateCursor.is() && xCursorSet.is() && xCursorSet.is()) + { + if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISNEW))) + xUpdateCursor->moveToCurrentRow(); + else if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISMODIFIED))) + xUpdateCursor->cancelRowUpdates(); + } + + return pfmscContextInfo->arrFields.size(); +} + + // XContainerListener +//------------------------------------------------------------------------------ +void FmXFormShell::elementInserted(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementInserted" ); + if ( impl_checkDisposed() ) + return; + + // neues Object zum lauschen + Reference< XInterface> xTemp; + evt.Element >>= xTemp; + AddElement(xTemp); + m_pShell->DetermineForms(sal_True); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::elementReplaced(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementReplaced" ); + if ( impl_checkDisposed() ) + return; + + Reference< XInterface> xTemp; + evt.ReplacedElement >>= xTemp; + RemoveElement(xTemp); + evt.Element >>= xTemp; + AddElement(xTemp); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::elementRemoved(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementRemoved" ); + if ( impl_checkDisposed() ) + return; + + Reference< XInterface> xTemp; + evt.Element >>= xTemp; + RemoveElement(xTemp); + m_pShell->DetermineForms(sal_True); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::UpdateForms( sal_Bool _bInvalidate ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::UpdateForms" ); + if ( impl_checkDisposed() ) + return; + + Reference< XIndexAccess > xForms; + + FmFormPage* pPage = m_pShell->GetCurPage(); + if ( pPage ) + { + if ( m_pShell->m_bDesignMode ) + xForms = xForms.query( pPage->GetForms( false ) ); + } + + if ( m_xForms != xForms ) + { + RemoveElement( m_xForms ); + m_xForms = xForms; + AddElement( m_xForms ); + } + + m_pShell->DetermineForms( _bInvalidate ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::AddElement(const Reference< XInterface>& _xElement) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::AddElement" ); + if ( impl_checkDisposed() ) + return; + impl_AddElement_nothrow(_xElement); +} +// ----------------------------------------------------------------------------- +void FmXFormShell::impl_AddElement_nothrow(const Reference< XInterface>& Element) +{ + // am Container horchen + const Reference< XIndexContainer> xContainer(Element, UNO_QUERY); + if (xContainer.is()) + { + const sal_uInt32 nCount = xContainer->getCount(); + Reference< XInterface> xElement; + for (sal_uInt32 i = 0; i < nCount; ++i) + { + xElement.set(xContainer->getByIndex(i),UNO_QUERY); + impl_AddElement_nothrow(xElement); + } + + const Reference< XContainer> xCont(Element, UNO_QUERY); + if (xCont.is()) + xCont->addContainerListener(this); + } + + const Reference< ::com::sun::star::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY); + if (xSelSupplier.is()) + xSelSupplier->addSelectionChangeListener(this); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::RemoveElement(const Reference< XInterface>& Element) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::RemoveElement" ); + if ( impl_checkDisposed() ) + return; + impl_RemoveElement_nothrow(Element); +} +//------------------------------------------------------------------------------ +void FmXFormShell::impl_RemoveElement_nothrow(const Reference< XInterface>& Element) +{ + const Reference< ::com::sun::star::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY); + if (xSelSupplier.is()) + xSelSupplier->removeSelectionChangeListener(this); + + // Verbindung zu Kindern aufheben + const Reference< XIndexContainer> xContainer(Element, UNO_QUERY); + if (xContainer.is()) + { + const Reference< XContainer> xCont(Element, UNO_QUERY); + if (xCont.is()) + xCont->removeContainerListener(this); + + const sal_uInt32 nCount = xContainer->getCount(); + Reference< XInterface> xElement; + for (sal_uInt32 i = 0; i < nCount; i++) + { + xElement.set(xContainer->getByIndex(i),UNO_QUERY); + impl_RemoveElement_nothrow(xElement); + } + } + + InterfaceBag::iterator wasSelectedPos = m_aCurrentSelection.find( Element ); + if ( wasSelectedPos != m_aCurrentSelection.end() ) + m_aCurrentSelection.erase( wasSelectedPos ); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::selectionChanged(const EventObject& rEvent) throw(::com::sun::star::uno::RuntimeException) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::selectionChanged" ); + if ( impl_checkDisposed() ) + return; + + Reference< XSelectionSupplier > xSupplier( rEvent.Source, UNO_QUERY ); + Reference< XInterface > xSelObj( xSupplier->getSelection(), UNO_QUERY ); + // es wurde eine Selektion weggenommen, dieses kann nur durch die Shell vorgenommen werden + if ( !xSelObj.is() ) + return; + + EnableTrackProperties(sal_False); + + sal_Bool bMarkChanged = m_pShell->GetFormView()->checkUnMarkAll(rEvent.Source); + Reference< XForm > xNewForm( GetForm( rEvent.Source ) ); + + InterfaceBag aNewSelection; + aNewSelection.insert( Reference< XInterface >( xSelObj, UNO_QUERY ) ); + + if ( setCurrentSelection( aNewSelection ) && IsPropBrwOpen() ) + ShowSelectionProperties( sal_True ); + + EnableTrackProperties(sal_True); + + if ( bMarkChanged ) + m_pShell->NotifyMarkListChanged( m_pShell->GetFormView() ); +} + +//------------------------------------------------------------------------------ +IMPL_LINK(FmXFormShell, OnTimeOut, void*, /*EMPTYTAG*/) +{ + if ( impl_checkDisposed() ) + return 0; + + if (m_pShell->IsDesignMode() && m_pShell->GetFormView()) + SetSelection(m_pShell->GetFormView()->GetMarkedObjectList()); + + return 0; +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetSelectionDelayed() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetSelectionDelayed" ); + if ( impl_checkDisposed() ) + return; + + if (m_pShell->IsDesignMode() && IsTrackPropertiesEnabled() && !m_aMarkTimer.IsActive()) + m_aMarkTimer.Start(); +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetSelection(const SdrMarkList& rMarkList) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetSelection" ); + if ( impl_checkDisposed() ) + return; + + DetermineSelection(rMarkList); + m_pShell->NotifyMarkListChanged(m_pShell->GetFormView()); +} + +//------------------------------------------------------------------------ +void FmXFormShell::DetermineSelection(const SdrMarkList& rMarkList) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::DetermineSelection" ); + if ( setCurrentSelectionFromMark( rMarkList ) && IsPropBrwOpen() ) + ShowSelectionProperties( sal_True ); +} + +//------------------------------------------------------------------------------ +sal_Bool FmXFormShell::IsPropBrwOpen() const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsPropBrwOpen" ); + if ( impl_checkDisposed() ) + return sal_False; + + return( ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() ) ? + m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES) : sal_False ); +} + +//------------------------------------------------------------------------------ +class FmXFormShell::SuspendPropertyTracking +{ +private: + FmXFormShell& m_rShell; + sal_Bool m_bEnabled; + +public: + SuspendPropertyTracking( FmXFormShell& _rShell ) + :m_rShell( _rShell ) + ,m_bEnabled( sal_False ) + { + if ( m_rShell.IsTrackPropertiesEnabled() ) + { + m_rShell.EnableTrackProperties( sal_False ); + m_bEnabled = sal_True; + } + } + + ~SuspendPropertyTracking( ) + { + if ( m_bEnabled ) // note that ( sal_False != m_bEnabled ) implies ( NULL != m_pShell ) + m_rShell.EnableTrackProperties( sal_True ); + } +}; + +//------------------------------------------------------------------------------ +void FmXFormShell::SetDesignMode(sal_Bool bDesign) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetDesignMode" ); + if ( impl_checkDisposed() ) + return; + + DBG_ASSERT(m_pShell->GetFormView(), "FmXFormShell::SetDesignMode : invalid call (have no shell or no view) !"); + m_bChangingDesignMode = sal_True; + + // 67506 - 15.07.99 - FS + // if we're switching off the design mode we have to force the property browser to be closed + // so it can commit it's changes _before_ we load the forms + if (!bDesign) + { + m_bHadPropertyBrowserInDesignMode = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES); + if (m_bHadPropertyBrowserInDesignMode) + m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES); + } + + FmFormView* pFormView = m_pShell->GetFormView(); + if (bDesign) + { + // we are currently filtering, so stop filtering + if (m_bFilterMode) + stopFiltering(sal_False); + + // an den Objekten meiner MarkList als Listener abmelden + pFormView->GetImpl()->stopMarkListWatching(); + } + else + { + m_aMarkTimer.Stop(); + + SuspendPropertyTracking aSuspend( *this ); + pFormView->GetImpl()->saveMarkList( sal_True ); + } + + if (bDesign && m_xExternalViewController.is()) + CloseExternalFormViewer(); + + pFormView->ChangeDesignMode(bDesign); + + // Listener benachrichtigen + FmDesignModeChangedHint aChangedHint( bDesign ); + m_pShell->Broadcast(aChangedHint); + + m_pShell->m_bDesignMode = bDesign; + UpdateForms( sal_False ); + + m_pTextShell->designModeChanged( m_pShell->m_bDesignMode ); + + if (bDesign) + { + SdrMarkList aList; + { + // during changing the mark list, don't track the selected objects in the property browser + SuspendPropertyTracking aSuspend( *this ); + // restore the marks + pFormView->GetImpl()->restoreMarkList( aList ); + } + + // synchronize with the restored mark list + if ( aList.GetMarkCount() ) + SetSelection( aList ); + } + else + { + // am Model der View als Listener anmelden (damit ich mitbekomme, wenn jemand waehrend des Alive-Modus + // Controls loescht, die ich eigentlich mit saveMarkList gespeichert habe) (60343) + pFormView->GetImpl()->startMarkListWatching(); + } + + m_pShell->UIFeatureChanged(); + + // 67506 - 15.07.99 - FS + if (bDesign && m_bHadPropertyBrowserInDesignMode) + { + // The UIFeatureChanged performes an update (a check of the available features) asynchronously. + // So we can't call ShowSelectionProperties directly as the according feature isn't enabled yet. + // That's why we use an asynchron execution on the dispatcher. + // (And that's why this has to be done AFTER the UIFeatureChanged.) + m_pShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON ); + } + m_bChangingDesignMode = sal_False; +} + +//------------------------------------------------------------------------------ +Reference< XControl> FmXFormShell::impl_getControl( const Reference< XControlModel >& i_rxModel, const FmFormObj& i_rKnownFormObj ) +{ + if ( impl_checkDisposed() ) + return NULL; + + Reference< XControl > xControl; + try + { + Reference< XControlContainer> xControlContainer( getControlContainerForView(), UNO_SET_THROW ); + + Sequence< Reference< XControl > > seqControls( xControlContainer->getControls() ); + const Reference< XControl >* pControls = seqControls.getArray(); + // ... die ich dann durchsuchen kann + for (sal_Int32 i=0; i<seqControls.getLength(); ++i) + { + xControl.set( pControls[i], UNO_SET_THROW ); + Reference< XControlModel > xCurrentModel( xControl->getModel() ); + if ( xCurrentModel == i_rxModel ) + break; + xControl.clear(); + } + + if ( !xControl.is() ) + { + // fallabck (some controls might not have been created, yet, since they were never visible so far) + Reference< XControl > xContainerControl( xControlContainer, UNO_QUERY_THROW ); + const Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerControl->getPeer() ); + ENSURE_OR_THROW( pContainerWindow, "unexpected control container implementation" ); + + const SdrView* pSdrView = m_pShell ? m_pShell->GetFormView() : NULL; + ENSURE_OR_THROW( pSdrView, "no current view" ); + + xControl.set( i_rKnownFormObj.GetUnoControl( *pSdrView, *pContainerWindow ), UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + OSL_ENSURE( xControl.is(), "FmXFormShell::impl_getControl: no control found!" ); + return xControl; +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_collectFormSearchContexts_nothrow( const Reference< XInterface>& _rxStartingPoint, + const ::rtl::OUString& _rCurrentLevelPrefix, FmFormArray& _out_rForms, ::std::vector< String >& _out_rNames ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_collectFormSearchContexts_nothrow" ); + try + { + Reference< XIndexAccess> xContainer( _rxStartingPoint, UNO_QUERY ); + if ( !xContainer.is() ) + return; + + sal_Int32 nCount( xContainer->getCount() ); + if ( nCount == 0 ) + return; + + ::rtl::OUString sCurrentFormName; + ::rtl::OUStringBuffer aNextLevelPrefix; + for ( sal_Int32 i=0; i<nCount; ++i ) + { + // is the current child a form? + Reference< XForm > xCurrentAsForm( xContainer->getByIndex(i), UNO_QUERY ); + if ( !xCurrentAsForm.is() ) + continue; + + Reference< XNamed > xNamed( xCurrentAsForm, UNO_QUERY_THROW ); + sCurrentFormName = xNamed->getName(); + + // the name of the current form + ::rtl::OUStringBuffer sCompleteCurrentName( sCurrentFormName ); + if ( _rCurrentLevelPrefix.getLength() ) + { + sCompleteCurrentName.appendAscii( " (" ); + sCompleteCurrentName.append ( _rCurrentLevelPrefix ); + sCompleteCurrentName.appendAscii( ")" ); + } + + // the prefix for the next level + aNextLevelPrefix = _rCurrentLevelPrefix; + if ( _rCurrentLevelPrefix.getLength() ) + aNextLevelPrefix.append( (sal_Unicode)'/' ); + aNextLevelPrefix.append( sCurrentFormName ); + + // remember both the form and it's "display name" + _out_rForms.push_back( xCurrentAsForm ); + _out_rNames.push_back( sCompleteCurrentName.makeStringAndClear() ); + + // und absteigen + impl_collectFormSearchContexts_nothrow( xCurrentAsForm, aNextLevelPrefix.makeStringAndClear(), _out_rForms, _out_rNames ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::startFiltering() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::startFiltering" ); + if ( impl_checkDisposed() ) + return; + + // setting all forms in filter mode + FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); + + // if the active controller is our external one we have to use the trigger controller + Reference< XControlContainer> xContainer; + if (getActiveController() == m_xExternalViewController) + { + DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but noone triggered this !"); + xContainer = m_xExtViewTriggerController->getContainer(); + } + else + xContainer = getActiveController()->getContainer(); + + FmWinRecList::iterator i = pXView->findWindow(xContainer); + if (i != pXView->getWindowList().end()) + { + const ::std::vector< Reference< runtime::XFormController> >& rControllerList = (*i)->GetList(); + for (::std::vector< Reference< runtime::XFormController> >::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + Reference< XModeSelector> xModeSelector(*j, UNO_QUERY); + if (xModeSelector.is()) + xModeSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) ) ); + } + } + + m_bFilterMode = sal_True; + + m_pShell->UIFeatureChanged(); + SfxViewFrame* pViewFrame = m_pShell->GetViewShell()->GetViewFrame(); + pViewFrame->GetBindings().InvalidateShell( *m_pShell ); + + if ( pViewFrame->KnowsChildWindow( SID_FM_FILTER_NAVIGATOR ) + && !pViewFrame->HasChildWindow( SID_FM_FILTER_NAVIGATOR ) + ) + { + pViewFrame->ToggleChildWindow( SID_FM_FILTER_NAVIGATOR ); + } +} + +//------------------------------------------------------------------------------ +void saveFilter(const Reference< runtime::XFormController >& _rxController) +{ + Reference< XPropertySet> xFormAsSet(_rxController->getModel(), UNO_QUERY); + Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY); + Reference< XIndexAccess> xControllerAsIndex(_rxController, UNO_QUERY); + + // call the subcontroller + Reference< runtime::XFormController > xController; + for (sal_Int32 i = 0, nCount = xControllerAsIndex->getCount(); i < nCount; ++i) + { + xControllerAsIndex->getByIndex(i) >>= xController; + saveFilter(xController); + } + + try + { + + xFormAsSet->setPropertyValue(FM_PROP_FILTER, xControllerAsSet->getPropertyValue(FM_PROP_FILTER)); + xFormAsSet->setPropertyValue(FM_PROP_APPLYFILTER, makeAny( (sal_Bool)sal_True ) ); + } + catch (const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + +} + +//------------------------------------------------------------------------------ +void FmXFormShell::stopFiltering(sal_Bool bSave) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::stopFiltering" ); + if ( impl_checkDisposed() ) + return; + + m_bFilterMode = sal_False; + + FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); + + // if the active controller is our external one we have to use the trigger controller + Reference< XControlContainer> xContainer; + if (getActiveController() == m_xExternalViewController) + { + DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::stopFiltering : inconsistent : active external controller, but noone triggered this !"); + xContainer = m_xExtViewTriggerController->getContainer(); + } + else + xContainer = getActiveController()->getContainer(); + + FmWinRecList::iterator i = pXView->findWindow(xContainer); + if (i != pXView->getWindowList().end()) + { + const ::std::vector< Reference< runtime::XFormController > >& rControllerList = (*i)->GetList(); + ::std::vector < ::rtl::OUString > aOriginalFilters; + ::std::vector < sal_Bool > aOriginalApplyFlags; + + if (bSave) + { + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + if (bSave) + { // remember the current filter settings in case we're goin to reload the forms below (which may fail) + try + { + Reference< XPropertySet > xFormAsSet((*j)->getModel(), UNO_QUERY); + aOriginalFilters.push_back(::comphelper::getString(xFormAsSet->getPropertyValue(FM_PROP_FILTER))); + aOriginalApplyFlags.push_back(::comphelper::getBOOL(xFormAsSet->getPropertyValue(FM_PROP_APPLYFILTER))); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::stopFiltering : could not get the original filter !"); + // put dummies into the arrays so the they have the right size + + if (aOriginalFilters.size() == aOriginalApplyFlags.size()) + // the first getPropertyValue failed -> use two dummies + aOriginalFilters.push_back( ::rtl::OUString() ); + aOriginalApplyFlags.push_back( sal_False ); + } + } + saveFilter(*j); + } + } + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + + Reference< XModeSelector> xModeSelector(*j, UNO_QUERY); + if (xModeSelector.is()) + xModeSelector->setMode( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) ) ); + } + if (bSave) // execute the filter + { + const ::std::vector< Reference< runtime::XFormController > > & rControllers = (*i)->GetList(); + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllers.begin(); + j != rControllers.end(); ++j) + { + Reference< XLoadable> xReload((*j)->getModel(), UNO_QUERY); + if (!xReload.is()) + continue; + Reference< XPropertySet > xFormSet(xReload, UNO_QUERY); + + try + { + xReload->reload(); + } + catch(Exception&) + { + DBG_ERROR("FmXFormShell::stopFiltering: Exception occured!"); + } + + if (!isRowSetAlive(xFormSet)) + { // something went wrong -> restore the original state + ::rtl::OUString sOriginalFilter = aOriginalFilters[ j - rControllers.begin() ]; + sal_Bool bOriginalApplyFlag = aOriginalApplyFlags[ j - rControllers.begin() ]; + try + { + xFormSet->setPropertyValue(FM_PROP_FILTER, makeAny(sOriginalFilter)); + xFormSet->setPropertyValue(FM_PROP_APPLYFILTER, makeAny(bOriginalApplyFlag)); + xReload->reload(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + } + } + } + } + + m_pShell->UIFeatureChanged(); + m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell); +} + +//------------------------------------------------------------------------------ +void clearFilter(const Reference< runtime::XFormController >& _rxController) +{ + Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY); + Reference< XIndexAccess> xControllerAsIndex(_rxController, UNO_QUERY); + + // call the subcontroller + Reference< runtime::XFormController > xController; + for (sal_Int32 i = 0, nCount = xControllerAsIndex->getCount(); + i < nCount; i++) + { + xControllerAsIndex->getByIndex(i) >>= xController; + clearFilter(xController); + } + + // clear the filter + Reference< XIndexContainer> xContainer; + xControllerAsSet->getPropertyValue(FM_PROP_FILTERSUPPLIER) >>= xContainer; + if (xContainer.is()) + { + // clear the current filter + Sequence< PropertyValue> aCondition; + + // as there is always an empty row, if we have a filter: + if (xContainer->getCount()) + { + xControllerAsSet->setPropertyValue(FM_PROP_CURRENTFILTER, makeAny(sal_Int32(xContainer->getCount() - 1))); + while (xContainer->getCount() > 1) + xContainer->removeByIndex(0); + } + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::clearFilter() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::clearFilter" ); + if ( impl_checkDisposed() ) + return; + + FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); + + // if the active controller is our external one we have to use the trigger controller + Reference< XControlContainer> xContainer; + if (getActiveController() == m_xExternalViewController) + { + DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::clearFilter : inconsistent : active external controller, but noone triggered this !"); + xContainer = m_xExtViewTriggerController->getContainer(); + } + else + xContainer = getActiveController()->getContainer(); + + FmWinRecList::iterator i = pXView->findWindow(xContainer); + if (i != pXView->getWindowList().end()) + { + const ::std::vector< Reference< runtime::XFormController > > & rControllerList = (*i)->GetList(); + for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllerList.begin(); + j != rControllerList.end(); ++j) + { + ::clearFilter(*j); + } + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::CreateExternalView() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::CreateExternalView" ); + if ( impl_checkDisposed() ) + return; + + DBG_ASSERT(m_xAttachedFrame.is(), "FmXFormShell::CreateExternalView : no frame !"); + + // the frame the external view is displayed in + sal_Bool bAlreadyExistent = m_xExternalViewController.is(); + Reference< ::com::sun::star::frame::XFrame> xExternalViewFrame; + ::rtl::OUString sFrameName = ::rtl::OUString::createFromAscii("_beamer"); + sal_Int32 nSearchFlags = ::com::sun::star::frame::FrameSearchFlag::CHILDREN | ::com::sun::star::frame::FrameSearchFlag::CREATE; + + Reference< runtime::XFormController > xCurrentNavController( getNavController()); + // the creation of the "partwindow" may cause a deactivate of the document which will result in our nav controller to be set to NULL + + // _first_ check if we have any valid fields we can use for the grid view + // FS - 21.10.99 - 69219 + { + FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel()); + Reference< XPropertySet> xCurrentModelSet; + sal_Bool bHaveUsableControls = sal_False; + while ((xCurrentModelSet = Reference< XPropertySet>(aModelIterator.Next(), UNO_QUERY)).is()) + { + // the FmXBoundFormFieldIterator only supplies controls with a valid control source + // so we just have to check the field type + sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID)); + switch (nClassId) + { + case FormComponentType::IMAGECONTROL: + case FormComponentType::CONTROL: + continue; + } + bHaveUsableControls = sal_True; + break; + } + + if (!bHaveUsableControls) + { + ErrorBox(NULL, WB_OK, SVX_RESSTR(RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY)).Execute(); + return; + } + } + + // load the component for external form views + if (!bAlreadyExistent) + { + URL aWantToDispatch; + aWantToDispatch.Complete = FMURL_COMPONENT_FORMGRIDVIEW; + + Reference< ::com::sun::star::frame::XDispatchProvider> xProv(m_xAttachedFrame, UNO_QUERY); + Reference< ::com::sun::star::frame::XDispatch> xDisp; + if (xProv.is()) + xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags); + if (xDisp.is()) + { + xDisp->dispatch(aWantToDispatch, Sequence< PropertyValue>()); + } + + // with this the component should be loaded, now search the frame where it resides in + xExternalViewFrame = m_xAttachedFrame->findFrame(sFrameName, ::com::sun::star::frame::FrameSearchFlag::CHILDREN); + if (xExternalViewFrame.is()) + { + m_xExternalViewController = xExternalViewFrame->getController(); + Reference< ::com::sun::star::lang::XComponent> xComp(m_xExternalViewController, UNO_QUERY); + if (xComp.is()) + xComp->addEventListener((XEventListener*)(XPropertyChangeListener*)this); + } + } + else + { + xExternalViewFrame = m_xExternalViewController->getFrame(); + Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); + + // if we display the active form we interpret the slot as "remove it" + Reference< XForm> xCurrentModel(xCurrentNavController->getModel(), UNO_QUERY); + if ((xCurrentModel == m_xExternalDisplayedForm) || (getInternalForm(xCurrentModel) == m_xExternalDisplayedForm)) + { + if ( m_xExternalViewController == getActiveController() ) + { + Reference< runtime::XFormController > xAsFormController( m_xExternalViewController, UNO_QUERY ); + ControllerFeatures aHelper( ::comphelper::getProcessServiceFactory(), xAsFormController, NULL ); + aHelper->commitCurrentControl(); + } + + Reference< runtime::XFormController > xNewController(m_xExtViewTriggerController); + CloseExternalFormViewer(); + setActiveController(xNewController); + return; + } + + URL aClearURL; + aClearURL.Complete = FMURL_GRIDVIEW_CLEARVIEW; + + Reference< ::com::sun::star::frame::XDispatch> xClear( xCommLink->queryDispatch(aClearURL, ::rtl::OUString::createFromAscii(""), 0)); + if (xClear.is()) + xClear->dispatch(aClearURL, Sequence< PropertyValue>()); + } + + // TODO: We need an interceptor at the xSupplier, which forwards all queryDispatch requests to the FormController + // instance for which this "external view" was triggered + + // get the dispatch interface of the frame so we can communicate (interceptable) with the controller + Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); + + if (m_xExternalViewController.is()) + { + DBG_ASSERT(xCommLink.is(), "FmXFormShell::CreateExternalView : the component doesn't have the necessary interfaces !"); + // collect the dispatchers we will need + URL aAddColumnURL; + aAddColumnURL.Complete = FMURL_GRIDVIEW_ADDCOLUMN; + Reference< ::com::sun::star::frame::XDispatch> xAddColumnDispatch( xCommLink->queryDispatch(aAddColumnURL, ::rtl::OUString::createFromAscii(""), 0)); + URL aAttachURL; + aAttachURL.Complete = FMURL_GRIDVIEW_ATTACHTOFORM; + Reference< ::com::sun::star::frame::XDispatch> xAttachDispatch( xCommLink->queryDispatch(aAttachURL, ::rtl::OUString::createFromAscii(""), 0)); + + if (xAddColumnDispatch.is() && xAttachDispatch.is()) + { + DBG_ASSERT(xCurrentNavController.is(), "FmXFormShell::CreateExternalView : invalid call : have no nav controller !"); + // first : dispatch the descriptions for the columns to add + Sequence< Reference< XControl> > aCurrentControls(xCurrentNavController->getControls()); + + sal_Int16 nAddedColumns = 0; + + // for radio buttons we need some special structures + DECLARE_STL_USTRINGACCESS_MAP(Sequence< ::rtl::OUString>, MapUString2UstringSeq); + DECLARE_STL_ITERATORS(MapUString2UstringSeq); + DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUString, FmMapUString2UString); + DECLARE_STL_USTRINGACCESS_MAP(sal_Int16, FmMapUString2Int16); + DECLARE_STL_ITERATORS(FmMapUString2Int16); + + MapUString2UstringSeq aRadioValueLists; + MapUString2UstringSeq aRadioListSources; + FmMapUString2UString aRadioControlSources; + FmMapUString2Int16 aRadioPositions; + + FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel()); + Reference< XPropertySet> xCurrentModelSet; + Any aCurrentBoundField; + ::rtl::OUString sColumnType,aGroupName,sControlSource; + Sequence< Property> aProps; + Reference< XPropertySet> xCurrentBoundField; + while ((xCurrentModelSet = Reference< XPropertySet>(aModelIterator.Next(), UNO_QUERY)).is()) + { + xCurrentModelSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xCurrentBoundField; + OSL_ENSURE(xCurrentModelSet.is(),"xCurrentModelSet is null!"); + // create a description of the column to be created + // first : determine it's type + + sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID)); + switch (nClassId) + { + case FormComponentType::RADIOBUTTON: + { + // get the label of the button (this is the access key for our structures) + aGroupName = getLabelName(xCurrentModelSet); + + // add the reference value of the radio button to the list source sequence + Sequence< ::rtl::OUString>& aThisGroupLabels = aRadioListSources[aGroupName]; + sal_Int32 nNewSizeL = aThisGroupLabels.getLength() + 1; + aThisGroupLabels.realloc(nNewSizeL); + aThisGroupLabels.getArray()[nNewSizeL - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_REFVALUE)); + + // add the label to the value list sequence + Sequence< ::rtl::OUString>& aThisGroupControlSources = aRadioValueLists[aGroupName]; + sal_Int32 nNewSizeC = aThisGroupControlSources.getLength() + 1; + aThisGroupControlSources.realloc(nNewSizeC); + aThisGroupControlSources.getArray()[nNewSizeC - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_LABEL)); + + // remember the controls source of the radio group + sControlSource = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_CONTROLSOURCE)); + if (aRadioControlSources.find(aGroupName) == aRadioControlSources.end()) + aRadioControlSources[aGroupName] = sControlSource; +#ifdef DBG_UTIL + else + DBG_ASSERT(aRadioControlSources[aGroupName] == sControlSource, + "FmXFormShell::CreateExternalView : inconsistent radio buttons detected !"); + // (radio buttons with the same name should have the same control source) +#endif + // remember the position within the columns + if (aRadioPositions.find(aGroupName) == aRadioPositions.end()) + aRadioPositions[aGroupName] = (sal_Int16)nAddedColumns; + + // any further handling is done below + } + continue; + + case FormComponentType::IMAGECONTROL: + case FormComponentType::CONTROL: + // no grid columns for these types (though they have a control source) + continue; + case FormComponentType::CHECKBOX: + sColumnType = FM_COL_CHECKBOX; break; + case FormComponentType::LISTBOX: + sColumnType = FM_COL_LISTBOX; break; + case FormComponentType::COMBOBOX: + sColumnType = FM_COL_COMBOBOX; break; + case FormComponentType::DATEFIELD: + sColumnType = FM_COL_DATEFIELD; break; + case FormComponentType::TIMEFIELD: + sColumnType = FM_COL_TIMEFIELD; break; + case FormComponentType::NUMERICFIELD: + sColumnType = FM_COL_NUMERICFIELD; break; + case FormComponentType::CURRENCYFIELD: + sColumnType = FM_COL_CURRENCYFIELD; break; + case FormComponentType::PATTERNFIELD: + sColumnType = FM_COL_PATTERNFIELD; break; + + case FormComponentType::TEXTFIELD: + { + sColumnType = FM_COL_TEXTFIELD; + // we know at least two different controls which are TextFields : the basic edit field and the formatted + // field. we distinguish them by their service name + Reference< XServiceInfo> xInfo(xCurrentModelSet, UNO_QUERY); + if (xInfo.is()) + { + sal_Int16 nObjectType = getControlTypeByObject(xInfo); + if (OBJ_FM_FORMATTEDFIELD == nObjectType) + sColumnType = FM_COL_FORMATTEDFIELD; + } + } + break; + default: + sColumnType = FM_COL_TEXTFIELD; break; + } + + const sal_Int16 nDispatchArgs = 3; + Sequence< PropertyValue> aDispatchArgs(nDispatchArgs); + PropertyValue* pDispatchArgs = aDispatchArgs.getArray(); + + // properties describing "meta data" about the column + // the type + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE; + pDispatchArgs->Value <<= sColumnType; + ++pDispatchArgs; + + // the pos : append the col + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS; + pDispatchArgs->Value <<= nAddedColumns; + ++pDispatchArgs; + + // the properties to forward to the new column + Sequence< PropertyValue> aColumnProps(1); + PropertyValue* pColumnProps = aColumnProps.getArray(); + + // the label + pColumnProps->Name = FM_PROP_LABEL; + pColumnProps->Value <<= getLabelName(xCurrentModelSet); + ++pColumnProps; + + // for all other props : transfer them + Reference< XPropertySetInfo> xControlModelInfo( xCurrentModelSet->getPropertySetInfo()); + DBG_ASSERT(xControlModelInfo.is(), "FmXFormShell::CreateExternalView : the control model has no property info ! This will crash !"); + aProps = xControlModelInfo->getProperties(); + const Property* pProps = aProps.getConstArray(); + + // realloc the control description sequence + sal_Int32 nExistentDescs = pColumnProps - aColumnProps.getArray(); + aColumnProps.realloc(nExistentDescs + aProps.getLength()); + pColumnProps = aColumnProps.getArray() + nExistentDescs; + + for (sal_Int32 i=0; i<aProps.getLength(); ++i, ++pProps) + { + if (pProps->Name.equals(FM_PROP_LABEL)) + // already set + continue; + if (pProps->Name.equals(FM_PROP_DEFAULTCONTROL)) + // allow the column's own "default control" + continue; + if (pProps->Attributes & PropertyAttribute::READONLY) + // assume that properties which are readonly for the control are ro for the column to be created, too + continue; + + pColumnProps->Name = pProps->Name; + pColumnProps->Value = xCurrentModelSet->getPropertyValue(pProps->Name); + ++pColumnProps; + } + aColumnProps.realloc(pColumnProps - aColumnProps.getArray()); + + // columns props are a dispatch argument + pDispatchArgs->Name = ::rtl::OUString::createFromAscii("ColumnProperties"); // TODO : fmurl.* + pDispatchArgs->Value = makeAny(aColumnProps); + ++pDispatchArgs; + DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()), + "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?"); + + // dispatch the "add column" + xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs); + ++nAddedColumns; + } + + // now for the radio button handling + sal_Int16 nOffset(0); + // properties describing the "direct" column properties + const sal_Int16 nListBoxDescription = 6; + Sequence< PropertyValue> aListBoxDescription(nListBoxDescription); + for ( ConstFmMapUString2UStringIterator aCtrlSource = aRadioControlSources.begin(); + aCtrlSource != aRadioControlSources.end(); + ++aCtrlSource, ++nOffset + ) + { + + PropertyValue* pListBoxDescription = aListBoxDescription.getArray(); + // label + pListBoxDescription->Name = FM_PROP_LABEL; + pListBoxDescription->Value <<= (*aCtrlSource).first; + ++pListBoxDescription; + + // control source + pListBoxDescription->Name = FM_PROP_CONTROLSOURCE; + pListBoxDescription->Value <<= (*aCtrlSource).second; + ++pListBoxDescription; + + // bound column + pListBoxDescription->Name = FM_PROP_BOUNDCOLUMN; + pListBoxDescription->Value <<= (sal_Int16)1; + ++pListBoxDescription; + + // content type + pListBoxDescription->Name = FM_PROP_LISTSOURCETYPE; + ListSourceType eType = ListSourceType_VALUELIST; + pListBoxDescription->Value = makeAny(eType); + ++pListBoxDescription; + + // list source + MapUString2UstringSeq::const_iterator aCurrentListSource = aRadioListSources.find((*aCtrlSource).first); + DBG_ASSERT(aCurrentListSource != aRadioListSources.end(), + "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); + pListBoxDescription->Name = FM_PROP_LISTSOURCE; + pListBoxDescription->Value = makeAny((*aCurrentListSource).second); + ++pListBoxDescription; + + // value list + MapUString2UstringSeq::const_iterator aCurrentValueList = aRadioValueLists.find((*aCtrlSource).first); + DBG_ASSERT(aCurrentValueList != aRadioValueLists.end(), + "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); + pListBoxDescription->Name = FM_PROP_STRINGITEMLIST; + pListBoxDescription->Value = makeAny(((*aCurrentValueList).second)); + ++pListBoxDescription; + + DBG_ASSERT(nListBoxDescription == (pListBoxDescription - aListBoxDescription.getConstArray()), + "FmXFormShell::CreateExternalView : forgot to adjust nListBoxDescription ?"); + + // properties describing the column "meta data" + const sal_Int16 nDispatchArgs = 3; + Sequence< PropertyValue> aDispatchArgs(nDispatchArgs); + PropertyValue* pDispatchArgs = aDispatchArgs.getArray(); + + // column type : listbox + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE; + ::rtl::OUString fColName = FM_COL_LISTBOX; + pDispatchArgs->Value <<= fColName; +// pDispatchArgs->Value <<= (::rtl::OUString)FM_COL_LISTBOX; + ++pDispatchArgs; + + // column position + pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS; + FmMapUString2Int16::const_iterator aOffset = aRadioPositions.find((*aCtrlSource).first); + DBG_ASSERT(aOffset != aRadioPositions.end(), + "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); + sal_Int16 nPosition = (*aOffset).second; + nPosition = nPosition + nOffset; + // we alread inserted nOffset additinal columns .... + pDispatchArgs->Value <<= nPosition; + ++pDispatchArgs; + + // the + pDispatchArgs->Name = ::rtl::OUString::createFromAscii("ColumnProperties"); // TODO : fmurl.* + pDispatchArgs->Value = makeAny(aListBoxDescription); + ++pDispatchArgs; + DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()), + "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?"); + + // dispatch the "add column" + xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs); + ++nAddedColumns; + } + + + DBG_ASSERT(nAddedColumns > 0, "FmXFormShell::CreateExternalView : no controls (inconsistent) !"); + // we should have checked if we have any usable controls (see above). + + // "load" the "form" of the external view + PropertyValue aArg; + aArg.Name = FMARG_ATTACHTO_MASTERFORM; + Reference< XResultSet> xForm(xCurrentNavController->getModel(), UNO_QUERY); + aArg.Value <<= xForm; + + m_xExternalDisplayedForm = Reference< XResultSet>(xForm, UNO_QUERY); + // do this before dispatching the "attach" command, as the atach may result in a call to our queryDispatch (for the FormSlots) + // whichs needs the m_xExternalDisplayedForm + + xAttachDispatch->dispatch(aAttachURL, Sequence< PropertyValue>(&aArg, 1)); + + m_xExtViewTriggerController = xCurrentNavController; + + // we want to know modifications done in the external view + // if the external controller is a XFormController we can use all our default handlings for it + Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY ); + OSL_ENSURE( xFormController.is(), "FmXFormShell::CreateExternalView:: invalid external view controller!" ); + if (xFormController.is()) + xFormController->addActivateListener((XFormControllerListener*)this); + } + } +#ifdef DBG_UTIL + else + { + DBG_ERROR("FmXFormShell::CreateExternalView : could not create the external form view !"); + } +#endif + InvalidateSlot( SID_FM_VIEW_AS_GRID, sal_False ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::implAdjustConfigCache() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::implAdjustConfigCache" ); + // get (cache) the wizard usage flag + Sequence< ::rtl::OUString > aNames(1); + aNames[0] = ::rtl::OUString::createFromAscii("FormControlPilotsEnabled"); + Sequence< Any > aFlags = GetProperties(aNames); + if (1 == aFlags.getLength()) + m_bUseWizards = ::cppu::any2bool(aFlags[0]); +} + +//------------------------------------------------------------------------ +void FmXFormShell::Notify( const com::sun::star::uno::Sequence< rtl::OUString >& _rPropertyNames) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::Notify" ); + if ( impl_checkDisposed() ) + return; + + const ::rtl::OUString* pSearch = _rPropertyNames.getConstArray(); + const ::rtl::OUString* pSearchTil = pSearch + _rPropertyNames.getLength(); + for (;pSearch < pSearchTil; ++pSearch) + if (0 == pSearch->compareToAscii("FormControlPilotsEnabled")) + { + implAdjustConfigCache(); + InvalidateSlot( SID_FM_USE_WIZARDS, sal_True ); + } +} + +void FmXFormShell::Commit() +{ +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetWizardUsing(sal_Bool _bUseThem) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetWizardUsing" ); + m_bUseWizards = _bUseThem; + + Sequence< ::rtl::OUString > aNames(1); + aNames[0] = ::rtl::OUString::createFromAscii("FormControlPilotsEnabled"); + Sequence< Any > aValues(1); + aValues[0] = ::cppu::bool2any(m_bUseWizards); + PutProperties(aNames, aValues); +} + +//------------------------------------------------------------------------ +void FmXFormShell::viewDeactivated( FmFormView& _rCurrentView, sal_Bool _bDeactivateController /* = sal_True */ ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::viewDeactivated" ); + + if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() ) + { + _rCurrentView.GetImpl()->Deactivate( _bDeactivateController ); + } + + // if we have an async load operation pending for the 0-th page for this view, + // we need to cancel this + // 103727 - 2002-09-26 - fs@openoffice.org + FmFormPage* pPage = _rCurrentView.GetCurPage(); + if ( pPage ) + { + // move all events from our queue to a new one, omit the events for the deactivated + // page + ::std::queue< FmLoadAction > aNewEvents; + while ( m_aLoadingPages.size() ) + { + FmLoadAction aAction = m_aLoadingPages.front(); + m_aLoadingPages.pop(); + if ( pPage != aAction.pPage ) + { + aNewEvents.push( aAction ); + } + else + { + Application::RemoveUserEvent( aAction.nEventId ); + } + } + m_aLoadingPages = aNewEvents; + } + + // remove callbacks at the page + if ( pPage ) + { + pPage->GetImpl().SetFormsCreationHdl( Link() ); + } + UpdateForms( sal_True ); +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmXFormShell, OnFirstTimeActivation, void*, /*NOTINTERESTEDIN*/ ) +{ + if ( impl_checkDisposed() ) + return 0L; + + m_nActivationEvent = 0; + SfxObjectShell* pDocument = m_pShell->GetObjectShell(); + + if ( pDocument && !pDocument->HasName() ) + { + if ( isEnhancedForm() ) + { + // show the data navigator + if ( !m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_DATANAVIGATOR ) ) + m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_SHOW_DATANAVIGATOR ); + } + } + + return 0L; +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmXFormShell, OnFormsCreated, FmFormPage*, /*_pPage*/ ) +{ + UpdateForms( sal_True ); + return 0L; +} + +//------------------------------------------------------------------------ +void FmXFormShell::viewActivated( FmFormView& _rCurrentView, sal_Bool _bSyncAction /* = sal_False */ ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::viewActivated" ); + + FmFormPage* pPage = _rCurrentView.GetCurPage(); + + // activate our view if we are activated ourself + // FS - 30.06.99 - 67308 + if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() ) + { + // load forms for the page the current view belongs to + if ( pPage ) + { + if ( !pPage->GetImpl().hasEverBeenActivated() ) + loadForms( pPage, FORMS_LOAD | ( _bSyncAction ? FORMS_SYNC : FORMS_ASYNC ) ); + pPage->GetImpl().setHasBeenActivated( ); + } + + // first-time initializations for the views + if ( !_rCurrentView.GetImpl()->hasEverBeenActivated( ) ) + { + _rCurrentView.GetImpl()->onFirstViewActivation( PTR_CAST( FmFormModel, _rCurrentView.GetModel() ) ); + _rCurrentView.GetImpl()->setHasBeenActivated( ); + } + + // activate the current view + _rCurrentView.GetImpl()->Activate( _bSyncAction ); + } + + // set callbacks at the page + if ( pPage ) + { + pPage->GetImpl().SetFormsCreationHdl( LINK( this, FmXFormShell, OnFormsCreated ) ); + } + + UpdateForms( sal_True ); + + if ( !hasEverBeenActivated() ) + { + m_nActivationEvent = Application::PostUserEvent( LINK( this, FmXFormShell, OnFirstTimeActivation ) ); + setHasBeenActivated(); + } + + // find a default "current form", if there is none, yet + // #i88186# / 2008-04-12 / frank.schoenheit@sun.com + impl_defaultCurrentForm_nothrow(); +} + +//------------------------------------------------------------------------------ +void FmXFormShell::impl_defaultCurrentForm_nothrow() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_defaultCurrentForm_nothrow" ); + if ( impl_checkDisposed() ) + return; + + if ( m_xCurrentForm.is() ) + // no action required + return; + + FmFormView* pFormView = m_pShell->GetFormView(); + FmFormPage* pPage = pFormView ? pFormView->GetCurPage() : NULL; + if ( !pPage ) + return; + + try + { + Reference< XIndexAccess > xForms( pPage->GetForms( false ), UNO_QUERY ); + if ( !xForms.is() || !xForms->hasElements() ) + return; + + Reference< XForm > xNewCurrentForm( xForms->getByIndex(0), UNO_QUERY_THROW ); + impl_updateCurrentForm( xNewCurrentForm ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } +} + +//------------------------------------------------------------------------------ +void FmXFormShell::smartControlReset( const Reference< XIndexAccess >& _rxModels ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::smartControlReset" ); + if (!_rxModels.is()) + { + DBG_ERROR("FmXFormShell::smartControlReset: invalid container!"); + return; + } + + static const ::rtl::OUString sClassIdPropertyName = FM_PROP_CLASSID; + static const ::rtl::OUString sBoundFieldPropertyName = FM_PROP_BOUNDFIELD; + sal_Int32 nCount = _rxModels->getCount(); + Reference< XPropertySet > xCurrent; + Reference< XPropertySetInfo > xCurrentInfo; + Reference< XPropertySet > xBoundField; + + for (sal_Int32 i=0; i<nCount; ++i) + { + _rxModels->getByIndex(i) >>= xCurrent; + if (xCurrent.is()) + xCurrentInfo = xCurrent->getPropertySetInfo(); + else + xCurrentInfo.clear(); + if (!xCurrentInfo.is()) + continue; + + if (xCurrentInfo->hasPropertyByName(sClassIdPropertyName)) + { // it's a control model + + // check if this control is bound to a living database field + if (xCurrentInfo->hasPropertyByName(sBoundFieldPropertyName)) + xCurrent->getPropertyValue(sBoundFieldPropertyName) >>= xBoundField; + else + xBoundField.clear(); + + // reset only if it's *not* bound + bool bReset = !xBoundField.is(); + + // and additionally, check if it has an external value binding + Reference< XBindableValue > xBindable( xCurrent, UNO_QUERY ); + if ( xBindable.is() && xBindable->getValueBinding().is() ) + bReset = false; + + if ( bReset ) + { + Reference< XReset > xControlReset( xCurrent, UNO_QUERY ); + if ( xControlReset.is() ) + xControlReset->reset(); + } + } + else + { + Reference< XIndexAccess > xContainer(xCurrent, UNO_QUERY); + if (xContainer.is()) + smartControlReset(xContainer); + } + } +} + +//------------------------------------------------------------------------ +IMPL_LINK( FmXFormShell, OnLoadForms, FmFormPage*, /*_pPage*/ ) +{ + FmLoadAction aAction = m_aLoadingPages.front(); + m_aLoadingPages.pop(); + + loadForms( aAction.pPage, aAction.nFlags & ~FORMS_ASYNC ); + return 0L; +} + +//------------------------------------------------------------------------------ +namespace +{ + sal_Bool lcl_isLoadable( const Reference< XInterface >& _rxLoadable ) + { + // determines whether a form should be loaded or not + // if there is no datasource or connection there is no reason to load a form + Reference< XPropertySet > xSet( _rxLoadable, UNO_QUERY ); + if ( !xSet.is() ) + return sal_False; + try + { + Reference< XConnection > xConn; + if ( OStaticDataAccessTools().isEmbeddedInDatabase( _rxLoadable.get(), xConn ) ) + return sal_True; + + // is there already a active connection + xSet->getPropertyValue(FM_PROP_ACTIVE_CONNECTION) >>= xConn; + if ( xConn.is() ) + return sal_True; + + ::rtl::OUString sPropertyValue; + OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DATASOURCE ) >>= sPropertyValue ); + if ( sPropertyValue.getLength() ) + return sal_True; + + OSL_VERIFY( xSet->getPropertyValue( FM_PROP_URL ) >>= sPropertyValue ); + if ( sPropertyValue.getLength() ) + return sal_True; + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION(); + } + return sal_False; + } +} + +//------------------------------------------------------------------------ +void FmXFormShell::loadForms( FmFormPage* _pPage, const sal_uInt16 _nBehaviour /* FORMS_LOAD | FORMS_SYNC */ ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::loadForms" ); + DBG_ASSERT( ( _nBehaviour & ( FORMS_ASYNC | FORMS_UNLOAD ) ) != ( FORMS_ASYNC | FORMS_UNLOAD ), + "FmXFormShell::loadForms: async loading not supported - this will heavily fail!" ); + + if ( _nBehaviour & FORMS_ASYNC ) + { + m_aLoadingPages.push( FmLoadAction( + _pPage, + _nBehaviour, + Application::PostUserEvent( LINK( this, FmXFormShell, OnLoadForms ), _pPage ) + ) ); + return; + } + + DBG_ASSERT( _pPage, "FmXFormShell::loadForms: invalid page!" ); + if ( _pPage ) + { + // lock the undo env so the forms can change non-transient properties while loading + // (without this my doc's modified flag would be set) + FmFormModel* pModel = PTR_CAST( FmFormModel, _pPage->GetModel() ); + DBG_ASSERT( pModel, "FmXFormShell::loadForms: invalid model!" ); + if ( pModel ) + pModel->GetUndoEnv().Lock(); + + // load all forms + Reference< XIndexAccess > xForms; + xForms = xForms.query( _pPage->GetForms( false ) ); + + if ( xForms.is() ) + { + Reference< XLoadable > xForm; + sal_Bool bFormWasLoaded = sal_False; + for ( sal_Int32 j = 0, nCount = xForms->getCount(); j < nCount; ++j ) + { + xForms->getByIndex( j ) >>= xForm; + bFormWasLoaded = sal_False; + // a database form must be loaded for + try + { + if ( 0 == ( _nBehaviour & FORMS_UNLOAD ) ) + { + if ( lcl_isLoadable( xForm ) && !xForm->isLoaded() ) + xForm->load(); + } + else + { + if ( xForm->isLoaded() ) + { + bFormWasLoaded = sal_True; + xForm->unload(); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + // reset the form if it was loaded + if ( bFormWasLoaded ) + { + Reference< XIndexAccess > xContainer( xForm, UNO_QUERY ); + DBG_ASSERT( xContainer.is(), "FmXFormShell::loadForms: the form is no container!" ); + if ( xContainer.is() ) + smartControlReset( xContainer ); + } + } + } + + if ( pModel ) + // unlock the environment + pModel->GetUndoEnv().UnLock(); + } +} + +//------------------------------------------------------------------------ +void FmXFormShell::ExecuteTextAttribute( SfxRequest& _rReq ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteTextAttribute" ); + m_pTextShell->ExecuteTextAttribute( _rReq ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::GetTextAttributeState( SfxItemSet& _rSet ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetTextAttributeState" ); + m_pTextShell->GetTextAttributeState( _rSet ); +} + +//------------------------------------------------------------------------ +bool FmXFormShell::IsActiveControl( bool _bCountRichTextOnly ) const +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsActiveControl" ); + return m_pTextShell->IsActiveControl( _bCountRichTextOnly ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::ForgetActiveControl() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ForgetActiveControl" ); + m_pTextShell->ForgetActiveControl(); +} + +//------------------------------------------------------------------------ +void FmXFormShell::SetControlActivationHandler( const Link& _rHdl ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetControlActivationHandler" ); + m_pTextShell->SetControlActivationHandler( _rHdl ); +} +//------------------------------------------------------------------------ +void FmXFormShell::handleShowPropertiesRequest() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::handleShowPropertiesRequest" ); + if ( onlyControlsAreMarked() ) + ShowSelectionProperties( sal_True ); +} + +//------------------------------------------------------------------------ +void FmXFormShell::handleMouseButtonDown( const SdrViewEvent& _rViewEvent ) +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::handleMouseButtonDown" ); + // catch simple double clicks + if ( ( _rViewEvent.nMouseClicks == 2 ) && ( _rViewEvent.nMouseCode == MOUSE_LEFT ) ) + { + if ( _rViewEvent.eHit == SDRHIT_MARKEDOBJECT ) + { + if ( onlyControlsAreMarked() ) + ShowSelectionProperties( sal_True ); + } + } +} + +//------------------------------------------------------------------------------ +bool FmXFormShell::HasControlFocus() const +{ + bool bHasControlFocus = false; + + try + { + Reference< XFormController > xController( getActiveController() ); + Reference< XControl > xCurrentControl; + if ( xController.is() ) + xCurrentControl.set( xController->getCurrentControl() ); + if ( xCurrentControl.is() ) + { + Reference< XWindow2 > xPeerWindow( xCurrentControl->getPeer(), UNO_QUERY_THROW ); + bHasControlFocus = xPeerWindow->hasFocus(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION(); + } + + return bHasControlFocus; +} + +//============================================================================== +//============================================================================== +SearchableControlIterator::SearchableControlIterator(Reference< XInterface> xStartingPoint) + :IndexAccessIterator(xStartingPoint) +{ +} + +//------------------------------------------------------------------------------ +sal_Bool SearchableControlIterator::ShouldHandleElement(const Reference< XInterface>& xElement) +{ + // wenn das Ding eine ControlSource und einen BoundField-Property hat + Reference< XPropertySet> xProperties(xElement, UNO_QUERY); + if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties)) + { + // und das BoundField gueltig ist + Reference< XPropertySet> xField; + xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; + if (xField.is()) + { + // nehmen wir's + m_sCurrentValue = ::comphelper::getString(xProperties->getPropertyValue(FM_PROP_CONTROLSOURCE)); + return sal_True; + } + } + + // wenn es ein Grid-Control ist + if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties)) + { + Any aClassId( xProperties->getPropertyValue(FM_PROP_CLASSID) ); + if (::comphelper::getINT16(aClassId) == FormComponentType::GRIDCONTROL) + { + m_sCurrentValue = ::rtl::OUString(); + return sal_True; + } + } + + return sal_False; +} + +//------------------------------------------------------------------------------ +sal_Bool SearchableControlIterator::ShouldStepInto(const Reference< XInterface>& /*xContainer*/) const +{ + return sal_True; +} + +//============================================================================== +//============================================================================== + +SV_IMPL_PTRARR(StatusForwarderArray, SfxStatusForwarder*) + +SFX_IMPL_MENU_CONTROL(ControlConversionMenuController, SfxBoolItem); + +//------------------------------------------------------------------------------ +ControlConversionMenuController::ControlConversionMenuController( sal_uInt16 _nId, Menu& _rMenu, SfxBindings& _rBindings ) + :SfxMenuControl( _nId, _rBindings ) + ,m_pMainMenu( &_rMenu ) + ,m_pConversionMenu( NULL ) +{ + if ( _nId == SID_FM_CHANGECONTROLTYPE ) + { + m_pConversionMenu = FmXFormShell::GetConversionMenu(); + _rMenu.SetPopupMenu( _nId, m_pConversionMenu ); + + for (sal_Int16 i=0; i<m_pConversionMenu->GetItemCount(); ++i) + { + _rBindings.Invalidate(m_pConversionMenu->GetItemId(i)); + SfxStatusForwarder* pForwarder = new SfxStatusForwarder(m_pConversionMenu->GetItemId(i), *this); + m_aStatusForwarders.C40_INSERT(SfxStatusForwarder, pForwarder, m_aStatusForwarders.Count()); + } + } +} + +//------------------------------------------------------------------------------ +ControlConversionMenuController::~ControlConversionMenuController() +{ + RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "ControlConversionMenuController::~ControlConversionMenuController" ); + m_pMainMenu->SetPopupMenu(SID_FM_CHANGECONTROLTYPE, NULL); + delete m_pConversionMenu; +} + +//------------------------------------------------------------------------------ +void ControlConversionMenuController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState) +{ + if (nSID == GetId()) + SfxMenuControl::StateChanged(nSID, eState, pState); + else if (FmXFormShell::isControlConversionSlot(nSID)) + { + if ((m_pConversionMenu->GetItemPos(nSID) != MENU_ITEM_NOTFOUND) && (eState == SFX_ITEM_DISABLED)) + { + m_pConversionMenu->RemoveItem(m_pConversionMenu->GetItemPos(nSID)); + } + else if ((m_pConversionMenu->GetItemPos(nSID) == MENU_ITEM_NOTFOUND) && (eState != SFX_ITEM_DISABLED)) + { + // We can't simply re-insert the item because we have a clear order for all the our items. + // So first we have to determine the position of the item to insert. + PopupMenu* pSource = FmXFormShell::GetConversionMenu(); + USHORT nSourcePos = pSource->GetItemPos(nSID); + DBG_ASSERT(nSourcePos != MENU_ITEM_NOTFOUND, "ControlConversionMenuController::StateChanged : FmXFormShell supplied an invalid menu !"); + USHORT nPrevInSource = nSourcePos; + USHORT nPrevInConversion = MENU_ITEM_NOTFOUND; + while (nPrevInSource>0) + { + sal_Int16 nPrevId = pSource->GetItemId(--nPrevInSource); + + // do we have the source's predecessor in our conversion menu, too ? + nPrevInConversion = m_pConversionMenu->GetItemPos(nPrevId); + if (nPrevInConversion != MENU_ITEM_NOTFOUND) + break; + } + if (MENU_ITEM_NOTFOUND == nPrevInConversion) + // none of the items which precede the nSID-slot in the source menu are present in our conversion menu + nPrevInConversion = sal::static_int_cast< USHORT >(-1); // put the item at the first position + m_pConversionMenu->InsertItem(nSID, pSource->GetItemText(nSID), pSource->GetItemBits(nSID), ++nPrevInConversion); + m_pConversionMenu->SetItemImage(nSID, pSource->GetItemImage(nSID)); + m_pConversionMenu->SetHelpId(nSID, pSource->GetHelpId(nSID)); + + delete pSource; + } + m_pMainMenu->EnableItem(SID_FM_CHANGECONTROLTYPE, m_pConversionMenu->GetItemCount() > 0); + } + else + { + DBG_ERROR("ControlConversionMenuController::StateChanged : unknown id !"); + } +} + +//============================================================================== |