/src/libreoffice/svx/source/form/fmshimp.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <sal/config.h> |
21 | | |
22 | | #include <o3tl/safeint.hxx> |
23 | | #include <sal/macros.h> |
24 | | #include <sal/log.hxx> |
25 | | #include <fmobj.hxx> |
26 | | #include <fmpgeimp.hxx> |
27 | | #include <svx/fmtools.hxx> |
28 | | #include <fmprop.hxx> |
29 | | #include <fmservs.hxx> |
30 | | #include <fmshimp.hxx> |
31 | | #include <fmtextcontrolshell.hxx> |
32 | | #include <fmundo.hxx> |
33 | | #include <fmurl.hxx> |
34 | | #include <fmvwimp.hxx> |
35 | | #include <gridcols.hxx> |
36 | | #include <svx/svditer.hxx> |
37 | | #include <svx/dialmgr.hxx> |
38 | | #include <svx/strings.hrc> |
39 | | #include <svx/svdobjkind.hxx> |
40 | | #include <svx/fmmodel.hxx> |
41 | | #include <svx/fmpage.hxx> |
42 | | #include <svx/fmshell.hxx> |
43 | | #include <svx/fmview.hxx> |
44 | | #include <svx/obj3d.hxx> |
45 | | #include <svx/sdrpagewindow.hxx> |
46 | | #include <svx/svdpagv.hxx> |
47 | | #include <svx/svxdlg.hxx> |
48 | | #include <svx/svxids.hrc> |
49 | | #include <bitmaps.hlst> |
50 | | #include <formnavi.hrc> |
51 | | |
52 | | #include <com/sun/star/awt/XWindow2.hpp> |
53 | | #include <com/sun/star/awt/XCheckBox.hpp> |
54 | | #include <com/sun/star/awt/XListBox.hpp> |
55 | | #include <com/sun/star/awt/XTextComponent.hpp> |
56 | | #include <com/sun/star/beans/theIntrospection.hpp> |
57 | | #include <com/sun/star/beans/PropertyAttribute.hpp> |
58 | | #include <com/sun/star/beans/XPropertyState.hpp> |
59 | | #include <com/sun/star/container/XContainer.hpp> |
60 | | #include <com/sun/star/container/XIndexAccess.hpp> |
61 | | #include <com/sun/star/container/XNamed.hpp> |
62 | | #include <com/sun/star/form/ListSourceType.hpp> |
63 | | #include <com/sun/star/form/TabOrderDialog.hpp> |
64 | | #include <com/sun/star/form/XGrid.hpp> |
65 | | #include <com/sun/star/form/XGridPeer.hpp> |
66 | | #include <com/sun/star/form/XLoadable.hpp> |
67 | | #include <com/sun/star/form/XReset.hpp> |
68 | | #include <com/sun/star/form/binding/XBindableValue.hpp> |
69 | | #include <com/sun/star/form/binding/XListEntrySink.hpp> |
70 | | #include <com/sun/star/frame/FrameSearchFlag.hpp> |
71 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
72 | | #include <com/sun/star/script/XEventAttacherManager.hpp> |
73 | | #include <com/sun/star/sdbc/SQLException.hpp> |
74 | | #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp> |
75 | | #include <com/sun/star/util/XModeSelector.hpp> |
76 | | #include <com/sun/star/util/XNumberFormatsSupplier.hpp> |
77 | | #include <com/sun/star/view/XSelectionSupplier.hpp> |
78 | | |
79 | | #include <comphelper/evtmethodhelper.hxx> |
80 | | #include <comphelper/processfactory.hxx> |
81 | | #include <comphelper/property.hxx> |
82 | | #include <comphelper/sequence.hxx> |
83 | | #include <comphelper/solarmutex.hxx> |
84 | | #include <comphelper/string.hxx> |
85 | | #include <comphelper/types.hxx> |
86 | | #include <connectivity/dbtools.hxx> |
87 | | #include <sfx2/dispatch.hxx> |
88 | | #include <sfx2/frame.hxx> |
89 | | #include <sfx2/objsh.hxx> |
90 | | #include <sfx2/viewfrm.hxx> |
91 | | #include <sfx2/viewsh.hxx> |
92 | | #include <toolkit/controls/unocontrolcontainer.hxx> |
93 | | #include <toolkit/helper/vclunohelper.hxx> |
94 | | #include <tools/debug.hxx> |
95 | | #include <comphelper/diagnose_ex.hxx> |
96 | | #include <comphelper/configuration.hxx> |
97 | | #include <vcl/settings.hxx> |
98 | | #include <vcl/svapp.hxx> |
99 | | #include <vcl/weld/Menu.hxx> |
100 | | #include <vcl/weld/MessageDialog.hxx> |
101 | | #include <vcl/window.hxx> |
102 | | |
103 | | #include <algorithm> |
104 | | #include <map> |
105 | | #include <memory> |
106 | | #include <string_view> |
107 | | #include <vector> |
108 | | |
109 | | // is used for Invalidate -> maintain it as well |
110 | | const sal_uInt16 DatabaseSlotMap[] = |
111 | | { |
112 | | SID_FM_RECORD_FIRST, |
113 | | SID_FM_RECORD_NEXT, |
114 | | SID_FM_RECORD_PREV, |
115 | | SID_FM_RECORD_LAST, |
116 | | SID_FM_RECORD_NEW, |
117 | | SID_FM_RECORD_DELETE, |
118 | | SID_FM_RECORD_ABSOLUTE, |
119 | | SID_FM_RECORD_TOTAL, |
120 | | SID_FM_RECORD_SAVE, |
121 | | SID_FM_RECORD_UNDO, |
122 | | SID_FM_REMOVE_FILTER_SORT, |
123 | | SID_FM_SORTUP, |
124 | | SID_FM_SORTDOWN, |
125 | | SID_FM_ORDERCRIT, |
126 | | SID_FM_AUTOFILTER, |
127 | | SID_FM_FORM_FILTERED, |
128 | | SID_FM_REFRESH, |
129 | | SID_FM_REFRESH_FORM_CONTROL, |
130 | | SID_FM_SEARCH, |
131 | | SID_FM_FILTER_START, |
132 | | SID_FM_VIEW_AS_GRID, |
133 | | 0 |
134 | | }; |
135 | | |
136 | | // is used for Invalidate -> maintain it as well |
137 | | // sort ascending !!!!!! |
138 | | const sal_uInt16 DlgSlotMap[] = // slots of the controller |
139 | | { |
140 | | SID_FM_CTL_PROPERTIES, |
141 | | SID_FM_PROPERTIES, |
142 | | SID_FM_TAB_DIALOG, |
143 | | SID_FM_ADD_FIELD, |
144 | | SID_FM_SHOW_FMEXPLORER, |
145 | | SID_FM_FIELDS_CONTROL, |
146 | | SID_FM_SHOW_PROPERTIES, |
147 | | SID_FM_PROPERTY_CONTROL, |
148 | | SID_FM_FMEXPLORER_CONTROL, |
149 | | SID_FM_SHOW_DATANAVIGATOR, |
150 | | SID_FM_DATANAVIGATOR_CONTROL, |
151 | | 0 |
152 | | }; |
153 | | |
154 | | const sal_uInt16 SelObjectSlotMap[] = // slots depending on the SelObject |
155 | | { |
156 | | SID_FM_CONVERTTO_EDIT, |
157 | | SID_FM_CONVERTTO_BUTTON, |
158 | | SID_FM_CONVERTTO_FIXEDTEXT, |
159 | | SID_FM_CONVERTTO_LISTBOX, |
160 | | SID_FM_CONVERTTO_CHECKBOX, |
161 | | SID_FM_CONVERTTO_RADIOBUTTON, |
162 | | SID_FM_CONVERTTO_GROUPBOX, |
163 | | SID_FM_CONVERTTO_COMBOBOX, |
164 | | SID_FM_CONVERTTO_IMAGEBUTTON, |
165 | | SID_FM_CONVERTTO_FILECONTROL, |
166 | | SID_FM_CONVERTTO_DATE, |
167 | | SID_FM_CONVERTTO_TIME, |
168 | | SID_FM_CONVERTTO_NUMERIC, |
169 | | SID_FM_CONVERTTO_CURRENCY, |
170 | | SID_FM_CONVERTTO_PATTERN, |
171 | | SID_FM_CONVERTTO_IMAGECONTROL, |
172 | | SID_FM_CONVERTTO_FORMATTED, |
173 | | SID_FM_CONVERTTO_SCROLLBAR, |
174 | | SID_FM_CONVERTTO_SPINBUTTON, |
175 | | SID_FM_CONVERTTO_NAVIGATIONBAR, |
176 | | |
177 | | SID_FM_FMEXPLORER_CONTROL, |
178 | | SID_FM_DATANAVIGATOR_CONTROL, |
179 | | |
180 | | 0 |
181 | | }; |
182 | | |
183 | | // the following arrays must be consistent, i.e., corresponding entries should |
184 | | // be at the same relative position within their respective arrays |
185 | | constexpr std::u16string_view aConvertSlots[] = |
186 | | { |
187 | | u"ConvertToEdit", |
188 | | u"ConvertToButton", |
189 | | u"ConvertToFixed", |
190 | | u"ConvertToList", |
191 | | u"ConvertToCheckBox", |
192 | | u"ConvertToRadio", |
193 | | u"ConvertToGroup", |
194 | | u"ConvertToCombo", |
195 | | u"ConvertToImageBtn", |
196 | | u"ConvertToFileControl", |
197 | | u"ConvertToDate", |
198 | | u"ConvertToTime", |
199 | | u"ConvertToNumeric", |
200 | | u"ConvertToCurrency", |
201 | | u"ConvertToPattern", |
202 | | u"ConvertToImageControl", |
203 | | u"ConvertToFormatted", |
204 | | u"ConvertToScrollBar", |
205 | | u"ConvertToSpinButton", |
206 | | u"ConvertToNavigationBar" |
207 | | }; |
208 | | |
209 | | constexpr OUString aImgIds[] = |
210 | | { |
211 | | RID_SVXBMP_EDITBOX, |
212 | | RID_SVXBMP_BUTTON, |
213 | | RID_SVXBMP_FIXEDTEXT, |
214 | | RID_SVXBMP_LISTBOX, |
215 | | RID_SVXBMP_CHECKBOX, |
216 | | RID_SVXBMP_RADIOBUTTON, |
217 | | RID_SVXBMP_GROUPBOX, |
218 | | RID_SVXBMP_COMBOBOX, |
219 | | RID_SVXBMP_IMAGEBUTTON, |
220 | | RID_SVXBMP_FILECONTROL, |
221 | | RID_SVXBMP_DATEFIELD, |
222 | | RID_SVXBMP_TIMEFIELD, |
223 | | RID_SVXBMP_NUMERICFIELD, |
224 | | RID_SVXBMP_CURRENCYFIELD, |
225 | | RID_SVXBMP_PATTERNFIELD, |
226 | | RID_SVXBMP_IMAGECONTROL, |
227 | | RID_SVXBMP_FORMATTEDFIELD, |
228 | | RID_SVXBMP_SCROLLBAR, |
229 | | RID_SVXBMP_SPINBUTTON, |
230 | | RID_SVXBMP_NAVIGATIONBAR |
231 | | }; |
232 | | |
233 | | const SdrObjKind nObjectTypes[] = |
234 | | { |
235 | | SdrObjKind::FormEdit, |
236 | | SdrObjKind::FormButton, |
237 | | SdrObjKind::FormFixedText, |
238 | | SdrObjKind::FormListbox, |
239 | | SdrObjKind::FormCheckbox, |
240 | | SdrObjKind::FormRadioButton, |
241 | | SdrObjKind::FormGroupBox, |
242 | | SdrObjKind::FormCombobox, |
243 | | SdrObjKind::FormImageButton, |
244 | | SdrObjKind::FormFileControl, |
245 | | SdrObjKind::FormDateField, |
246 | | SdrObjKind::FormTimeField, |
247 | | SdrObjKind::FormNumericField, |
248 | | SdrObjKind::FormCurrencyField, |
249 | | SdrObjKind::FormPatternField, |
250 | | SdrObjKind::FormImageControl, |
251 | | SdrObjKind::FormFormattedField, |
252 | | SdrObjKind::FormScrollbar, |
253 | | SdrObjKind::FormSpinButton, |
254 | | SdrObjKind::FormNavigationBar |
255 | | }; |
256 | | |
257 | | using namespace ::com::sun::star; |
258 | | using namespace ::com::sun::star::ui; |
259 | | using namespace ::com::sun::star::uno; |
260 | | using namespace ::com::sun::star::sdb; |
261 | | using namespace ::com::sun::star::sdbc; |
262 | | using namespace ::com::sun::star::sdbcx; |
263 | | using namespace ::com::sun::star::beans; |
264 | | using namespace ::com::sun::star::container; |
265 | | using namespace ::com::sun::star::form; |
266 | | using namespace ::com::sun::star::form::binding; |
267 | | using namespace ::com::sun::star::form::runtime; |
268 | | using namespace ::com::sun::star::awt; |
269 | | using namespace ::com::sun::star::view; |
270 | | using namespace ::com::sun::star::util; |
271 | | using namespace ::com::sun::star::script; |
272 | | using namespace ::svxform; |
273 | | using namespace ::svx; |
274 | | using namespace ::dbtools; |
275 | | |
276 | | |
277 | | //= helper |
278 | | |
279 | | namespace |
280 | | { |
281 | | |
282 | | void collectInterfacesFromMarkList( const SdrMarkList& _rMarkList, InterfaceBag& /* [out] */ _rInterfaces ) |
283 | 0 | { |
284 | 0 | _rInterfaces.clear(); |
285 | |
|
286 | 0 | const size_t nMarkCount = _rMarkList.GetMarkCount(); |
287 | 0 | for ( size_t i = 0; i < nMarkCount; ++i) |
288 | 0 | { |
289 | 0 | SdrObject* pCurrent = _rMarkList.GetMark( i )->GetMarkedSdrObj(); |
290 | 0 | assert(pCurrent && "marked object will exist"); |
291 | |
|
292 | 0 | std::optional<SdrObjListIter> oGroupIterator; |
293 | 0 | if ( pCurrent->IsGroupObject() ) |
294 | 0 | { |
295 | 0 | oGroupIterator.emplace( pCurrent->GetSubList() ); |
296 | 0 | pCurrent = oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr; |
297 | 0 | } |
298 | |
|
299 | 0 | while ( pCurrent ) |
300 | 0 | { |
301 | 0 | FmFormObj* pAsFormObject = FmFormObj::GetFormObject( pCurrent ); |
302 | | // note this will de-reference virtual objects, if necessary/possible |
303 | 0 | if ( pAsFormObject ) |
304 | 0 | { |
305 | 0 | Reference< XInterface > xControlModel( pAsFormObject->GetUnoControlModel(), UNO_QUERY ); |
306 | | // the UNO_QUERY is important for normalization |
307 | 0 | if ( xControlModel.is() ) |
308 | 0 | _rInterfaces.insert( xControlModel ); |
309 | 0 | } |
310 | | |
311 | | // next element |
312 | 0 | pCurrent = oGroupIterator && oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr; |
313 | 0 | } |
314 | 0 | } |
315 | 0 | } |
316 | | |
317 | | |
318 | | sal_Int32 GridView2ModelPos(const Reference< XIndexAccess>& rColumns, sal_Int16 nViewPos) |
319 | 0 | { |
320 | 0 | try |
321 | 0 | { |
322 | 0 | if (rColumns.is()) |
323 | 0 | { |
324 | | // loop through all columns |
325 | 0 | sal_Int32 i; |
326 | 0 | Reference< XPropertySet> xCur; |
327 | 0 | for (i=0; i<rColumns->getCount(); ++i) |
328 | 0 | { |
329 | 0 | rColumns->getByIndex(i) >>= xCur; |
330 | 0 | if (!::comphelper::getBOOL(xCur->getPropertyValue(FM_PROP_HIDDEN))) |
331 | 0 | { |
332 | | // for every visible col : if nViewPos is greater zero, decrement it, else we |
333 | | // have found the model position |
334 | 0 | if (!nViewPos) |
335 | 0 | break; |
336 | 0 | else |
337 | 0 | --nViewPos; |
338 | 0 | } |
339 | 0 | } |
340 | 0 | if (i<rColumns->getCount()) |
341 | 0 | return i; |
342 | 0 | } |
343 | 0 | } |
344 | 0 | catch(const Exception&) |
345 | 0 | { |
346 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
347 | 0 | } |
348 | 0 | return -1; |
349 | 0 | } |
350 | | |
351 | | |
352 | | void TransferEventScripts(const Reference< XControlModel>& xModel, const Reference< XControl>& xControl, |
353 | | const Sequence< ScriptEventDescriptor>& rTransferIfAvailable) |
354 | 0 | { |
355 | | // first check if we have a XEventAttacherManager for the model |
356 | 0 | Reference< XChild> xModelChild(xModel, UNO_QUERY); |
357 | 0 | if (!xModelChild.is()) |
358 | 0 | return; // nothing to do |
359 | | |
360 | 0 | Reference< XEventAttacherManager> xEventManager(xModelChild->getParent(), UNO_QUERY); |
361 | 0 | if (!xEventManager.is()) |
362 | 0 | return; // nothing to do |
363 | | |
364 | 0 | if (!rTransferIfAvailable.hasElements()) |
365 | 0 | return; // nothing to do |
366 | | |
367 | | // check for the index of the model within its parent |
368 | 0 | Reference< XIndexAccess> xParentIndex(xModelChild->getParent(), UNO_QUERY); |
369 | 0 | if (!xParentIndex.is()) |
370 | 0 | return; // nothing to do |
371 | 0 | sal_Int32 nIndex = getElementPos(xParentIndex, xModel); |
372 | 0 | if (nIndex<0 || nIndex>=xParentIndex->getCount()) |
373 | 0 | return; // nothing to do |
374 | | |
375 | | // then we need information about the listeners supported by the control and the model |
376 | 0 | Sequence< Type> aModelListeners; |
377 | 0 | Sequence< Type> aControlListeners; |
378 | |
|
379 | 0 | Reference< XIntrospection> xIntrospection = theIntrospection::get(::comphelper::getProcessComponentContext()); |
380 | |
|
381 | 0 | if (xModel.is()) |
382 | 0 | { |
383 | 0 | Any aModel(xModel); |
384 | 0 | aModelListeners = xIntrospection->inspect(aModel)->getSupportedListeners(); |
385 | 0 | } |
386 | |
|
387 | 0 | if (xControl.is()) |
388 | 0 | { |
389 | 0 | Any aControl(xControl); |
390 | 0 | aControlListeners = xIntrospection->inspect(aControl)->getSupportedListeners(); |
391 | 0 | } |
392 | |
|
393 | 0 | sal_Int32 nMaxNewLen = aModelListeners.getLength() + aControlListeners.getLength(); |
394 | 0 | if (!nMaxNewLen) |
395 | 0 | return; // the model and the listener don't support any listeners (or we were unable to retrieve these infos) |
396 | | |
397 | 0 | Sequence< ScriptEventDescriptor> aTransferable(nMaxNewLen); |
398 | 0 | ScriptEventDescriptor* pTransferable = aTransferable.getArray(); |
399 | |
|
400 | 0 | for (const ScriptEventDescriptor& rCurrent : rTransferIfAvailable) |
401 | 0 | { |
402 | | // search the model/control idl classes for the event described by pCurrent |
403 | 0 | for (const Sequence< Type>* pCurrentArray : { &aModelListeners, &aControlListeners }) |
404 | 0 | { |
405 | 0 | for (const Type& rCurrentListener : *pCurrentArray) |
406 | 0 | { |
407 | 0 | OUString aListener = rCurrentListener.getTypeName(); |
408 | 0 | if (!aListener.isEmpty()) |
409 | 0 | aListener = aListener.copy(aListener.lastIndexOf('.')+1); |
410 | |
|
411 | 0 | if (aListener == rCurrent.ListenerType) |
412 | | // the current ScriptEventDescriptor doesn't match the current listeners class |
413 | 0 | continue; |
414 | | |
415 | | // now check the methods |
416 | 0 | Sequence< OUString> aMethodsNames = ::comphelper::getEventMethodsForType(rCurrentListener); |
417 | |
|
418 | 0 | if (comphelper::findValue(aMethodsNames, rCurrent.EventMethod) != -1) |
419 | 0 | { |
420 | | // we can transfer the script event : the model (control) supports it |
421 | 0 | *pTransferable = rCurrent; |
422 | 0 | ++pTransferable; |
423 | 0 | break; |
424 | 0 | } |
425 | 0 | } |
426 | 0 | } |
427 | 0 | } |
428 | |
|
429 | 0 | sal_Int32 nRealNewLen = pTransferable - aTransferable.getArray(); |
430 | 0 | aTransferable.realloc(nRealNewLen); |
431 | |
|
432 | 0 | xEventManager->registerScriptEvents(nIndex, aTransferable); |
433 | 0 | } |
434 | | |
435 | | |
436 | | const OUString & getServiceNameByControlType(SdrObjKind nType) |
437 | 0 | { |
438 | 0 | switch (nType) |
439 | 0 | { |
440 | 0 | case SdrObjKind::FormEdit : return FM_COMPONENT_TEXTFIELD; |
441 | 0 | case SdrObjKind::FormButton : return FM_COMPONENT_COMMANDBUTTON; |
442 | 0 | case SdrObjKind::FormFixedText : return FM_COMPONENT_FIXEDTEXT; |
443 | 0 | case SdrObjKind::FormListbox : return FM_COMPONENT_LISTBOX; |
444 | 0 | case SdrObjKind::FormCheckbox : return FM_COMPONENT_CHECKBOX; |
445 | 0 | case SdrObjKind::FormRadioButton : return FM_COMPONENT_RADIOBUTTON; |
446 | 0 | case SdrObjKind::FormGroupBox : return FM_COMPONENT_GROUPBOX; |
447 | 0 | case SdrObjKind::FormCombobox : return FM_COMPONENT_COMBOBOX; |
448 | 0 | case SdrObjKind::FormGrid : return FM_COMPONENT_GRIDCONTROL; |
449 | 0 | case SdrObjKind::FormImageButton : return FM_COMPONENT_IMAGEBUTTON; |
450 | 0 | case SdrObjKind::FormFileControl : return FM_COMPONENT_FILECONTROL; |
451 | 0 | case SdrObjKind::FormDateField : return FM_COMPONENT_DATEFIELD; |
452 | 0 | case SdrObjKind::FormTimeField : return FM_COMPONENT_TIMEFIELD; |
453 | 0 | case SdrObjKind::FormNumericField : return FM_COMPONENT_NUMERICFIELD; |
454 | 0 | case SdrObjKind::FormCurrencyField : return FM_COMPONENT_CURRENCYFIELD; |
455 | 0 | case SdrObjKind::FormPatternField : return FM_COMPONENT_PATTERNFIELD; |
456 | 0 | case SdrObjKind::FormHidden : return FM_COMPONENT_HIDDENCONTROL; |
457 | 0 | case SdrObjKind::FormImageControl : return FM_COMPONENT_IMAGECONTROL; |
458 | 0 | case SdrObjKind::FormFormattedField : return FM_COMPONENT_FORMATTEDFIELD; |
459 | 0 | case SdrObjKind::FormScrollbar : return FM_SUN_COMPONENT_SCROLLBAR; |
460 | 0 | case SdrObjKind::FormSpinButton : return FM_SUN_COMPONENT_SPINBUTTON; |
461 | 0 | case SdrObjKind::FormNavigationBar : return FM_SUN_COMPONENT_NAVIGATIONBAR; |
462 | 0 | default:; |
463 | 0 | } |
464 | 0 | return EMPTY_OUSTRING; |
465 | 0 | } |
466 | | |
467 | | } |
468 | | |
469 | | |
470 | | // check if the control has one of the interfaces we can use for searching |
471 | | // *_pCurrentText will be filled with the current text of the control (as used when searching this control) |
472 | | bool IsSearchableControl( const css::uno::Reference< css::uno::XInterface>& _rxControl, |
473 | | OUString* _pCurrentText ) |
474 | 0 | { |
475 | 0 | if ( !_rxControl.is() ) |
476 | 0 | return false; |
477 | | |
478 | 0 | Reference< XTextComponent > xAsText( _rxControl, UNO_QUERY ); |
479 | 0 | if ( xAsText.is() ) |
480 | 0 | { |
481 | 0 | if ( _pCurrentText ) |
482 | 0 | *_pCurrentText = xAsText->getText(); |
483 | 0 | return true; |
484 | 0 | } |
485 | | |
486 | 0 | Reference< XListBox > xListBox( _rxControl, UNO_QUERY ); |
487 | 0 | if ( xListBox.is() ) |
488 | 0 | { |
489 | 0 | if ( _pCurrentText ) |
490 | 0 | *_pCurrentText = xListBox->getSelectedItem(); |
491 | 0 | return true; |
492 | 0 | } |
493 | | |
494 | 0 | Reference< XCheckBox > xCheckBox( _rxControl, UNO_QUERY ); |
495 | 0 | if ( xCheckBox.is() ) |
496 | 0 | { |
497 | 0 | if ( _pCurrentText ) |
498 | 0 | { |
499 | 0 | switch ( static_cast<::TriState>(xCheckBox->getState()) ) |
500 | 0 | { |
501 | 0 | case TRISTATE_FALSE: *_pCurrentText = "0"; break; |
502 | 0 | case TRISTATE_TRUE: *_pCurrentText = "1"; break; |
503 | 0 | default: _pCurrentText->clear(); break; |
504 | 0 | } |
505 | 0 | } |
506 | 0 | return true; |
507 | 0 | } |
508 | | |
509 | 0 | return false; |
510 | 0 | } |
511 | | |
512 | | |
513 | | bool FmXBoundFormFieldIterator::ShouldStepInto(const Reference< XInterface>& _rContainer) const |
514 | 0 | { |
515 | 0 | if (_rContainer == m_xStartingPoint) |
516 | | // would be quite stupid to step over the root... |
517 | 0 | return true; |
518 | | |
519 | 0 | return Reference< XControlModel>(_rContainer, UNO_QUERY).is(); |
520 | 0 | } |
521 | | |
522 | | |
523 | | bool FmXBoundFormFieldIterator::ShouldHandleElement(const Reference< XInterface>& _rElement) |
524 | 0 | { |
525 | 0 | if (!_rElement.is()) |
526 | | // NULL element |
527 | 0 | return false; |
528 | | |
529 | 0 | if (Reference< XForm>(_rElement, UNO_QUERY).is() || Reference< XGrid>(_rElement, UNO_QUERY).is()) |
530 | | // a forms or a grid |
531 | 0 | return false; |
532 | | |
533 | 0 | Reference< XPropertySet> xSet(_rElement, UNO_QUERY); |
534 | 0 | if (!xSet.is() || !::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet)) |
535 | | // no "BoundField" property |
536 | 0 | return false; |
537 | | |
538 | 0 | Any aVal( xSet->getPropertyValue(FM_PROP_BOUNDFIELD) ); |
539 | 0 | if (aVal.getValueTypeClass() != TypeClass_INTERFACE) |
540 | | // void or invalid property value |
541 | 0 | return false; |
542 | | |
543 | 0 | return aVal.hasValue(); |
544 | 0 | } |
545 | | |
546 | | |
547 | | static bool isControlList(const SdrMarkList& rMarkList) |
548 | 0 | { |
549 | | // the list contains only controls and at least one control |
550 | 0 | const size_t nMarkCount = rMarkList.GetMarkCount(); |
551 | 0 | bool bControlList = nMarkCount != 0; |
552 | |
|
553 | 0 | bool bHadAnyLeafs = false; |
554 | |
|
555 | 0 | for (size_t i = 0; i < nMarkCount && bControlList; ++i) |
556 | 0 | { |
557 | 0 | SdrObject *pObj = rMarkList.GetMark(i)->GetMarkedSdrObj(); |
558 | 0 | E3dObject* pAs3DObject = DynCastE3dObject( pObj); |
559 | | // E3dObject's do not contain any 2D-objects (by definition) |
560 | | // we need this extra check here : an E3dObject->IsGroupObject says "YES", but an SdrObjListIter working |
561 | | // with an E3dObject doesn't give me any Nodes (E3dObject has a sub list, but no members in that list, |
562 | | // cause their implementation differs from the one of "normal" SdrObject's. Unfortunately SdrObject::IsGroupObject |
563 | | // doesn't check the element count of the sub list, which is simply a bug in IsGroupObject we can't fix at the moment). |
564 | | // So at the end of this function bControlList would have the same value it was initialized with above : sal_True |
565 | | // And this would be wrong :) |
566 | | // 03.02.00 - 72529 - FS |
567 | 0 | if (!pAs3DObject) |
568 | 0 | { |
569 | 0 | if (pObj->IsGroupObject()) |
570 | 0 | { |
571 | 0 | SdrObjListIter aIter(pObj->GetSubList()); |
572 | 0 | while (aIter.IsMore() && bControlList) |
573 | 0 | { |
574 | 0 | bControlList = SdrInventor::FmForm == aIter.Next()->GetObjInventor(); |
575 | 0 | bHadAnyLeafs = true; |
576 | 0 | } |
577 | 0 | } |
578 | 0 | else |
579 | 0 | { |
580 | 0 | bHadAnyLeafs = true; |
581 | 0 | bControlList = SdrInventor::FmForm == pObj->GetObjInventor(); |
582 | 0 | } |
583 | 0 | } |
584 | 0 | } |
585 | |
|
586 | 0 | return bControlList && bHadAnyLeafs; |
587 | 0 | } |
588 | | |
589 | | |
590 | | static Reference< XForm > GetForm(const Reference< XInterface>& _rxElement) |
591 | 0 | { |
592 | 0 | Reference< XForm > xForm( _rxElement, UNO_QUERY ); |
593 | 0 | if ( xForm.is() ) |
594 | 0 | return xForm; |
595 | | |
596 | 0 | Reference< XChild > xChild( _rxElement, UNO_QUERY ); |
597 | 0 | if ( xChild.is() ) |
598 | 0 | return GetForm( xChild->getParent() ); |
599 | | |
600 | 0 | return Reference< XForm >(); |
601 | 0 | } |
602 | | |
603 | | FmXFormShell_Base_Disambiguation::FmXFormShell_Base_Disambiguation( ::osl::Mutex& _rMutex ) |
604 | 8.87k | :FmXFormShell_BD_BASE( _rMutex ) |
605 | 8.87k | { |
606 | 8.87k | } |
607 | | |
608 | | FmXFormShell::FmXFormShell( FmFormShell& _rShell, SfxViewFrame* _pViewFrame ) |
609 | 8.87k | :FmXFormShell_BASE(m_aMutex) |
610 | 8.87k | ,FmXFormShell_CFGBASE(u"Office.Common/Misc"_ustr, ConfigItemMode::NONE) |
611 | 8.87k | ,m_aMarkTimer("svx::FmXFormShell m_aMarkTimer") |
612 | 8.87k | ,m_eNavigate( NavigationBarMode_NONE ) |
613 | 8.87k | ,m_nInvalidationEvent( nullptr ) |
614 | 8.87k | ,m_nActivationEvent( nullptr ) |
615 | 8.87k | ,m_pShell( &_rShell ) |
616 | 8.87k | ,m_pTextShell( new svx::FmTextControlShell( _pViewFrame ) ) |
617 | 8.87k | ,m_aActiveControllerFeatures( this ) |
618 | 8.87k | ,m_aNavControllerFeatures( this ) |
619 | 8.87k | ,m_eDocumentType( eUnknownDocumentType ) |
620 | 8.87k | ,m_nLockSlotInvalidation( 0 ) |
621 | 8.87k | ,m_bHadPropertyBrowserInDesignMode( false ) |
622 | 8.87k | ,m_bTrackProperties( true ) |
623 | 8.87k | ,m_bUseWizards( true ) |
624 | 8.87k | ,m_bDatabaseBar( false ) |
625 | 8.87k | ,m_bInActivate( false ) |
626 | 8.87k | ,m_bSetFocus( false ) |
627 | 8.87k | ,m_bFilterMode( false ) |
628 | 8.87k | ,m_bChangingDesignMode( false ) |
629 | 8.87k | ,m_bPreparedClose( false ) |
630 | 8.87k | ,m_bFirstActivation( true ) |
631 | 8.87k | { |
632 | 8.87k | m_aMarkTimer.SetTimeout(100); |
633 | 8.87k | m_aMarkTimer.SetInvokeHandler(LINK(this, FmXFormShell, OnTimeOut_Lock)); |
634 | | |
635 | 8.87k | m_xAttachedFrame = _pViewFrame->GetFrame().GetFrameInterface(); |
636 | | |
637 | | // to prevent deletion of this we acquire our refcounter once |
638 | 8.87k | osl_atomic_increment(&m_refCount); |
639 | | |
640 | | // correct the refcounter |
641 | 8.87k | osl_atomic_decrement(&m_refCount); |
642 | | |
643 | | // cache the current configuration settings we're interested in |
644 | 8.87k | implAdjustConfigCache_Lock(); |
645 | | // and register for changes on this settings |
646 | 8.87k | Sequence< OUString > aNames { u"FormControlPilotsEnabled"_ustr }; |
647 | 8.87k | EnableNotification(aNames); |
648 | 8.87k | } |
649 | | |
650 | | |
651 | | FmXFormShell::~FmXFormShell() |
652 | 8.87k | { |
653 | 8.87k | } |
654 | | |
655 | | |
656 | | Reference< css::frame::XModel > FmXFormShell::getContextDocument_Lock() const |
657 | 8.87k | { |
658 | 8.87k | Reference< css::frame::XModel > xModel; |
659 | | |
660 | | // determine the type of document we live in |
661 | 8.87k | try |
662 | 8.87k | { |
663 | 8.87k | Reference< css::frame::XController > xController; |
664 | 8.87k | if ( m_xAttachedFrame.is() ) |
665 | 8.87k | xController = m_xAttachedFrame->getController(); |
666 | 8.87k | if ( xController.is() ) |
667 | 8.87k | xModel = xController->getModel(); |
668 | 8.87k | } |
669 | 8.87k | catch( const Exception& ) |
670 | 8.87k | { |
671 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
672 | 0 | } |
673 | 8.87k | return xModel; |
674 | 8.87k | } |
675 | | |
676 | | |
677 | | bool FmXFormShell::isEnhancedForm_Lock() const |
678 | 8.87k | { |
679 | 8.87k | return getDocumentType_Lock() == eEnhancedForm; |
680 | 8.87k | } |
681 | | |
682 | | |
683 | | bool FmXFormShell::impl_checkDisposed_Lock() const |
684 | 71.0k | { |
685 | 71.0k | DBG_TESTSOLARMUTEX(); |
686 | 71.0k | if ( !m_pShell ) |
687 | 0 | { |
688 | 0 | OSL_FAIL( "FmXFormShell::impl_checkDisposed: already disposed!" ); |
689 | 0 | return true; |
690 | 0 | } |
691 | 71.0k | return false; |
692 | 71.0k | } |
693 | | |
694 | | |
695 | | ::svxform::DocumentType FmXFormShell::getDocumentType_Lock() const |
696 | 8.87k | { |
697 | 8.87k | if ( m_eDocumentType != eUnknownDocumentType ) |
698 | 0 | return m_eDocumentType; |
699 | | |
700 | | // determine the type of document we live in |
701 | 8.87k | Reference<css::frame::XModel> xModel = getContextDocument_Lock(); |
702 | 8.87k | if ( xModel.is() ) |
703 | 8.87k | m_eDocumentType = DocumentClassification::classifyDocument( xModel ); |
704 | 0 | else |
705 | 0 | { |
706 | 0 | OSL_FAIL( "FmXFormShell::getDocumentType: can't determine the document type!" ); |
707 | 0 | m_eDocumentType = eTextDocument; |
708 | | // fallback, just to have a defined state |
709 | 0 | } |
710 | | |
711 | 8.87k | return m_eDocumentType; |
712 | 8.87k | } |
713 | | |
714 | | |
715 | | bool FmXFormShell::IsReadonlyDoc_Lock() const |
716 | 8.87k | { |
717 | 8.87k | if (impl_checkDisposed_Lock()) |
718 | 0 | return true; |
719 | | |
720 | 8.87k | FmFormModel* pModel = m_pShell->GetFormModel(); |
721 | 8.87k | if ( pModel && pModel->GetObjectShell() ) |
722 | 8.87k | return pModel->GetObjectShell()->IsReadOnly() || pModel->GetObjectShell()->IsReadOnlyUI(); |
723 | 0 | return true; |
724 | 8.87k | } |
725 | | |
726 | | // EventListener |
727 | | |
728 | | void SAL_CALL FmXFormShell::disposing(const lang::EventObject& e) |
729 | 0 | { |
730 | 0 | SolarMutexGuard g; |
731 | |
|
732 | 0 | if (m_xActiveController == e.Source) |
733 | 0 | { |
734 | | // the controller will release, then release everything |
735 | 0 | stopListening_Lock(); |
736 | 0 | m_xActiveForm = nullptr; |
737 | 0 | m_xActiveController = nullptr; |
738 | 0 | m_xNavigationController = nullptr; |
739 | |
|
740 | 0 | m_aActiveControllerFeatures.dispose(); |
741 | 0 | m_aNavControllerFeatures.dispose(); |
742 | |
|
743 | 0 | if ( m_pShell ) |
744 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell); |
745 | 0 | } |
746 | |
|
747 | 0 | if (e.Source != m_xExternalViewController) |
748 | 0 | return; |
749 | | |
750 | 0 | Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY ); |
751 | 0 | OSL_ENSURE( xFormController.is(), "FmXFormShell::disposing: invalid external view controller!" ); |
752 | 0 | if (xFormController.is()) |
753 | 0 | xFormController->removeActivateListener(static_cast<XFormControllerListener*>(this)); |
754 | |
|
755 | 0 | if (m_xExternalViewController.is()) |
756 | 0 | m_xExternalViewController->removeEventListener(static_cast<XEventListener*>(static_cast<XPropertyChangeListener*>(this))); |
757 | |
|
758 | 0 | m_xExternalViewController = nullptr; |
759 | 0 | m_xExternalDisplayedForm = nullptr; |
760 | 0 | m_xExtViewTriggerController = nullptr; |
761 | |
|
762 | 0 | InvalidateSlot_Lock( SID_FM_VIEW_AS_GRID, false ); |
763 | 0 | } |
764 | | |
765 | | |
766 | | void SAL_CALL FmXFormShell::propertyChange(const PropertyChangeEvent& evt) |
767 | 0 | { |
768 | 0 | SolarMutexGuard g; |
769 | |
|
770 | 0 | if (impl_checkDisposed_Lock()) |
771 | 0 | return; |
772 | | |
773 | 0 | if (evt.PropertyName == FM_PROP_ROWCOUNT) |
774 | 0 | { |
775 | | // The update following this forces a re-painting of the corresponding |
776 | | // slots. But if I am not in the MainThread of the application (because, |
777 | | // for example, a cursor is counting data sets at the moment and always |
778 | | // gives me this PropertyChanges), this can clash with normal paints in |
779 | | // the MainThread of the application. (Such paints happen, for example, |
780 | | // if one simply places another application over the office and switches |
781 | | // back again). |
782 | | // Therefore the use of the SolarMutex, which safeguards that. |
783 | 0 | comphelper::SolarMutex& rSolarSafety = Application::GetSolarMutex(); |
784 | 0 | if (rSolarSafety.tryToAcquire()) |
785 | 0 | { |
786 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate(SID_FM_RECORD_TOTAL, true); |
787 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Update(SID_FM_RECORD_TOTAL); |
788 | 0 | rSolarSafety.release(); |
789 | 0 | } |
790 | 0 | else |
791 | 0 | { |
792 | | // with the following the slot is invalidated asynchronously |
793 | 0 | LockSlotInvalidation_Lock(true); |
794 | 0 | InvalidateSlot_Lock(SID_FM_RECORD_TOTAL, false); |
795 | 0 | LockSlotInvalidation_Lock(false); |
796 | 0 | } |
797 | 0 | } |
798 | | |
799 | | // this may be called from a non-main-thread so invalidate the shell asynchronously |
800 | 0 | LockSlotInvalidation_Lock(true); |
801 | 0 | InvalidateSlot_Lock(0, false); // special meaning : invalidate m_pShell |
802 | 0 | LockSlotInvalidation_Lock(false); |
803 | 0 | } |
804 | | |
805 | | |
806 | | void FmXFormShell::invalidateFeatures( const ::std::vector< sal_Int32 >& _rFeatures ) |
807 | 0 | { |
808 | 0 | SolarMutexGuard g; |
809 | |
|
810 | 0 | if (impl_checkDisposed_Lock()) |
811 | 0 | return; |
812 | | |
813 | 0 | OSL_ENSURE( !_rFeatures.empty(), "FmXFormShell::invalidateFeatures: invalid arguments!" ); |
814 | |
|
815 | 0 | if (!m_pShell->GetViewShell()) |
816 | 0 | return; |
817 | | |
818 | | // unfortunately, SFX requires sal_uInt16 |
819 | 0 | ::std::vector< sal_uInt16 > aSlotIds( _rFeatures.begin(), _rFeatures.end() ); |
820 | | |
821 | | // furthermore, SFX wants a terminating 0 |
822 | 0 | aSlotIds.push_back( 0 ); |
823 | | |
824 | | // and, last but not least, SFX wants the ids to be sorted |
825 | 0 | ::std::sort( aSlotIds.begin(), aSlotIds.end() - 1 ); |
826 | |
|
827 | 0 | sal_uInt16 *pSlotIds = aSlotIds.data(); |
828 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate( pSlotIds ); |
829 | 0 | } |
830 | | |
831 | | |
832 | | void SAL_CALL FmXFormShell::formActivated(const lang::EventObject& rEvent) |
833 | 0 | { |
834 | 0 | SolarMutexGuard g; |
835 | |
|
836 | 0 | if (impl_checkDisposed_Lock()) |
837 | 0 | return; |
838 | | |
839 | 0 | Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW ); |
840 | 0 | m_pTextShell->formActivated( xController ); |
841 | 0 | setActiveController_Lock(xController); |
842 | 0 | } |
843 | | |
844 | | |
845 | | void SAL_CALL FmXFormShell::formDeactivated(const lang::EventObject& rEvent) |
846 | 0 | { |
847 | 0 | SolarMutexGuard g; |
848 | |
|
849 | 0 | if (impl_checkDisposed_Lock()) |
850 | 0 | return; |
851 | | |
852 | 0 | Reference< runtime::XFormController > xController( rEvent.Source, UNO_QUERY_THROW ); |
853 | 0 | m_pTextShell->formDeactivated( xController ); |
854 | 0 | } |
855 | | |
856 | | |
857 | | void FmXFormShell::disposing() |
858 | 8.87k | { |
859 | 8.87k | SolarMutexGuard g; |
860 | | |
861 | 8.87k | FmXFormShell_BASE::disposing(); |
862 | | |
863 | 8.87k | if ( m_pShell && !m_pShell->IsDesignMode() ) |
864 | 32 | setActiveController_Lock(nullptr, true); |
865 | | // do NOT save the content of the old form (the second parameter tells this) |
866 | | // if we're here, then we expect that PrepareClose has been called, and thus the user |
867 | | // got a chance to commit or reject any changes. So in case we're here and there |
868 | | // are still uncommitted changes, the user explicitly wanted this. |
869 | | |
870 | 8.87k | m_pTextShell->dispose(); |
871 | | |
872 | 8.87k | m_xAttachedFrame = nullptr; |
873 | | |
874 | 8.87k | CloseExternalFormViewer_Lock(); |
875 | | |
876 | 8.87k | while ( !m_aLoadingPages.empty() ) |
877 | 0 | { |
878 | 0 | Application::RemoveUserEvent( m_aLoadingPages.front().nEventId ); |
879 | 0 | m_aLoadingPages.pop(); |
880 | 0 | } |
881 | | |
882 | 8.87k | { |
883 | 8.87k | if (m_nInvalidationEvent) |
884 | 0 | { |
885 | 0 | Application::RemoveUserEvent(m_nInvalidationEvent); |
886 | 0 | m_nInvalidationEvent = nullptr; |
887 | 0 | } |
888 | 8.87k | if ( m_nActivationEvent ) |
889 | 8.87k | { |
890 | 8.87k | Application::RemoveUserEvent( m_nActivationEvent ); |
891 | 8.87k | m_nActivationEvent = nullptr; |
892 | 8.87k | } |
893 | 8.87k | } |
894 | | |
895 | 8.87k | { |
896 | 8.87k | DBG_ASSERT(!m_nInvalidationEvent, "FmXFormShell::~FmXFormShell : still have an invalidation event !"); |
897 | | // should have been deleted while being disposed |
898 | | |
899 | 8.87k | m_aMarkTimer.Stop(); |
900 | 8.87k | } |
901 | | |
902 | 8.87k | DisableNotification(); |
903 | | |
904 | 8.87k | RemoveElement_Lock(m_xForms); |
905 | 8.87k | m_xForms.clear(); |
906 | | |
907 | 8.87k | impl_switchActiveControllerListening_Lock(false); |
908 | 8.87k | m_xActiveController = nullptr; |
909 | 8.87k | m_xActiveForm = nullptr; |
910 | | |
911 | 8.87k | m_pShell = nullptr; |
912 | 8.87k | m_xNavigationController = nullptr; |
913 | 8.87k | m_xCurrentForm = nullptr; |
914 | 8.87k | m_xLastGridFound = nullptr; |
915 | 8.87k | m_xAttachedFrame = nullptr; |
916 | 8.87k | m_xExternalViewController = nullptr; |
917 | 8.87k | m_xExtViewTriggerController = nullptr; |
918 | 8.87k | m_xExternalDisplayedForm = nullptr; |
919 | | |
920 | 8.87k | InterfaceBag().swap(m_aCurrentSelection); |
921 | | |
922 | 8.87k | m_aActiveControllerFeatures.dispose(); |
923 | 8.87k | m_aNavControllerFeatures.dispose(); |
924 | 8.87k | } |
925 | | |
926 | | |
927 | | void FmXFormShell::UpdateSlot_Lock(sal_Int16 _nId) |
928 | 0 | { |
929 | 0 | if (impl_checkDisposed_Lock()) |
930 | 0 | return; |
931 | | |
932 | 0 | if ( m_nLockSlotInvalidation ) |
933 | 0 | { |
934 | 0 | OSL_FAIL( "FmXFormShell::UpdateSlot: cannot update if invalidation is currently locked!" ); |
935 | 0 | InvalidateSlot_Lock(_nId, false); |
936 | 0 | } |
937 | 0 | else |
938 | 0 | { |
939 | 0 | OSL_ENSURE( _nId, "FmXFormShell::UpdateSlot: can't update the complete shell!" ); |
940 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate( _nId, true, true ); |
941 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Update( _nId ); |
942 | 0 | } |
943 | 0 | } |
944 | | |
945 | | void FmXFormShell::InvalidateSlot_Lock(sal_Int16 nId, bool bWithId) |
946 | 0 | { |
947 | 0 | if (impl_checkDisposed_Lock()) |
948 | 0 | return; |
949 | | |
950 | 0 | if (m_nLockSlotInvalidation) |
951 | 0 | { |
952 | 0 | sal_uInt8 nFlags = ( bWithId ? 0x01 : 0 ); |
953 | 0 | m_arrInvalidSlots.emplace_back(nId, nFlags ); |
954 | 0 | } |
955 | 0 | else |
956 | 0 | if (nId) |
957 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate(nId, true, bWithId); |
958 | 0 | else |
959 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell); |
960 | 0 | } |
961 | | |
962 | | void FmXFormShell::LockSlotInvalidation_Lock(bool bLock) |
963 | 0 | { |
964 | 0 | if (impl_checkDisposed_Lock()) |
965 | 0 | return; |
966 | | |
967 | 0 | DBG_ASSERT(bLock || m_nLockSlotInvalidation>0, "FmXFormShell::LockSlotInvalidation : invalid call !"); |
968 | |
|
969 | 0 | if (bLock) |
970 | 0 | ++m_nLockSlotInvalidation; |
971 | 0 | else if (!--m_nLockSlotInvalidation) |
972 | 0 | { |
973 | | // (asynchronously) invalidate everything accumulated during the locked phase |
974 | 0 | if (!m_nInvalidationEvent) |
975 | 0 | m_nInvalidationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnInvalidateSlots_Lock)); |
976 | 0 | } |
977 | 0 | } |
978 | | |
979 | | IMPL_LINK_NOARG(FmXFormShell, OnInvalidateSlots_Lock, void*,void) |
980 | 0 | { |
981 | 0 | if (impl_checkDisposed_Lock()) |
982 | 0 | return; |
983 | | |
984 | 0 | m_nInvalidationEvent = nullptr; |
985 | |
|
986 | 0 | for (const auto& rInvalidSlot : m_arrInvalidSlots) |
987 | 0 | { |
988 | 0 | if (rInvalidSlot.id) |
989 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Invalidate(rInvalidSlot.id, true, (rInvalidSlot.flags & 0x01)); |
990 | 0 | else |
991 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell); |
992 | 0 | } |
993 | 0 | m_arrInvalidSlots.clear(); |
994 | 0 | } |
995 | | |
996 | | void FmXFormShell::ForceUpdateSelection_Lock() |
997 | 0 | { |
998 | 0 | if (impl_checkDisposed_Lock()) |
999 | 0 | return; |
1000 | | |
1001 | 0 | if (IsSelectionUpdatePending_Lock()) |
1002 | 0 | { |
1003 | 0 | m_aMarkTimer.Stop(); |
1004 | | |
1005 | | // optionally turn off the invalidation of slots which is implicitly done by SetSelection |
1006 | 0 | LockSlotInvalidation_Lock(true); |
1007 | |
|
1008 | 0 | SetSelection_Lock(m_pShell->GetFormView()->GetMarkedObjectList()); |
1009 | |
|
1010 | 0 | LockSlotInvalidation_Lock(false); |
1011 | 0 | } |
1012 | 0 | } |
1013 | | |
1014 | | void FmXFormShell::GetConversionMenu_Lock(weld::Menu& rNewMenu) |
1015 | 0 | { |
1016 | 0 | for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i) |
1017 | 0 | { |
1018 | | // the corresponding image at it |
1019 | 0 | rNewMenu.append(OUString(aConvertSlots[i]), SvxResId(RID_SVXSW_CONVERTMENU[i]), aImgIds[i]); |
1020 | 0 | } |
1021 | 0 | } |
1022 | | |
1023 | | OUString FmXFormShell::SlotToIdent(sal_uInt16 nSlot) |
1024 | 0 | { |
1025 | 0 | static_assert(SAL_N_ELEMENTS(SelObjectSlotMap) >= SAL_N_ELEMENTS(aConvertSlots)); |
1026 | |
|
1027 | 0 | for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i) |
1028 | 0 | { |
1029 | 0 | if (nSlot == SelObjectSlotMap[i]) |
1030 | 0 | return OUString(aConvertSlots[i]); |
1031 | 0 | } |
1032 | | |
1033 | 0 | return {}; |
1034 | 0 | } |
1035 | | |
1036 | | bool FmXFormShell::isControlConversionSlot(std::u16string_view rIdent) |
1037 | 0 | { |
1038 | 0 | for (const auto& rConvertSlot : aConvertSlots) |
1039 | 0 | if (rIdent == rConvertSlot) |
1040 | 0 | return true; |
1041 | 0 | return false; |
1042 | 0 | } |
1043 | | |
1044 | | void FmXFormShell::executeControlConversionSlot_Lock(std::u16string_view rIdent) |
1045 | 0 | { |
1046 | 0 | OSL_PRECOND( canConvertCurrentSelectionToControl_Lock(rIdent), "FmXFormShell::executeControlConversionSlot: illegal call!" ); |
1047 | 0 | InterfaceBag::const_iterator aSelectedElement = m_aCurrentSelection.begin(); |
1048 | 0 | if ( aSelectedElement == m_aCurrentSelection.end() ) |
1049 | 0 | return; |
1050 | | |
1051 | 0 | executeControlConversionSlot_Lock(Reference<XFormComponent>(*aSelectedElement, UNO_QUERY), rIdent); |
1052 | 0 | } |
1053 | | |
1054 | | bool FmXFormShell::executeControlConversionSlot_Lock(const Reference<XFormComponent>& _rxObject, std::u16string_view rIdent) |
1055 | 0 | { |
1056 | 0 | if (impl_checkDisposed_Lock()) |
1057 | 0 | return false; |
1058 | | |
1059 | 0 | OSL_ENSURE( _rxObject.is(), "FmXFormShell::executeControlConversionSlot: invalid object!" ); |
1060 | 0 | if ( !_rxObject.is() ) |
1061 | 0 | return false; |
1062 | | |
1063 | 0 | SdrPage* pPage = m_pShell->GetCurPage(); |
1064 | 0 | FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( pPage ); |
1065 | 0 | OSL_ENSURE( pFormPage, "FmXFormShell::executeControlConversionSlot: no current (form) page!" ); |
1066 | 0 | if ( !pFormPage ) |
1067 | 0 | return false; |
1068 | | |
1069 | 0 | OSL_ENSURE( isSolelySelected_Lock(_rxObject), |
1070 | 0 | "FmXFormShell::executeControlConversionSlot: hmm ... shouldn't this parameter be redundant?" ); |
1071 | |
|
1072 | 0 | for (size_t lookupSlot = 0; lookupSlot < SAL_N_ELEMENTS(aConvertSlots); ++lookupSlot) |
1073 | 0 | { |
1074 | 0 | if (rIdent == aConvertSlots[lookupSlot]) |
1075 | 0 | { |
1076 | 0 | Reference< XInterface > xNormalizedObject( _rxObject, UNO_QUERY ); |
1077 | |
|
1078 | 0 | FmFormObj* pFormObject = nullptr; |
1079 | 0 | SdrObjListIter aPageIter( pFormPage ); |
1080 | 0 | while ( aPageIter.IsMore() ) |
1081 | 0 | { |
1082 | 0 | SdrObject* pCurrent = aPageIter.Next(); |
1083 | 0 | pFormObject = FmFormObj::GetFormObject( pCurrent ); |
1084 | 0 | if ( !pFormObject ) |
1085 | 0 | continue; |
1086 | | |
1087 | 0 | Reference< XInterface > xCurrentNormalized( pFormObject->GetUnoControlModel(), UNO_QUERY ); |
1088 | 0 | if ( xCurrentNormalized.get() == xNormalizedObject.get() ) |
1089 | 0 | break; |
1090 | | |
1091 | 0 | pFormObject = nullptr; |
1092 | 0 | } |
1093 | |
|
1094 | 0 | if ( !pFormObject ) |
1095 | 0 | return false; |
1096 | | |
1097 | 0 | OUString sNewName( getServiceNameByControlType( nObjectTypes[ lookupSlot ] ) ); |
1098 | 0 | const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext(); |
1099 | 0 | Reference< XControlModel> xNewModel( xContext->getServiceManager()->createInstanceWithContext(sNewName, xContext), UNO_QUERY ); |
1100 | 0 | if (!xNewModel.is()) |
1101 | 0 | return false; |
1102 | | |
1103 | 0 | Reference< XControlModel> xOldModel( pFormObject->GetUnoControlModel() ); |
1104 | | |
1105 | | // transfer properties |
1106 | 0 | Reference< XPropertySet> xOldSet(xOldModel, UNO_QUERY); |
1107 | 0 | Reference< XPropertySet> xNewSet(xNewModel, UNO_QUERY); |
1108 | | |
1109 | |
|
1110 | 0 | lang::Locale aNewLanguage = Application::GetSettings().GetUILanguageTag().getLocale(); |
1111 | 0 | TransferFormComponentProperties(xOldSet, xNewSet, aNewLanguage); |
1112 | |
|
1113 | 0 | Sequence< css::script::ScriptEventDescriptor> aOldScripts; |
1114 | 0 | Reference< XChild> xChild(xOldModel, UNO_QUERY); |
1115 | 0 | if (xChild.is()) |
1116 | 0 | { |
1117 | 0 | Reference< XIndexAccess> xParent(xChild->getParent(), UNO_QUERY); |
1118 | | |
1119 | | // remember old script events |
1120 | 0 | Reference< css::script::XEventAttacherManager> xEvManager(xChild->getParent(), UNO_QUERY); |
1121 | 0 | if (xParent.is() && xEvManager.is()) |
1122 | 0 | { |
1123 | 0 | sal_Int32 nIndex = getElementPos(xParent, xOldModel); |
1124 | 0 | if (nIndex>=0 && nIndex<xParent->getCount()) |
1125 | 0 | aOldScripts = xEvManager->getScriptEvents(nIndex); |
1126 | 0 | } |
1127 | | |
1128 | | // replace the model within the parent container |
1129 | 0 | Reference< XIndexContainer> xIndexParent(xChild->getParent(), UNO_QUERY); |
1130 | 0 | if (xIndexParent.is()) |
1131 | 0 | { |
1132 | | // the form container works with FormComponents |
1133 | 0 | Reference< XFormComponent> xComponent(xNewModel, UNO_QUERY); |
1134 | 0 | DBG_ASSERT(xComponent.is(), "FmXFormShell::executeControlConversionSlot: the new model is no form component !"); |
1135 | 0 | Any aNewModel(xComponent); |
1136 | 0 | try |
1137 | 0 | { |
1138 | |
|
1139 | 0 | sal_Int32 nIndex = getElementPos(xParent, xOldModel); |
1140 | 0 | if (nIndex>=0 && nIndex<xParent->getCount()) |
1141 | 0 | xIndexParent->replaceByIndex(nIndex, aNewModel); |
1142 | 0 | else |
1143 | 0 | { |
1144 | 0 | OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !"); |
1145 | 0 | Reference< css::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY); |
1146 | 0 | if (xNewComponent.is()) |
1147 | 0 | xNewComponent->dispose(); |
1148 | 0 | return false; |
1149 | 0 | } |
1150 | 0 | } |
1151 | 0 | catch(Exception&) |
1152 | 0 | { |
1153 | 0 | OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !"); |
1154 | 0 | Reference< css::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY); |
1155 | 0 | if (xNewComponent.is()) |
1156 | 0 | xNewComponent->dispose(); |
1157 | 0 | return false; |
1158 | 0 | } |
1159 | |
|
1160 | 0 | } |
1161 | 0 | } |
1162 | | |
1163 | | // special handling for the LabelControl-property : can only be set when the model is placed |
1164 | | // within the forms hierarchy |
1165 | 0 | if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xOldSet) && ::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xNewSet)) |
1166 | 0 | { |
1167 | 0 | try |
1168 | 0 | { |
1169 | 0 | xNewSet->setPropertyValue(FM_PROP_CONTROLLABEL, xOldSet->getPropertyValue(FM_PROP_CONTROLLABEL)); |
1170 | 0 | } |
1171 | 0 | catch(Exception&) |
1172 | 0 | { |
1173 | 0 | } |
1174 | |
|
1175 | 0 | } |
1176 | | |
1177 | | // set new model |
1178 | 0 | pFormObject->SetChanged(); |
1179 | 0 | pFormObject->SetUnoControlModel(xNewModel); |
1180 | | |
1181 | | // transfer script events |
1182 | | // (do this _after_ SetUnoControlModel as we need the new (implicitly created) control) |
1183 | 0 | if (aOldScripts.hasElements()) |
1184 | 0 | { |
1185 | | // find the control for the model |
1186 | 0 | Reference<XControlContainer> xControlContainer(getControlContainerForView_Lock()); |
1187 | |
|
1188 | 0 | const Sequence< Reference< XControl> > aControls( xControlContainer->getControls() ); |
1189 | |
|
1190 | 0 | Reference< XControl> xControl; |
1191 | 0 | auto pControl = std::find_if(aControls.begin(), aControls.end(), |
1192 | 0 | [&xNewModel](const Reference< XControl>& rControl) { return rControl->getModel() == xNewModel; }); |
1193 | 0 | if (pControl != aControls.end()) |
1194 | 0 | xControl = *pControl; |
1195 | 0 | TransferEventScripts(xNewModel, xControl, aOldScripts); |
1196 | 0 | } |
1197 | | |
1198 | | // transfer value bindings, if possible |
1199 | 0 | { |
1200 | 0 | Reference< XBindableValue > xOldBindable( xOldModel, UNO_QUERY ); |
1201 | 0 | Reference< XBindableValue > xNewBindable( xNewModel, UNO_QUERY ); |
1202 | 0 | if ( xOldBindable.is() ) |
1203 | 0 | { |
1204 | 0 | try |
1205 | 0 | { |
1206 | 0 | if ( xNewBindable.is() ) |
1207 | 0 | xNewBindable->setValueBinding( xOldBindable->getValueBinding() ); |
1208 | 0 | xOldBindable->setValueBinding( nullptr ); |
1209 | 0 | } |
1210 | 0 | catch(const Exception&) |
1211 | 0 | { |
1212 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
1213 | 0 | } |
1214 | 0 | } |
1215 | 0 | } |
1216 | | // same for list entry sources |
1217 | 0 | { |
1218 | 0 | Reference< XListEntrySink > xOldSink( xOldModel, UNO_QUERY ); |
1219 | 0 | Reference< XListEntrySink > xNewSink( xNewModel, UNO_QUERY ); |
1220 | 0 | if ( xOldSink.is() ) |
1221 | 0 | { |
1222 | 0 | try |
1223 | 0 | { |
1224 | 0 | if ( xNewSink.is() ) |
1225 | 0 | xNewSink->setListEntrySource( xOldSink->getListEntrySource() ); |
1226 | 0 | xOldSink->setListEntrySource( nullptr ); |
1227 | 0 | } |
1228 | 0 | catch(const Exception&) |
1229 | 0 | { |
1230 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
1231 | 0 | } |
1232 | 0 | } |
1233 | 0 | } |
1234 | | |
1235 | | // create an undo action |
1236 | 0 | FmFormModel* pModel = m_pShell->GetFormModel(); |
1237 | 0 | DBG_ASSERT(pModel != nullptr, "FmXFormShell::executeControlConversionSlot: my shell has no model !"); |
1238 | 0 | if (pModel && pModel->IsUndoEnabled() ) |
1239 | 0 | { |
1240 | 0 | pModel->AddUndo(std::make_unique<FmUndoModelReplaceAction>(*pModel, pFormObject, xOldModel)); |
1241 | 0 | } |
1242 | 0 | else |
1243 | 0 | { |
1244 | 0 | FmUndoModelReplaceAction::DisposeElement( xOldModel ); |
1245 | 0 | } |
1246 | |
|
1247 | 0 | return true; |
1248 | 0 | } |
1249 | 0 | } |
1250 | 0 | return false; |
1251 | 0 | } |
1252 | | |
1253 | | bool FmXFormShell::canConvertCurrentSelectionToControl_Lock(std::u16string_view rIdent) |
1254 | 0 | { |
1255 | 0 | if ( m_aCurrentSelection.empty() ) |
1256 | 0 | return false; |
1257 | | |
1258 | 0 | InterfaceBag::const_iterator aCheck = m_aCurrentSelection.begin(); |
1259 | 0 | Reference< lang::XServiceInfo > xElementInfo( *aCheck, UNO_QUERY ); |
1260 | 0 | if ( !xElementInfo.is() ) |
1261 | | // no service info -> cannot determine this |
1262 | 0 | return false; |
1263 | | |
1264 | 0 | if ( ++aCheck != m_aCurrentSelection.end() ) |
1265 | | // more than one element |
1266 | 0 | return false; |
1267 | | |
1268 | 0 | if ( Reference< XForm >::query( xElementInfo ).is() ) |
1269 | | // it's a form |
1270 | 0 | return false; |
1271 | | |
1272 | 0 | SdrObjKind nObjectType = getControlTypeByObject( xElementInfo ); |
1273 | |
|
1274 | 0 | if ( ( SdrObjKind::FormHidden == nObjectType ) |
1275 | 0 | || ( SdrObjKind::FormControl == nObjectType ) |
1276 | 0 | || ( SdrObjKind::FormGrid == nObjectType ) |
1277 | 0 | ) |
1278 | 0 | return false; // those types cannot be converted |
1279 | | |
1280 | 0 | DBG_ASSERT(SAL_N_ELEMENTS(aConvertSlots) == SAL_N_ELEMENTS(nObjectTypes), |
1281 | 0 | "FmXFormShell::canConvertCurrentSelectionToControl: aConvertSlots & nObjectTypes must have the same size !"); |
1282 | |
|
1283 | 0 | for (size_t i = 0; i < SAL_N_ELEMENTS(aConvertSlots); ++i) |
1284 | 0 | if (rIdent == aConvertSlots[i]) |
1285 | 0 | return nObjectTypes[i] != nObjectType; |
1286 | | |
1287 | 0 | return true; // all other slots: assume "yes" |
1288 | 0 | } |
1289 | | |
1290 | | void FmXFormShell::checkControlConversionSlotsForCurrentSelection_Lock(weld::Menu& rMenu) |
1291 | 0 | { |
1292 | 0 | for (int i = 0, nCount = rMenu.n_children(); i < nCount; ++i) |
1293 | 0 | { |
1294 | | // the context is already of a type that corresponds to the entry -> disable |
1295 | 0 | OUString sIdent(aConvertSlots[i]); |
1296 | 0 | rMenu.set_sensitive(sIdent, canConvertCurrentSelectionToControl_Lock(sIdent)); |
1297 | 0 | } |
1298 | 0 | } |
1299 | | |
1300 | | void FmXFormShell::LoopGrids_Lock(LoopGridsSync nSync, LoopGridsFlags nFlags) |
1301 | 0 | { |
1302 | 0 | if (impl_checkDisposed_Lock()) |
1303 | 0 | return; |
1304 | | |
1305 | 0 | Reference< XIndexContainer> xControlModels(m_xActiveForm, UNO_QUERY); |
1306 | 0 | if (!xControlModels.is()) |
1307 | 0 | return; |
1308 | | |
1309 | 0 | for (sal_Int32 i=0; i<xControlModels->getCount(); ++i) |
1310 | 0 | { |
1311 | 0 | Reference< XPropertySet> xModelSet; |
1312 | 0 | xControlModels->getByIndex(i) >>= xModelSet; |
1313 | 0 | if (!xModelSet.is()) |
1314 | 0 | continue; |
1315 | | |
1316 | 0 | if (!::comphelper::hasProperty(FM_PROP_CLASSID, xModelSet)) |
1317 | 0 | continue; |
1318 | 0 | sal_Int16 nClassId = ::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_CLASSID)); |
1319 | 0 | if (FormComponentType::GRIDCONTROL != nClassId) |
1320 | 0 | continue; |
1321 | | |
1322 | 0 | if (!::comphelper::hasProperty(FM_PROP_CURSORCOLOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_ALWAYSSHOWCURSOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_DISPLAYSYNCHRON, xModelSet)) |
1323 | 0 | continue; |
1324 | | |
1325 | 0 | switch (nSync) |
1326 | 0 | { |
1327 | 0 | case LoopGridsSync::DISABLE_SYNC: |
1328 | 0 | { |
1329 | 0 | xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(false)); |
1330 | 0 | } |
1331 | 0 | break; |
1332 | 0 | case LoopGridsSync::FORCE_SYNC: |
1333 | 0 | { |
1334 | 0 | Any aOldVal( xModelSet->getPropertyValue(FM_PROP_DISPLAYSYNCHRON) ); |
1335 | 0 | xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(true)); |
1336 | 0 | xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, aOldVal); |
1337 | 0 | } |
1338 | 0 | break; |
1339 | 0 | case LoopGridsSync::ENABLE_SYNC: |
1340 | 0 | { |
1341 | 0 | xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(true)); |
1342 | 0 | } |
1343 | 0 | break; |
1344 | 0 | } |
1345 | | |
1346 | 0 | if (nFlags & LoopGridsFlags::DISABLE_ROCTRLR) |
1347 | 0 | { |
1348 | 0 | xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(false)); |
1349 | 0 | Reference< XPropertyState> xModelPropState(xModelSet, UNO_QUERY); |
1350 | 0 | if (xModelPropState.is()) |
1351 | 0 | xModelPropState->setPropertyToDefault(FM_PROP_CURSORCOLOR); |
1352 | 0 | else |
1353 | 0 | xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); // this should be the default |
1354 | 0 | } |
1355 | 0 | } |
1356 | 0 | } |
1357 | | |
1358 | | |
1359 | | Reference< XControlContainer > FmXFormShell::getControlContainerForView_Lock() const |
1360 | 0 | { |
1361 | 0 | if (impl_checkDisposed_Lock()) |
1362 | 0 | return nullptr; |
1363 | | |
1364 | 0 | SdrPageView* pPageView = nullptr; |
1365 | 0 | if ( m_pShell && m_pShell->GetFormView() ) |
1366 | 0 | pPageView = m_pShell->GetFormView()->GetSdrPageView(); |
1367 | |
|
1368 | 0 | Reference< XControlContainer> xControlContainer; |
1369 | 0 | if ( pPageView ) |
1370 | 0 | xControlContainer = pPageView->GetPageWindow(0)->GetControlContainer(); |
1371 | |
|
1372 | 0 | return xControlContainer; |
1373 | 0 | } |
1374 | | |
1375 | | |
1376 | | void FmXFormShell::ExecuteTabOrderDialog_Lock(const Reference<XTabControllerModel>& _rxForForm) |
1377 | 0 | { |
1378 | 0 | if (impl_checkDisposed_Lock()) |
1379 | 0 | return; |
1380 | | |
1381 | 0 | OSL_PRECOND( _rxForForm.is(), "FmXFormShell::ExecuteTabOrderDialog: invalid tabbing model!" ); |
1382 | 0 | if ( !_rxForForm.is() ) |
1383 | 0 | return; |
1384 | | |
1385 | 0 | try |
1386 | 0 | { |
1387 | 0 | Reference< XWindow > xParentWindow; |
1388 | 0 | if (m_pShell->GetViewShell()) |
1389 | 0 | xParentWindow = VCLUnoHelper::GetInterface ( &m_pShell->GetViewShell()->GetViewFrame().GetWindow() ); |
1390 | |
|
1391 | 0 | Reference< dialogs::XExecutableDialog > xDialog = form::TabOrderDialog::createWithModel( |
1392 | 0 | comphelper::getProcessComponentContext(), |
1393 | 0 | _rxForForm, getControlContainerForView_Lock(), xParentWindow |
1394 | 0 | ); |
1395 | |
|
1396 | 0 | (void)xDialog->execute(); |
1397 | 0 | } |
1398 | 0 | catch( const Exception& ) |
1399 | 0 | { |
1400 | 0 | TOOLS_WARN_EXCEPTION( "svx", "FmXFormShell::ExecuteTabOrderDialog" ); |
1401 | 0 | } |
1402 | 0 | } |
1403 | | |
1404 | | |
1405 | | void FmXFormShell::ExecuteSearch_Lock() |
1406 | 0 | { |
1407 | 0 | if (impl_checkDisposed_Lock()) |
1408 | 0 | return; |
1409 | | |
1410 | | // a collection of all (logical) forms |
1411 | 0 | FmFormArray().swap(m_aSearchForms); |
1412 | 0 | ::std::vector< OUString > aContextNames; |
1413 | 0 | impl_collectFormSearchContexts_nothrow_Lock( |
1414 | 0 | m_pShell->GetCurPage()->GetForms(), u"", |
1415 | 0 | m_aSearchForms, aContextNames); |
1416 | |
|
1417 | 0 | if ( m_aSearchForms.size() != aContextNames.size() ) |
1418 | 0 | { |
1419 | 0 | SAL_WARN ( "svx.form", "FmXFormShell::ExecuteSearch: nonsense!" ); |
1420 | 0 | return; |
1421 | 0 | } |
1422 | | |
1423 | | // filter out the forms which do not contain valid controls at all |
1424 | 0 | { |
1425 | 0 | FmFormArray aValidForms; |
1426 | 0 | ::std::vector< OUString > aValidContexts; |
1427 | 0 | FmFormArray::const_iterator form = m_aSearchForms.begin(); |
1428 | 0 | ::std::vector< OUString >::const_iterator contextName = aContextNames.begin(); |
1429 | 0 | for ( ; form != m_aSearchForms.end(); ++form, ++contextName ) |
1430 | 0 | { |
1431 | 0 | FmSearchContext aTestContext; |
1432 | 0 | aTestContext.nContext = static_cast< sal_Int16 >( form - m_aSearchForms.begin() ); |
1433 | 0 | sal_uInt32 nValidControls = OnSearchContextRequest_Lock(aTestContext); |
1434 | 0 | if ( nValidControls > 0 ) |
1435 | 0 | { |
1436 | 0 | aValidForms.push_back( *form ); |
1437 | 0 | aValidContexts.push_back( *contextName ); |
1438 | 0 | } |
1439 | 0 | } |
1440 | |
|
1441 | 0 | m_aSearchForms.swap( aValidForms ); |
1442 | 0 | aContextNames.swap( aValidContexts ); |
1443 | 0 | } |
1444 | |
|
1445 | 0 | if (m_aSearchForms.empty() ) |
1446 | 0 | { |
1447 | | // there are no controls that meet all the conditions for a search |
1448 | 0 | std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr, |
1449 | 0 | VclMessageType::Warning, VclButtonsType::Ok, |
1450 | 0 | SvxResId(RID_STR_NODATACONTROLS))); |
1451 | 0 | xBox->run(); |
1452 | 0 | return; |
1453 | 0 | } |
1454 | | |
1455 | | // now I need another 'initial context' |
1456 | 0 | sal_Int16 nInitialContext = 0; |
1457 | 0 | Reference<XForm> xActiveForm(getActiveForm_Lock()); |
1458 | 0 | for ( size_t i=0; i<m_aSearchForms.size(); ++i ) |
1459 | 0 | { |
1460 | 0 | if (m_aSearchForms.at(i) == xActiveForm) |
1461 | 0 | { |
1462 | 0 | nInitialContext = static_cast<sal_Int16>(i); |
1463 | 0 | break; |
1464 | 0 | } |
1465 | 0 | } |
1466 | | |
1467 | | // If the dialog should initially offer the text of the active control, |
1468 | | // this must have an XTextComponent interface. An addition, this makes |
1469 | | // sense only if the current field is also bound to a table (or whatever) field. |
1470 | 0 | OUString strActiveField; |
1471 | 0 | OUString strInitialText; |
1472 | | // ... this I get from my FormController |
1473 | 0 | DBG_ASSERT(m_xActiveController.is(), "FmXFormShell::ExecuteSearch : no active controller !"); |
1474 | 0 | Reference< XControl> xActiveControl( m_xActiveController->getCurrentControl()); |
1475 | 0 | if (xActiveControl.is()) |
1476 | 0 | { |
1477 | | // the control can tell me its model ... |
1478 | 0 | Reference< XControlModel> xActiveModel( xActiveControl->getModel()); |
1479 | 0 | DBG_ASSERT(xActiveModel.is(), "FmXFormShell::ExecuteSearch : active control has no model !"); |
1480 | | |
1481 | | // I ask the model for the ControlSource property ... |
1482 | 0 | Reference< XPropertySet> xProperties(xActiveControl->getModel(), UNO_QUERY); |
1483 | 0 | if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties)) |
1484 | 0 | { |
1485 | 0 | Reference< XPropertySet> xField; |
1486 | 0 | xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; |
1487 | 0 | if (xField.is()) // (only when the thing is really bound) |
1488 | 0 | { |
1489 | | // and the control itself for a TextComponent interface (so that I can pick up the text there) |
1490 | 0 | Reference< XTextComponent> xText(xActiveControl, UNO_QUERY); |
1491 | 0 | if (xText.is()) |
1492 | 0 | { |
1493 | 0 | strActiveField = getLabelName(xProperties); |
1494 | 0 | strInitialText = xText->getText(); |
1495 | 0 | } |
1496 | 0 | } |
1497 | 0 | } |
1498 | 0 | else |
1499 | 0 | { |
1500 | | // the control itself has no ControlSource, but maybe it is a GridControl |
1501 | 0 | Reference< XGrid> xGrid(xActiveControl, UNO_QUERY); |
1502 | 0 | if (xGrid.is()) |
1503 | 0 | { |
1504 | | // for strActiveField I need the ControlSource of the column, |
1505 | | // for that the columns container, for that the GridPeer |
1506 | 0 | Reference< XGridPeer> xGridPeer(xActiveControl->getPeer(), UNO_QUERY); |
1507 | 0 | Reference< XIndexAccess> xColumns; |
1508 | 0 | if (xGridPeer.is()) |
1509 | 0 | xColumns = xGridPeer->getColumns(); |
1510 | |
|
1511 | 0 | sal_Int16 nViewCol = xGrid->getCurrentColumnPosition(); |
1512 | 0 | sal_Int32 nModelCol = GridView2ModelPos(xColumns, nViewCol); |
1513 | 0 | Reference< XPropertySet> xCurrentCol; |
1514 | 0 | if(xColumns.is()) |
1515 | 0 | xColumns->getByIndex(nModelCol) >>= xCurrentCol; |
1516 | 0 | if (xCurrentCol.is()) |
1517 | 0 | strActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(FM_PROP_LABEL)); |
1518 | | |
1519 | | // the text of the current column |
1520 | 0 | Reference< XIndexAccess> xColControls(xGridPeer, UNO_QUERY); |
1521 | 0 | Reference< XInterface> xCurControl; |
1522 | 0 | xColControls->getByIndex(nViewCol) >>= xCurControl; |
1523 | 0 | OUString sInitialText; |
1524 | 0 | if (IsSearchableControl(xCurControl, &sInitialText)) |
1525 | 0 | strInitialText = sInitialText; |
1526 | 0 | } |
1527 | 0 | } |
1528 | 0 | } |
1529 | | |
1530 | | // taking care of possible GridControls that I know |
1531 | 0 | LoopGrids_Lock(LoopGridsSync::DISABLE_SYNC); |
1532 | | |
1533 | | // Now I am ready for the dialogue. |
1534 | | // When the potential deadlocks caused by the use of the solar mutex in |
1535 | | // MTs VCLX... classes are eventually cleared, an SM_USETHREAD should be |
1536 | | // placed here, because the search in a separate thread is nevertheless |
1537 | | // somewhat more fluid. Should be, however, somehow made dependent of the |
1538 | | // underlying cursor. DAO for example is not thread-safe. |
1539 | 0 | SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); |
1540 | 0 | ScopedVclPtr<AbstractFmSearchDialog> pDialog( |
1541 | 0 | pFact->CreateFmSearchDialog( |
1542 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetFrameWeld(), |
1543 | 0 | strInitialText, aContextNames, nInitialContext, |
1544 | 0 | LINK(this, FmXFormShell, OnSearchContextRequest_Lock) )); |
1545 | 0 | pDialog->SetActiveField( strActiveField ); |
1546 | 0 | pDialog->SetFoundHandler(LINK(this, FmXFormShell, OnFoundData_Lock)); |
1547 | 0 | pDialog->SetCanceledNotFoundHdl(LINK(this, FmXFormShell, OnCanceledNotFound_Lock)); |
1548 | 0 | pDialog->Execute(); |
1549 | 0 | pDialog.disposeAndClear(); |
1550 | | |
1551 | | // restore GridControls again |
1552 | 0 | LoopGrids_Lock(LoopGridsSync::ENABLE_SYNC, LoopGridsFlags::DISABLE_ROCTRLR); |
1553 | |
|
1554 | 0 | m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); |
1555 | | // because I marked controls in OnFoundData (if I was there) |
1556 | 0 | } |
1557 | | |
1558 | | |
1559 | | bool FmXFormShell::GetY2KState_Lock(sal_uInt16& n) |
1560 | 0 | { |
1561 | 0 | if (impl_checkDisposed_Lock()) |
1562 | 0 | return false; |
1563 | | |
1564 | 0 | if (m_pShell->IsDesignMode()) |
1565 | | // in the design mode (without active controls) the main document is to take care of it |
1566 | 0 | return false; |
1567 | | |
1568 | 0 | Reference<XForm> xForm(getActiveForm_Lock()); |
1569 | 0 | if (!xForm.is()) |
1570 | | // no current form (in particular no current control) -> the main document is to take care |
1571 | 0 | return false; |
1572 | | |
1573 | 0 | Reference< XRowSet> xDB(xForm, UNO_QUERY); |
1574 | 0 | DBG_ASSERT(xDB.is(), "FmXFormShell::GetY2KState : current form has no dbform-interface !"); |
1575 | |
|
1576 | 0 | Reference< XNumberFormatsSupplier> xSupplier( getNumberFormats(getConnection(xDB))); |
1577 | 0 | if (xSupplier.is()) |
1578 | 0 | { |
1579 | 0 | Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); |
1580 | 0 | if (xSet.is()) |
1581 | 0 | { |
1582 | 0 | try |
1583 | 0 | { |
1584 | 0 | Any aVal( xSet->getPropertyValue(u"TwoDigitDateStart"_ustr) ); |
1585 | 0 | aVal >>= n; |
1586 | 0 | return true; |
1587 | 0 | } |
1588 | 0 | catch(Exception&) |
1589 | 0 | { |
1590 | 0 | } |
1591 | |
|
1592 | 0 | } |
1593 | 0 | } |
1594 | 0 | return false; |
1595 | 0 | } |
1596 | | |
1597 | | |
1598 | | void FmXFormShell::SetY2KState_Lock(sal_uInt16 n) |
1599 | 0 | { |
1600 | 0 | if (impl_checkDisposed_Lock()) |
1601 | 0 | return; |
1602 | | |
1603 | 0 | Reference<XForm> xActiveForm(getActiveForm_Lock()); |
1604 | 0 | Reference< XRowSet > xActiveRowSet( xActiveForm, UNO_QUERY ); |
1605 | 0 | if ( xActiveRowSet.is() ) |
1606 | 0 | { |
1607 | 0 | Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getConnection( xActiveRowSet ) ) ); |
1608 | 0 | if (xSupplier.is()) |
1609 | 0 | { |
1610 | 0 | Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); |
1611 | 0 | if (xSet.is()) |
1612 | 0 | { |
1613 | 0 | try |
1614 | 0 | { |
1615 | 0 | xSet->setPropertyValue(u"TwoDigitDateStart"_ustr, Any(sal_uInt16(n))); |
1616 | 0 | } |
1617 | 0 | catch(Exception&) |
1618 | 0 | { |
1619 | 0 | TOOLS_WARN_EXCEPTION("svx.form", ""); |
1620 | 0 | } |
1621 | |
|
1622 | 0 | } |
1623 | 0 | return; |
1624 | 0 | } |
1625 | 0 | } |
1626 | | |
1627 | | // no active form found -> iterate through all current forms |
1628 | 0 | Reference< XIndexAccess> xCurrentForms( m_xForms); |
1629 | 0 | if (!xCurrentForms.is()) |
1630 | 0 | { // in the alive mode, my forms are not set, but the ones on the page are |
1631 | 0 | if (m_pShell->GetCurPage()) |
1632 | 0 | xCurrentForms = m_pShell->GetCurPage()->GetForms( false ); |
1633 | 0 | } |
1634 | 0 | if (!xCurrentForms.is()) |
1635 | 0 | return; |
1636 | | |
1637 | 0 | ::comphelper::IndexAccessIterator aIter(xCurrentForms); |
1638 | 0 | Reference< XInterface> xCurrentElement( aIter.Next()); |
1639 | 0 | while (xCurrentElement.is()) |
1640 | 0 | { |
1641 | | // is the current element a DatabaseForm? |
1642 | 0 | Reference< XRowSet> xElementAsRowSet( xCurrentElement, UNO_QUERY ); |
1643 | 0 | if ( xElementAsRowSet.is() ) |
1644 | 0 | { |
1645 | 0 | Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getConnection( xElementAsRowSet ) ) ); |
1646 | 0 | if (!xSupplier.is()) |
1647 | 0 | continue; |
1648 | | |
1649 | 0 | Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings()); |
1650 | 0 | if (xSet.is()) |
1651 | 0 | { |
1652 | 0 | try |
1653 | 0 | { |
1654 | 0 | xSet->setPropertyValue(u"TwoDigitDateStart"_ustr, Any(sal_uInt16(n))); |
1655 | 0 | } |
1656 | 0 | catch(Exception&) |
1657 | 0 | { |
1658 | 0 | TOOLS_WARN_EXCEPTION("svx.form", ""); |
1659 | 0 | } |
1660 | |
|
1661 | 0 | } |
1662 | 0 | } |
1663 | 0 | xCurrentElement = aIter.Next(); |
1664 | 0 | } |
1665 | 0 | } |
1666 | | |
1667 | | |
1668 | | void FmXFormShell::CloseExternalFormViewer_Lock() |
1669 | 8.87k | { |
1670 | 8.87k | if (impl_checkDisposed_Lock()) |
1671 | 0 | return; |
1672 | | |
1673 | 8.87k | if (!m_xExternalViewController.is()) |
1674 | 8.87k | return; |
1675 | | |
1676 | 0 | Reference< css::frame::XFrame> xExternalViewFrame( m_xExternalViewController->getFrame()); |
1677 | 0 | Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); |
1678 | 0 | if (!xCommLink.is()) |
1679 | 0 | return; |
1680 | | |
1681 | 0 | xExternalViewFrame->setComponent(nullptr,nullptr); |
1682 | 0 | ::comphelper::disposeComponent(xExternalViewFrame); |
1683 | 0 | m_xExternalViewController = nullptr; |
1684 | 0 | m_xExtViewTriggerController = nullptr; |
1685 | 0 | m_xExternalDisplayedForm = nullptr; |
1686 | 0 | } |
1687 | | |
1688 | | |
1689 | | Reference<XResultSet> FmXFormShell::getInternalForm_Lock(const Reference<XResultSet>& _xForm) const |
1690 | 0 | { |
1691 | 0 | if (impl_checkDisposed_Lock()) |
1692 | 0 | return nullptr; |
1693 | | |
1694 | 0 | Reference< runtime::XFormController> xExternalCtrlr(m_xExternalViewController, UNO_QUERY); |
1695 | 0 | if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel())) |
1696 | 0 | { |
1697 | 0 | DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !"); |
1698 | 0 | return m_xExternalDisplayedForm; |
1699 | 0 | } |
1700 | 0 | return _xForm; |
1701 | 0 | } |
1702 | | |
1703 | | |
1704 | | Reference<XForm> FmXFormShell::getInternalForm_Lock(const Reference<XForm>& _xForm) const |
1705 | 0 | { |
1706 | 0 | if (impl_checkDisposed_Lock()) |
1707 | 0 | return nullptr; |
1708 | | |
1709 | 0 | Reference< runtime::XFormController > xExternalCtrlr(m_xExternalViewController, UNO_QUERY); |
1710 | 0 | if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel())) |
1711 | 0 | { |
1712 | 0 | DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !"); |
1713 | 0 | return Reference< XForm>(m_xExternalDisplayedForm, UNO_QUERY); |
1714 | 0 | } |
1715 | 0 | return _xForm; |
1716 | 0 | } |
1717 | | |
1718 | | |
1719 | | namespace |
1720 | | { |
1721 | | bool lcl_isNavigationRelevant( sal_Int32 _nWhich ) |
1722 | 0 | { |
1723 | 0 | return ( _nWhich == SID_FM_RECORD_FIRST ) |
1724 | 0 | || ( _nWhich == SID_FM_RECORD_PREV ) |
1725 | 0 | || ( _nWhich == SID_FM_RECORD_NEXT ) |
1726 | 0 | || ( _nWhich == SID_FM_RECORD_LAST ) |
1727 | 0 | || ( _nWhich == SID_FM_RECORD_NEW ); |
1728 | 0 | } |
1729 | | } |
1730 | | |
1731 | | |
1732 | | bool FmXFormShell::IsFormSlotEnabled( sal_Int32 _nSlot, FeatureState* _pCompleteState ) const |
1733 | 0 | { |
1734 | 0 | const svx::ControllerFeatures& rController = |
1735 | 0 | lcl_isNavigationRelevant( _nSlot ) |
1736 | 0 | ? getNavControllerFeatures_Lock() |
1737 | 0 | : getActiveControllerFeatures_Lock(); |
1738 | |
|
1739 | 0 | if ( !_pCompleteState ) |
1740 | 0 | return rController->isEnabled( _nSlot ); |
1741 | | |
1742 | 0 | rController->getState( _nSlot, *_pCompleteState ); |
1743 | 0 | return _pCompleteState->Enabled; |
1744 | 0 | } |
1745 | | |
1746 | | |
1747 | | void FmXFormShell::ExecuteFormSlot_Lock( sal_Int32 _nSlot ) |
1748 | 0 | { |
1749 | 0 | const svx::ControllerFeatures& rController = |
1750 | 0 | lcl_isNavigationRelevant( _nSlot ) |
1751 | 0 | ? getNavControllerFeatures_Lock() |
1752 | 0 | : getActiveControllerFeatures_Lock(); |
1753 | |
|
1754 | 0 | rController->execute( _nSlot ); |
1755 | |
|
1756 | 0 | if ( _nSlot != SID_FM_RECORD_UNDO ) |
1757 | 0 | return; |
1758 | | |
1759 | | // if we're doing an UNDO, *and* if the affected form is the form which we also display |
1760 | | // as external view, then we need to reset the controls of the external form, too |
1761 | 0 | if (getInternalForm_Lock(getActiveForm_Lock()) != m_xExternalDisplayedForm) |
1762 | 0 | return; |
1763 | | |
1764 | 0 | Reference< XIndexAccess > xContainer( m_xExternalDisplayedForm, UNO_QUERY ); |
1765 | 0 | if ( !xContainer.is() ) |
1766 | 0 | return; |
1767 | | |
1768 | 0 | Reference< XReset > xReset; |
1769 | 0 | for ( sal_Int32 i = 0; i < xContainer->getCount(); ++i ) |
1770 | 0 | { |
1771 | 0 | if ( ( xContainer->getByIndex( i ) >>= xReset ) && xReset.is() ) |
1772 | 0 | { |
1773 | | // no resets on sub forms |
1774 | 0 | Reference< XForm > xAsForm( xReset, UNO_QUERY ); |
1775 | 0 | if ( !xAsForm.is() ) |
1776 | 0 | xReset->reset(); |
1777 | 0 | } |
1778 | 0 | } |
1779 | 0 | } |
1780 | | |
1781 | | void FmXFormShell::impl_switchActiveControllerListening_Lock(const bool _bListen) |
1782 | 8.87k | { |
1783 | 8.87k | if ( !m_xActiveController.is() ) |
1784 | 8.87k | return; |
1785 | | |
1786 | 0 | if ( _bListen ) |
1787 | 0 | m_xActiveController->addEventListener( static_cast<XFormControllerListener*>(this) ); |
1788 | 0 | else |
1789 | 0 | m_xActiveController->removeEventListener( static_cast<XFormControllerListener*>(this) ); |
1790 | 0 | } |
1791 | | |
1792 | | void FmXFormShell::setActiveController_Lock(const Reference<runtime::XFormController>& xController, bool _bNoSaveOldContent) |
1793 | 32 | { |
1794 | 32 | if (impl_checkDisposed_Lock()) |
1795 | 0 | return; |
1796 | | |
1797 | 32 | if (m_bChangingDesignMode) |
1798 | 0 | return; |
1799 | 32 | DBG_ASSERT(!m_pShell->IsDesignMode(), "only to be used in alive mode"); |
1800 | | |
1801 | | // if the routine has been called a second time, |
1802 | | // the focus should no longer be transferred |
1803 | 32 | if (m_bInActivate) |
1804 | 0 | { |
1805 | 0 | m_bSetFocus = xController != m_xActiveController; |
1806 | 0 | return; |
1807 | 0 | } |
1808 | | |
1809 | 32 | if (xController == m_xActiveController) |
1810 | 32 | return; |
1811 | | |
1812 | | // switch all nav dispatchers belonging to the form of the current nav controller to 'non active' |
1813 | 0 | Reference< XResultSet> xNavigationForm; |
1814 | 0 | if (m_xNavigationController.is()) |
1815 | 0 | xNavigationForm.set(m_xNavigationController->getModel(), UNO_QUERY); |
1816 | |
|
1817 | 0 | m_bInActivate = true; |
1818 | | |
1819 | | // check if the 2 controllers serve different forms |
1820 | 0 | Reference< XResultSet> xOldForm; |
1821 | 0 | if (m_xActiveController.is()) |
1822 | 0 | xOldForm.set(m_xActiveController->getModel(), UNO_QUERY); |
1823 | 0 | Reference< XResultSet> xNewForm; |
1824 | 0 | if (xController.is()) |
1825 | 0 | xNewForm = Reference< XResultSet>(xController->getModel(), UNO_QUERY); |
1826 | 0 | xOldForm = getInternalForm_Lock(xOldForm); |
1827 | 0 | xNewForm = getInternalForm_Lock(xNewForm); |
1828 | |
|
1829 | 0 | bool bDifferentForm = ( xOldForm.get() != xNewForm.get() ); |
1830 | 0 | bool bNeedSave = bDifferentForm && !_bNoSaveOldContent; |
1831 | | // we save the content of the old form if we move to a new form, and saving old content is allowed |
1832 | |
|
1833 | 0 | if ( m_xActiveController.is() && bNeedSave ) |
1834 | 0 | { |
1835 | | // save content on change of the controller; a commit has already been executed |
1836 | 0 | if ( m_aActiveControllerFeatures->commitCurrentControl() ) |
1837 | 0 | { |
1838 | 0 | m_bSetFocus = true; |
1839 | 0 | if ( m_aActiveControllerFeatures->isModifiedRow() ) |
1840 | 0 | { |
1841 | 0 | bool bIsNew = m_aActiveControllerFeatures->isInsertionRow(); |
1842 | 0 | bool bResult = m_aActiveControllerFeatures->commitCurrentRecord(); |
1843 | 0 | if ( !bResult && m_bSetFocus ) |
1844 | 0 | { |
1845 | | // if we couldn't save the current record, set the focus back to the |
1846 | | // current control |
1847 | 0 | Reference< XWindow > xWindow( m_xActiveController->getCurrentControl(), UNO_QUERY ); |
1848 | 0 | if ( xWindow.is() ) |
1849 | 0 | xWindow->setFocus(); |
1850 | 0 | m_bInActivate = false; |
1851 | 0 | return; |
1852 | 0 | } |
1853 | 0 | else if ( bResult && bIsNew ) |
1854 | 0 | { |
1855 | 0 | Reference< XResultSet > xCursor( m_aActiveControllerFeatures->getCursor() ); |
1856 | 0 | if ( xCursor.is() ) |
1857 | 0 | { |
1858 | 0 | DO_SAFE( xCursor->last(); ); |
1859 | 0 | } |
1860 | 0 | } |
1861 | 0 | } |
1862 | 0 | } |
1863 | 0 | } |
1864 | | |
1865 | 0 | stopListening_Lock(); |
1866 | |
|
1867 | 0 | impl_switchActiveControllerListening_Lock(false); |
1868 | |
|
1869 | 0 | m_aActiveControllerFeatures.dispose(); |
1870 | 0 | m_xActiveController = xController; |
1871 | 0 | if ( m_xActiveController.is() ) |
1872 | 0 | m_aActiveControllerFeatures.assign( m_xActiveController ); |
1873 | |
|
1874 | 0 | impl_switchActiveControllerListening_Lock(true); |
1875 | |
|
1876 | 0 | if ( m_xActiveController.is() ) |
1877 | 0 | m_xActiveForm = getInternalForm_Lock(Reference<XForm>(m_xActiveController->getModel(), UNO_QUERY)); |
1878 | 0 | else |
1879 | 0 | m_xActiveForm = nullptr; |
1880 | |
|
1881 | 0 | startListening_Lock(); |
1882 | | |
1883 | | // activate all dispatchers belonging to form of the new navigation controller |
1884 | 0 | xNavigationForm = nullptr; |
1885 | 0 | if (m_xNavigationController.is()) |
1886 | 0 | xNavigationForm.set(m_xNavigationController->getModel(), UNO_QUERY); |
1887 | |
|
1888 | 0 | m_bInActivate = false; |
1889 | |
|
1890 | 0 | m_pShell->UIFeatureChanged(); |
1891 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell); |
1892 | |
|
1893 | 0 | InvalidateSlot_Lock(SID_FM_FILTER_NAVIGATOR_CONTROL, true); |
1894 | 0 | } |
1895 | | |
1896 | | InterfaceBag FmXFormShell::getCurrentSelection_Lock() const |
1897 | 0 | { |
1898 | 0 | return m_aCurrentSelection; |
1899 | 0 | } |
1900 | | |
1901 | | bool FmXFormShell::setCurrentSelectionFromMark_Lock(const SdrMarkList& _rMarkList) |
1902 | 0 | { |
1903 | 0 | m_aLastKnownMarkedControls.clear(); |
1904 | |
|
1905 | 0 | if ( ( _rMarkList.GetMarkCount() > 0 ) && isControlList( _rMarkList ) ) |
1906 | 0 | collectInterfacesFromMarkList( _rMarkList, m_aLastKnownMarkedControls ); |
1907 | |
|
1908 | 0 | return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls)); |
1909 | 0 | } |
1910 | | |
1911 | | |
1912 | | bool FmXFormShell::selectLastMarkedControls_Lock() |
1913 | 0 | { |
1914 | 0 | return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls)); |
1915 | 0 | } |
1916 | | |
1917 | | |
1918 | | bool FmXFormShell::setCurrentSelection_Lock( InterfaceBag&& _rSelection ) |
1919 | 0 | { |
1920 | 0 | if (impl_checkDisposed_Lock()) |
1921 | 0 | return false; |
1922 | | |
1923 | 0 | DBG_ASSERT( m_pShell->IsDesignMode(), "FmXFormShell::setCurrentSelection: only to be used in design mode!" ); |
1924 | |
|
1925 | 0 | if ( _rSelection.empty() && m_aCurrentSelection.empty() ) |
1926 | | // nothing to do |
1927 | 0 | return false; |
1928 | | |
1929 | 0 | if ( _rSelection.size() == m_aCurrentSelection.size() ) |
1930 | 0 | { |
1931 | 0 | InterfaceBag::const_iterator aNew = _rSelection.begin(); |
1932 | 0 | InterfaceBag::const_iterator aOld = m_aCurrentSelection.begin(); |
1933 | 0 | for ( ; aNew != _rSelection.end(); ++aNew, ++aOld ) |
1934 | 0 | { |
1935 | 0 | OSL_ENSURE( Reference< XInterface >( *aNew, UNO_QUERY ).get() == aNew->get(), "FmXFormShell::setCurrentSelection: new interface not normalized!" ); |
1936 | 0 | OSL_ENSURE( Reference< XInterface >( *aOld, UNO_QUERY ).get() == aOld->get(), "FmXFormShell::setCurrentSelection: old interface not normalized!" ); |
1937 | |
|
1938 | 0 | if ( aNew->get() != aOld->get() ) |
1939 | 0 | break; |
1940 | 0 | } |
1941 | |
|
1942 | 0 | if ( aNew == _rSelection.end() ) |
1943 | | // both bags equal |
1944 | 0 | return false; |
1945 | 0 | } |
1946 | | |
1947 | | // the following is some strange code to ensure that when you have two grid controls in a document, |
1948 | | // only one of them can have a selected column. |
1949 | | // TODO: this should happen elsewhere, but not here - shouldn't it? |
1950 | 0 | if ( !m_aCurrentSelection.empty() ) |
1951 | 0 | { |
1952 | 0 | Reference< XChild > xCur; if ( m_aCurrentSelection.size() == 1 ) xCur.set(*m_aCurrentSelection.begin(), css::uno::UNO_QUERY); |
1953 | 0 | Reference< XChild > xNew; if ( _rSelection.size() == 1 ) xNew.set(*_rSelection.begin(), css::uno::UNO_QUERY); |
1954 | | |
1955 | | // is there nothing to be selected, or the parents differ, and the parent of the current object |
1956 | | // is a selection supplier, then deselect |
1957 | 0 | if ( xCur.is() && ( !xNew.is() || ( xCur->getParent() != xNew->getParent() ) ) ) |
1958 | 0 | { |
1959 | 0 | Reference< XSelectionSupplier > xSel( xCur->getParent(), UNO_QUERY ); |
1960 | 0 | if ( xSel.is() ) |
1961 | 0 | xSel->select( Any() ); |
1962 | 0 | } |
1963 | 0 | } |
1964 | |
|
1965 | 0 | m_aCurrentSelection = std::move(_rSelection); |
1966 | | |
1967 | | // determine the form which all the selected objects belong to, if any |
1968 | 0 | Reference< XForm > xNewCurrentForm; |
1969 | 0 | for (const auto& rpSelection : m_aCurrentSelection) |
1970 | 0 | { |
1971 | 0 | Reference< XForm > xThisRoundsForm( GetForm( rpSelection ) ); |
1972 | 0 | OSL_ENSURE( xThisRoundsForm.is(), "FmXFormShell::setCurrentSelection: *everything* should belong to a form!" ); |
1973 | |
|
1974 | 0 | if ( !xNewCurrentForm.is() ) |
1975 | 0 | { // the first form we encountered |
1976 | 0 | xNewCurrentForm = std::move(xThisRoundsForm); |
1977 | 0 | } |
1978 | 0 | else if ( xNewCurrentForm != xThisRoundsForm ) |
1979 | 0 | { // different forms -> no "current form" at all |
1980 | 0 | xNewCurrentForm.clear(); |
1981 | 0 | break; |
1982 | 0 | } |
1983 | 0 | } |
1984 | |
|
1985 | 0 | if ( !m_aCurrentSelection.empty() ) |
1986 | 0 | impl_updateCurrentForm_Lock(xNewCurrentForm); |
1987 | | |
1988 | | // ensure some slots are updated |
1989 | 0 | for (sal_Int16 i : SelObjectSlotMap) |
1990 | 0 | InvalidateSlot_Lock(i, false); |
1991 | |
|
1992 | 0 | return true; |
1993 | 0 | } |
1994 | | |
1995 | | |
1996 | | bool FmXFormShell::isSolelySelected_Lock(const Reference<XInterface>& _rxObject) |
1997 | 0 | { |
1998 | 0 | return ( m_aCurrentSelection.size() == 1 ) && ( *m_aCurrentSelection.begin() == _rxObject ); |
1999 | 0 | } |
2000 | | |
2001 | | |
2002 | | void FmXFormShell::forgetCurrentForm_Lock() |
2003 | 0 | { |
2004 | 0 | if ( !m_xCurrentForm.is() ) |
2005 | 0 | return; |
2006 | | |
2007 | | // reset ... |
2008 | 0 | impl_updateCurrentForm_Lock(nullptr); |
2009 | | |
2010 | | // ... and try finding a new current form |
2011 | | // #i88186# / 2008-04-12 / frank.schoenheit@sun.com |
2012 | 0 | impl_defaultCurrentForm_nothrow_Lock(); |
2013 | 0 | } |
2014 | | |
2015 | | |
2016 | | void FmXFormShell::impl_updateCurrentForm_Lock(const Reference<XForm>& _rxNewCurForm) |
2017 | 0 | { |
2018 | 0 | if (impl_checkDisposed_Lock()) |
2019 | 0 | return; |
2020 | | |
2021 | 0 | m_xCurrentForm = _rxNewCurForm; |
2022 | | |
2023 | | // propagate to the FormPage(Impl) |
2024 | 0 | FmFormPage* pPage = m_pShell->GetCurPage(); |
2025 | 0 | if ( pPage ) |
2026 | 0 | pPage->GetImpl().setCurForm( m_xCurrentForm ); |
2027 | | |
2028 | | // ensure the UI which depends on the current form is up-to-date |
2029 | 0 | for (sal_Int16 i : DlgSlotMap) |
2030 | 0 | InvalidateSlot_Lock(i, false); |
2031 | 0 | } |
2032 | | |
2033 | | |
2034 | | void FmXFormShell::startListening_Lock() |
2035 | 0 | { |
2036 | 0 | if (impl_checkDisposed_Lock()) |
2037 | 0 | return; |
2038 | | |
2039 | 0 | Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY); |
2040 | 0 | if (xDatabaseForm.is() && getConnection(xDatabaseForm).is()) |
2041 | 0 | { |
2042 | 0 | Reference< XPropertySet> xActiveFormSet(m_xActiveForm, UNO_QUERY); |
2043 | 0 | if (xActiveFormSet.is()) |
2044 | 0 | { |
2045 | | // if there is a data source, then build the listener |
2046 | | // TODO: this is strange - shouldn't this depend on a isLoaded instead of |
2047 | | // a "has command value"? Finally, the command value only means that it was |
2048 | | // intended to be loaded, not that it actually *is* loaded |
2049 | 0 | OUString aSource = ::comphelper::getString(xActiveFormSet->getPropertyValue(FM_PROP_COMMAND)); |
2050 | 0 | if (!aSource.isEmpty()) |
2051 | 0 | { |
2052 | 0 | m_bDatabaseBar = true; |
2053 | |
|
2054 | 0 | xActiveFormSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate; |
2055 | |
|
2056 | 0 | switch (m_eNavigate) |
2057 | 0 | { |
2058 | 0 | case NavigationBarMode_PARENT: |
2059 | 0 | { |
2060 | | // search for the controller via which navigation is possible |
2061 | 0 | Reference< XChild> xChild = m_xActiveController; |
2062 | 0 | Reference< runtime::XFormController > xParent; |
2063 | 0 | while (xChild.is()) |
2064 | 0 | { |
2065 | 0 | xChild.set(xChild->getParent(), UNO_QUERY); |
2066 | 0 | xParent.set(xChild, UNO_QUERY); |
2067 | 0 | Reference< XPropertySet> xParentSet; |
2068 | 0 | if (xParent.is()) |
2069 | 0 | xParentSet.set(xParent->getModel(), UNO_QUERY); |
2070 | 0 | if (xParentSet.is()) |
2071 | 0 | { |
2072 | 0 | xParentSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate; |
2073 | 0 | if (m_eNavigate == NavigationBarMode_CURRENT) |
2074 | 0 | break; |
2075 | 0 | } |
2076 | 0 | } |
2077 | 0 | m_xNavigationController = std::move(xParent); |
2078 | 0 | } |
2079 | 0 | break; |
2080 | | |
2081 | 0 | case NavigationBarMode_CURRENT: |
2082 | 0 | m_xNavigationController = m_xActiveController; |
2083 | 0 | break; |
2084 | | |
2085 | 0 | default: |
2086 | 0 | m_xNavigationController = nullptr; |
2087 | 0 | m_bDatabaseBar = false; |
2088 | 0 | } |
2089 | | |
2090 | 0 | m_aNavControllerFeatures.dispose(); |
2091 | 0 | if ( m_xNavigationController.is() && ( m_xNavigationController != m_xActiveController ) ) |
2092 | 0 | m_aNavControllerFeatures.assign( m_xNavigationController ); |
2093 | | |
2094 | | // because of RecordCount, listen at the controller which controls the navigation |
2095 | 0 | Reference< XPropertySet> xNavigationSet; |
2096 | 0 | if (m_xNavigationController.is()) |
2097 | 0 | { |
2098 | 0 | xNavigationSet.set(m_xNavigationController->getModel(), UNO_QUERY); |
2099 | 0 | if (xNavigationSet.is()) |
2100 | 0 | xNavigationSet->addPropertyChangeListener(FM_PROP_ROWCOUNT,this); |
2101 | 0 | } |
2102 | 0 | return; |
2103 | 0 | } |
2104 | 0 | } |
2105 | 0 | } |
2106 | | |
2107 | 0 | m_eNavigate = NavigationBarMode_NONE; |
2108 | 0 | m_bDatabaseBar = false; |
2109 | 0 | m_xNavigationController = nullptr; |
2110 | 0 | } |
2111 | | |
2112 | | |
2113 | | void FmXFormShell::stopListening_Lock() |
2114 | 0 | { |
2115 | 0 | if (impl_checkDisposed_Lock()) |
2116 | 0 | return; |
2117 | | |
2118 | 0 | Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY); |
2119 | 0 | if ( xDatabaseForm.is() ) |
2120 | 0 | { |
2121 | 0 | if (m_xNavigationController.is()) |
2122 | 0 | { |
2123 | 0 | Reference< XPropertySet> xSet(m_xNavigationController->getModel(), UNO_QUERY); |
2124 | 0 | if (xSet.is()) |
2125 | 0 | xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this); |
2126 | |
|
2127 | 0 | } |
2128 | 0 | } |
2129 | |
|
2130 | 0 | m_bDatabaseBar = false; |
2131 | 0 | m_eNavigate = NavigationBarMode_NONE; |
2132 | 0 | m_xNavigationController = nullptr; |
2133 | 0 | } |
2134 | | |
2135 | | void FmXFormShell::ShowSelectionProperties_Lock(bool bShow) |
2136 | 0 | { |
2137 | 0 | if (impl_checkDisposed_Lock()) |
2138 | 0 | return; |
2139 | | |
2140 | | // if the window is already visible, only update the state |
2141 | 0 | bool bHasChild = m_pShell->GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_SHOW_PROPERTIES ); |
2142 | 0 | if ( bHasChild && bShow ) |
2143 | 0 | UpdateSlot_Lock(SID_FM_PROPERTY_CONTROL); |
2144 | | |
2145 | | // else toggle state |
2146 | 0 | else |
2147 | 0 | m_pShell->GetViewShell()->GetViewFrame().ToggleChildWindow(SID_FM_SHOW_PROPERTIES); |
2148 | |
|
2149 | 0 | InvalidateSlot_Lock(SID_FM_PROPERTIES, false); |
2150 | 0 | InvalidateSlot_Lock(SID_FM_CTL_PROPERTIES, false); |
2151 | 0 | } |
2152 | | |
2153 | | IMPL_LINK(FmXFormShell, OnFoundData_Lock, FmFoundRecordInformation&, rfriWhere, void) |
2154 | 0 | { |
2155 | 0 | if (impl_checkDisposed_Lock()) |
2156 | 0 | return; |
2157 | | |
2158 | 0 | DBG_ASSERT((rfriWhere.nContext >= 0) && (o3tl::make_unsigned(rfriWhere.nContext) < m_aSearchForms.size()), |
2159 | 0 | "FmXFormShell::OnFoundData : invalid context!"); |
2160 | 0 | Reference< XForm> xForm( m_aSearchForms.at(rfriWhere.nContext)); |
2161 | 0 | DBG_ASSERT(xForm.is(), "FmXFormShell::OnFoundData : invalid form!"); |
2162 | |
|
2163 | 0 | Reference< XRowLocate> xCursor(xForm, UNO_QUERY); |
2164 | 0 | if (!xCursor.is()) |
2165 | 0 | return; // what should I do there? |
2166 | | |
2167 | | // to the record |
2168 | 0 | try |
2169 | 0 | { |
2170 | 0 | xCursor->moveToBookmark(rfriWhere.aPosition); |
2171 | 0 | } |
2172 | 0 | catch(const SQLException&) |
2173 | 0 | { |
2174 | 0 | OSL_FAIL("Can position on bookmark!"); |
2175 | 0 | } |
2176 | |
|
2177 | 0 | LoopGrids_Lock(LoopGridsSync::FORCE_SYNC); |
2178 | | |
2179 | | // and to the field (for that, I collected the XVclComponent interfaces before the start of the search) |
2180 | 0 | SAL_WARN_IF(o3tl::make_unsigned(rfriWhere.nFieldPos) >= |
2181 | 0 | m_arrSearchedControls.size(), |
2182 | 0 | "svx.form", "FmXFormShell::OnFoundData : invalid index!"); |
2183 | 0 | SdrObject* pObject = m_arrSearchedControls.at(rfriWhere.nFieldPos); |
2184 | |
|
2185 | 0 | m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); |
2186 | 0 | m_pShell->GetFormView()->MarkObj(pObject, m_pShell->GetFormView()->GetSdrPageView()); |
2187 | |
|
2188 | 0 | FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject ); |
2189 | 0 | Reference< XControlModel > xControlModel( pFormObject ? pFormObject->GetUnoControlModel() : Reference< XControlModel >() ); |
2190 | 0 | DBG_ASSERT( xControlModel.is(), "FmXFormShell::OnFoundData: invalid control!" ); |
2191 | 0 | if ( !xControlModel.is() ) |
2192 | 0 | return; |
2193 | | |
2194 | | // disable the permanent cursor for the last grid we found a record |
2195 | 0 | if (m_xLastGridFound.is() && (m_xLastGridFound != xControlModel)) |
2196 | 0 | { |
2197 | 0 | Reference< XPropertySet> xOldSet(m_xLastGridFound, UNO_QUERY); |
2198 | 0 | xOldSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any( false ) ); |
2199 | 0 | Reference< XPropertyState> xOldSetState(xOldSet, UNO_QUERY); |
2200 | 0 | if (xOldSetState.is()) |
2201 | 0 | xOldSetState->setPropertyToDefault(FM_PROP_CURSORCOLOR); |
2202 | 0 | else |
2203 | 0 | xOldSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); |
2204 | 0 | } |
2205 | | |
2206 | | // if the field is in a GridControl, I have to additionally go into the corresponding column there |
2207 | 0 | sal_Int32 nGridColumn = m_arrRelativeGridColumn[rfriWhere.nFieldPos]; |
2208 | 0 | if (nGridColumn != -1) |
2209 | 0 | { // unfortunately, I have to first get the control again |
2210 | 0 | Reference<XControl> xControl(pFormObject ? impl_getControl_Lock(xControlModel, *pFormObject) : Reference<XControl>()); |
2211 | 0 | Reference< XGrid> xGrid(xControl, UNO_QUERY); |
2212 | 0 | DBG_ASSERT(xGrid.is(), "FmXFormShell::OnFoundData : invalid control!"); |
2213 | | // if one of the asserts fires, I probably did something wrong on building of m_arrSearchedControls |
2214 | | |
2215 | | // enable a permanent cursor for the grid so we can see the found text |
2216 | 0 | Reference< XPropertySet> xModelSet(xControlModel, UNO_QUERY); |
2217 | 0 | DBG_ASSERT(xModelSet.is(), "FmXFormShell::OnFoundData : invalid control model (no property set) !"); |
2218 | 0 | xModelSet->setPropertyValue( FM_PROP_ALWAYSSHOWCURSOR, Any( true ) ); |
2219 | 0 | xModelSet->setPropertyValue( FM_PROP_CURSORCOLOR, Any( COL_LIGHTRED ) ); |
2220 | 0 | m_xLastGridFound = std::move(xControlModel); |
2221 | |
|
2222 | 0 | if ( xGrid.is() ) |
2223 | 0 | xGrid->setCurrentColumnPosition(static_cast<sal_Int16>(nGridColumn)); |
2224 | 0 | } |
2225 | | |
2226 | | // As the cursor has been repositioned, I have (in positioned) invalidated |
2227 | | // my form bar slots. But that does not take effect here unfortunately, as |
2228 | | // generally the (modal) search dialog is of course at the top ... So, force ... |
2229 | 0 | sal_uInt16 nPos = 0; |
2230 | 0 | while (DatabaseSlotMap[nPos]) |
2231 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().Update(DatabaseSlotMap[nPos++]); |
2232 | | // unfortunately the update goes against the invalidate with only individual slots |
2233 | 0 | } |
2234 | | |
2235 | | IMPL_LINK(FmXFormShell, OnCanceledNotFound_Lock, FmFoundRecordInformation&, rfriWhere, void) |
2236 | 0 | { |
2237 | 0 | if (impl_checkDisposed_Lock()) |
2238 | 0 | return; |
2239 | | |
2240 | 0 | DBG_ASSERT((rfriWhere.nContext >= 0) && (o3tl::make_unsigned(rfriWhere.nContext) < m_aSearchForms.size()), |
2241 | 0 | "FmXFormShell::OnCanceledNotFound : invalid context!"); |
2242 | 0 | Reference< XForm> xForm( m_aSearchForms.at(rfriWhere.nContext)); |
2243 | 0 | DBG_ASSERT(xForm.is(), "FmXFormShell::OnCanceledNotFound : invalid form!"); |
2244 | |
|
2245 | 0 | Reference< XRowLocate> xCursor(xForm, UNO_QUERY); |
2246 | 0 | if (!xCursor.is()) |
2247 | 0 | return; // what should I do there? |
2248 | | |
2249 | | // to the record |
2250 | 0 | try |
2251 | 0 | { |
2252 | 0 | xCursor->moveToBookmark(rfriWhere.aPosition); |
2253 | 0 | } |
2254 | 0 | catch(const SQLException&) |
2255 | 0 | { |
2256 | 0 | OSL_FAIL("Can position on bookmark!"); |
2257 | 0 | } |
2258 | | |
2259 | |
|
2260 | 0 | m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView()); |
2261 | 0 | } |
2262 | | |
2263 | | |
2264 | | IMPL_LINK(FmXFormShell, OnSearchContextRequest_Lock, FmSearchContext&, rfmscContextInfo, sal_uInt32) |
2265 | 0 | { |
2266 | 0 | if (impl_checkDisposed_Lock()) |
2267 | 0 | return 0; |
2268 | | |
2269 | 0 | DBG_ASSERT(rfmscContextInfo.nContext < static_cast<sal_Int16>(m_aSearchForms.size()), "FmXFormShell::OnSearchContextRequest : invalid parameter !"); |
2270 | 0 | Reference< XForm> xForm( m_aSearchForms.at(rfmscContextInfo.nContext)); |
2271 | 0 | DBG_ASSERT(xForm.is(), "FmXFormShell::OnSearchContextRequest : unexpected : invalid context !"); |
2272 | |
|
2273 | 0 | Reference< XResultSet> xIter(xForm, UNO_QUERY); |
2274 | 0 | DBG_ASSERT(xIter.is(), "FmXFormShell::OnSearchContextRequest : unexpected : context has no iterator !"); |
2275 | | |
2276 | | |
2277 | | // assemble the list of fields to involve (that is, the ControlSources of all fields that have such a property) |
2278 | 0 | OUString strFieldList, sFieldDisplayNames; |
2279 | 0 | m_arrSearchedControls.clear(); |
2280 | 0 | m_arrRelativeGridColumn.clear(); |
2281 | | |
2282 | | // small problem: To mark found fields, I need SdrObjects. To determine which controls |
2283 | | // to include in the search, I need Controls (that is, XControl interfaces). So I have |
2284 | | // to iterate over one of them and get the other in some way. Unfortunately, there is |
2285 | | // no direct connection between the two worlds (except from a GetUnoControl to a |
2286 | | // SdrUnoObject, but this requires an OutputDevice I can not do anything with. |
2287 | | // However I can get to the Model from the Control and also from the SdrObject, and in |
2288 | | // this way the assignment SdrObject<->Control is possible with a double loop. |
2289 | | // The alternative to this (ugly but certainly not entirely fixable) solution would be |
2290 | | // to renounce the caching of the SdrObjects, which would lead to significant extra |
2291 | | // work in OnFoundData (since there I'd have to get the SdrObject first thing every |
2292 | | // time). But since OnFoundData is usually called more often than ExecuteSearch, I'll |
2293 | | // do that here. |
2294 | |
|
2295 | 0 | Reference< XNameAccess> xValidFormFields; |
2296 | 0 | Reference< XColumnsSupplier> xSupplyCols(xIter, UNO_QUERY); |
2297 | 0 | DBG_ASSERT(xSupplyCols.is(), "FmXFormShell::OnSearchContextRequest : invalid cursor : no columns supplier !"); |
2298 | 0 | if (xSupplyCols.is()) |
2299 | 0 | xValidFormFields = xSupplyCols->getColumns(); |
2300 | 0 | DBG_ASSERT(xValidFormFields.is(), "FmXFormShell::OnSearchContextRequest : form has no fields !"); |
2301 | | |
2302 | | // current Page/Controller |
2303 | 0 | FmFormPage* pCurrentPage = m_pShell->GetCurPage(); |
2304 | 0 | assert(pCurrentPage && "FmXFormShell::OnSearchContextRequest : no page !"); |
2305 | | // Search all SdrControls of this page... |
2306 | 0 | OUString sControlSource, aName; |
2307 | |
|
2308 | 0 | SdrObjListIter aPageIter( pCurrentPage ); |
2309 | 0 | while ( aPageIter.IsMore() ) |
2310 | 0 | { |
2311 | 0 | SdrObject* pCurrent = aPageIter.Next(); |
2312 | 0 | FmFormObj* pFormObject = FmFormObj::GetFormObject( pCurrent ); |
2313 | | // note that in case pCurrent is a virtual object, pFormObject points to the referenced object |
2314 | |
|
2315 | 0 | if ( !pFormObject ) |
2316 | 0 | continue; |
2317 | | |
2318 | | // the current object's model, in different tastes |
2319 | 0 | Reference< XControlModel> xControlModel( pFormObject->GetUnoControlModel() ); |
2320 | 0 | Reference< XFormComponent > xCurrentFormComponent( xControlModel, UNO_QUERY ); |
2321 | 0 | DBG_ASSERT( xCurrentFormComponent.is(), "FmXFormShell::OnSearchContextRequest: invalid objects!" ); |
2322 | 0 | if ( !xCurrentFormComponent.is() ) |
2323 | 0 | continue; |
2324 | | |
2325 | | // does the component belong to the form which we're interested in? |
2326 | 0 | if ( xCurrentFormComponent->getParent() != xForm ) |
2327 | 0 | continue; |
2328 | | |
2329 | | // ... ask for the ControlSource property |
2330 | 0 | SearchableControlIterator iter( xCurrentFormComponent ); |
2331 | 0 | Reference< XControl> xControl; |
2332 | | // the control that has model xControlModel |
2333 | | // (the following while can be passed through several times, without the Control |
2334 | | // being modified, so I don't have to search every time from scratch) |
2335 | |
|
2336 | 0 | Reference< XInterface > xSearchable( iter.Next() ); |
2337 | 0 | while ( xSearchable.is() ) |
2338 | 0 | { |
2339 | 0 | sControlSource = iter.getCurrentValue(); |
2340 | 0 | if ( sControlSource.isEmpty() ) |
2341 | 0 | { |
2342 | | // the current element has no ControlSource, so it is a GridControl (that |
2343 | | // is the only thing that still permits the SearchableControlIterator) |
2344 | 0 | xControl = impl_getControl_Lock(xControlModel, *pFormObject); |
2345 | 0 | DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !"); |
2346 | |
|
2347 | 0 | Reference< XGridPeer> xGridPeer; |
2348 | 0 | if ( xControl.is() ) |
2349 | 0 | xGridPeer.set( xControl->getPeer(), UNO_QUERY ); |
2350 | 0 | do |
2351 | 0 | { |
2352 | 0 | if (!xGridPeer.is()) |
2353 | 0 | break; |
2354 | | |
2355 | 0 | Reference< XIndexAccess> xPeerContainer(xGridPeer, UNO_QUERY); |
2356 | 0 | if (!xPeerContainer.is()) |
2357 | 0 | break; |
2358 | | |
2359 | 0 | Reference< XIndexAccess> xModelColumns = xGridPeer->getColumns(); |
2360 | 0 | DBG_ASSERT(xModelColumns.is(), "FmXFormShell::OnSearchContextRequest : there is a grid control without columns !"); |
2361 | | // the case 'no columns' should be indicated with an empty container, I think ... |
2362 | 0 | DBG_ASSERT(xModelColumns->getCount() >= xPeerContainer->getCount(), "FmXFormShell::OnSearchContextRequest : impossible : have more view than model columns !"); |
2363 | |
|
2364 | 0 | Reference< XInterface> xCurrentColumn; |
2365 | 0 | for (sal_Int32 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos) |
2366 | 0 | { |
2367 | 0 | xPeerContainer->getByIndex(nViewPos) >>= xCurrentColumn; |
2368 | 0 | if (!xCurrentColumn.is()) |
2369 | 0 | continue; |
2370 | | |
2371 | | // can we use this column control for searching ? |
2372 | 0 | if (!IsSearchableControl(xCurrentColumn)) |
2373 | 0 | continue; |
2374 | | |
2375 | 0 | sal_Int32 nModelPos = GridView2ModelPos(xModelColumns, nViewPos); |
2376 | 0 | Reference< XPropertySet> xCurrentColModel; |
2377 | 0 | xModelColumns->getByIndex(nModelPos) >>= xCurrentColModel; |
2378 | 0 | aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_CONTROLSOURCE)); |
2379 | | // the cursor has a field matching the control source ? |
2380 | 0 | if (xValidFormFields->hasByName(aName)) |
2381 | 0 | { |
2382 | 0 | strFieldList += aName + ";"; |
2383 | |
|
2384 | 0 | sFieldDisplayNames += |
2385 | 0 | ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_LABEL)) + |
2386 | 0 | ";"; |
2387 | |
|
2388 | 0 | rfmscContextInfo.arrFields.push_back(xCurrentColumn); |
2389 | | |
2390 | | // and the SdrOject to the Field |
2391 | 0 | m_arrSearchedControls.push_back(pCurrent); |
2392 | | // the number of the column |
2393 | 0 | m_arrRelativeGridColumn.push_back(nViewPos); |
2394 | 0 | } |
2395 | 0 | } |
2396 | 0 | } while (false); |
2397 | 0 | } |
2398 | 0 | else |
2399 | 0 | { |
2400 | 0 | if (!sControlSource.isEmpty() && xValidFormFields->hasByName(sControlSource)) |
2401 | 0 | { |
2402 | | // now I need the Control to SdrObject |
2403 | 0 | if (!xControl.is()) |
2404 | 0 | { |
2405 | 0 | xControl = impl_getControl_Lock(xControlModel, *pFormObject); |
2406 | 0 | DBG_ASSERT(xControl.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !"); |
2407 | 0 | } |
2408 | |
|
2409 | 0 | if (IsSearchableControl(xControl)) |
2410 | 0 | { |
2411 | | // all tests passed -> take along in the list |
2412 | 0 | strFieldList += sControlSource + ";"; |
2413 | | |
2414 | | // the label which should appear for the control : |
2415 | 0 | sFieldDisplayNames += |
2416 | 0 | getLabelName(Reference< XPropertySet>(xControlModel, UNO_QUERY)) + |
2417 | 0 | ";"; |
2418 | | |
2419 | | // mark the SdrObject (accelerates the treatment in OnFoundData) |
2420 | 0 | m_arrSearchedControls.push_back(pCurrent); |
2421 | | |
2422 | | // the number of the column (here a dummy, since it is only interesting for GridControls) |
2423 | 0 | m_arrRelativeGridColumn.push_back(-1); |
2424 | | |
2425 | | // and for the formatted search... |
2426 | 0 | rfmscContextInfo.arrFields.emplace_back( xControl, UNO_QUERY ); |
2427 | 0 | } |
2428 | 0 | } |
2429 | 0 | } |
2430 | |
|
2431 | 0 | xSearchable = iter.Next(); |
2432 | 0 | } |
2433 | 0 | } |
2434 | |
|
2435 | 0 | strFieldList = comphelper::string::stripEnd(strFieldList, ';'); |
2436 | 0 | sFieldDisplayNames = comphelper::string::stripEnd(sFieldDisplayNames, ';'); |
2437 | |
|
2438 | 0 | if (rfmscContextInfo.arrFields.empty()) |
2439 | 0 | { |
2440 | 0 | rfmscContextInfo.arrFields.clear(); |
2441 | 0 | rfmscContextInfo.xCursor = nullptr; |
2442 | 0 | rfmscContextInfo.strUsedFields.clear(); |
2443 | 0 | return 0; |
2444 | 0 | } |
2445 | | |
2446 | 0 | rfmscContextInfo.xCursor = std::move(xIter); |
2447 | 0 | rfmscContextInfo.strUsedFields = strFieldList; |
2448 | 0 | rfmscContextInfo.sFieldDisplayNames = sFieldDisplayNames; |
2449 | | |
2450 | | // 66463 - 31.05.99 - FS |
2451 | | // when the cursor is a non-STANDARD RecordMode, set it back |
2452 | 0 | Reference< XPropertySet> xCursorSet(rfmscContextInfo.xCursor, UNO_QUERY); |
2453 | 0 | Reference< XResultSetUpdate> xUpdateCursor(rfmscContextInfo.xCursor, UNO_QUERY); |
2454 | 0 | if (xUpdateCursor.is() && xCursorSet.is()) |
2455 | 0 | { |
2456 | 0 | if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISNEW))) |
2457 | 0 | xUpdateCursor->moveToCurrentRow(); |
2458 | 0 | else if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISMODIFIED))) |
2459 | 0 | xUpdateCursor->cancelRowUpdates(); |
2460 | 0 | } |
2461 | |
|
2462 | 0 | return rfmscContextInfo.arrFields.size(); |
2463 | 0 | } |
2464 | | |
2465 | | // XContainerListener |
2466 | | |
2467 | | void SAL_CALL FmXFormShell::elementInserted(const ContainerEvent& evt) |
2468 | 0 | { |
2469 | 0 | SolarMutexGuard g; |
2470 | |
|
2471 | 0 | if (impl_checkDisposed_Lock()) |
2472 | 0 | return; |
2473 | | |
2474 | | // new object to listen to |
2475 | 0 | Reference< XInterface> xTemp; |
2476 | 0 | evt.Element >>= xTemp; |
2477 | 0 | AddElement_Lock(xTemp); |
2478 | |
|
2479 | 0 | m_pShell->DetermineForms(true); |
2480 | 0 | } |
2481 | | |
2482 | | |
2483 | | void SAL_CALL FmXFormShell::elementReplaced(const ContainerEvent& evt) |
2484 | 0 | { |
2485 | 0 | SolarMutexGuard g; |
2486 | |
|
2487 | 0 | if (impl_checkDisposed_Lock() ) |
2488 | 0 | return; |
2489 | | |
2490 | 0 | Reference< XInterface> xTemp; |
2491 | 0 | evt.ReplacedElement >>= xTemp; |
2492 | 0 | RemoveElement_Lock(xTemp); |
2493 | 0 | evt.Element >>= xTemp; |
2494 | 0 | AddElement_Lock(xTemp); |
2495 | 0 | } |
2496 | | |
2497 | | |
2498 | | void SAL_CALL FmXFormShell::elementRemoved(const ContainerEvent& evt) |
2499 | 0 | { |
2500 | 0 | SolarMutexGuard g; |
2501 | |
|
2502 | 0 | if (impl_checkDisposed_Lock()) |
2503 | 0 | return; |
2504 | | |
2505 | 0 | Reference< XInterface> xTemp; |
2506 | 0 | evt.Element >>= xTemp; |
2507 | 0 | RemoveElement_Lock(xTemp); |
2508 | |
|
2509 | 0 | m_pShell->DetermineForms(true); |
2510 | 0 | } |
2511 | | |
2512 | | |
2513 | | void FmXFormShell::UpdateForms_Lock(bool _bInvalidate) |
2514 | 26.6k | { |
2515 | 26.6k | if (impl_checkDisposed_Lock()) |
2516 | 0 | return; |
2517 | | |
2518 | 26.6k | Reference< XIndexAccess > xForms; |
2519 | | |
2520 | 26.6k | FmFormPage* pPage = m_pShell->GetCurPage(); |
2521 | 26.6k | if ( pPage && m_pShell->m_bDesignMode ) |
2522 | 26.5k | xForms = pPage->GetForms( false ); |
2523 | | |
2524 | 26.6k | if ( m_xForms != xForms ) |
2525 | 0 | { |
2526 | 0 | RemoveElement_Lock( m_xForms ); |
2527 | 0 | m_xForms = std::move(xForms); |
2528 | 0 | AddElement_Lock(m_xForms); |
2529 | 0 | } |
2530 | | |
2531 | 26.6k | SolarMutexGuard g; |
2532 | 26.6k | m_pShell->DetermineForms( _bInvalidate ); |
2533 | 26.6k | } |
2534 | | |
2535 | | |
2536 | | void FmXFormShell::AddElement_Lock(const Reference<XInterface>& _xElement) |
2537 | 0 | { |
2538 | 0 | if (impl_checkDisposed_Lock()) |
2539 | 0 | return; |
2540 | 0 | impl_AddElement_nothrow(_xElement); |
2541 | 0 | } |
2542 | | |
2543 | | void FmXFormShell::impl_AddElement_nothrow(const Reference< XInterface>& Element) |
2544 | 0 | { |
2545 | | // listen at the container |
2546 | 0 | const Reference< XIndexContainer> xContainer(Element, UNO_QUERY); |
2547 | 0 | if (xContainer.is()) |
2548 | 0 | { |
2549 | 0 | const sal_uInt32 nCount = xContainer->getCount(); |
2550 | 0 | Reference< XInterface> xElement; |
2551 | 0 | for (sal_uInt32 i = 0; i < nCount; ++i) |
2552 | 0 | { |
2553 | 0 | xElement.set(xContainer->getByIndex(i),UNO_QUERY); |
2554 | 0 | impl_AddElement_nothrow(xElement); |
2555 | 0 | } |
2556 | |
|
2557 | 0 | const Reference< XContainer> xCont(Element, UNO_QUERY); |
2558 | 0 | if (xCont.is()) |
2559 | 0 | xCont->addContainerListener(this); |
2560 | 0 | } |
2561 | |
|
2562 | 0 | const Reference< css::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY); |
2563 | 0 | if (xSelSupplier.is()) |
2564 | 0 | xSelSupplier->addSelectionChangeListener(this); |
2565 | 0 | } |
2566 | | |
2567 | | |
2568 | | void FmXFormShell::RemoveElement_Lock(const Reference<XInterface>& Element) |
2569 | 8.87k | { |
2570 | 8.87k | if (impl_checkDisposed_Lock()) |
2571 | 0 | return; |
2572 | 8.87k | impl_RemoveElement_nothrow_Lock(Element); |
2573 | 8.87k | } |
2574 | | |
2575 | | void FmXFormShell::impl_RemoveElement_nothrow_Lock(const Reference<XInterface>& Element) |
2576 | 8.87k | { |
2577 | 8.87k | const Reference< css::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY); |
2578 | 8.87k | if (xSelSupplier.is()) |
2579 | 0 | xSelSupplier->removeSelectionChangeListener(this); |
2580 | | |
2581 | | // remove connection to children |
2582 | 8.87k | const Reference< XIndexContainer> xContainer(Element, UNO_QUERY); |
2583 | 8.87k | if (xContainer.is()) |
2584 | 0 | { |
2585 | 0 | const Reference< XContainer> xCont(Element, UNO_QUERY); |
2586 | 0 | if (xCont.is()) |
2587 | 0 | xCont->removeContainerListener(this); |
2588 | |
|
2589 | 0 | const sal_uInt32 nCount = xContainer->getCount(); |
2590 | 0 | Reference< XInterface> xElement; |
2591 | 0 | for (sal_uInt32 i = 0; i < nCount; i++) |
2592 | 0 | { |
2593 | 0 | xElement.set(xContainer->getByIndex(i),UNO_QUERY); |
2594 | 0 | impl_RemoveElement_nothrow_Lock(xElement); |
2595 | 0 | } |
2596 | 0 | } |
2597 | | |
2598 | 8.87k | auto wasSelectedPos = m_aCurrentSelection.find( Element ); |
2599 | 8.87k | if ( wasSelectedPos != m_aCurrentSelection.end() ) |
2600 | 0 | m_aCurrentSelection.erase( wasSelectedPos ); |
2601 | 8.87k | } |
2602 | | |
2603 | | |
2604 | | void SAL_CALL FmXFormShell::selectionChanged(const lang::EventObject& rEvent) |
2605 | 0 | { |
2606 | 0 | SolarMutexGuard g; |
2607 | |
|
2608 | 0 | if (impl_checkDisposed_Lock()) |
2609 | 0 | return; |
2610 | | |
2611 | 0 | Reference< XSelectionSupplier > xSupplier( rEvent.Source, UNO_QUERY ); |
2612 | 0 | Reference< XInterface > xSelObj( xSupplier->getSelection(), UNO_QUERY ); |
2613 | | // a selection was removed, this can only be done by the shell |
2614 | 0 | if ( !xSelObj.is() ) |
2615 | 0 | return; |
2616 | | |
2617 | 0 | EnableTrackProperties_Lock(false); |
2618 | |
|
2619 | 0 | bool bMarkChanged = m_pShell->GetFormView()->checkUnMarkAll(rEvent.Source); |
2620 | |
|
2621 | 0 | InterfaceBag aNewSelection; |
2622 | 0 | aNewSelection.insert( Reference<XInterface>( xSelObj, UNO_QUERY ) ); |
2623 | |
|
2624 | 0 | if (setCurrentSelection_Lock(std::move(aNewSelection)) && IsPropBrwOpen_Lock()) |
2625 | 0 | ShowSelectionProperties_Lock(true); |
2626 | |
|
2627 | 0 | EnableTrackProperties_Lock(true); |
2628 | |
|
2629 | 0 | if ( bMarkChanged ) |
2630 | 0 | m_pShell->NotifyMarkListChanged( m_pShell->GetFormView() ); |
2631 | 0 | } |
2632 | | |
2633 | | |
2634 | | IMPL_LINK_NOARG(FmXFormShell, OnTimeOut_Lock, Timer*, void) |
2635 | 0 | { |
2636 | 0 | if (impl_checkDisposed_Lock()) |
2637 | 0 | return; |
2638 | | |
2639 | 0 | if (m_pShell->IsDesignMode() && m_pShell->GetFormView()) |
2640 | 0 | SetSelection_Lock(m_pShell->GetFormView()->GetMarkedObjectList()); |
2641 | 0 | } |
2642 | | |
2643 | | |
2644 | | void FmXFormShell::SetSelectionDelayed_Lock() |
2645 | 36 | { |
2646 | 36 | if (impl_checkDisposed_Lock()) |
2647 | 0 | return; |
2648 | | |
2649 | 36 | if (m_pShell->IsDesignMode() && IsTrackPropertiesEnabled_Lock() && !m_aMarkTimer.IsActive()) |
2650 | 18 | m_aMarkTimer.Start(); |
2651 | 36 | } |
2652 | | |
2653 | | |
2654 | | void FmXFormShell::SetSelection_Lock(const SdrMarkList& rMarkList) |
2655 | 0 | { |
2656 | 0 | if (impl_checkDisposed_Lock()) |
2657 | 0 | return; |
2658 | | |
2659 | 0 | DetermineSelection_Lock(rMarkList); |
2660 | 0 | m_pShell->NotifyMarkListChanged(m_pShell->GetFormView()); |
2661 | 0 | } |
2662 | | |
2663 | | void FmXFormShell::DetermineSelection_Lock(const SdrMarkList& rMarkList) |
2664 | 0 | { |
2665 | 0 | if (setCurrentSelectionFromMark_Lock(rMarkList) && IsPropBrwOpen_Lock()) |
2666 | 0 | ShowSelectionProperties_Lock(true); |
2667 | 0 | } |
2668 | | |
2669 | | bool FmXFormShell::IsPropBrwOpen_Lock() const |
2670 | 0 | { |
2671 | 0 | if (impl_checkDisposed_Lock()) |
2672 | 0 | return false; |
2673 | | |
2674 | 0 | return m_pShell->GetViewShell() && |
2675 | 0 | m_pShell->GetViewShell()->GetViewFrame().HasChildWindow(SID_FM_SHOW_PROPERTIES); |
2676 | 0 | } |
2677 | | |
2678 | | class FmXFormShell::SuspendPropertyTracking |
2679 | | { |
2680 | | private: |
2681 | | FmXFormShell& m_rShell; |
2682 | | bool m_bEnabled; |
2683 | | |
2684 | | public: |
2685 | | explicit SuspendPropertyTracking( FmXFormShell& _rShell ) |
2686 | 8.87k | :m_rShell( _rShell ) |
2687 | 8.87k | ,m_bEnabled( false ) |
2688 | 8.87k | { |
2689 | 8.87k | if (m_rShell.IsTrackPropertiesEnabled_Lock()) |
2690 | 8.87k | { |
2691 | 8.87k | m_rShell.EnableTrackProperties_Lock(false); |
2692 | 8.87k | m_bEnabled = true; |
2693 | 8.87k | } |
2694 | 8.87k | } |
2695 | | |
2696 | | ~SuspendPropertyTracking( ) |
2697 | 8.87k | { |
2698 | 8.87k | if ( m_bEnabled ) // note that ( false != m_bEnabled ) implies ( NULL != m_pShell ) |
2699 | 8.87k | m_rShell.EnableTrackProperties_Lock(true); |
2700 | 8.87k | } |
2701 | | }; |
2702 | | |
2703 | | void FmXFormShell::SetDesignMode_Lock(bool bDesign) |
2704 | 8.87k | { |
2705 | 8.87k | if (impl_checkDisposed_Lock()) |
2706 | 0 | return; |
2707 | | |
2708 | 8.87k | DBG_ASSERT(m_pShell->GetFormView(), "FmXFormShell::SetDesignMode : invalid call (have no shell or no view) !"); |
2709 | 8.87k | m_bChangingDesignMode = true; |
2710 | | |
2711 | | // 67506 - 15.07.99 - FS |
2712 | | // if we're switching off the design mode we have to force the property browser to be closed |
2713 | | // so it can commit its changes _before_ we load the forms |
2714 | 8.87k | if (!bDesign) |
2715 | 32 | { |
2716 | 32 | m_bHadPropertyBrowserInDesignMode = m_pShell->GetViewShell()->GetViewFrame().HasChildWindow(SID_FM_SHOW_PROPERTIES); |
2717 | 32 | if (m_bHadPropertyBrowserInDesignMode) |
2718 | 0 | m_pShell->GetViewShell()->GetViewFrame().ToggleChildWindow(SID_FM_SHOW_PROPERTIES); |
2719 | 32 | } |
2720 | | |
2721 | 8.87k | FmFormView* pFormView = m_pShell->GetFormView(); |
2722 | 8.87k | if (bDesign) |
2723 | 8.84k | { |
2724 | | // we are currently filtering, so stop filtering |
2725 | 8.84k | if (m_bFilterMode) |
2726 | 0 | stopFiltering_Lock(false); |
2727 | | |
2728 | | // unsubscribe from the objects of my MarkList |
2729 | 8.84k | pFormView->GetImpl()->stopMarkListWatching(); |
2730 | 8.84k | } |
2731 | 32 | else |
2732 | 32 | { |
2733 | 32 | m_aMarkTimer.Stop(); |
2734 | | |
2735 | 32 | SuspendPropertyTracking aSuspend( *this ); |
2736 | 32 | pFormView->GetImpl()->saveMarkList(); |
2737 | 32 | } |
2738 | | |
2739 | 8.87k | if (bDesign && m_xExternalViewController.is()) |
2740 | 0 | CloseExternalFormViewer_Lock(); |
2741 | | |
2742 | 8.87k | pFormView->ChangeDesignMode(bDesign); |
2743 | | |
2744 | | // notify listeners |
2745 | 8.87k | FmDesignModeChangedHint aChangedHint( bDesign ); |
2746 | 8.87k | m_pShell->Broadcast(aChangedHint); |
2747 | | |
2748 | 8.87k | m_pShell->m_bDesignMode = bDesign; |
2749 | 8.87k | UpdateForms_Lock(false); |
2750 | | |
2751 | 8.87k | m_pTextShell->designModeChanged(); |
2752 | | |
2753 | 8.87k | if (bDesign) |
2754 | 8.84k | { |
2755 | 8.84k | SdrMarkList aList; |
2756 | 8.84k | { |
2757 | | // during changing the mark list, don't track the selected objects in the property browser |
2758 | 8.84k | SuspendPropertyTracking aSuspend( *this ); |
2759 | | // restore the marks |
2760 | 8.84k | pFormView->GetImpl()->restoreMarkList( aList ); |
2761 | 8.84k | } |
2762 | | |
2763 | | // synchronize with the restored mark list |
2764 | 8.84k | if ( aList.GetMarkCount() ) |
2765 | 0 | SetSelection_Lock(aList); |
2766 | 8.84k | } |
2767 | 32 | else |
2768 | 32 | { |
2769 | | // subscribe to the model of the view (so that I'm informed when someone deletes |
2770 | | // during the alive mode controls that I had saved in the saveMarklist (60343) |
2771 | 32 | pFormView->GetImpl()->startMarkListWatching(); |
2772 | 32 | } |
2773 | | |
2774 | 8.87k | m_pShell->UIFeatureChanged(); |
2775 | | |
2776 | | // 67506 - 15.07.99 - FS |
2777 | 8.87k | if (bDesign && m_bHadPropertyBrowserInDesignMode) |
2778 | 0 | { |
2779 | | // The UIFeatureChanged performs an update (a check of the available features) asynchronously. |
2780 | | // So we can't call ShowSelectionProperties directly as the according feature isn't enabled yet. |
2781 | | // That's why we use an asynchronous execution on the dispatcher. |
2782 | | // (And that's why this has to be done AFTER the UIFeatureChanged.) |
2783 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SfxCallMode::ASYNCHRON ); |
2784 | 0 | } |
2785 | 8.87k | m_bChangingDesignMode = false; |
2786 | 8.87k | } |
2787 | | |
2788 | | Reference< XControl> FmXFormShell::impl_getControl_Lock(const Reference<XControlModel>& i_rxModel, const FmFormObj& i_rKnownFormObj) |
2789 | 0 | { |
2790 | 0 | if (impl_checkDisposed_Lock()) |
2791 | 0 | return nullptr; |
2792 | | |
2793 | 0 | Reference< XControl > xControl; |
2794 | 0 | try |
2795 | 0 | { |
2796 | 0 | Reference< XControlContainer> xControlContainer(getControlContainerForView_Lock(), UNO_SET_THROW); |
2797 | |
|
2798 | 0 | const Sequence< Reference< XControl > > seqControls( xControlContainer->getControls() ); |
2799 | | // ... that I can then search |
2800 | 0 | for (Reference< XControl > const & control : seqControls) |
2801 | 0 | { |
2802 | 0 | xControl.set( control, UNO_SET_THROW ); |
2803 | 0 | Reference< XControlModel > xCurrentModel( xControl->getModel() ); |
2804 | 0 | if ( xCurrentModel == i_rxModel ) |
2805 | 0 | break; |
2806 | 0 | xControl.clear(); |
2807 | 0 | } |
2808 | |
|
2809 | 0 | if ( !xControl.is() ) |
2810 | 0 | { |
2811 | | // fallback (some controls might not have been created, yet, since they were never visible so far) |
2812 | 0 | Reference< XControl > xContainerControl( xControlContainer, UNO_QUERY_THROW ); |
2813 | 0 | const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerControl->getPeer() ); |
2814 | 0 | ENSURE_OR_THROW( pContainerWindow, "unexpected control container implementation" ); |
2815 | |
|
2816 | 0 | const SdrView* pSdrView = m_pShell ? m_pShell->GetFormView() : nullptr; |
2817 | 0 | ENSURE_OR_THROW( pSdrView, "no current view" ); |
2818 | |
|
2819 | 0 | xControl.set( i_rKnownFormObj.GetUnoControl( *pSdrView, *pContainerWindow->GetOutDev() ), UNO_SET_THROW ); |
2820 | 0 | } |
2821 | 0 | } |
2822 | 0 | catch( const Exception& ) |
2823 | 0 | { |
2824 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
2825 | 0 | } |
2826 | | |
2827 | 0 | OSL_ENSURE( xControl.is(), "FmXFormShell::impl_getControl: no control found!" ); |
2828 | 0 | return xControl; |
2829 | 0 | } |
2830 | | |
2831 | | // note: _out_rForms is a member so needs lock |
2832 | | void FmXFormShell::impl_collectFormSearchContexts_nothrow_Lock( const Reference<XInterface>& _rxStartingPoint, |
2833 | | std::u16string_view _rCurrentLevelPrefix, FmFormArray& _out_rForms, ::std::vector< OUString >& _out_rNames ) |
2834 | 0 | { |
2835 | 0 | try |
2836 | 0 | { |
2837 | 0 | Reference< XIndexAccess> xContainer( _rxStartingPoint, UNO_QUERY ); |
2838 | 0 | if ( !xContainer.is() ) |
2839 | 0 | return; |
2840 | | |
2841 | 0 | sal_Int32 nCount( xContainer->getCount() ); |
2842 | 0 | if ( nCount == 0 ) |
2843 | 0 | return; |
2844 | | |
2845 | 0 | OUString sCurrentFormName; |
2846 | 0 | OUStringBuffer aNextLevelPrefix; |
2847 | 0 | for ( sal_Int32 i=0; i<nCount; ++i ) |
2848 | 0 | { |
2849 | | // is the current child a form? |
2850 | 0 | Reference< XForm > xCurrentAsForm( xContainer->getByIndex(i), UNO_QUERY ); |
2851 | 0 | if ( !xCurrentAsForm.is() ) |
2852 | 0 | continue; |
2853 | | |
2854 | 0 | Reference< XNamed > xNamed( xCurrentAsForm, UNO_QUERY_THROW ); |
2855 | 0 | sCurrentFormName = xNamed->getName(); |
2856 | | |
2857 | | // the name of the current form |
2858 | 0 | OUString sCompleteCurrentName( sCurrentFormName ); |
2859 | 0 | if ( !_rCurrentLevelPrefix.empty() ) |
2860 | 0 | { |
2861 | 0 | sCompleteCurrentName += OUString::Concat(" (") + _rCurrentLevelPrefix + ")"; |
2862 | 0 | } |
2863 | | |
2864 | | // the prefix for the next level |
2865 | 0 | aNextLevelPrefix = _rCurrentLevelPrefix; |
2866 | 0 | if ( !_rCurrentLevelPrefix.empty() ) |
2867 | 0 | aNextLevelPrefix.append( '/' ); |
2868 | 0 | aNextLevelPrefix.append( sCurrentFormName ); |
2869 | | |
2870 | | // remember both the form and its "display name" |
2871 | 0 | _out_rForms.push_back( xCurrentAsForm ); |
2872 | 0 | _out_rNames.push_back( sCompleteCurrentName ); |
2873 | | |
2874 | | // and descend |
2875 | 0 | impl_collectFormSearchContexts_nothrow_Lock( |
2876 | 0 | xCurrentAsForm, aNextLevelPrefix, |
2877 | 0 | _out_rForms, _out_rNames); |
2878 | 0 | aNextLevelPrefix.setLength(0); |
2879 | 0 | } |
2880 | 0 | } |
2881 | 0 | catch( const Exception& ) |
2882 | 0 | { |
2883 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
2884 | 0 | } |
2885 | 0 | } |
2886 | | |
2887 | | void FmXFormShell::startFiltering_Lock() |
2888 | 0 | { |
2889 | 0 | if (impl_checkDisposed_Lock()) |
2890 | 0 | return; |
2891 | | |
2892 | | // setting all forms in filter mode |
2893 | 0 | FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); |
2894 | | |
2895 | | // if the active controller is our external one we have to use the trigger controller |
2896 | 0 | Reference< XControlContainer> xContainer; |
2897 | 0 | if (getActiveController_Lock() == m_xExternalViewController) |
2898 | 0 | { |
2899 | 0 | DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but no one triggered this !"); |
2900 | 0 | xContainer = m_xExtViewTriggerController->getContainer(); |
2901 | 0 | } |
2902 | 0 | else |
2903 | 0 | xContainer = getActiveController_Lock()->getContainer(); |
2904 | |
|
2905 | 0 | rtl::Reference< FormViewPageWindowAdapter > pAdapter = pXView->findWindow( xContainer ); |
2906 | 0 | if ( pAdapter.is() ) |
2907 | 0 | { |
2908 | 0 | const ::std::vector< Reference< runtime::XFormController> >& rControllerList = pAdapter->GetList(); |
2909 | 0 | for (const auto& rpController : rControllerList) |
2910 | 0 | { |
2911 | 0 | Reference< XModeSelector> xModeSelector(rpController, UNO_QUERY); |
2912 | 0 | if (xModeSelector.is()) |
2913 | 0 | xModeSelector->setMode( u"FilterMode"_ustr ); |
2914 | 0 | } |
2915 | 0 | } |
2916 | |
|
2917 | 0 | m_bFilterMode = true; |
2918 | |
|
2919 | 0 | m_pShell->UIFeatureChanged(); |
2920 | 0 | SfxViewFrame& rViewFrame = m_pShell->GetViewShell()->GetViewFrame(); |
2921 | 0 | rViewFrame.GetBindings().InvalidateShell( *m_pShell ); |
2922 | |
|
2923 | 0 | if ( rViewFrame.KnowsChildWindow( SID_FM_FILTER_NAVIGATOR ) |
2924 | 0 | && !rViewFrame.HasChildWindow( SID_FM_FILTER_NAVIGATOR ) |
2925 | 0 | ) |
2926 | 0 | { |
2927 | 0 | rViewFrame.ToggleChildWindow( SID_FM_FILTER_NAVIGATOR ); |
2928 | 0 | } |
2929 | 0 | } |
2930 | | |
2931 | | static void saveFilter(const Reference< runtime::XFormController >& _rxController) |
2932 | 0 | { |
2933 | 0 | Reference< XPropertySet> xFormAsSet(_rxController->getModel(), UNO_QUERY); |
2934 | 0 | Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY); |
2935 | | |
2936 | | // call the subcontroller |
2937 | 0 | Reference< runtime::XFormController > xController; |
2938 | 0 | for (sal_Int32 i = 0, nCount = _rxController->getCount(); i < nCount; ++i) |
2939 | 0 | { |
2940 | 0 | _rxController->getByIndex(i) >>= xController; |
2941 | 0 | saveFilter(xController); |
2942 | 0 | } |
2943 | |
|
2944 | 0 | try |
2945 | 0 | { |
2946 | |
|
2947 | 0 | xFormAsSet->setPropertyValue(FM_PROP_FILTER, xControllerAsSet->getPropertyValue(FM_PROP_FILTER)); |
2948 | 0 | xFormAsSet->setPropertyValue(FM_PROP_APPLYFILTER, Any( true ) ); |
2949 | 0 | } |
2950 | 0 | catch (const Exception& ) |
2951 | 0 | { |
2952 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
2953 | 0 | } |
2954 | |
|
2955 | 0 | } |
2956 | | |
2957 | | |
2958 | | void FmXFormShell::stopFiltering_Lock(bool bSave) |
2959 | 0 | { |
2960 | 0 | if (impl_checkDisposed_Lock()) |
2961 | 0 | return; |
2962 | | |
2963 | 0 | m_bFilterMode = false; |
2964 | |
|
2965 | 0 | FmXFormView* pXView = m_pShell->GetFormView()->GetImpl(); |
2966 | | |
2967 | | // if the active controller is our external one we have to use the trigger controller |
2968 | 0 | Reference< XControlContainer> xContainer; |
2969 | 0 | if (getActiveController_Lock() == m_xExternalViewController) |
2970 | 0 | { |
2971 | 0 | DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::stopFiltering : inconsistent : active external controller, but no one triggered this !"); |
2972 | 0 | xContainer = m_xExtViewTriggerController->getContainer(); |
2973 | 0 | } |
2974 | 0 | else |
2975 | 0 | xContainer = getActiveController_Lock()->getContainer(); |
2976 | |
|
2977 | 0 | rtl::Reference< FormViewPageWindowAdapter > pAdapter = pXView->findWindow(xContainer); |
2978 | 0 | if ( pAdapter.is() ) |
2979 | 0 | { |
2980 | 0 | const ::std::vector< Reference< runtime::XFormController > >& rControllerList = pAdapter->GetList(); |
2981 | 0 | ::std::vector < OUString > aOriginalFilters; |
2982 | 0 | ::std::vector < bool > aOriginalApplyFlags; |
2983 | |
|
2984 | 0 | if (bSave) |
2985 | 0 | { |
2986 | 0 | for (const auto& rpController : rControllerList) |
2987 | 0 | { |
2988 | | // remember the current filter settings in case we're going to reload the forms below (which may fail) |
2989 | 0 | try |
2990 | 0 | { |
2991 | 0 | Reference< XPropertySet > xFormAsSet(rpController->getModel(), UNO_QUERY); |
2992 | 0 | aOriginalFilters.push_back(::comphelper::getString(xFormAsSet->getPropertyValue(FM_PROP_FILTER))); |
2993 | 0 | aOriginalApplyFlags.push_back(::comphelper::getBOOL(xFormAsSet->getPropertyValue(FM_PROP_APPLYFILTER))); |
2994 | 0 | } |
2995 | 0 | catch(Exception&) |
2996 | 0 | { |
2997 | 0 | OSL_FAIL("FmXFormShell::stopFiltering : could not get the original filter !"); |
2998 | | // put dummies into the arrays so the they have the right size |
2999 | |
|
3000 | 0 | if (aOriginalFilters.size() == aOriginalApplyFlags.size()) |
3001 | | // the first getPropertyValue failed -> use two dummies |
3002 | 0 | aOriginalFilters.emplace_back( ); |
3003 | 0 | aOriginalApplyFlags.push_back( false ); |
3004 | 0 | } |
3005 | 0 | saveFilter(rpController); |
3006 | 0 | } |
3007 | 0 | } |
3008 | 0 | for (const auto& rController : rControllerList) |
3009 | 0 | { |
3010 | |
|
3011 | 0 | Reference< XModeSelector> xModeSelector(rController, UNO_QUERY); |
3012 | 0 | if (xModeSelector.is()) |
3013 | 0 | xModeSelector->setMode( u"DataMode"_ustr ); |
3014 | 0 | } |
3015 | 0 | if (bSave) // execute the filter |
3016 | 0 | { |
3017 | 0 | const ::std::vector< Reference< runtime::XFormController > > & rControllers = pAdapter->GetList(); |
3018 | 0 | for (::std::vector< Reference< runtime::XFormController > > ::const_iterator j = rControllers.begin(); |
3019 | 0 | j != rControllers.end(); ++j) |
3020 | 0 | { |
3021 | 0 | Reference< XLoadable> xReload((*j)->getModel(), UNO_QUERY); |
3022 | 0 | if (!xReload.is()) |
3023 | 0 | continue; |
3024 | 0 | Reference< XPropertySet > xFormSet(xReload, UNO_QUERY); |
3025 | |
|
3026 | 0 | try |
3027 | 0 | { |
3028 | 0 | xReload->reload(); |
3029 | 0 | } |
3030 | 0 | catch(Exception&) |
3031 | 0 | { |
3032 | 0 | TOOLS_WARN_EXCEPTION("svx.form", ""); |
3033 | 0 | } |
3034 | | |
3035 | 0 | if (!isRowSetAlive(xFormSet)) |
3036 | 0 | { // something went wrong -> restore the original state |
3037 | 0 | OUString sOriginalFilter = aOriginalFilters[ j - rControllers.begin() ]; |
3038 | 0 | bool bOriginalApplyFlag = aOriginalApplyFlags[ j - rControllers.begin() ]; |
3039 | 0 | try |
3040 | 0 | { |
3041 | 0 | xFormSet->setPropertyValue(FM_PROP_FILTER, Any(sOriginalFilter)); |
3042 | 0 | xFormSet->setPropertyValue(FM_PROP_APPLYFILTER, Any(bOriginalApplyFlag)); |
3043 | 0 | xReload->reload(); |
3044 | 0 | } |
3045 | 0 | catch(const Exception&) |
3046 | 0 | { |
3047 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
3048 | 0 | } |
3049 | 0 | } |
3050 | 0 | } |
3051 | 0 | } |
3052 | 0 | } |
3053 | | |
3054 | 0 | m_pShell->UIFeatureChanged(); |
3055 | 0 | m_pShell->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell); |
3056 | 0 | } |
3057 | | |
3058 | | |
3059 | | void FmXFormShell::CreateExternalView_Lock() |
3060 | 0 | { |
3061 | 0 | if (impl_checkDisposed_Lock()) |
3062 | 0 | return; |
3063 | | |
3064 | 0 | DBG_ASSERT(m_xAttachedFrame.is(), "FmXFormShell::CreateExternalView : no frame !"); |
3065 | | |
3066 | | // the frame the external view is displayed in |
3067 | 0 | bool bAlreadyExistent = m_xExternalViewController.is(); |
3068 | 0 | Reference< css::frame::XFrame> xExternalViewFrame; |
3069 | |
|
3070 | 0 | Reference<runtime::XFormController> xCurrentNavController(getNavController_Lock()); |
3071 | | // the creation of the "partwindow" may cause a deactivate of the document which will result in our nav controller to be set to NULL |
3072 | | |
3073 | | // _first_ check if we have any valid fields we can use for the grid view |
3074 | | // FS - 21.10.99 - 69219 |
3075 | 0 | { |
3076 | 0 | FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel()); |
3077 | 0 | bool bHaveUsableControls = false; |
3078 | 0 | for (;;) |
3079 | 0 | { |
3080 | 0 | Reference< XPropertySet> xCurrentModelSet(aModelIterator.Next(), UNO_QUERY); |
3081 | 0 | if (!xCurrentModelSet.is()) |
3082 | 0 | break; |
3083 | | // the FmXBoundFormFieldIterator only supplies controls with a valid control source |
3084 | | // so we just have to check the field type |
3085 | 0 | sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID)); |
3086 | 0 | switch (nClassId) |
3087 | 0 | { |
3088 | 0 | case FormComponentType::IMAGECONTROL: |
3089 | 0 | case FormComponentType::CONTROL: |
3090 | 0 | continue; |
3091 | 0 | } |
3092 | 0 | bHaveUsableControls = true; |
3093 | 0 | break; |
3094 | 0 | } |
3095 | | |
3096 | 0 | if (!bHaveUsableControls) |
3097 | 0 | { |
3098 | 0 | std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(nullptr, |
3099 | 0 | VclMessageType::Warning, VclButtonsType::Ok, |
3100 | 0 | SvxResId(RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY))); |
3101 | 0 | xBox->run(); |
3102 | 0 | return; |
3103 | 0 | } |
3104 | 0 | } |
3105 | | |
3106 | | // load the component for external form views |
3107 | 0 | if (!bAlreadyExistent) |
3108 | 0 | { |
3109 | 0 | OUString sFrameName(u"_beamer"_ustr); |
3110 | 0 | URL aWantToDispatch; |
3111 | 0 | aWantToDispatch.Complete = FMURL_COMPONENT_FORMGRIDVIEW; |
3112 | |
|
3113 | 0 | Reference< css::frame::XDispatchProvider> xProv(m_xAttachedFrame, UNO_QUERY); |
3114 | 0 | Reference< css::frame::XDispatch> xDisp; |
3115 | 0 | if (xProv.is()) |
3116 | 0 | xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, |
3117 | 0 | css::frame::FrameSearchFlag::CHILDREN | css::frame::FrameSearchFlag::CREATE); |
3118 | 0 | if (xDisp.is()) |
3119 | 0 | { |
3120 | 0 | xDisp->dispatch(aWantToDispatch, Sequence< PropertyValue>()); |
3121 | 0 | } |
3122 | | |
3123 | | // with this the component should be loaded, now search the frame where it resides in |
3124 | 0 | xExternalViewFrame = m_xAttachedFrame->findFrame(sFrameName, css::frame::FrameSearchFlag::CHILDREN); |
3125 | 0 | if (xExternalViewFrame.is()) |
3126 | 0 | { |
3127 | 0 | m_xExternalViewController = xExternalViewFrame->getController(); |
3128 | 0 | if (m_xExternalViewController.is()) |
3129 | 0 | m_xExternalViewController->addEventListener(static_cast<XEventListener*>(static_cast<XPropertyChangeListener*>(this))); |
3130 | 0 | } |
3131 | 0 | } |
3132 | 0 | else |
3133 | 0 | { |
3134 | 0 | xExternalViewFrame = m_xExternalViewController->getFrame(); |
3135 | 0 | Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); |
3136 | | |
3137 | | // if we display the active form we interpret the slot as "remove it" |
3138 | 0 | Reference< XForm> xCurrentModel(xCurrentNavController->getModel(), UNO_QUERY); |
3139 | 0 | if ((xCurrentModel == m_xExternalDisplayedForm) || (getInternalForm_Lock(xCurrentModel) == m_xExternalDisplayedForm)) |
3140 | 0 | { |
3141 | 0 | if (m_xExternalViewController == getActiveController_Lock()) |
3142 | 0 | { |
3143 | 0 | Reference< runtime::XFormController > xAsFormController( m_xExternalViewController, UNO_QUERY ); |
3144 | 0 | ControllerFeatures aHelper( xAsFormController ); |
3145 | 0 | (void)aHelper->commitCurrentControl(); |
3146 | 0 | } |
3147 | |
|
3148 | 0 | Reference< runtime::XFormController > xNewController(m_xExtViewTriggerController); |
3149 | 0 | CloseExternalFormViewer_Lock(); |
3150 | 0 | setActiveController_Lock(xNewController); |
3151 | 0 | return; |
3152 | 0 | } |
3153 | | |
3154 | 0 | URL aClearURL; |
3155 | 0 | aClearURL.Complete = FMURL_GRIDVIEW_CLEARVIEW; |
3156 | |
|
3157 | 0 | Reference< css::frame::XDispatch> xClear( xCommLink->queryDispatch(aClearURL, OUString(), 0)); |
3158 | 0 | if (xClear.is()) |
3159 | 0 | xClear->dispatch(aClearURL, Sequence< PropertyValue>()); |
3160 | 0 | } |
3161 | | |
3162 | | // TODO: We need an interceptor at the xSupplier, which forwards all queryDispatch requests to the FormController |
3163 | | // instance for which this "external view" was triggered |
3164 | | |
3165 | | // get the dispatch interface of the frame so we can communicate (interceptable) with the controller |
3166 | 0 | Reference< css::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY); |
3167 | |
|
3168 | 0 | if (m_xExternalViewController.is()) |
3169 | 0 | { |
3170 | 0 | DBG_ASSERT(xCommLink.is(), "FmXFormShell::CreateExternalView : the component doesn't have the necessary interfaces !"); |
3171 | | // collect the dispatchers we will need |
3172 | 0 | URL aAddColumnURL; |
3173 | 0 | aAddColumnURL.Complete = FMURL_GRIDVIEW_ADDCOLUMN; |
3174 | 0 | Reference< css::frame::XDispatch> xAddColumnDispatch( xCommLink->queryDispatch(aAddColumnURL, OUString(), 0)); |
3175 | 0 | URL aAttachURL; |
3176 | 0 | aAttachURL.Complete = FMURL_GRIDVIEW_ATTACHTOFORM; |
3177 | 0 | Reference< css::frame::XDispatch> xAttachDispatch( xCommLink->queryDispatch(aAttachURL, OUString(), 0)); |
3178 | |
|
3179 | 0 | if (xAddColumnDispatch.is() && xAttachDispatch.is()) |
3180 | 0 | { |
3181 | 0 | DBG_ASSERT(xCurrentNavController.is(), "FmXFormShell::CreateExternalView : invalid call : have no nav controller !"); |
3182 | | // first : dispatch the descriptions for the columns to add |
3183 | 0 | sal_Int16 nAddedColumns = 0; |
3184 | | |
3185 | | // for radio buttons we need some special structures |
3186 | 0 | typedef std::map< OUString, Sequence< OUString> > MapUString2UstringSeq; |
3187 | 0 | typedef std::map< OUString, OUString > FmMapUString2UString; |
3188 | 0 | typedef std::map< OUString, sal_Int16 > FmMapUString2Int16; |
3189 | |
|
3190 | 0 | MapUString2UstringSeq aRadioValueLists; |
3191 | 0 | MapUString2UstringSeq aRadioListSources; |
3192 | 0 | FmMapUString2UString aRadioControlSources; |
3193 | 0 | FmMapUString2Int16 aRadioPositions; |
3194 | |
|
3195 | 0 | FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel()); |
3196 | 0 | OUString sColumnType,aGroupName,sControlSource; |
3197 | 0 | Sequence< Property> aProps; |
3198 | 0 | for (;;) |
3199 | 0 | { |
3200 | 0 | Reference< XPropertySet> xCurrentModelSet(aModelIterator.Next(), UNO_QUERY); |
3201 | 0 | if (!xCurrentModelSet.is()) |
3202 | 0 | break; |
3203 | 0 | OSL_ENSURE(xCurrentModelSet.is(),"xCurrentModelSet is null!"); |
3204 | | // create a description of the column to be created |
3205 | | // first : determine its type |
3206 | |
|
3207 | 0 | sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID)); |
3208 | 0 | switch (nClassId) |
3209 | 0 | { |
3210 | 0 | case FormComponentType::RADIOBUTTON: |
3211 | 0 | { |
3212 | | // get the label of the button (this is the access key for our structures) |
3213 | 0 | aGroupName = getLabelName(xCurrentModelSet); |
3214 | | |
3215 | | // add the reference value of the radio button to the list source sequence |
3216 | 0 | Sequence< OUString>& aThisGroupLabels = aRadioListSources[aGroupName]; |
3217 | 0 | sal_Int32 nNewSizeL = aThisGroupLabels.getLength() + 1; |
3218 | 0 | aThisGroupLabels.realloc(nNewSizeL); |
3219 | 0 | aThisGroupLabels.getArray()[nNewSizeL - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_REFVALUE)); |
3220 | | |
3221 | | // add the label to the value list sequence |
3222 | 0 | Sequence< OUString>& aThisGroupControlSources = aRadioValueLists[aGroupName]; |
3223 | 0 | sal_Int32 nNewSizeC = aThisGroupControlSources.getLength() + 1; |
3224 | 0 | aThisGroupControlSources.realloc(nNewSizeC); |
3225 | 0 | aThisGroupControlSources.getArray()[nNewSizeC - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_LABEL)); |
3226 | | |
3227 | | // remember the controls source of the radio group |
3228 | 0 | sControlSource = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_CONTROLSOURCE)); |
3229 | 0 | if (aRadioControlSources.find(aGroupName) == aRadioControlSources.end()) |
3230 | 0 | aRadioControlSources[aGroupName] = sControlSource; |
3231 | | #ifdef DBG_UTIL |
3232 | | else |
3233 | | DBG_ASSERT(aRadioControlSources[aGroupName] == sControlSource, |
3234 | | "FmXFormShell::CreateExternalView : inconsistent radio buttons detected !"); |
3235 | | // (radio buttons with the same name should have the same control source) |
3236 | | #endif |
3237 | | // remember the position within the columns |
3238 | 0 | if (aRadioPositions.find(aGroupName) == aRadioPositions.end()) |
3239 | 0 | aRadioPositions[aGroupName] = nAddedColumns; |
3240 | | |
3241 | | // any further handling is done below |
3242 | 0 | } |
3243 | 0 | continue; |
3244 | | |
3245 | 0 | case FormComponentType::IMAGECONTROL: |
3246 | 0 | case FormComponentType::CONTROL: |
3247 | | // no grid columns for these types (though they have a control source) |
3248 | 0 | continue; |
3249 | 0 | case FormComponentType::CHECKBOX: |
3250 | 0 | sColumnType = FM_COL_CHECKBOX; break; |
3251 | 0 | case FormComponentType::LISTBOX: |
3252 | 0 | sColumnType = FM_COL_LISTBOX; break; |
3253 | 0 | case FormComponentType::COMBOBOX: |
3254 | 0 | sColumnType = FM_COL_COMBOBOX; break; |
3255 | 0 | case FormComponentType::DATEFIELD: |
3256 | 0 | sColumnType = FM_COL_DATEFIELD; break; |
3257 | 0 | case FormComponentType::TIMEFIELD: |
3258 | 0 | sColumnType = FM_COL_TIMEFIELD; break; |
3259 | 0 | case FormComponentType::NUMERICFIELD: |
3260 | 0 | sColumnType = FM_COL_NUMERICFIELD; break; |
3261 | 0 | case FormComponentType::CURRENCYFIELD: |
3262 | 0 | sColumnType = FM_COL_CURRENCYFIELD; break; |
3263 | 0 | case FormComponentType::PATTERNFIELD: |
3264 | 0 | sColumnType = FM_COL_PATTERNFIELD; break; |
3265 | | |
3266 | 0 | case FormComponentType::TEXTFIELD: |
3267 | 0 | { |
3268 | 0 | sColumnType = FM_COL_TEXTFIELD; |
3269 | | // we know at least two different controls which are TextFields : the basic edit field and the formatted |
3270 | | // field. we distinguish them by their service name |
3271 | 0 | Reference< lang::XServiceInfo> xInfo(xCurrentModelSet, UNO_QUERY); |
3272 | 0 | if (xInfo.is()) |
3273 | 0 | { |
3274 | 0 | SdrObjKind nObjectType = getControlTypeByObject(xInfo); |
3275 | 0 | if (SdrObjKind::FormFormattedField == nObjectType) |
3276 | 0 | sColumnType = FM_COL_FORMATTEDFIELD; |
3277 | 0 | } |
3278 | 0 | } |
3279 | 0 | break; |
3280 | 0 | default: |
3281 | 0 | sColumnType = FM_COL_TEXTFIELD; break; |
3282 | 0 | } |
3283 | | |
3284 | 0 | const sal_Int16 nDispatchArgs = 3; |
3285 | 0 | Sequence< PropertyValue> aDispatchArgs(nDispatchArgs); |
3286 | 0 | PropertyValue* pDispatchArgs = aDispatchArgs.getArray(); |
3287 | | |
3288 | | // properties describing "meta data" about the column |
3289 | | // the type |
3290 | 0 | pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE; |
3291 | 0 | pDispatchArgs->Value <<= sColumnType; |
3292 | 0 | ++pDispatchArgs; |
3293 | | |
3294 | | // the pos : append the col |
3295 | 0 | pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS; |
3296 | 0 | pDispatchArgs->Value <<= nAddedColumns; |
3297 | 0 | ++pDispatchArgs; |
3298 | | |
3299 | | // the properties to forward to the new column |
3300 | 0 | Sequence< PropertyValue> aColumnProps(1); |
3301 | 0 | PropertyValue* pColumnProps = aColumnProps.getArray(); |
3302 | | |
3303 | | // the label |
3304 | 0 | pColumnProps->Name = FM_PROP_LABEL; |
3305 | 0 | pColumnProps->Value <<= getLabelName(xCurrentModelSet); |
3306 | 0 | ++pColumnProps; |
3307 | | |
3308 | | // for all other props : transfer them |
3309 | 0 | Reference< XPropertySetInfo> xControlModelInfo( xCurrentModelSet->getPropertySetInfo()); |
3310 | 0 | DBG_ASSERT(xControlModelInfo.is(), "FmXFormShell::CreateExternalView : the control model has no property info ! This will crash !"); |
3311 | 0 | aProps = xControlModelInfo->getProperties(); |
3312 | | |
3313 | | // realloc the control description sequence |
3314 | 0 | sal_Int32 nExistentDescs = pColumnProps - aColumnProps.getArray(); |
3315 | 0 | aColumnProps.realloc(nExistentDescs + aProps.getLength()); |
3316 | 0 | pColumnProps = aColumnProps.getArray() + nExistentDescs; |
3317 | |
|
3318 | 0 | for (const Property& rProp : aProps) |
3319 | 0 | { |
3320 | 0 | if (rProp.Name == FM_PROP_LABEL) |
3321 | | // already set |
3322 | 0 | continue; |
3323 | 0 | if (rProp.Name == FM_PROP_DEFAULTCONTROL) |
3324 | | // allow the column's own "default control" |
3325 | 0 | continue; |
3326 | 0 | if (rProp.Attributes & PropertyAttribute::READONLY) |
3327 | | // assume that properties which are readonly for the control are ro for the column to be created, too |
3328 | 0 | continue; |
3329 | | |
3330 | 0 | pColumnProps->Name = rProp.Name; |
3331 | 0 | pColumnProps->Value = xCurrentModelSet->getPropertyValue(rProp.Name); |
3332 | 0 | ++pColumnProps; |
3333 | 0 | } |
3334 | 0 | aColumnProps.realloc(pColumnProps - aColumnProps.getArray()); |
3335 | | |
3336 | | // columns props are a dispatch argument |
3337 | 0 | pDispatchArgs->Name = "ColumnProperties"; // TODO : fmurl.* |
3338 | 0 | pDispatchArgs->Value <<= aColumnProps; |
3339 | 0 | ++pDispatchArgs; |
3340 | 0 | DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()), |
3341 | 0 | "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?"); |
3342 | | |
3343 | | // dispatch the "add column" |
3344 | 0 | xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs); |
3345 | 0 | ++nAddedColumns; |
3346 | 0 | } |
3347 | | |
3348 | | // now for the radio button handling |
3349 | 0 | sal_Int16 nOffset(0); |
3350 | | // properties describing the "direct" column properties |
3351 | 0 | const sal_Int16 nListBoxDescription = 6; |
3352 | 0 | Sequence< PropertyValue> aListBoxDescription(nListBoxDescription); |
3353 | 0 | for (const auto& rCtrlSource : aRadioControlSources) |
3354 | 0 | { |
3355 | 0 | PropertyValue* pListBoxDescription = aListBoxDescription.getArray(); |
3356 | | // label |
3357 | 0 | pListBoxDescription->Name = FM_PROP_LABEL; |
3358 | 0 | pListBoxDescription->Value <<= rCtrlSource.first; |
3359 | 0 | ++pListBoxDescription; |
3360 | | |
3361 | | // control source |
3362 | 0 | pListBoxDescription->Name = FM_PROP_CONTROLSOURCE; |
3363 | 0 | pListBoxDescription->Value <<= rCtrlSource.second; |
3364 | 0 | ++pListBoxDescription; |
3365 | | |
3366 | | // bound column |
3367 | 0 | pListBoxDescription->Name = FM_PROP_BOUNDCOLUMN; |
3368 | 0 | pListBoxDescription->Value <<= sal_Int16(1); |
3369 | 0 | ++pListBoxDescription; |
3370 | | |
3371 | | // content type |
3372 | 0 | pListBoxDescription->Name = FM_PROP_LISTSOURCETYPE; |
3373 | 0 | pListBoxDescription->Value <<= ListSourceType_VALUELIST; |
3374 | 0 | ++pListBoxDescription; |
3375 | | |
3376 | | // list source |
3377 | 0 | MapUString2UstringSeq::const_iterator aCurrentListSource = aRadioListSources.find(rCtrlSource.first); |
3378 | 0 | assert(aCurrentListSource != aRadioListSources.end() && |
3379 | 0 | "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); |
3380 | 0 | pListBoxDescription->Name = FM_PROP_LISTSOURCE; |
3381 | 0 | pListBoxDescription->Value <<= (*aCurrentListSource).second; |
3382 | 0 | ++pListBoxDescription; |
3383 | | |
3384 | | // value list |
3385 | 0 | MapUString2UstringSeq::const_iterator aCurrentValueList = aRadioValueLists.find(rCtrlSource.first); |
3386 | 0 | assert(aCurrentValueList != aRadioValueLists.end() && "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); |
3387 | 0 | pListBoxDescription->Name = FM_PROP_STRINGITEMLIST; |
3388 | 0 | pListBoxDescription->Value <<= (*aCurrentValueList).second; |
3389 | 0 | ++pListBoxDescription; |
3390 | |
|
3391 | 0 | DBG_ASSERT(nListBoxDescription == (pListBoxDescription - aListBoxDescription.getConstArray()), |
3392 | 0 | "FmXFormShell::CreateExternalView : forgot to adjust nListBoxDescription ?"); |
3393 | | |
3394 | | // properties describing the column "meta data" |
3395 | 0 | const sal_Int16 nDispatchArgs = 3; |
3396 | 0 | Sequence< PropertyValue> aDispatchArgs(nDispatchArgs); |
3397 | 0 | PropertyValue* pDispatchArgs = aDispatchArgs.getArray(); |
3398 | | |
3399 | | // column type : listbox |
3400 | 0 | pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE; |
3401 | 0 | pDispatchArgs->Value <<= u"" FM_COL_LISTBOX ""_ustr; |
3402 | | // pDispatchArgs->Value <<= (OUString)FM_COL_LISTBOX; |
3403 | 0 | ++pDispatchArgs; |
3404 | | |
3405 | | // column position |
3406 | 0 | pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS; |
3407 | 0 | FmMapUString2Int16::const_iterator aOffset = aRadioPositions.find(rCtrlSource.first); |
3408 | 0 | assert(aOffset != aRadioPositions.end() && "FmXFormShell::CreateExternalView : inconsistent radio descriptions !"); |
3409 | 0 | sal_Int16 nPosition = (*aOffset).second; |
3410 | 0 | nPosition = nPosition + nOffset; |
3411 | | // we already inserted nOffset additional columns... |
3412 | 0 | pDispatchArgs->Value <<= nPosition; |
3413 | 0 | ++pDispatchArgs; |
3414 | | |
3415 | | // the |
3416 | 0 | pDispatchArgs->Name = "ColumnProperties"; // TODO : fmurl.* |
3417 | 0 | pDispatchArgs->Value <<= aListBoxDescription; |
3418 | 0 | ++pDispatchArgs; |
3419 | 0 | DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()), |
3420 | 0 | "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?"); |
3421 | | |
3422 | | // dispatch the "add column" |
3423 | 0 | xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs); |
3424 | 0 | ++nAddedColumns; |
3425 | 0 | ++nOffset; |
3426 | 0 | } |
3427 | | |
3428 | |
|
3429 | 0 | DBG_ASSERT(nAddedColumns > 0, "FmXFormShell::CreateExternalView : no controls (inconsistent) !"); |
3430 | | // we should have checked if we have any usable controls (see above). |
3431 | | |
3432 | | // "load" the "form" of the external view |
3433 | 0 | PropertyValue aArg; |
3434 | 0 | aArg.Name = FMARG_ATTACHTO_MASTERFORM; |
3435 | 0 | Reference< XResultSet> xForm(xCurrentNavController->getModel(), UNO_QUERY); |
3436 | 0 | aArg.Value <<= xForm; |
3437 | |
|
3438 | 0 | m_xExternalDisplayedForm = std::move(xForm); |
3439 | | // do this before dispatching the "attach" command, as the attach may result in a call to our queryDispatch (for the FormSlots) |
3440 | | // which needs the m_xExternalDisplayedForm |
3441 | |
|
3442 | 0 | xAttachDispatch->dispatch(aAttachURL, Sequence< PropertyValue>(&aArg, 1)); |
3443 | |
|
3444 | 0 | m_xExtViewTriggerController = std::move(xCurrentNavController); |
3445 | | |
3446 | | // we want to know modifications done in the external view |
3447 | | // if the external controller is a XFormController we can use all our default handlings for it |
3448 | 0 | Reference< runtime::XFormController > xFormController( m_xExternalViewController, UNO_QUERY ); |
3449 | 0 | OSL_ENSURE( xFormController.is(), "FmXFormShell::CreateExternalView:: invalid external view controller!" ); |
3450 | 0 | if (xFormController.is()) |
3451 | 0 | xFormController->addActivateListener(static_cast<XFormControllerListener*>(this)); |
3452 | 0 | } |
3453 | 0 | } |
3454 | | #ifdef DBG_UTIL |
3455 | | else |
3456 | | { |
3457 | | OSL_FAIL("FmXFormShell::CreateExternalView : could not create the external form view !"); |
3458 | | } |
3459 | | #endif |
3460 | 0 | InvalidateSlot_Lock(SID_FM_VIEW_AS_GRID, false); |
3461 | 0 | } |
3462 | | |
3463 | | |
3464 | | void FmXFormShell::implAdjustConfigCache_Lock() |
3465 | 8.87k | { |
3466 | 8.87k | const bool bFuzzing(comphelper::IsFuzzing()); |
3467 | 8.87k | if (bFuzzing) |
3468 | 8.87k | return; |
3469 | | |
3470 | | // get (cache) the wizard usage flag |
3471 | 0 | Sequence< OUString > aNames { u"FormControlPilotsEnabled"_ustr }; |
3472 | 0 | Sequence< Any > aFlags = GetProperties(aNames); |
3473 | 0 | if (1 == aFlags.getLength()) |
3474 | 0 | m_bUseWizards = ::cppu::any2bool(aFlags[0]); |
3475 | 0 | } |
3476 | | |
3477 | | |
3478 | | void FmXFormShell::Notify( const css::uno::Sequence< OUString >& _rPropertyNames) |
3479 | 0 | { |
3480 | 0 | DBG_TESTSOLARMUTEX(); |
3481 | 0 | if (impl_checkDisposed_Lock()) |
3482 | 0 | return; |
3483 | | |
3484 | 0 | for (const OUString& rName : _rPropertyNames) |
3485 | 0 | if (rName == "FormControlPilotsEnabled") |
3486 | 0 | { |
3487 | 0 | implAdjustConfigCache_Lock(); |
3488 | 0 | InvalidateSlot_Lock(SID_FM_USE_WIZARDS, true); |
3489 | 0 | } |
3490 | 0 | } |
3491 | | |
3492 | | void FmXFormShell::ImplCommit() |
3493 | 0 | { |
3494 | 0 | } |
3495 | | |
3496 | | |
3497 | | void FmXFormShell::SetWizardUsing_Lock(bool _bUseThem) |
3498 | 0 | { |
3499 | 0 | m_bUseWizards = _bUseThem; |
3500 | |
|
3501 | 0 | Sequence< OUString > aNames { u"FormControlPilotsEnabled"_ustr }; |
3502 | 0 | Sequence< Any > aValues{ Any(m_bUseWizards) }; |
3503 | 0 | PutProperties(aNames, aValues); |
3504 | 0 | } |
3505 | | |
3506 | | |
3507 | | void FmXFormShell::viewDeactivated_Lock(FmFormView& _rCurrentView, bool _bDeactivateController) |
3508 | 8.87k | { |
3509 | | |
3510 | 8.87k | if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() ) |
3511 | 32 | { |
3512 | 32 | _rCurrentView.GetImpl()->Deactivate( _bDeactivateController ); |
3513 | 32 | } |
3514 | | |
3515 | | // if we have an async load operation pending for the 0-th page for this view, |
3516 | | // we need to cancel this |
3517 | 8.87k | if (FmFormPage* pPage = _rCurrentView.GetCurPage()) |
3518 | 8.87k | { |
3519 | | // move all events from our queue to a new one, omit the events for the deactivated |
3520 | | // page |
3521 | 8.87k | ::std::queue< FmLoadAction > aNewEvents; |
3522 | 8.91k | while ( !m_aLoadingPages.empty() ) |
3523 | 32 | { |
3524 | 32 | FmLoadAction aAction = m_aLoadingPages.front(); |
3525 | 32 | m_aLoadingPages.pop(); |
3526 | 32 | if ( pPage != aAction.pPage ) |
3527 | 0 | { |
3528 | 0 | aNewEvents.push( aAction ); |
3529 | 0 | } |
3530 | 32 | else |
3531 | 32 | { |
3532 | 32 | Application::RemoveUserEvent( aAction.nEventId ); |
3533 | 32 | } |
3534 | 32 | } |
3535 | 8.87k | m_aLoadingPages = std::move(aNewEvents); |
3536 | | |
3537 | | // remove callbacks at the page |
3538 | 8.87k | pPage->GetImpl().SetFormsCreationHdl( Link<FmFormPageImpl&,void>() ); |
3539 | 8.87k | } |
3540 | 8.87k | UpdateForms_Lock(true); |
3541 | 8.87k | } |
3542 | | |
3543 | | |
3544 | | IMPL_LINK_NOARG( FmXFormShell, OnFirstTimeActivation_Lock, void*, void ) |
3545 | 0 | { |
3546 | 0 | if (impl_checkDisposed_Lock()) |
3547 | 0 | return; |
3548 | | |
3549 | 0 | m_nActivationEvent = nullptr; |
3550 | 0 | SfxObjectShell* pDocument = m_pShell->GetObjectShell(); |
3551 | |
|
3552 | 0 | if ( pDocument && !pDocument->HasName() ) |
3553 | 0 | { |
3554 | 0 | if (isEnhancedForm_Lock()) |
3555 | 0 | { |
3556 | | // show the data navigator |
3557 | 0 | if ( !m_pShell->GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_SHOW_DATANAVIGATOR ) ) |
3558 | 0 | m_pShell->GetViewShell()->GetViewFrame().ToggleChildWindow( SID_FM_SHOW_DATANAVIGATOR ); |
3559 | 0 | } |
3560 | 0 | } |
3561 | 0 | } |
3562 | | |
3563 | | |
3564 | | IMPL_LINK_NOARG( FmXFormShell, OnFormsCreated_Lock, FmFormPageImpl&, void ) |
3565 | 0 | { |
3566 | 0 | UpdateForms_Lock(true); |
3567 | 0 | } |
3568 | | |
3569 | | |
3570 | | void FmXFormShell::viewActivated_Lock(FmFormView& _rCurrentView, bool _bSyncAction) |
3571 | 8.87k | { |
3572 | 8.87k | FmFormPage* pPage = _rCurrentView.GetCurPage(); |
3573 | | |
3574 | | // activate our view if we are activated ourself |
3575 | | // FS - 30.06.99 - 67308 |
3576 | 8.87k | if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() ) |
3577 | 32 | { |
3578 | | // load forms for the page the current view belongs to |
3579 | 32 | if ( pPage ) |
3580 | 32 | { |
3581 | 32 | if ( !pPage->GetImpl().hasEverBeenActivated() ) |
3582 | 32 | loadForms_Lock(pPage, LoadFormsFlags::Load |
3583 | 32 | | (_bSyncAction ? LoadFormsFlags::Sync |
3584 | 32 | : LoadFormsFlags::Async)); |
3585 | 32 | pPage->GetImpl().setHasBeenActivated( ); |
3586 | 32 | } |
3587 | | |
3588 | | // first-time initializations for the views |
3589 | 32 | if ( !_rCurrentView.GetImpl()->hasEverBeenActivated( ) ) |
3590 | 32 | { |
3591 | 32 | auto* pFormModel = dynamic_cast<FmFormModel*>(&_rCurrentView.GetModel()); |
3592 | 32 | _rCurrentView.GetImpl()->onFirstViewActivation(pFormModel); |
3593 | 32 | _rCurrentView.GetImpl()->setHasBeenActivated(); |
3594 | 32 | } |
3595 | | |
3596 | | // activate the current view |
3597 | 32 | _rCurrentView.GetImpl()->Activate( _bSyncAction ); |
3598 | 32 | } |
3599 | | |
3600 | | // set callbacks at the page |
3601 | 8.87k | if ( pPage ) |
3602 | 8.87k | { |
3603 | 8.87k | pPage->GetImpl().SetFormsCreationHdl(LINK(this, FmXFormShell, OnFormsCreated_Lock)); |
3604 | 8.87k | } |
3605 | | |
3606 | 8.87k | UpdateForms_Lock(true); |
3607 | | |
3608 | 8.87k | if ( m_bFirstActivation ) |
3609 | 8.87k | { |
3610 | 8.87k | m_nActivationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnFirstTimeActivation_Lock)); |
3611 | 8.87k | m_bFirstActivation = false; |
3612 | 8.87k | } |
3613 | | |
3614 | | // find a default "current form", if there is none, yet |
3615 | | // #i88186# / 2008-04-12 / frank.schoenheit@sun.com |
3616 | 8.87k | impl_defaultCurrentForm_nothrow_Lock(); |
3617 | 8.87k | } |
3618 | | |
3619 | | |
3620 | | void FmXFormShell::impl_defaultCurrentForm_nothrow_Lock() |
3621 | 8.87k | { |
3622 | 8.87k | if (impl_checkDisposed_Lock()) |
3623 | 0 | return; |
3624 | | |
3625 | 8.87k | if ( m_xCurrentForm.is() ) |
3626 | | // no action required |
3627 | 0 | return; |
3628 | | |
3629 | 8.87k | FmFormView* pFormView = m_pShell->GetFormView(); |
3630 | 8.87k | FmFormPage* pPage = pFormView ? pFormView->GetCurPage() : nullptr; |
3631 | 8.87k | if ( !pPage ) |
3632 | 0 | return; |
3633 | | |
3634 | 8.87k | try |
3635 | 8.87k | { |
3636 | 8.87k | Reference< XIndexAccess > xForms = pPage->GetForms( false ); |
3637 | 8.87k | if ( !xForms.is() || !xForms->hasElements() ) |
3638 | 8.87k | return; |
3639 | | |
3640 | 0 | Reference< XForm > xNewCurrentForm( xForms->getByIndex(0), UNO_QUERY_THROW ); |
3641 | 0 | impl_updateCurrentForm_Lock(xNewCurrentForm); |
3642 | 0 | } |
3643 | 8.87k | catch( const Exception& ) |
3644 | 8.87k | { |
3645 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
3646 | 0 | } |
3647 | 8.87k | } |
3648 | | |
3649 | | |
3650 | | void FmXFormShell::smartControlReset( const Reference< XIndexAccess >& _rxModels ) |
3651 | 0 | { |
3652 | 0 | if (!_rxModels.is()) |
3653 | 0 | { |
3654 | 0 | OSL_FAIL("FmXFormShell::smartControlReset: invalid container!"); |
3655 | 0 | return; |
3656 | 0 | } |
3657 | | |
3658 | 0 | sal_Int32 nCount = _rxModels->getCount(); |
3659 | 0 | Reference< XPropertySet > xCurrent; |
3660 | 0 | Reference< XPropertySetInfo > xCurrentInfo; |
3661 | 0 | Reference< XPropertySet > xBoundField; |
3662 | |
|
3663 | 0 | for (sal_Int32 i=0; i<nCount; ++i) |
3664 | 0 | { |
3665 | 0 | _rxModels->getByIndex(i) >>= xCurrent; |
3666 | 0 | if (xCurrent.is()) |
3667 | 0 | xCurrentInfo = xCurrent->getPropertySetInfo(); |
3668 | 0 | else |
3669 | 0 | xCurrentInfo.clear(); |
3670 | 0 | if (!xCurrentInfo.is()) |
3671 | 0 | continue; |
3672 | | |
3673 | 0 | if (xCurrentInfo->hasPropertyByName(FM_PROP_CLASSID)) |
3674 | 0 | { // it's a control model |
3675 | | |
3676 | | // check if this control is bound to a living database field |
3677 | 0 | if (xCurrentInfo->hasPropertyByName(FM_PROP_BOUNDFIELD)) |
3678 | 0 | xCurrent->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xBoundField; |
3679 | 0 | else |
3680 | 0 | xBoundField.clear(); |
3681 | | |
3682 | | // reset only if it's *not* bound |
3683 | 0 | bool bReset = !xBoundField.is(); |
3684 | | |
3685 | | // and additionally, check if it has an external value binding |
3686 | 0 | Reference< XBindableValue > xBindable( xCurrent, UNO_QUERY ); |
3687 | 0 | if ( xBindable.is() && xBindable->getValueBinding().is() ) |
3688 | 0 | bReset = false; |
3689 | |
|
3690 | 0 | if ( bReset ) |
3691 | 0 | { |
3692 | 0 | Reference< XReset > xControlReset( xCurrent, UNO_QUERY ); |
3693 | 0 | if ( xControlReset.is() ) |
3694 | 0 | xControlReset->reset(); |
3695 | 0 | } |
3696 | 0 | } |
3697 | 0 | else |
3698 | 0 | { |
3699 | 0 | Reference< XIndexAccess > xContainer(xCurrent, UNO_QUERY); |
3700 | 0 | if (xContainer.is()) |
3701 | 0 | smartControlReset(xContainer); |
3702 | 0 | } |
3703 | 0 | } |
3704 | 0 | } |
3705 | | |
3706 | | |
3707 | | IMPL_LINK_NOARG( FmXFormShell, OnLoadForms_Lock, void*, void ) |
3708 | 0 | { |
3709 | 0 | FmLoadAction aAction = m_aLoadingPages.front(); |
3710 | 0 | m_aLoadingPages.pop(); |
3711 | |
|
3712 | 0 | loadForms_Lock(aAction.pPage, aAction.nFlags & ~LoadFormsFlags::Async); |
3713 | 0 | } |
3714 | | |
3715 | | |
3716 | | namespace |
3717 | | { |
3718 | | bool lcl_isLoadable( const Reference< XInterface >& _rxLoadable ) |
3719 | 0 | { |
3720 | | // determines whether a form should be loaded or not |
3721 | | // if there is no datasource or connection there is no reason to load a form |
3722 | 0 | Reference< XPropertySet > xSet( _rxLoadable, UNO_QUERY ); |
3723 | 0 | if ( !xSet.is() ) |
3724 | 0 | return false; |
3725 | 0 | try |
3726 | 0 | { |
3727 | 0 | Reference< XConnection > xConn; |
3728 | 0 | if ( isEmbeddedInDatabase( _rxLoadable, xConn ) ) |
3729 | 0 | return true; |
3730 | | |
3731 | | // is there already an active connection |
3732 | 0 | xSet->getPropertyValue(FM_PROP_ACTIVE_CONNECTION) >>= xConn; |
3733 | 0 | if ( xConn.is() ) |
3734 | 0 | return true; |
3735 | | |
3736 | 0 | OUString sPropertyValue; |
3737 | 0 | OSL_VERIFY( xSet->getPropertyValue( FM_PROP_DATASOURCE ) >>= sPropertyValue ); |
3738 | 0 | if ( !sPropertyValue.isEmpty() ) |
3739 | 0 | return true; |
3740 | | |
3741 | 0 | OSL_VERIFY( xSet->getPropertyValue( FM_PROP_URL ) >>= sPropertyValue ); |
3742 | 0 | if ( !sPropertyValue.isEmpty() ) |
3743 | 0 | return true; |
3744 | 0 | } |
3745 | 0 | catch(const Exception&) |
3746 | 0 | { |
3747 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
3748 | 0 | } |
3749 | 0 | return false; |
3750 | 0 | } |
3751 | | } |
3752 | | |
3753 | | |
3754 | | void FmXFormShell::loadForms_Lock(FmFormPage* _pPage, const LoadFormsFlags _nBehaviour /* LoadFormsFlags::Load | LoadFormsFlags::Sync */) |
3755 | 32 | { |
3756 | 32 | DBG_ASSERT( ( _nBehaviour & ( LoadFormsFlags::Async | LoadFormsFlags::Unload ) ) != ( LoadFormsFlags::Async | LoadFormsFlags::Unload ), |
3757 | 32 | "FmXFormShell::loadForms: async loading not supported - this will heavily fail!" ); |
3758 | | |
3759 | 32 | if ( _nBehaviour & LoadFormsFlags::Async ) |
3760 | 32 | { |
3761 | 32 | m_aLoadingPages.push( FmLoadAction( |
3762 | 32 | _pPage, |
3763 | 32 | _nBehaviour, |
3764 | 32 | Application::PostUserEvent(LINK(this, FmXFormShell, OnLoadForms_Lock), _pPage) |
3765 | 32 | ) ); |
3766 | 32 | return; |
3767 | 32 | } |
3768 | | |
3769 | 0 | DBG_ASSERT( _pPage, "FmXFormShell::loadForms: invalid page!" ); |
3770 | 0 | if ( !_pPage ) |
3771 | 0 | return; |
3772 | | |
3773 | | // lock the undo env so the forms can change non-transient properties while loading |
3774 | | // (without this my doc's modified flag would be set) |
3775 | 0 | FmFormModel& rFmFormModel(dynamic_cast< FmFormModel& >(_pPage->getSdrModelFromSdrPage())); |
3776 | 0 | rFmFormModel.GetUndoEnv().Lock(); |
3777 | | |
3778 | | // load all forms |
3779 | 0 | Reference< XIndexAccess > xForms = _pPage->GetForms( false ); |
3780 | |
|
3781 | 0 | if ( xForms.is() ) |
3782 | 0 | { |
3783 | 0 | Reference< XLoadable > xForm; |
3784 | 0 | for ( sal_Int32 j = 0, nCount = xForms->getCount(); j < nCount; ++j ) |
3785 | 0 | { |
3786 | 0 | xForms->getByIndex( j ) >>= xForm; |
3787 | 0 | bool bFormWasLoaded = false; |
3788 | | // a database form must be loaded for |
3789 | 0 | try |
3790 | 0 | { |
3791 | 0 | if ( !( _nBehaviour & LoadFormsFlags::Unload ) ) |
3792 | 0 | { |
3793 | 0 | if ( lcl_isLoadable( xForm ) && !xForm->isLoaded() ) |
3794 | 0 | xForm->load(); |
3795 | 0 | } |
3796 | 0 | else |
3797 | 0 | { |
3798 | 0 | if ( xForm->isLoaded() ) |
3799 | 0 | { |
3800 | 0 | bFormWasLoaded = true; |
3801 | 0 | xForm->unload(); |
3802 | 0 | } |
3803 | 0 | } |
3804 | 0 | } |
3805 | 0 | catch( const Exception& ) |
3806 | 0 | { |
3807 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
3808 | 0 | } |
3809 | | |
3810 | | // reset the form if it was loaded |
3811 | 0 | if ( bFormWasLoaded ) |
3812 | 0 | { |
3813 | 0 | Reference< XIndexAccess > xContainer( xForm, UNO_QUERY ); |
3814 | 0 | DBG_ASSERT( xContainer.is(), "FmXFormShell::loadForms: the form is no container!" ); |
3815 | 0 | if ( xContainer.is() ) |
3816 | 0 | smartControlReset( xContainer ); |
3817 | 0 | } |
3818 | 0 | } |
3819 | 0 | } |
3820 | | |
3821 | | // unlock the environment |
3822 | 0 | rFmFormModel.GetUndoEnv().UnLock(); |
3823 | 0 | } |
3824 | | |
3825 | | |
3826 | | void FmXFormShell::ExecuteTextAttribute_Lock(SfxRequest& _rReq) |
3827 | 0 | { |
3828 | 0 | DBG_TESTSOLARMUTEX(); |
3829 | 0 | m_pTextShell->ExecuteTextAttribute( _rReq ); |
3830 | 0 | } |
3831 | | |
3832 | | |
3833 | | void FmXFormShell::GetTextAttributeState_Lock(SfxItemSet& _rSet) |
3834 | 0 | { |
3835 | 0 | DBG_TESTSOLARMUTEX(); |
3836 | 0 | m_pTextShell->GetTextAttributeState( _rSet ); |
3837 | 0 | } |
3838 | | |
3839 | | |
3840 | | bool FmXFormShell::IsActiveControl_Lock(bool _bCountRichTextOnly ) const |
3841 | 34.2k | { |
3842 | 34.2k | DBG_TESTSOLARMUTEX(); |
3843 | 34.2k | return m_pTextShell->IsActiveControl( _bCountRichTextOnly ); |
3844 | 34.2k | } |
3845 | | |
3846 | | |
3847 | | void FmXFormShell::ForgetActiveControl_Lock() |
3848 | 0 | { |
3849 | 0 | DBG_TESTSOLARMUTEX(); |
3850 | 0 | m_pTextShell->ForgetActiveControl(); |
3851 | 0 | } |
3852 | | |
3853 | | |
3854 | | void FmXFormShell::SetControlActivationHandler_Lock(const Link<LinkParamNone*,void>& _rHdl) |
3855 | 8.87k | { |
3856 | 8.87k | DBG_TESTSOLARMUTEX(); |
3857 | 8.87k | m_pTextShell->SetControlActivationHandler( _rHdl ); |
3858 | 8.87k | } |
3859 | | |
3860 | | void FmXFormShell::handleShowPropertiesRequest_Lock() |
3861 | 0 | { |
3862 | 0 | if (onlyControlsAreMarked_Lock()) |
3863 | 0 | ShowSelectionProperties_Lock( true ); |
3864 | 0 | } |
3865 | | |
3866 | | |
3867 | | void FmXFormShell::handleMouseButtonDown_Lock(const SdrViewEvent& _rViewEvent) |
3868 | 0 | { |
3869 | | // catch simple double clicks |
3870 | 0 | if (_rViewEvent.mnMouseClicks == 2 && _rViewEvent.mnMouseCode == MOUSE_LEFT) |
3871 | 0 | { |
3872 | 0 | if ( _rViewEvent.meHit == SdrHitKind::MarkedObject ) |
3873 | 0 | { |
3874 | 0 | if (onlyControlsAreMarked_Lock()) |
3875 | 0 | ShowSelectionProperties_Lock( true ); |
3876 | 0 | } |
3877 | 0 | } |
3878 | 0 | } |
3879 | | |
3880 | | |
3881 | | bool FmXFormShell::HasControlFocus_Lock() const |
3882 | 0 | { |
3883 | 0 | bool bHasControlFocus = false; |
3884 | |
|
3885 | 0 | try |
3886 | 0 | { |
3887 | 0 | Reference<runtime::XFormController> xController(getActiveController_Lock()); |
3888 | 0 | Reference< XControl > xCurrentControl; |
3889 | 0 | if ( xController.is() ) |
3890 | 0 | xCurrentControl.set( xController->getCurrentControl() ); |
3891 | 0 | if ( xCurrentControl.is() ) |
3892 | 0 | { |
3893 | 0 | Reference< XWindow2 > xPeerWindow( xCurrentControl->getPeer(), UNO_QUERY_THROW ); |
3894 | 0 | bHasControlFocus = xPeerWindow->hasFocus(); |
3895 | 0 | } |
3896 | 0 | } |
3897 | 0 | catch( const Exception& ) |
3898 | 0 | { |
3899 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
3900 | 0 | } |
3901 | |
|
3902 | 0 | return bHasControlFocus; |
3903 | 0 | } |
3904 | | |
3905 | | |
3906 | | SearchableControlIterator::SearchableControlIterator(Reference< XInterface> const & xStartingPoint) |
3907 | 0 | :IndexAccessIterator(xStartingPoint) |
3908 | 0 | { |
3909 | 0 | } |
3910 | | |
3911 | | |
3912 | | bool SearchableControlIterator::ShouldHandleElement(const Reference< XInterface>& xElement) |
3913 | 0 | { |
3914 | | // if the thing has a ControlSource and a BoundField property |
3915 | 0 | Reference< XPropertySet> xProperties(xElement, UNO_QUERY); |
3916 | 0 | if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties)) |
3917 | 0 | { |
3918 | | // and the BoundField is valid |
3919 | 0 | Reference< XPropertySet> xField; |
3920 | 0 | xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField; |
3921 | 0 | if (xField.is()) |
3922 | 0 | { |
3923 | | // we take it |
3924 | 0 | m_sCurrentValue = ::comphelper::getString(xProperties->getPropertyValue(FM_PROP_CONTROLSOURCE)); |
3925 | 0 | return true; |
3926 | 0 | } |
3927 | 0 | } |
3928 | | |
3929 | | // if it is a grid control |
3930 | 0 | if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties)) |
3931 | 0 | { |
3932 | 0 | Any aClassId( xProperties->getPropertyValue(FM_PROP_CLASSID) ); |
3933 | 0 | if (::comphelper::getINT16(aClassId) == FormComponentType::GRIDCONTROL) |
3934 | 0 | { |
3935 | 0 | m_sCurrentValue.clear(); |
3936 | 0 | return true; |
3937 | 0 | } |
3938 | 0 | } |
3939 | | |
3940 | 0 | return false; |
3941 | 0 | } |
3942 | | |
3943 | | |
3944 | | bool SearchableControlIterator::ShouldStepInto(const Reference< XInterface>& /*xContainer*/) const |
3945 | 0 | { |
3946 | 0 | return true; |
3947 | 0 | } |
3948 | | |
3949 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |