/src/libreoffice/sfx2/source/control/shell.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 <com/sun/star/embed/VerbDescriptor.hpp> |
21 | | #include <com/sun/star/embed/VerbAttributes.hpp> |
22 | | #include <com/sun/star/lang/XInitialization.hpp> |
23 | | #include <officecfg/Office/Common.hxx> |
24 | | #include <rtl/ustring.hxx> |
25 | | #include <sal/log.hxx> |
26 | | #include <osl/diagnose.h> |
27 | | #include <svl/itempool.hxx> |
28 | | #include <svl/setitem.hxx> |
29 | | #include <svl/voiditem.hxx> |
30 | | #include <svl/undo.hxx> |
31 | | #include <svtools/asynclink.hxx> |
32 | | #include <unotools/configmgr.hxx> |
33 | | #include <comphelper/lok.hxx> |
34 | | #include <comphelper/propertysequence.hxx> |
35 | | #include <sfx2/shell.hxx> |
36 | | #include <sfx2/bindings.hxx> |
37 | | #include <sfx2/dispatch.hxx> |
38 | | #include <sfx2/viewfrm.hxx> |
39 | | #include <sfx2/objface.hxx> |
40 | | #include <sfx2/objsh.hxx> |
41 | | #include <sfx2/viewsh.hxx> |
42 | | #include <sfx2/request.hxx> |
43 | | #include <sfx2/sfxsids.hrc> |
44 | | #include <statcach.hxx> |
45 | | #include <sidebar/ContextChangeBroadcaster.hxx> |
46 | | #include <com/sun/star/ui/dialogs/XSLTFilterDialog.hpp> |
47 | | #include <toolkit/helper/vclunohelper.hxx> |
48 | | #include <tools/debug.hxx> |
49 | | |
50 | | #include <memory> |
51 | | #include <vector> |
52 | | #include <map> |
53 | | |
54 | | #include <desktop/crashreport.hxx> |
55 | | |
56 | | using namespace com::sun::star; |
57 | | |
58 | | struct SfxShell_Impl: public SfxBroadcaster |
59 | | { |
60 | | OUString aObjectName; // Name of Sbx-Objects |
61 | | // Maps the Which() field to a pointer to a SfxPoolItem |
62 | | std::map<sal_uInt16, std::unique_ptr<SfxPoolItem>> |
63 | | m_Items; // Data exchange on Item level |
64 | | SfxViewShell* pViewSh; // SfxViewShell if Shell is |
65 | | // ViewFrame/ViewShell/SubShell list |
66 | | SfxViewFrame* pFrame; // Frame, if <UI-active> |
67 | | SfxRepeatTarget* pRepeatTarget; // SbxObjectRef xParent; |
68 | | bool bActive; |
69 | | SfxDisableFlags nDisableFlags; |
70 | | std::unique_ptr<svtools::AsynchronLink> pExecuter; |
71 | | std::unique_ptr<svtools::AsynchronLink> pUpdater; |
72 | | std::vector<std::unique_ptr<SfxSlot> > aSlotArr; |
73 | | |
74 | | css::uno::Sequence < css::embed::VerbDescriptor > aVerbList; |
75 | | ::sfx2::sidebar::ContextChangeBroadcaster maContextChangeBroadcaster; |
76 | | |
77 | | SfxShell_Impl() |
78 | 228k | : pViewSh(nullptr) |
79 | 228k | , pFrame(nullptr) |
80 | 228k | , pRepeatTarget(nullptr) |
81 | 228k | , bActive(false) |
82 | 228k | , nDisableFlags(SfxDisableFlags::NONE) |
83 | 228k | { |
84 | 228k | } |
85 | | |
86 | 227k | virtual ~SfxShell_Impl() override { pExecuter.reset(); pUpdater.reset();} |
87 | | }; |
88 | | |
89 | | |
90 | | void SfxShell::EmptyExecStub(SfxShell *, SfxRequest &) |
91 | 0 | { |
92 | 0 | } |
93 | | |
94 | | void SfxShell::EmptyStateStub(SfxShell *, SfxItemSet &) |
95 | 0 | { |
96 | 0 | } |
97 | | |
98 | | SfxShell::SfxShell() |
99 | 211k | : pImpl(new SfxShell_Impl), |
100 | 211k | pPool(nullptr), |
101 | 211k | pUndoMgr(nullptr) |
102 | 211k | { |
103 | 211k | } |
104 | | |
105 | | SfxShell::SfxShell( SfxViewShell *pViewSh ) |
106 | 16.3k | : pImpl(new SfxShell_Impl), |
107 | 16.3k | pPool(nullptr), |
108 | 16.3k | pUndoMgr(nullptr) |
109 | 16.3k | { |
110 | 16.3k | pImpl->pViewSh = pViewSh; |
111 | 16.3k | } |
112 | | |
113 | | SfxShell::~SfxShell() |
114 | 227k | { |
115 | 227k | } |
116 | | |
117 | | void SfxShell::SetName( const OUString &rName ) |
118 | 55.3k | { |
119 | 55.3k | pImpl->aObjectName = rName; |
120 | 55.3k | } |
121 | | |
122 | | const OUString& SfxShell::GetName() const |
123 | 177k | { |
124 | 177k | return pImpl->aObjectName; |
125 | 177k | } |
126 | | |
127 | | SfxDispatcher* SfxShell::GetDispatcher() const |
128 | 306k | { |
129 | 306k | return pImpl->pFrame ? pImpl->pFrame->GetDispatcher() : nullptr; |
130 | 306k | } |
131 | | |
132 | | SfxViewShell* SfxShell::GetViewShell() const |
133 | 447k | { |
134 | 447k | return pImpl->pViewSh; |
135 | 447k | } |
136 | | |
137 | | SfxViewFrame* SfxShell::GetFrame() const |
138 | 132k | { |
139 | 132k | if ( pImpl->pFrame ) |
140 | 28.6k | return pImpl->pFrame; |
141 | 103k | if ( pImpl->pViewSh ) |
142 | 24.5k | return &pImpl->pViewSh->GetViewFrame(); |
143 | 79.4k | return nullptr; |
144 | 103k | } |
145 | | |
146 | | const SfxPoolItem* SfxShell::GetItem |
147 | | ( |
148 | | sal_uInt16 nSlotId // Slot-Id of the querying <SfxPoolItem>s |
149 | | ) const |
150 | 126k | { |
151 | 126k | auto const it = pImpl->m_Items.find( nSlotId ); |
152 | 126k | if (it != pImpl->m_Items.end()) |
153 | 29.3k | return it->second.get(); |
154 | 97.0k | return nullptr; |
155 | 126k | } |
156 | | |
157 | | void SfxShell::PutItem |
158 | | ( |
159 | | const SfxPoolItem& rItem /* Instance, of which a copy is created, |
160 | | which is stored in the SfxShell in a list. */ |
161 | | ) |
162 | 1.12M | { |
163 | 1.12M | DBG_ASSERT( !rItem.isSetItem(), "SetItems aren't allowed here" ); |
164 | 1.12M | DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ), |
165 | 1.12M | "items with Which-Ids aren't allowed here" ); |
166 | | |
167 | | // MSC made a mess here of WNT/W95, beware of changes |
168 | 1.12M | SfxPoolItem *pItem = rItem.Clone(); |
169 | 1.12M | SfxPoolItemHint aItemHint( pItem ); |
170 | 1.12M | sal_uInt16 nWhich = rItem.Which(); |
171 | | |
172 | 1.12M | auto const it = pImpl->m_Items.find(nWhich); |
173 | 1.12M | if (it != pImpl->m_Items.end()) |
174 | 94.6k | { |
175 | | // Replace Item |
176 | 94.6k | it->second = std::unique_ptr<SfxPoolItem>(pItem); |
177 | | |
178 | | // if active, notify Bindings |
179 | 94.6k | SfxDispatcher *pDispat = GetDispatcher(); |
180 | 94.6k | if ( pDispat ) |
181 | 116 | { |
182 | 116 | SfxBindings* pBindings = pDispat->GetBindings(); |
183 | 116 | pBindings->Broadcast( aItemHint ); |
184 | 116 | sal_uInt16 nSlotId = nWhich; //pItem->GetSlotId(); |
185 | 116 | SfxStateCache* pCache = pBindings->GetStateCache( nSlotId ); |
186 | 116 | if ( pCache ) |
187 | 0 | { |
188 | 0 | pCache->SetState( SfxItemState::DEFAULT, pItem, true ); |
189 | 0 | pCache->SetCachedState( true ); |
190 | 0 | } |
191 | 116 | } |
192 | 94.6k | return; |
193 | 94.6k | } |
194 | 1.03M | else |
195 | 1.03M | { |
196 | 1.03M | Broadcast( aItemHint ); |
197 | 1.03M | pImpl->m_Items.insert(std::make_pair(nWhich, std::unique_ptr<SfxPoolItem>(pItem))); |
198 | 1.03M | } |
199 | 1.12M | } |
200 | | |
201 | | SfxInterface* SfxShell::GetInterface() const |
202 | 0 | { |
203 | 0 | return GetStaticInterface(); |
204 | 0 | } |
205 | | |
206 | | SfxUndoManager* SfxShell::GetUndoManager() |
207 | 0 | { |
208 | 0 | return pUndoMgr; |
209 | 0 | } |
210 | | |
211 | | void SfxShell::SetUndoManager( SfxUndoManager *pNewUndoMgr ) |
212 | 154k | { |
213 | 154k | OSL_ENSURE( ( pUndoMgr == nullptr ) || ( pNewUndoMgr == nullptr ) || ( pUndoMgr == pNewUndoMgr ), |
214 | 154k | "SfxShell::SetUndoManager: exchanging one non-NULL manager with another non-NULL manager? Suspicious!" ); |
215 | | // there's at least one client of our UndoManager - the DocumentUndoManager at the SfxBaseModel - which |
216 | | // caches the UndoManager, and registers itself as listener. If exchanging non-NULL UndoManagers is really |
217 | | // a supported scenario (/me thinks it is not), then we would need to notify all such clients instances. |
218 | | |
219 | 154k | pUndoMgr = pNewUndoMgr; |
220 | 154k | if (pUndoMgr && !comphelper::IsFuzzing()) |
221 | 0 | { |
222 | 0 | pUndoMgr->SetMaxUndoActionCount( |
223 | 0 | officecfg::Office::Common::Undo::Steps::get()); |
224 | 0 | } |
225 | 154k | } |
226 | | |
227 | | SfxRepeatTarget* SfxShell::GetRepeatTarget() const |
228 | 0 | { |
229 | 0 | return pImpl->pRepeatTarget; |
230 | 0 | } |
231 | | |
232 | | void SfxShell::SetRepeatTarget( SfxRepeatTarget *pTarget ) |
233 | 0 | { |
234 | 0 | pImpl->pRepeatTarget = pTarget; |
235 | 0 | } |
236 | | |
237 | | void SfxShell::Invalidate |
238 | | ( |
239 | | sal_uInt16 nId /* Invalidated Slot-Id or Which-Id. |
240 | | If these are 0 (default), then all |
241 | | by this Shell currently handled Slot-Ids are |
242 | | invalidated. */ |
243 | | ) |
244 | 668 | { |
245 | 668 | if ( !GetViewShell() ) |
246 | 0 | { |
247 | 0 | OSL_FAIL( "wrong Invalidate method called!" ); |
248 | 0 | return; |
249 | 0 | } |
250 | | |
251 | 668 | Invalidate_Impl( GetViewShell()->GetViewFrame().GetBindings(), nId ); |
252 | 668 | } |
253 | | |
254 | | void SfxShell::Invalidate_Impl( SfxBindings& rBindings, sal_uInt16 nId ) |
255 | 668 | { |
256 | 668 | if ( nId == 0 ) |
257 | 0 | { |
258 | 0 | rBindings.InvalidateShell( *this ); |
259 | 0 | } |
260 | 668 | else |
261 | 668 | { |
262 | 668 | const SfxInterface *pIF = GetInterface(); |
263 | 668 | do |
264 | 668 | { |
265 | 668 | const SfxSlot *pSlot = pIF->GetSlot(nId); |
266 | 668 | if ( pSlot ) |
267 | 668 | { |
268 | | // Invalidate the Slot itself |
269 | 668 | rBindings.Invalidate( pSlot->GetSlotId() ); |
270 | 668 | return; |
271 | 668 | } |
272 | | |
273 | 0 | pIF = pIF->GetGenoType(); |
274 | 0 | } |
275 | | |
276 | 668 | while ( pIF ); |
277 | | |
278 | 0 | SAL_INFO( "sfx.control", "W3: invalidating slot-id unknown in shell" ); |
279 | 0 | } |
280 | 668 | } |
281 | | |
282 | | void SfxShell::HandleOpenXmlFilterSettings(SfxRequest & rReq) |
283 | 0 | { |
284 | 0 | try |
285 | 0 | { |
286 | 0 | uno::Reference < ui::dialogs::XExecutableDialog > xDialog = ui::dialogs::XSLTFilterDialog::create( ::comphelper::getProcessComponentContext() ); |
287 | | |
288 | | // set dialog parent |
289 | 0 | css::uno::Reference<com::sun::star::lang::XInitialization> xInit(xDialog, |
290 | 0 | css::uno::UNO_QUERY); |
291 | 0 | if (xInit.is()) |
292 | 0 | { |
293 | 0 | if (SfxViewShell* pViewShell = GetViewShell()) |
294 | 0 | { |
295 | 0 | css::uno::Reference<css::awt::XWindow> xDialogParent |
296 | 0 | = VCLUnoHelper::GetInterface(pViewShell->GetWindow()); |
297 | 0 | css::uno::Sequence<css::uno::Any> aSeq(comphelper::InitAnyPropertySequence( |
298 | 0 | { { "ParentWindow", uno::Any(xDialogParent) } })); |
299 | 0 | xInit->initialize(aSeq); |
300 | 0 | } |
301 | 0 | } |
302 | |
|
303 | 0 | (void)xDialog->execute(); |
304 | 0 | } |
305 | 0 | catch (const uno::Exception&) |
306 | 0 | { |
307 | 0 | } |
308 | 0 | rReq.Ignore (); |
309 | 0 | } |
310 | | |
311 | | void SfxShell::DoActivate_Impl( SfxViewFrame *pFrame, bool bMDI ) |
312 | 32.6k | { |
313 | 32.6k | SfxObjectShell* pObjectShell = GetObjectShell(); |
314 | 32.6k | if ( pObjectShell ) |
315 | 24.5k | { |
316 | 24.5k | const OUString sActiveDocName = pObjectShell->GetTitle(); |
317 | 24.5k | if( !pImpl->aObjectName.startsWith(sActiveDocName) ) |
318 | 16.3k | { |
319 | 16.3k | CrashReporter::setActiveSfxObjectName(pImpl->aObjectName); |
320 | 16.3k | } |
321 | 24.5k | } |
322 | 8.16k | else |
323 | 8.16k | { |
324 | 8.16k | CrashReporter::setActiveSfxObjectName(pImpl->aObjectName); |
325 | 8.16k | } |
326 | | |
327 | | #ifdef DBG_UTIL |
328 | | const SfxInterface *p_IF = GetInterface(); |
329 | | if ( !p_IF ) |
330 | | return; |
331 | | #endif |
332 | 32.6k | SAL_INFO( |
333 | 32.6k | "sfx.control", |
334 | 32.6k | "SfxShell::DoActivate() " << this << " " << GetInterface()->GetClassName() |
335 | 32.6k | << " bMDI " << (bMDI ? "MDI" : "")); |
336 | | |
337 | 32.6k | if ( bMDI ) |
338 | 32.6k | { |
339 | | // Remember Frame, in which it was activated |
340 | 32.6k | pImpl->pFrame = pFrame; |
341 | 32.6k | pImpl->bActive = true; |
342 | 32.6k | } |
343 | | |
344 | | // Notify Subclass |
345 | 32.6k | Activate(bMDI); |
346 | 32.6k | } |
347 | | |
348 | | void SfxShell::DoDeactivate_Impl( SfxViewFrame const *pFrame, bool bMDI ) |
349 | 36.7k | { |
350 | | #ifdef DBG_UTIL |
351 | | const SfxInterface *p_IF = GetInterface(); |
352 | | if ( !p_IF ) |
353 | | return; |
354 | | #endif |
355 | 36.7k | SAL_INFO( |
356 | 36.7k | "sfx.control", |
357 | 36.7k | "SfxShell::DoDeactivate()" << this << " " << GetInterface()->GetClassName() |
358 | 36.7k | << " bMDI " << (bMDI ? "MDI" : "")); |
359 | | |
360 | | // Only when it comes from a Frame |
361 | | // (not when for instance by popping BASIC-IDE from AppDisp) |
362 | 36.7k | if ( bMDI && pImpl->pFrame == pFrame ) |
363 | 32.6k | { |
364 | | // deliver |
365 | 32.6k | pImpl->pFrame = nullptr; |
366 | 32.6k | pImpl->bActive = false; |
367 | 32.6k | } |
368 | | |
369 | | // Notify Subclass |
370 | 36.7k | Deactivate(bMDI); |
371 | 36.7k | } |
372 | | |
373 | | bool SfxShell::IsActive() const |
374 | 8.16k | { |
375 | 8.16k | return pImpl->bActive; |
376 | 8.16k | } |
377 | | |
378 | | void SfxShell::Activate |
379 | | ( |
380 | | bool /*bMDI*/ /* TRUE |
381 | | the <SfxDispatcher>, on which the SfxShell is |
382 | | located, is activated or the SfxShell instance |
383 | | was pushed on an active SfxDispatcher. |
384 | | (compare with SystemWindow::IsMDIActivate()) |
385 | | |
386 | | FALSE |
387 | | the <SfxViewFrame>, on which SfxDispatcher |
388 | | the SfxShell instance is located, was |
389 | | activated. (for example by a closing dialog) */ |
390 | | ) |
391 | 24.5k | { |
392 | 24.5k | BroadcastContextForActivation(true); |
393 | 24.5k | } |
394 | | |
395 | | void SfxShell::Deactivate |
396 | | ( |
397 | | bool /*bMDI*/ /* TRUE |
398 | | the <SfxDispatcher>, on which the SfxShell is |
399 | | located, is inactivated or the SfxShell instance |
400 | | was popped on an active SfxDispatcher. |
401 | | (compare with SystemWindow::IsMDIActivate()) |
402 | | |
403 | | FALSE |
404 | | the <SfxViewFrame>, on which SfxDispatcher |
405 | | the SfxShell instance is located, was |
406 | | deactivated. (for example by a dialog) */ |
407 | | ) |
408 | 28.6k | { |
409 | 28.6k | BroadcastContextForActivation(false); |
410 | 28.6k | } |
411 | | |
412 | | bool SfxShell::CanExecuteSlot_Impl( const SfxSlot &rSlot ) |
413 | 0 | { |
414 | | // Get Slot status |
415 | 0 | SfxItemPool &rPool = GetPool(); |
416 | 0 | const sal_uInt16 nId = rSlot.GetWhich( rPool ); |
417 | 0 | SfxItemSet aSet(rPool, nId, nId); |
418 | 0 | SfxStateFunc pFunc = rSlot.GetStateFnc(); |
419 | 0 | (*pFunc)( this, aSet ); |
420 | 0 | return aSet.GetItemState(nId) != SfxItemState::DISABLED; |
421 | 0 | } |
422 | | |
423 | | bool SfxShell::IsConditionalFastCall( const SfxRequest &rReq ) |
424 | 0 | { |
425 | 0 | sal_uInt16 nId = rReq.GetSlot(); |
426 | 0 | bool bRet = false; |
427 | |
|
428 | 0 | if (nId == SID_UNDO || nId == SID_REDO) |
429 | 0 | { |
430 | 0 | const SfxItemSet* pArgs = rReq.GetArgs(); |
431 | 0 | if (pArgs && pArgs->HasItem(SID_REPAIRPACKAGE)) |
432 | 0 | bRet = true; |
433 | 0 | } |
434 | 0 | return bRet; |
435 | 0 | } |
436 | | |
437 | | |
438 | | static void ShellCall_Impl( void* pObj, void* pArg ) |
439 | 0 | { |
440 | 0 | static_cast<SfxShell*>(pObj)->ExecuteSlot( *static_cast<SfxRequest*>(pArg) ); |
441 | 0 | } |
442 | | |
443 | | void SfxShell::ExecuteSlot( SfxRequest& rReq, bool bAsync ) |
444 | 0 | { |
445 | 0 | if( !bAsync ) |
446 | 0 | ExecuteSlot( rReq ); |
447 | 0 | else |
448 | 0 | { |
449 | 0 | if( !pImpl->pExecuter ) |
450 | 0 | pImpl->pExecuter.reset( new svtools::AsynchronLink( |
451 | 0 | LINK_NONMEMBER( this, ShellCall_Impl ) ) ); |
452 | 0 | pImpl->pExecuter->Call( new SfxRequest( rReq ) ); |
453 | 0 | } |
454 | 0 | } |
455 | | |
456 | | const SfxPoolItemHolder& SfxShell::ExecuteSlot |
457 | | ( |
458 | | SfxRequest &rReq, // the relayed <SfxRequest> |
459 | | const SfxInterface* pIF // default = 0 means get virtually |
460 | | ) |
461 | 0 | { |
462 | 0 | if ( !pIF ) |
463 | 0 | pIF = GetInterface(); |
464 | |
|
465 | 0 | sal_uInt16 nSlot = rReq.GetSlot(); |
466 | 0 | const SfxSlot* pSlot = nullptr; |
467 | 0 | if ( nSlot >= SID_VERB_START && nSlot <= SID_VERB_END ) |
468 | 0 | pSlot = GetVerbSlot_Impl(nSlot); |
469 | 0 | if ( !pSlot ) |
470 | 0 | pSlot = pIF->GetSlot(nSlot); |
471 | 0 | assert(pSlot && "slot not supported"); |
472 | |
|
473 | 0 | SfxExecFunc pFunc = pSlot->GetExecFnc(); |
474 | 0 | if ( pFunc ) |
475 | 0 | (*pFunc)( this, rReq ); |
476 | |
|
477 | 0 | return rReq.GetReturnValue(); |
478 | 0 | } |
479 | | |
480 | | SfxPoolItemHolder SfxShell::GetSlotState |
481 | | ( |
482 | | sal_uInt16 nSlotId, // Slot-Id to the Slots in question |
483 | | const SfxInterface* pIF, // default = 0 means get virtually |
484 | | SfxItemSet* pStateSet // SfxItemSet of the Slot-State method |
485 | | ) |
486 | 4.08k | { |
487 | | // Get Slot on the given Interface |
488 | 4.08k | if ( !pIF ) |
489 | 4.08k | pIF = GetInterface(); |
490 | 4.08k | SfxItemState eState(SfxItemState::DEFAULT); |
491 | 4.08k | bool bItemStateSet(false); |
492 | 4.08k | SfxItemPool &rPool = GetPool(); |
493 | | |
494 | 4.08k | const SfxSlot* pSlot = nullptr; |
495 | 4.08k | if ( nSlotId >= SID_VERB_START && nSlotId <= SID_VERB_END ) |
496 | 0 | pSlot = GetVerbSlot_Impl(nSlotId); |
497 | 4.08k | if ( !pSlot ) |
498 | 4.08k | pSlot = pIF->GetSlot(nSlotId); |
499 | 4.08k | if ( pSlot ) |
500 | | // Map on Which-Id if possible |
501 | 4.08k | nSlotId = pSlot->GetWhich( rPool ); |
502 | | |
503 | | // Get Item and Item status |
504 | 4.08k | const SfxPoolItem *pItem = nullptr; |
505 | 4.08k | SfxItemSet aSet( rPool, nSlotId, nSlotId ); // else pItem dies too soon |
506 | 4.08k | if ( nullptr != pSlot ) |
507 | 4.08k | { |
508 | | // Call Status method |
509 | 4.08k | SfxStateFunc pFunc = pSlot->GetStateFnc(); |
510 | 4.08k | if ( pFunc ) |
511 | 4.08k | (*pFunc)( this, aSet ); |
512 | 4.08k | eState = aSet.GetItemState( nSlotId, true, &pItem ); |
513 | 4.08k | bItemStateSet = true; |
514 | | |
515 | | // get default Item if possible |
516 | 4.08k | if ( eState == SfxItemState::DEFAULT ) |
517 | 0 | { |
518 | 0 | if ( SfxItemPool::IsWhich(nSlotId) ) |
519 | 0 | pItem = &rPool.GetUserOrPoolDefaultItem(nSlotId); |
520 | 0 | else |
521 | 0 | eState = SfxItemState::INVALID; |
522 | 0 | } |
523 | 4.08k | } |
524 | | |
525 | | // Evaluate Item and item status and possibly maintain them in pStateSet |
526 | 4.08k | if ( !bItemStateSet || eState <= SfxItemState::DISABLED ) |
527 | 0 | { |
528 | 0 | if ( pStateSet ) |
529 | 0 | pStateSet->DisableItem(nSlotId); |
530 | 0 | return SfxPoolItemHolder(); |
531 | 0 | } |
532 | | |
533 | 4.08k | if ( bItemStateSet && eState == SfxItemState::INVALID ) |
534 | 0 | { |
535 | 0 | if ( pStateSet ) |
536 | 0 | pStateSet->ClearItem(nSlotId); |
537 | 0 | return SfxPoolItemHolder(rPool, DISABLED_POOL_ITEM); |
538 | 0 | } |
539 | | |
540 | | // bItemStateSet && eState >= SfxItemState::DEFAULT |
541 | 4.08k | if ( pStateSet && pStateSet->Put( *pItem ) ) |
542 | 0 | { |
543 | 0 | return SfxPoolItemHolder(rPool, &pStateSet->Get(pItem->Which())); |
544 | 0 | } |
545 | | |
546 | 4.08k | return SfxPoolItemHolder(rPool, pItem); |
547 | 4.08k | } |
548 | | |
549 | | static SFX_EXEC_STUB(SfxShell, VerbExec) |
550 | | static void SfxStubSfxShellVerbState(SfxShell *, SfxItemSet& rSet) |
551 | 0 | { |
552 | 0 | SfxShell::VerbState( rSet ); |
553 | 0 | } |
554 | | |
555 | | void SfxShell::SetVerbs(const css::uno::Sequence < css::embed::VerbDescriptor >& aVerbs) |
556 | 0 | { |
557 | 0 | SfxViewShell *pViewSh = dynamic_cast<SfxViewShell*>( this ); |
558 | |
|
559 | 0 | DBG_ASSERT(pViewSh, "Only call SetVerbs at the ViewShell!"); |
560 | 0 | if ( !pViewSh ) |
561 | 0 | return; |
562 | | |
563 | | // First make all Statecaches dirty, so that no-one no longer tries to use |
564 | | // the Slots |
565 | 0 | { |
566 | 0 | SfxBindings *pBindings = |
567 | 0 | pViewSh->GetViewFrame().GetDispatcher()->GetBindings(); |
568 | 0 | sal_uInt16 nCount = pImpl->aSlotArr.size(); |
569 | 0 | for (sal_uInt16 n1=0; n1<nCount ; n1++) |
570 | 0 | { |
571 | 0 | sal_uInt16 nId = SID_VERB_START + n1; |
572 | 0 | pBindings->Invalidate(nId, false, true); |
573 | 0 | } |
574 | 0 | } |
575 | |
|
576 | 0 | sal_uInt16 nr=0; |
577 | 0 | for (sal_Int32 n=0; n<aVerbs.getLength(); n++) |
578 | 0 | { |
579 | 0 | sal_uInt16 nSlotId = SID_VERB_START + nr++; |
580 | 0 | DBG_ASSERT(nSlotId <= SID_VERB_END, "Too many Verbs!"); |
581 | 0 | if (nSlotId > SID_VERB_END) |
582 | 0 | break; |
583 | | |
584 | 0 | SfxSlot* pNewSlot = new SfxSlot{ |
585 | 0 | nSlotId, SfxGroupId::NONE, |
586 | | // Verb slots must be executed asynchronously, so that they can be |
587 | | // destroyed while executing. |
588 | 0 | SfxSlotMode::ASYNCHRON | SfxSlotMode::CONTAINER, |
589 | 0 | 0, 0, |
590 | 0 | SFX_STUB_PTR(SfxShell, VerbExec), SFX_STUB_PTR(SfxShell, VerbState), |
591 | 0 | nullptr, // HACK(SFX_TYPE(SfxVoidItem)) ??? |
592 | 0 | nullptr, nullptr, 0, SfxDisableFlags::NONE, u""_ustr}; |
593 | |
|
594 | 0 | if (!pImpl->aSlotArr.empty()) |
595 | 0 | { |
596 | 0 | SfxSlot& rSlot = *pImpl->aSlotArr[0]; |
597 | 0 | pNewSlot->pNextSlot = rSlot.pNextSlot; |
598 | 0 | rSlot.pNextSlot = pNewSlot; |
599 | 0 | } |
600 | 0 | else |
601 | 0 | pNewSlot->pNextSlot = pNewSlot; |
602 | |
|
603 | 0 | pImpl->aSlotArr.insert(pImpl->aSlotArr.begin() + static_cast<sal_uInt16>(n), std::unique_ptr<SfxSlot>(pNewSlot)); |
604 | 0 | } |
605 | |
|
606 | 0 | pImpl->aVerbList = aVerbs; |
607 | | |
608 | | // The status of SID_OBJECT is collected in the controller directly on |
609 | | // the Shell, it is thus enough to encourage a new status update |
610 | 0 | SfxBindings* pBindings = pViewSh->GetViewFrame().GetDispatcher()->GetBindings(); |
611 | 0 | pBindings->Invalidate(SID_OBJECT, true, true); |
612 | 0 | } |
613 | | |
614 | | const css::uno::Sequence < css::embed::VerbDescriptor >& SfxShell::GetVerbs() const |
615 | 0 | { |
616 | 0 | return pImpl->aVerbList; |
617 | 0 | } |
618 | | |
619 | | void SfxShell::VerbExec(SfxRequest& rReq) |
620 | 0 | { |
621 | 0 | sal_uInt16 nId = rReq.GetSlot(); |
622 | 0 | SfxViewShell *pViewShell = GetViewShell(); |
623 | 0 | if ( !pViewShell ) |
624 | 0 | return; |
625 | | |
626 | 0 | bool bReadOnly = pViewShell->GetObjectShell()->IsReadOnly(); |
627 | 0 | const css::uno::Sequence < css::embed::VerbDescriptor > aList = pViewShell->GetVerbs(); |
628 | 0 | sal_Int32 nVerb = 0; |
629 | 0 | for (const auto& rVerb : aList) |
630 | 0 | { |
631 | | // check for ReadOnly verbs |
632 | 0 | if ( bReadOnly && !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_NEVERDIRTIES) ) |
633 | 0 | continue; |
634 | | |
635 | | // check for verbs that shouldn't appear in the menu |
636 | 0 | if ( !(rVerb.VerbAttributes & embed::VerbAttributes::MS_VERBATTR_ONCONTAINERMENU) ) |
637 | 0 | continue; |
638 | | |
639 | 0 | if (nId == SID_VERB_START + nVerb++) |
640 | 0 | { |
641 | 0 | pViewShell->DoVerb(rVerb.VerbID); |
642 | 0 | rReq.Done(); |
643 | 0 | return; |
644 | 0 | } |
645 | 0 | } |
646 | 0 | } |
647 | | |
648 | | void SfxShell::VerbState(SfxItemSet& ) |
649 | 0 | { |
650 | 0 | } |
651 | | |
652 | | const SfxSlot* SfxShell::GetVerbSlot_Impl(sal_uInt16 nId) const |
653 | 0 | { |
654 | 0 | css::uno::Sequence < css::embed::VerbDescriptor > rList = pImpl->aVerbList; |
655 | |
|
656 | 0 | DBG_ASSERT(nId >= SID_VERB_START && nId <= SID_VERB_END,"Wrong VerbId!"); |
657 | 0 | sal_uInt16 nIndex = nId - SID_VERB_START; |
658 | 0 | DBG_ASSERT(nIndex < rList.getLength(),"Wrong VerbId!"); |
659 | |
|
660 | 0 | if (nIndex < rList.getLength()) |
661 | 0 | return pImpl->aSlotArr[nIndex].get(); |
662 | 0 | else |
663 | 0 | return nullptr; |
664 | 0 | } |
665 | | |
666 | | SfxObjectShell* SfxShell::GetObjectShell() |
667 | 20.4k | { |
668 | 20.4k | if ( GetViewShell() ) |
669 | 12.2k | return GetViewShell()->GetViewFrame().GetObjectShell(); |
670 | 8.16k | else |
671 | 8.16k | return nullptr; |
672 | 20.4k | } |
673 | | |
674 | | bool SfxShell::HasUIFeature(SfxShellFeature) const |
675 | 0 | { |
676 | 0 | return false; |
677 | 0 | } |
678 | | |
679 | | static void DispatcherUpdate_Impl( void*, void* pArg ) |
680 | 0 | { |
681 | 0 | static_cast<SfxDispatcher*>(pArg)->Update_Impl( true ); |
682 | 0 | static_cast<SfxDispatcher*>(pArg)->GetBindings()->InvalidateAll(false); |
683 | 0 | } |
684 | | |
685 | | void SfxShell::UIFeatureChanged() |
686 | 4.08k | { |
687 | 4.08k | SfxViewFrame *pFrame = GetFrame(); |
688 | 4.08k | if ( pFrame && pFrame->IsVisible() ) |
689 | 4.08k | { |
690 | | // Also force an update, if dispatcher is already updated otherwise |
691 | | // something may get stuck in the bunkered tools. Asynchronous call to |
692 | | // prevent recursion. |
693 | 4.08k | if ( !pImpl->pUpdater ) |
694 | 4.08k | pImpl->pUpdater.reset( new svtools::AsynchronLink( LINK_NONMEMBER( this, DispatcherUpdate_Impl ) ) ); |
695 | | |
696 | | // Multiple views allowed |
697 | 4.08k | pImpl->pUpdater->Call( pFrame->GetDispatcher(), true ); |
698 | 4.08k | } |
699 | 4.08k | } |
700 | | |
701 | | void SfxShell::SetDisableFlags( SfxDisableFlags nFlags ) |
702 | 81.7k | { |
703 | 81.7k | pImpl->nDisableFlags = nFlags; |
704 | 81.7k | } |
705 | | |
706 | | SfxDisableFlags SfxShell::GetDisableFlags() const |
707 | 0 | { |
708 | 0 | return pImpl->nDisableFlags; |
709 | 0 | } |
710 | | |
711 | | std::optional<SfxItemSet> SfxShell::CreateItemSet( sal_uInt16 ) |
712 | 0 | { |
713 | 0 | return {}; |
714 | 0 | } |
715 | | |
716 | | void SfxShell::ApplyItemSet( sal_uInt16, const SfxItemSet& ) |
717 | 0 | { |
718 | 0 | } |
719 | | |
720 | | void SfxShell::SetContextName (const OUString& rsContextName) |
721 | 4.09k | { |
722 | 4.09k | pImpl->maContextChangeBroadcaster.Initialize(rsContextName); |
723 | 4.09k | } |
724 | | |
725 | | void SfxShell::SetViewShell_Impl( SfxViewShell* pView ) |
726 | 20.4k | { |
727 | 20.4k | pImpl->pViewSh = pView; |
728 | 20.4k | } |
729 | | |
730 | | void SfxShell::BroadcastContextForActivation (const bool bIsActivated) |
731 | 53.1k | { |
732 | | // Avoids activation and de-activation (can be seen on switching view) from causing |
733 | | // the sidebar to re-build. Such switching can happen as we change view to render |
734 | | // using LOK for example, and is un-necessary for Online. |
735 | 53.1k | if (comphelper::LibreOfficeKit::isDialogPainting()) |
736 | 0 | return; |
737 | | |
738 | 53.1k | SfxViewFrame* pViewFrame = GetFrame(); |
739 | 53.1k | if (pViewFrame != nullptr) |
740 | 40.8k | { |
741 | 40.8k | if (bIsActivated) |
742 | 24.5k | pImpl->maContextChangeBroadcaster.Activate(pViewFrame->GetFrame().GetFrameInterface()); |
743 | 16.3k | else |
744 | 16.3k | pImpl->maContextChangeBroadcaster.Deactivate(pViewFrame->GetFrame().GetFrameInterface()); |
745 | 40.8k | } |
746 | 53.1k | } |
747 | | |
748 | | bool SfxShell::SetContextBroadcasterEnabled (const bool bIsEnabled) |
749 | 0 | { |
750 | 0 | return pImpl->maContextChangeBroadcaster.SetBroadcasterEnabled(bIsEnabled); |
751 | 0 | } |
752 | | |
753 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |