Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sfx2 / source / view / viewsh.cxx
blobe21afa25276279406eb0820a1a9e16e3671c7c36
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include <boost/property_tree/json_parser.hpp>
24 #include <sal/log.hxx>
25 #include <svl/stritem.hxx>
26 #include <svl/eitem.hxx>
27 #include <svl/whiter.hxx>
28 #include <utility>
29 #include <vcl/svapp.hxx>
30 #include <vcl/toolbox.hxx>
31 #include <vcl/weld.hxx>
32 #include <svl/intitem.hxx>
33 #include <svtools/langhelp.hxx>
34 #include <com/sun/star/awt/XPopupMenu.hpp>
35 #include <com/sun/star/frame/XLayoutManager.hpp>
36 #include <com/sun/star/frame/ModuleManager.hpp>
37 #include <com/sun/star/io/IOException.hpp>
38 #include <com/sun/star/beans/XPropertySet.hpp>
39 #include <com/sun/star/embed/EmbedStates.hpp>
40 #include <com/sun/star/embed/EmbedMisc.hpp>
41 #include <com/sun/star/embed/XEmbeddedObject.hpp>
42 #include <com/sun/star/container/XContainerQuery.hpp>
43 #include <com/sun/star/frame/XStorable.hpp>
44 #include <com/sun/star/frame/XModel.hpp>
45 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
46 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
47 #include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp>
48 #include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
49 #include <com/sun/star/view/XRenderable.hpp>
50 #include <com/sun/star/uno/Reference.hxx>
51 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
52 #include <com/sun/star/accessibility/XAccessibleContext.hpp>
53 #include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
54 #include <com/sun/star/accessibility/XAccessibleSelection.hpp>
55 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
56 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
57 #include <com/sun/star/accessibility/XAccessibleText.hpp>
58 #include <cppuhelper/implbase.hxx>
59 #include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
61 #include <cppuhelper/weakref.hxx>
63 #include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
64 #include <com/sun/star/accessibility/AccessibleTextType.hpp>
65 #include <com/sun/star/awt/FontSlant.hpp>
67 #include <comphelper/diagnose_ex.hxx>
68 #include <tools/urlobj.hxx>
69 #include <unotools/tempfile.hxx>
70 #include <svtools/soerr.hxx>
71 #include <tools/svborder.hxx>
73 #include <framework/actiontriggerhelper.hxx>
74 #include <comphelper/lok.hxx>
75 #include <comphelper/processfactory.hxx>
76 #include <comphelper/propertyvalue.hxx>
77 #include <comphelper/sequenceashashmap.hxx>
78 #include <toolkit/helper/vclunohelper.hxx>
79 #include <vcl/settings.hxx>
80 #include <vcl/commandinfoprovider.hxx>
81 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
83 #include <officecfg/Setup.hxx>
84 #include <sfx2/app.hxx>
85 #include <sfx2/flatpak.hxx>
86 #include <sfx2/viewsh.hxx>
87 #include "viewimp.hxx"
88 #include <sfx2/sfxresid.hxx>
89 #include <sfx2/request.hxx>
90 #include <sfx2/printer.hxx>
91 #include <sfx2/docfile.hxx>
92 #include <sfx2/dispatch.hxx>
93 #include <sfx2/strings.hrc>
94 #include <sfx2/sfxbasecontroller.hxx>
95 #include <sfx2/mailmodelapi.hxx>
96 #include <bluthsndapi.hxx>
97 #include <sfx2/viewfrm.hxx>
98 #include <sfx2/event.hxx>
99 #include <sfx2/ipclient.hxx>
100 #include <sfx2/sfxsids.hrc>
101 #include <sfx2/objface.hxx>
102 #include <sfx2/lokhelper.hxx>
103 #include <sfx2/lokcallback.hxx>
104 #include <openuriexternally.hxx>
105 #include <iostream>
106 #include <vector>
107 #include <libxml/xmlwriter.h>
108 #include <toolkit/awt/vclxmenu.hxx>
109 #include <unordered_map>
111 using namespace ::com::sun::star;
112 using namespace ::com::sun::star::uno;
113 using namespace ::com::sun::star::frame;
114 using namespace ::com::sun::star::beans;
115 using namespace ::com::sun::star::util;
116 using namespace ::cppu;
118 #define ShellClass_SfxViewShell
119 #include <sfxslots.hxx>
122 class SfxClipboardChangeListener : public ::cppu::WeakImplHelper<
123 datatransfer::clipboard::XClipboardListener >
125 public:
126 SfxClipboardChangeListener( SfxViewShell* pView, uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClpbrdNtfr );
128 // XEventListener
129 virtual void SAL_CALL disposing( const lang::EventObject& rEventObject ) override;
131 // XClipboardListener
132 virtual void SAL_CALL changedContents( const datatransfer::clipboard::ClipboardEvent& rEventObject ) override;
134 void DisconnectViewShell() { m_pViewShell = nullptr; }
135 void ChangedContents();
137 enum AsyncExecuteCmd
139 ASYNCEXECUTE_CMD_DISPOSING,
140 ASYNCEXECUTE_CMD_CHANGEDCONTENTS
143 struct AsyncExecuteInfo
145 AsyncExecuteInfo( AsyncExecuteCmd eCmd, SfxClipboardChangeListener* pListener ) :
146 m_eCmd( eCmd ), m_xListener( pListener ) {}
148 AsyncExecuteCmd m_eCmd;
149 rtl::Reference<SfxClipboardChangeListener> m_xListener;
152 private:
153 SfxViewShell* m_pViewShell;
154 uno::Reference< datatransfer::clipboard::XClipboardNotifier > m_xClpbrdNtfr;
155 uno::Reference< lang::XComponent > m_xCtrl;
157 DECL_STATIC_LINK( SfxClipboardChangeListener, AsyncExecuteHdl_Impl, void*, void );
160 SfxClipboardChangeListener::SfxClipboardChangeListener( SfxViewShell* pView, uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClpbrdNtfr )
161 : m_pViewShell( nullptr ), m_xClpbrdNtfr(std::move( xClpbrdNtfr )), m_xCtrl(pView->GetController())
163 if ( m_xCtrl.is() )
165 m_xCtrl->addEventListener( uno::Reference < lang::XEventListener > ( static_cast < lang::XEventListener* >( this ) ) );
166 m_pViewShell = pView;
168 if ( m_xClpbrdNtfr.is() )
170 m_xClpbrdNtfr->addClipboardListener( uno::Reference< datatransfer::clipboard::XClipboardListener >(
171 static_cast< datatransfer::clipboard::XClipboardListener* >( this )));
175 void SfxClipboardChangeListener::ChangedContents()
177 const SolarMutexGuard aGuard;
178 if (!m_pViewShell)
179 return;
181 SfxBindings& rBind = m_pViewShell->GetViewFrame().GetBindings();
182 rBind.Invalidate(SID_PASTE);
183 rBind.Invalidate(SID_PASTE_SPECIAL);
184 rBind.Invalidate(SID_CLIPBOARD_FORMAT_ITEMS);
186 if (comphelper::LibreOfficeKit::isActive())
188 // In the future we might send the payload as well.
189 SfxLokHelper::notifyAllViews(LOK_CALLBACK_CLIPBOARD_CHANGED, "");
193 IMPL_STATIC_LINK( SfxClipboardChangeListener, AsyncExecuteHdl_Impl, void*, p, void )
195 AsyncExecuteInfo* pAsyncExecuteInfo = static_cast<AsyncExecuteInfo*>(p);
196 if ( pAsyncExecuteInfo )
198 if ( pAsyncExecuteInfo->m_xListener.is() )
200 if ( pAsyncExecuteInfo->m_eCmd == ASYNCEXECUTE_CMD_DISPOSING )
201 pAsyncExecuteInfo->m_xListener->DisconnectViewShell();
202 else if ( pAsyncExecuteInfo->m_eCmd == ASYNCEXECUTE_CMD_CHANGEDCONTENTS )
203 pAsyncExecuteInfo->m_xListener->ChangedContents();
206 delete pAsyncExecuteInfo;
209 void SAL_CALL SfxClipboardChangeListener::disposing( const lang::EventObject& /*rEventObject*/ )
211 // Either clipboard or ViewShell is going to be destroyed -> no interest in listening anymore
212 uno::Reference< lang::XComponent > xCtrl( m_xCtrl );
213 uno::Reference< datatransfer::clipboard::XClipboardNotifier > xNotify( m_xClpbrdNtfr );
215 uno::Reference< datatransfer::clipboard::XClipboardListener > xThis( static_cast< datatransfer::clipboard::XClipboardListener* >( this ));
216 if ( xCtrl.is() )
217 xCtrl->removeEventListener( uno::Reference < lang::XEventListener > ( static_cast < lang::XEventListener* >( this )));
218 if ( xNotify.is() )
219 xNotify->removeClipboardListener( xThis );
221 // Make asynchronous call to avoid locking SolarMutex which is the
222 // root for many deadlocks, especially in conjunction with the "Windows"
223 // based single thread apartment clipboard code!
224 AsyncExecuteInfo* pInfo = new AsyncExecuteInfo( ASYNCEXECUTE_CMD_DISPOSING, this );
225 if (!Application::PostUserEvent( LINK( nullptr, SfxClipboardChangeListener, AsyncExecuteHdl_Impl ), pInfo ))
226 delete pInfo;
229 void SAL_CALL SfxClipboardChangeListener::changedContents( const datatransfer::clipboard::ClipboardEvent& )
231 // Make asynchronous call to avoid locking SolarMutex which is the
232 // root for many deadlocks, especially in conjunction with the "Windows"
233 // based single thread apartment clipboard code!
234 AsyncExecuteInfo* pInfo = new AsyncExecuteInfo( ASYNCEXECUTE_CMD_CHANGEDCONTENTS, this );
235 if (!Application::PostUserEvent( LINK( nullptr, SfxClipboardChangeListener, AsyncExecuteHdl_Impl ), pInfo ))
236 delete pInfo;
239 class LOKDocumentFocusListener :
240 public ::cppu::WeakImplHelper< accessibility::XAccessibleEventListener >
242 static constexpr sal_Int64 MAX_ATTACHABLE_CHILDREN = 30;
244 const SfxViewShell* m_pViewShell;
245 std::set< uno::Reference< uno::XInterface > > m_aRefList;
246 OUString m_sFocusedParagraph;
247 bool m_bFocusedParagraphNotified;
248 sal_Int32 m_nCaretPosition;
249 sal_Int32 m_nSelectionStart;
250 sal_Int32 m_nSelectionEnd;
251 OUString m_sSelectedText;
252 bool m_bIsEditingCell;
253 OUString m_sSelectedCellAddress;
255 public:
256 LOKDocumentFocusListener(const SfxViewShell* pViewShell);
258 /// @throws lang::IndexOutOfBoundsException
259 /// @throws uno::RuntimeException
260 void attachRecursive(
261 const uno::Reference< accessibility::XAccessible >& xAccessible
264 /// @throws lang::IndexOutOfBoundsException
265 /// @throws uno::RuntimeException
266 void attachRecursive(
267 const uno::Reference< accessibility::XAccessible >& xAccessible,
268 const uno::Reference< accessibility::XAccessibleContext >& xContext
271 /// @throws lang::IndexOutOfBoundsException
272 /// @throws uno::RuntimeException
273 void attachRecursive(
274 const uno::Reference< accessibility::XAccessible >& xAccessible,
275 const uno::Reference< accessibility::XAccessibleContext >& xContext,
276 const sal_Int64 nStateSet
279 /// @throws lang::IndexOutOfBoundsException
280 /// @throws uno::RuntimeException
281 void detachRecursive(
282 const uno::Reference< accessibility::XAccessible >& xAccessible
285 /// @throws lang::IndexOutOfBoundsException
286 /// @throws uno::RuntimeException
287 void detachRecursive(
288 const uno::Reference< accessibility::XAccessibleContext >& xContext
291 /// @throws lang::IndexOutOfBoundsException
292 /// @throws uno::RuntimeException
293 void detachRecursive(
294 const uno::Reference< accessibility::XAccessibleContext >& xContext,
295 const sal_Int64 nStateSet
298 /// @throws lang::IndexOutOfBoundsException
299 /// @throws uno::RuntimeException
300 static uno::Reference< accessibility::XAccessible > getAccessible(const lang::EventObject& aEvent );
302 // XEventListener
303 virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
305 // XAccessibleEventListener
306 virtual void SAL_CALL notifyEvent( const accessibility::AccessibleEventObject& aEvent ) override;
308 void notifyFocusedParagraphChanged();
309 void notifyCaretChanged();
310 void notifyTextSelectionChanged();
312 OUString getFocusedParagraph() const;
313 int getCaretPosition() const;
316 LOKDocumentFocusListener::LOKDocumentFocusListener(const SfxViewShell* pViewShell)
317 : m_pViewShell(pViewShell)
318 , m_bFocusedParagraphNotified(false)
319 , m_nCaretPosition(0)
320 , m_nSelectionStart(0)
321 , m_nSelectionEnd(0)
322 , m_bIsEditingCell(false)
326 OUString LOKDocumentFocusListener::getFocusedParagraph() const
328 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::getFocusedParagraph: " << m_sFocusedParagraph);
329 const_cast<LOKDocumentFocusListener*>(this)->m_bFocusedParagraphNotified = true;
331 sal_Int32 nSelectionStart = m_nSelectionStart;
332 sal_Int32 nSelectionEnd = m_nSelectionEnd;
333 if (nSelectionStart < 0 || nSelectionEnd < 0)
334 nSelectionStart = nSelectionEnd = m_nCaretPosition;
336 boost::property_tree::ptree aPayloadTree;
337 aPayloadTree.put("content", m_sFocusedParagraph.toUtf8().getStr());
338 aPayloadTree.put("start", nSelectionStart);
339 aPayloadTree.put("end", nSelectionEnd);
340 std::stringstream aStream;
341 boost::property_tree::write_json(aStream, aPayloadTree);
342 std::string aPayload = aStream.str();
343 OUString sRet = OUString::fromUtf8(aPayload);
344 return sRet;
347 int LOKDocumentFocusListener::getCaretPosition() const
349 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::getCaretPosition: " << m_nCaretPosition);
350 return m_nCaretPosition;
353 void LOKDocumentFocusListener::notifyFocusedParagraphChanged()
355 boost::property_tree::ptree aPayloadTree;
356 aPayloadTree.put("content", m_sFocusedParagraph.toUtf8().getStr());
357 aPayloadTree.put("position", m_nCaretPosition);
358 std::stringstream aStream;
359 boost::property_tree::write_json(aStream, aPayloadTree);
360 std::string aPayload = aStream.str();
361 if (m_pViewShell)
363 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyFocusedParagraphChanged: " << m_sFocusedParagraph);
364 m_bFocusedParagraphNotified = true;
365 const char* pPayload = aPayload.c_str();
366 m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_FOCUS_CHANGED, pPayload);
370 void LOKDocumentFocusListener::notifyCaretChanged()
372 boost::property_tree::ptree aPayloadTree;
373 aPayloadTree.put("position", m_nCaretPosition);
374 std::stringstream aStream;
375 boost::property_tree::write_json(aStream, aPayloadTree);
376 std::string aPayload = aStream.str();
377 if (m_pViewShell)
379 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyCaretChanged: " << m_nCaretPosition);
380 const char* pPayload = aPayload.c_str();
381 m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_CARET_CHANGED, pPayload);
385 void LOKDocumentFocusListener::notifyTextSelectionChanged()
387 boost::property_tree::ptree aPayloadTree;
388 aPayloadTree.put("start", m_nSelectionStart);
389 aPayloadTree.put("end", m_nSelectionEnd);
390 std::stringstream aStream;
391 boost::property_tree::write_json(aStream, aPayloadTree);
392 std::string aPayload = aStream.str();
393 if (m_pViewShell)
395 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyTextSelectionChanged: start: " << m_nSelectionStart << ", end: " << m_nSelectionEnd);
396 const char* pPayload = aPayload.c_str();
397 m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_TEXT_SELECTION_CHANGED, pPayload);
401 void LOKDocumentFocusListener::disposing( const lang::EventObject& aEvent )
403 // Unref the object here, but do not remove as listener since the object
404 // might no longer be in a state that safely allows this.
405 if( aEvent.Source.is() )
406 m_aRefList.erase(aEvent.Source);
410 namespace
412 bool hasState(const accessibility::AccessibleEventObject& aEvent, ::sal_Int64 nState)
414 bool res = false;
415 uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
416 if (xContext.is())
418 ::sal_Int64 nStateSet = xContext->getAccessibleStateSet();
419 res = (nStateSet & nState) != 0;
421 return res;
424 bool isFocused(const accessibility::AccessibleEventObject& aEvent)
426 return hasState(aEvent, accessibility::AccessibleStateType::FOCUSED);
428 } // anonymous namespace
430 void LOKDocumentFocusListener::notifyEvent( const accessibility::AccessibleEventObject& aEvent )
434 switch( aEvent.EventId )
436 case accessibility::AccessibleEventId::STATE_CHANGED:
438 uno::Reference< accessibility::XAccessible > xAccStateChanged = getAccessible(aEvent);
439 sal_Int64 nState = accessibility::AccessibleStateType::INVALID;
440 aEvent.NewValue >>= nState;
441 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: STATE_CHANGED: XAccessible: " << xAccStateChanged.get() << ", nState: " << nState);
443 if( accessibility::AccessibleStateType::FOCUSED == nState )
445 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: FOCUSED");
447 if (m_bIsEditingCell)
449 if (!hasState(aEvent, accessibility::AccessibleStateType::ACTIVE))
451 SAL_WARN("lok.a11y",
452 "LOKDocumentFocusListener::notifyEvent: FOCUSED: Cell not ACTIVE for editing yet");
453 return;
456 uno::Reference<css::accessibility::XAccessibleText> xAccText(xAccStateChanged, uno::UNO_QUERY);
457 if( xAccText.is() )
459 OUString sText = xAccText->getText();
460 sal_Int32 nLength = sText.getLength();
461 sal_Int32 nCaretPosition = xAccText->getCaretPosition();
462 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: xAccText: " << xAccText.get()
463 << ", text: >" << sText << "<, caret pos: " << nCaretPosition);
465 if (nLength)
467 css::uno::Reference<css::accessibility::XAccessibleTextAttributes>
468 xAccTextAttr(xAccText, uno::UNO_QUERY);
469 css::uno::Sequence< OUString > aRequestedAttributes;
471 sal_Int32 nPos = 0;
472 while (nPos < nLength)
474 css::accessibility::TextSegment aTextSegment =
475 xAccText->getTextAtIndex(nPos, css::accessibility::AccessibleTextType::ATTRIBUTE_RUN);
476 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: "
477 "text segment: '" << aTextSegment.SegmentText
478 << "', start: " << aTextSegment.SegmentStart
479 << ", end: " << aTextSegment.SegmentEnd);
481 css::uno::Sequence< css::beans::PropertyValue > aRunAttributeList;
482 if (xAccTextAttr.is())
484 aRunAttributeList = xAccTextAttr->getRunAttributes(nPos, aRequestedAttributes);
486 else
488 aRunAttributeList = xAccText->getCharacterAttributes(nPos, aRequestedAttributes);
491 sal_Int32 nSize = aRunAttributeList.getLength();
492 SAL_INFO("lok.a11y",
493 "LOKDocumentFocusListener::notifyEvent: attribute list size: " << nSize);
494 if (nSize)
496 OUString sValue;
497 OUString sAttributes = "{ ";
498 for (const auto& attribute: aRunAttributeList)
500 if (attribute.Name.isEmpty())
501 continue;
503 if (attribute.Name == "CharHeight" || attribute.Name == "CharWeight")
505 float fValue(0.0);
506 attribute.Value >>= fValue;
507 sValue = OUString::number(fValue);
509 else if (attribute.Name == "CharPosture")
511 awt::FontSlant nValue;
512 attribute.Value >>= nValue;
513 sValue = OUString::number(static_cast<unsigned int>(nValue));
515 else if (attribute.Name == "CharUnderline")
517 sal_Int16 nValue(0);
518 attribute.Value >>= nValue;
519 sValue = OUString::number(nValue);
521 else if (attribute.Name == "CharFontName")
523 attribute.Value >>= sValue;
525 else if (attribute.Name == "Rsid")
527 sal_uInt32 nValue(0);
528 attribute.Value >>= nValue;
529 sValue = OUString::number(nValue);
532 if (!sValue.isEmpty())
534 if (sAttributes != "{ ")
535 sAttributes += ", ";
536 sAttributes += attribute.Name + ": " + sValue;
537 sValue = "";
540 sAttributes += " }";
541 SAL_INFO("lok.a11y",
542 "LOKDocumentFocusListener::notifyEvent: attributes: " << sAttributes);
544 nPos = aTextSegment.SegmentEnd + 1;
547 if (!m_bFocusedParagraphNotified || m_sFocusedParagraph != sText)
549 m_sFocusedParagraph = sText;
550 m_nCaretPosition = nCaretPosition;
551 notifyFocusedParagraphChanged();
556 break;
559 case accessibility::AccessibleEventId::CARET_CHANGED:
561 if (!isFocused(aEvent))
563 SAL_WARN("lok.a11y",
564 "LOKDocumentFocusListener::notifyEvent: CARET_CHANGED: skip non focused paragraph");
565 return;
568 sal_Int32 nNewPos = -1;
569 aEvent.NewValue >>= nNewPos;
570 sal_Int32 nOldPos = -1;
571 aEvent.OldValue >>= nOldPos;
573 if (nNewPos >= 0)
575 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: CARET_CHANGED: new pos: " << nNewPos << ", nOldPos: " << nOldPos);
576 uno::Reference<css::accessibility::XAccessibleText>
577 xAccText(getAccessible(aEvent), uno::UNO_QUERY);
578 if( xAccText.is() )
580 OUString sText = xAccText->getText();
581 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: CARET_CHANGED: xAccText: " << xAccText.get() << ", text: >" << sText << "<");
583 m_nCaretPosition = nNewPos;
584 m_nSelectionStart = m_nSelectionEnd = m_nCaretPosition;
585 notifyCaretChanged();
589 break;
592 case accessibility::AccessibleEventId::TEXT_CHANGED:
594 if (!isFocused(aEvent))
596 SAL_WARN("lok.a11y",
597 "LOKDocumentFocusListener::notifyEvent: TEXT_CHANGED: skip non focused paragraph");
598 return;
601 accessibility::TextSegment aDeletedText;
602 accessibility::TextSegment aInsertedText;
604 if (aEvent.OldValue >>= aDeletedText)
606 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: TEXT_CHANGED: deleted text: >" << aDeletedText.SegmentText << "<");
608 if (aEvent.NewValue >>= aInsertedText)
610 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: TEXT_CHANGED: inserted text: >" << aInsertedText.SegmentText << "<");
612 uno::Reference<css::accessibility::XAccessibleText> xAccText(getAccessible(aEvent), uno::UNO_QUERY);
613 if (xAccText.is())
615 OUString sText = xAccText->getText();
616 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: TEXT_CHANGED: "
617 "xAccText: " << xAccText.get() << ", text: >" << sText << "<");
618 m_sFocusedParagraph = sText;
619 m_bFocusedParagraphNotified = false;
622 break;
624 case accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED:
626 if (!isFocused(aEvent))
628 SAL_WARN("lok.a11y",
629 "LOKDocumentFocusListener::notifyEvent: TEXT_SELECTION_CHANGED: skip non focused paragraph");
630 return;
633 uno::Reference<css::accessibility::XAccessibleText> xAccText(getAccessible(aEvent), uno::UNO_QUERY);
634 if (xAccText.is())
636 OUString sText = xAccText->getText();
637 sal_Int32 nSelectionStart = xAccText->getSelectionStart();
638 sal_Int32 nSelectionEnd = xAccText->getSelectionEnd();
639 m_sSelectedText = xAccText->getSelectedText();
641 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: TEXT_SELECTION_CHANGED: "
642 "\n xAccText: " << xAccText.get() << ", text: >" << sText << "<"
643 "\n start: " << nSelectionStart << ", end: " << nSelectionEnd
644 << "\n selected text: >" << m_sSelectedText << "<");
646 // This should not be risky since selection start/end are set also on CARET_CHANGED event
647 if (nSelectionStart == m_nSelectionStart && nSelectionEnd == m_nSelectionEnd)
648 return;
650 // We send a message to client also when start/end are -1, in this way the client knows
651 // if a text selection object exists or not. That's needed because of the odd behavior
652 // occurring when <backspace>/<delete> are hit and a text selection is empty but it still exists.
653 // Such keys delete the empty selection instead of the previous/next char.
654 m_nSelectionStart = nSelectionStart;
655 m_nSelectionEnd = nSelectionEnd;
657 // Calc: when editing a formula send the update content
658 if (m_bIsEditingCell && !m_sSelectedCellAddress.isEmpty()
659 && !m_sSelectedText.isEmpty() && sText.startsWith("="))
661 notifyFocusedParagraphChanged();
663 notifyTextSelectionChanged();
666 break;
668 case accessibility::AccessibleEventId::SELECTION_CHANGED:
670 uno::Reference< accessibility::XAccessible > xNewValue;
671 aEvent.NewValue >>= xNewValue;
672 if (xNewValue.is())
674 uno::Reference< accessibility::XAccessibleContext > xContext =
675 xNewValue->getAccessibleContext();
677 if (xContext.is())
679 OUString sName = xContext->getAccessibleName();
680 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: SELECTION_CHANGED: this: " << this
681 << ", selected cell address: >" << sName << "<"
682 ", m_bIsEditingCell: " << m_bIsEditingCell);
683 if (m_bIsEditingCell && !sName.isEmpty())
685 m_sSelectedCellAddress = sName;
686 // Check cell address: "$Sheet1.A10".
687 // On cell editing SELECTION_CHANGED is not emitted when selection is expanded.
688 // So selection can't be a cell range.
689 sal_Int32 nDotIndex = m_sSelectedText.indexOf('.');
690 OUString sCellAddress = m_sSelectedText.copy(nDotIndex + 1);
691 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: SELECTION_CHANGED: "
692 "cell address: >" << sCellAddress << "<");
693 if (m_sSelectedCellAddress == sCellAddress)
695 notifyFocusedParagraphChanged();
696 notifyTextSelectionChanged();
701 break;
703 case accessibility::AccessibleEventId::CHILD:
705 uno::Reference< accessibility::XAccessible > xChild;
706 if( (aEvent.OldValue >>= xChild) && xChild.is() )
707 detachRecursive(xChild);
709 if( (aEvent.NewValue >>= xChild) && xChild.is() )
710 attachRecursive(xChild);
712 break;
715 case accessibility::AccessibleEventId::INVALIDATE_ALL_CHILDREN:
716 SAL_INFO("lok.a11y", "Invalidate all children called");
717 break;
719 default:
720 break;
723 catch( const lang::IndexOutOfBoundsException& )
725 SAL_WARN("lok.a11y", "Focused object has invalid index in parent");
729 uno::Reference< accessibility::XAccessible > LOKDocumentFocusListener::getAccessible(const lang::EventObject& aEvent )
731 uno::Reference< accessibility::XAccessible > xAccessible(aEvent.Source, uno::UNO_QUERY);
733 if( xAccessible.is() )
734 return xAccessible;
736 uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
738 if( xContext.is() )
740 uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
741 if( xParent.is() )
743 uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
744 if( xParentContext.is() )
746 return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
751 return uno::Reference< accessibility::XAccessible >();
754 void LOKDocumentFocusListener::attachRecursive(
755 const uno::Reference< accessibility::XAccessible >& xAccessible
758 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(1): xAccessible: " << xAccessible.get());
760 uno::Reference< accessibility::XAccessibleContext > xContext =
761 xAccessible->getAccessibleContext();
763 if( xContext.is() )
764 attachRecursive(xAccessible, xContext);
767 void LOKDocumentFocusListener::attachRecursive(
768 const uno::Reference< accessibility::XAccessible >& xAccessible,
769 const uno::Reference< accessibility::XAccessibleContext >& xContext
772 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(2): xAccessible: " << xAccessible.get()
773 << ", role: " << xContext->getAccessibleRole()
774 << ", name: " << xContext->getAccessibleName()
775 << ", parent: " << xContext->getAccessibleParent().get()
776 << ", child count: " << xContext->getAccessibleChildCount());
778 sal_Int64 nStateSet = xContext->getAccessibleStateSet();
780 if (!m_bIsEditingCell)
782 ::rtl::OUString sName = xContext->getAccessibleName();
783 m_bIsEditingCell = sName.startsWith("Cell");
786 attachRecursive(xAccessible, xContext, nStateSet);
789 void LOKDocumentFocusListener::attachRecursive(
790 const uno::Reference< accessibility::XAccessible >& xAccessible,
791 const uno::Reference< accessibility::XAccessibleContext >& xContext,
792 const sal_Int64 nStateSet
795 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #1: this: " << this
796 << ", xAccessible: " << xAccessible.get()
797 << ", role: " << xContext->getAccessibleRole()
798 << ", name: " << xContext->getAccessibleName()
799 << ", parent: " << xContext->getAccessibleParent().get()
800 << ", child count: " << xContext->getAccessibleChildCount());
802 uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
804 if (!xBroadcaster.is())
805 return;
806 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #2: xBroadcaster.is()");
807 // If not already done, add the broadcaster to the list and attach as listener.
808 const uno::Reference< uno::XInterface >& xInterface = xBroadcaster;
809 if( m_aRefList.insert(xInterface).second )
811 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #3: m_aRefList.insert(xInterface).second");
812 xBroadcaster->addAccessibleEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
815 if( !(nStateSet & accessibility::AccessibleStateType::MANAGES_DESCENDANTS) )
817 sal_Int64 nmax = xContext->getAccessibleChildCount();
818 if( nmax > MAX_ATTACHABLE_CHILDREN )
819 nmax = MAX_ATTACHABLE_CHILDREN;
821 for( sal_Int64 n = 0; n < nmax; n++ )
823 uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
825 if( xChild.is() )
826 attachRecursive(xChild);
832 void LOKDocumentFocusListener::detachRecursive(
833 const uno::Reference< accessibility::XAccessible >& xAccessible
836 uno::Reference< accessibility::XAccessibleContext > xContext =
837 xAccessible->getAccessibleContext();
839 if( xContext.is() )
840 detachRecursive(xContext);
843 void LOKDocumentFocusListener::detachRecursive(
844 const uno::Reference< accessibility::XAccessibleContext >& xContext
847 sal_Int64 nStateSet = xContext->getAccessibleStateSet();
849 SAL_INFO("lok.a11y", "LOKDocumentFocusListener::detachRecursive(2): this: " << this
850 << ", name: " << xContext->getAccessibleName()
851 << ", parent: " << xContext->getAccessibleParent().get()
852 << ", child count: " << xContext->getAccessibleChildCount());
854 if (m_bIsEditingCell)
856 ::rtl::OUString sName = xContext->getAccessibleName();
857 m_bIsEditingCell = !sName.startsWith("Cell");
858 if (!m_bIsEditingCell)
860 m_sFocusedParagraph = "";
861 m_nCaretPosition = 0;
862 notifyFocusedParagraphChanged();
866 detachRecursive(xContext, nStateSet);
869 void LOKDocumentFocusListener::detachRecursive(
870 const uno::Reference< accessibility::XAccessibleContext >& xContext,
871 const sal_Int64 nStateSet
874 uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
876 if( xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster) )
878 xBroadcaster->removeAccessibleEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
880 if( !( nStateSet & accessibility::AccessibleStateType::MANAGES_DESCENDANTS ) )
882 sal_Int64 nmax = xContext->getAccessibleChildCount();
883 if( nmax > MAX_ATTACHABLE_CHILDREN )
884 nmax = MAX_ATTACHABLE_CHILDREN;
886 for( sal_Int64 n = 0; n < nmax; n++ )
888 uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
890 if( xChild.is() )
891 detachRecursive(xChild);
897 sal_uInt32 SfxViewShell_Impl::m_nLastViewShellId = 0;
899 SfxViewShell_Impl::SfxViewShell_Impl(SfxViewShellFlags const nFlags, ViewShellDocId nDocId)
900 : m_bHasPrintOptions(nFlags & SfxViewShellFlags::HAS_PRINTOPTIONS)
901 , m_nFamily(0xFFFF) // undefined, default set by TemplateDialog
902 , m_pLibreOfficeKitViewCallback(nullptr)
903 , m_bTiledSearching(false)
904 , m_nViewShellId(SfxViewShell_Impl::m_nLastViewShellId++)
905 , m_nDocId(nDocId)
909 SfxViewShell_Impl::~SfxViewShell_Impl()
913 std::vector< SfxInPlaceClient* >& SfxViewShell_Impl::GetIPClients_Impl()
915 return maIPClients;
918 SFX_IMPL_SUPERCLASS_INTERFACE(SfxViewShell,SfxShell)
920 void SfxViewShell::InitInterface_Impl()
925 /** search for a filter name dependent on type and module
927 static OUString impl_retrieveFilterNameFromTypeAndModule(
928 const css::uno::Reference< css::container::XContainerQuery >& rContainerQuery,
929 const OUString& rType,
930 const OUString& rModuleIdentifier,
931 const sal_Int32 nFlags )
933 // Retrieve filter from type
934 css::uno::Sequence< css::beans::NamedValue > aQuery {
935 { "Type", css::uno::Any( rType ) },
936 { "DocumentService", css::uno::Any( rModuleIdentifier ) }
939 css::uno::Reference< css::container::XEnumeration > xEnumeration =
940 rContainerQuery->createSubSetEnumerationByProperties( aQuery );
942 OUString aFoundFilterName;
943 while ( xEnumeration->hasMoreElements() )
945 ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() );
946 OUString aFilterName = aFilterPropsHM.getUnpackedValueOrDefault(
947 "Name",
948 OUString() );
950 sal_Int32 nFilterFlags = aFilterPropsHM.getUnpackedValueOrDefault(
951 "Flags",
952 sal_Int32( 0 ) );
954 if ( nFilterFlags & nFlags )
956 aFoundFilterName = aFilterName;
957 break;
961 return aFoundFilterName;
964 namespace {
966 /** search for an internal typename, which map to the current app module
967 and map also to a "family" of file formats as e.g. PDF/MS Doc/OOo Doc.
969 enum ETypeFamily
971 E_MS_DOC,
972 E_OOO_DOC
977 static OUString impl_searchFormatTypeForApp(const css::uno::Reference< css::frame::XFrame >& xFrame ,
978 ETypeFamily eTypeFamily)
982 css::uno::Reference< css::uno::XComponentContext > xContext (::comphelper::getProcessComponentContext());
983 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager(css::frame::ModuleManager::create(xContext));
985 OUString sModule = xModuleManager->identify(xFrame);
986 OUString sType ;
988 switch(eTypeFamily)
990 case E_MS_DOC:
992 if ( sModule == "com.sun.star.text.TextDocument" )
993 sType = "writer_MS_Word_2007";
994 else
995 if ( sModule == "com.sun.star.sheet.SpreadsheetDocument" )
996 sType = "MS Excel 2007 XML";
997 else
998 if ( sModule == "com.sun.star.presentation.PresentationDocument" )
999 sType = "MS PowerPoint 2007 XML";
1001 break;
1003 case E_OOO_DOC:
1005 if ( sModule == "com.sun.star.text.TextDocument" )
1006 sType = "writer8";
1007 else
1008 if ( sModule == "com.sun.star.sheet.SpreadsheetDocument" )
1009 sType = "calc8";
1010 else
1011 if ( sModule == "com.sun.star.drawing.DrawingDocument" )
1012 sType = "draw8";
1013 else
1014 if ( sModule == "com.sun.star.presentation.PresentationDocument" )
1015 sType = "impress8";
1017 break;
1020 return sType;
1022 catch (const css::uno::RuntimeException&)
1024 throw;
1026 catch (const css::uno::Exception&)
1030 return OUString();
1033 void SfxViewShell::NewIPClient_Impl( SfxInPlaceClient *pIPClient )
1035 pImpl->GetIPClients_Impl().push_back(pIPClient);
1038 void SfxViewShell::IPClientGone_Impl( SfxInPlaceClient const *pIPClient )
1040 std::vector< SfxInPlaceClient* >& pClients = pImpl->GetIPClients_Impl();
1042 auto it = std::find(pClients.begin(), pClients.end(), pIPClient);
1043 if (it != pClients.end())
1044 pClients.erase( it );
1048 void SfxViewShell::ExecMisc_Impl( SfxRequest &rReq )
1050 const sal_uInt16 nId = rReq.GetSlot();
1051 switch( nId )
1053 case SID_STYLE_FAMILY :
1055 const SfxUInt16Item* pItem = rReq.GetArg<SfxUInt16Item>(nId);
1056 if (pItem)
1058 pImpl->m_nFamily = pItem->GetValue();
1060 break;
1062 case SID_ACTIVATE_STYLE_APPLY:
1064 uno::Reference< frame::XFrame > xFrame =
1065 GetViewFrame().GetFrame().GetFrameInterface();
1067 Reference< beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
1068 Reference< frame::XLayoutManager > xLayoutManager;
1069 if ( xPropSet.is() )
1073 Any aValue = xPropSet->getPropertyValue("LayoutManager");
1074 aValue >>= xLayoutManager;
1075 if ( xLayoutManager.is() )
1077 uno::Reference< ui::XUIElement > xElement = xLayoutManager->getElement( "private:resource/toolbar/textobjectbar" );
1078 if(!xElement.is())
1080 xElement = xLayoutManager->getElement( "private:resource/toolbar/frameobjectbar" );
1082 if(!xElement.is())
1084 xElement = xLayoutManager->getElement( "private:resource/toolbar/oleobjectbar" );
1086 if(xElement.is())
1088 uno::Reference< awt::XWindow > xWin( xElement->getRealInterface(), uno::UNO_QUERY_THROW );
1089 VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xWin );
1090 ToolBox* pTextToolbox = dynamic_cast< ToolBox* >( pWin.get() );
1091 if( pTextToolbox )
1093 ToolBox::ImplToolItems::size_type nItemCount = pTextToolbox->GetItemCount();
1094 for( ToolBox::ImplToolItems::size_type nItem = 0; nItem < nItemCount; ++nItem )
1096 ToolBoxItemId nItemId = pTextToolbox->GetItemId( nItem );
1097 const OUString& rCommand = pTextToolbox->GetItemCommand( nItemId );
1098 if (rCommand == ".uno:StyleApply")
1100 vcl::Window* pItemWin = pTextToolbox->GetItemWindow( nItemId );
1101 if( pItemWin )
1102 pItemWin->GrabFocus();
1103 break;
1110 catch (const Exception&)
1114 rReq.Done();
1116 break;
1118 case SID_MAIL_SENDDOCASMS:
1119 case SID_MAIL_SENDDOCASOOO:
1120 case SID_MAIL_SENDDOCASPDF:
1121 case SID_MAIL_SENDDOC:
1122 case SID_MAIL_SENDDOCASFORMAT:
1124 SfxObjectShell* pDoc = GetObjectShell();
1125 if ( pDoc && pDoc->QueryHiddenInformation(
1126 HiddenWarningFact::WhenSaving, GetViewFrame().GetFrameWeld() ) != RET_YES )
1127 break;
1130 SfxMailModel aModel;
1131 OUString aDocType;
1133 const SfxStringItem* pMailRecipient = rReq.GetArg<SfxStringItem>(SID_MAIL_RECIPIENT);
1134 if ( pMailRecipient )
1136 OUString aRecipient( pMailRecipient->GetValue() );
1137 OUString aMailToStr("mailto:");
1139 if ( aRecipient.startsWith( aMailToStr ) )
1140 aRecipient = aRecipient.copy( aMailToStr.getLength() );
1141 aModel.AddToAddress( aRecipient );
1143 const SfxStringItem* pMailDocType = rReq.GetArg<SfxStringItem>(SID_TYPE_NAME);
1144 if ( pMailDocType )
1145 aDocType = pMailDocType->GetValue();
1147 uno::Reference < frame::XFrame > xFrame( rFrame.GetFrame().GetFrameInterface() );
1148 SfxMailModel::SendMailResult eResult = SfxMailModel::SEND_MAIL_ERROR;
1150 if ( nId == SID_MAIL_SENDDOC )
1151 eResult = aModel.SaveAndSend( xFrame, OUString() );
1152 else if ( nId == SID_MAIL_SENDDOCASPDF )
1153 eResult = aModel.SaveAndSend( xFrame, "pdf_Portable_Document_Format");
1154 else if ( nId == SID_MAIL_SENDDOCASMS )
1156 aDocType = impl_searchFormatTypeForApp(xFrame, E_MS_DOC);
1157 if (!aDocType.isEmpty())
1158 eResult = aModel.SaveAndSend( xFrame, aDocType );
1160 else if ( nId == SID_MAIL_SENDDOCASOOO )
1162 aDocType = impl_searchFormatTypeForApp(xFrame, E_OOO_DOC);
1163 if (!aDocType.isEmpty())
1164 eResult = aModel.SaveAndSend( xFrame, aDocType );
1167 if ( eResult == SfxMailModel::SEND_MAIL_ERROR )
1169 weld::Window* pWin = SfxGetpApp()->GetTopWindow();
1170 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
1171 VclMessageType::Info, VclButtonsType::Ok,
1172 SfxResId(STR_ERROR_SEND_MAIL)));
1173 xBox->run();
1174 rReq.Ignore();
1176 else
1177 rReq.Done();
1179 break;
1181 case SID_BLUETOOTH_SENDDOC:
1183 SfxBluetoothModel aModel;
1184 SfxObjectShell* pDoc = GetObjectShell();
1185 if ( pDoc && pDoc->QueryHiddenInformation(
1186 HiddenWarningFact::WhenSaving, GetViewFrame().GetFrameWeld() ) != RET_YES )
1187 break;
1188 uno::Reference < frame::XFrame > xFrame( rFrame.GetFrame().GetFrameInterface() );
1189 SfxMailModel::SendMailResult eResult = aModel.SaveAndSend( xFrame );
1190 if( eResult == SfxMailModel::SEND_MAIL_ERROR )
1192 weld::Window* pWin = SfxGetpApp()->GetTopWindow();
1193 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
1194 VclMessageType::Info, VclButtonsType::Ok,
1195 SfxResId(STR_ERROR_SEND_MAIL)));
1196 xBox->run();
1197 rReq.Ignore();
1199 else
1200 rReq.Done();
1202 break;
1204 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1205 case SID_WEBHTML:
1207 css::uno::Reference< lang::XMultiServiceFactory > xSMGR(::comphelper::getProcessServiceFactory(), css::uno::UNO_SET_THROW);
1208 css::uno::Reference< uno::XComponentContext > xContext(::comphelper::getProcessComponentContext(), css::uno::UNO_SET_THROW);
1209 css::uno::Reference< css::frame::XFrame > xFrame( rFrame.GetFrame().GetFrameInterface() );
1210 css::uno::Reference< css::frame::XModel > xModel;
1212 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager( css::frame::ModuleManager::create(xContext) );
1214 OUString aModule;
1217 aModule = xModuleManager->identify( xFrame );
1219 catch (const css::uno::RuntimeException&)
1221 throw;
1223 catch (const css::uno::Exception&)
1227 if ( xFrame.is() )
1229 css::uno::Reference< css::frame::XController > xController = xFrame->getController();
1230 if ( xController.is() )
1231 xModel = xController->getModel();
1234 // We need at least a valid module name and model reference
1235 css::uno::Reference< css::frame::XStorable > xStorable( xModel, css::uno::UNO_QUERY );
1236 if ( xModel.is() && xStorable.is() )
1238 OUString aFilterName;
1239 OUString aTypeName( "generic_HTML" );
1240 OUString aFileName;
1242 OUString aLocation = xStorable->getLocation();
1243 INetURLObject aFileObj( aLocation );
1245 bool bPrivateProtocol = ( aFileObj.GetProtocol() == INetProtocol::PrivSoffice );
1246 bool bHasLocation = !aLocation.isEmpty() && !bPrivateProtocol;
1248 css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
1249 xSMGR->createInstance( "com.sun.star.document.FilterFactory" ),
1250 css::uno::UNO_QUERY_THROW );
1252 // Retrieve filter from type
1254 sal_Int32 nFilterFlags = 0x00000002; // export
1255 aFilterName = impl_retrieveFilterNameFromTypeAndModule( xContainerQuery, aTypeName, aModule, nFilterFlags );
1256 if ( aFilterName.isEmpty() )
1258 // Draw/Impress uses a different type. 2nd chance try to use alternative type name
1259 aFilterName = impl_retrieveFilterNameFromTypeAndModule(
1260 xContainerQuery, "graphic_HTML", aModule, nFilterFlags );
1263 // No filter found => error
1264 // No type and no location => error
1265 if ( aFilterName.isEmpty() || aTypeName.isEmpty())
1267 rReq.Done();
1268 return;
1271 // Use provided save file name. If empty determine file name
1272 if ( !bHasLocation )
1274 // Create a default file name with the correct extension
1275 aFileName = "webpreview";
1277 else
1279 // Determine file name from model
1280 INetURLObject aFObj( xStorable->getLocation() );
1281 aFileName = aFObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::NONE );
1284 OSL_ASSERT( !aFilterName.isEmpty() );
1285 OSL_ASSERT( !aFileName.isEmpty() );
1287 // Creates a temporary directory to store our predefined file into it (for the
1288 // flatpak case, create it in XDG_CACHE_HOME instead of /tmp for technical reasons,
1289 // so that it can be accessed by the browser running outside the sandbox):
1290 OUString * parent = nullptr;
1291 if (flatpak::isFlatpak() && !flatpak::createTemporaryHtmlDirectory(&parent))
1293 SAL_WARN("sfx.view", "cannot create Flatpak html temp dir");
1296 INetURLObject aFilePathObj( ::utl::CreateTempURL(parent, true) );
1297 aFilePathObj.insertName( aFileName );
1298 aFilePathObj.setExtension( u"htm" );
1300 OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1302 css::uno::Sequence< css::beans::PropertyValue > aArgs{
1303 comphelper::makePropertyValue("FilterName", aFilterName)
1306 // Store document in the html format
1309 xStorable->storeToURL( aFileURL, aArgs );
1311 catch (const io::IOException&)
1313 rReq.Done();
1314 return;
1317 sfx2::openUriExternally(aFileURL, true, rReq.GetFrameWeld());
1318 rReq.Done(true);
1319 break;
1321 else
1323 rReq.Done();
1324 return;
1331 void SfxViewShell::GetState_Impl( SfxItemSet &rSet )
1334 SfxWhichIter aIter( rSet );
1335 SfxObjectShell *pSh = GetViewFrame().GetObjectShell();
1336 for ( sal_uInt16 nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() )
1338 switch ( nSID )
1341 case SID_BLUETOOTH_SENDDOC:
1342 case SID_MAIL_SENDDOC:
1343 case SID_MAIL_SENDDOCASFORMAT:
1344 case SID_MAIL_SENDDOCASMS:
1345 case SID_MAIL_SENDDOCASOOO:
1346 case SID_MAIL_SENDDOCASPDF:
1348 #if HAVE_FEATURE_MACOSX_SANDBOX
1349 rSet.DisableItem(nSID);
1350 #endif
1351 if (pSh && pSh->isExportLocked())
1352 rSet.DisableItem(nSID);
1353 break;
1355 case SID_WEBHTML:
1357 if (pSh && pSh->isExportLocked())
1358 rSet.DisableItem(nSID);
1359 break;
1361 // Printer functions
1362 case SID_PRINTDOC:
1363 case SID_PRINTDOCDIRECT:
1364 case SID_SETUPPRINTER:
1365 case SID_PRINTER_NAME:
1367 if (Application::GetSettings().GetMiscSettings().GetDisablePrinting()
1368 || (pSh && pSh->isPrintLocked()))
1370 rSet.DisableItem(nSID);
1371 break;
1374 SfxPrinter *pPrinter = GetPrinter();
1376 if ( SID_PRINTDOCDIRECT == nSID )
1378 OUString aPrinterName;
1379 if ( pPrinter != nullptr )
1380 aPrinterName = pPrinter->GetName();
1381 else
1383 // tdf#109149 don't poll the Default Printer Name on every query.
1384 // We are queried on every change, so on every
1385 // keystroke, and we are only using this to fill in the
1386 // printername inside the label of "Print Directly (printer-name)"
1387 // On Printer::GetDefaultPrinterName() is implemented with
1388 // GetDefaultPrinter so don't call this excessively. 5 mins
1389 // seems a reasonable refresh time.
1390 std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
1391 std::chrono::minutes five_mins(5);
1392 if (now > pImpl->m_nDefaultPrinterNameFetchTime + five_mins)
1394 pImpl->m_sDefaultPrinterName = Printer::GetDefaultPrinterName();
1395 pImpl->m_nDefaultPrinterNameFetchTime = now;
1397 aPrinterName = pImpl->m_sDefaultPrinterName;
1399 if ( !aPrinterName.isEmpty() )
1401 uno::Reference < frame::XFrame > xFrame( rFrame.GetFrame().GetFrameInterface() );
1403 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:PrintDefault",
1404 vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
1405 OUString val = vcl::CommandInfoProvider::GetLabelForCommand(aProperties) +
1406 " (" + aPrinterName + ")";
1408 rSet.Put( SfxStringItem( SID_PRINTDOCDIRECT, val ) );
1411 break;
1413 case SID_STYLE_FAMILY :
1415 rSet.Put( SfxUInt16Item( SID_STYLE_FAMILY, pImpl->m_nFamily ) );
1416 break;
1422 void SfxViewShell::SetZoomFactor( const Fraction &rZoomX,
1423 const Fraction &rZoomY )
1425 DBG_ASSERT( GetWindow(), "no window" );
1426 MapMode aMap( GetWindow()->GetMapMode() );
1427 aMap.SetScaleX( rZoomX );
1428 aMap.SetScaleY( rZoomY );
1429 GetWindow()->SetMapMode( aMap );
1432 ErrCode SfxViewShell::DoVerb(sal_Int32 /*nVerb*/)
1434 /* [Description]
1436 Virtual Method used to perform a Verb on a selected Object.
1437 Since this Object is only known by the derived classes, they must override
1438 DoVerb.
1442 return ERRCODE_SO_NOVERBS;
1445 void SfxViewShell::OutplaceActivated( bool bActive )
1447 if ( !bActive )
1448 GetFrame()->GetFrame().Appear();
1451 void SfxViewShell::UIActivating( SfxInPlaceClient* /*pClient*/ )
1453 uno::Reference < frame::XFrame > xOwnFrame( rFrame.GetFrame().GetFrameInterface() );
1454 uno::Reference < frame::XFramesSupplier > xParentFrame = xOwnFrame->getCreator();
1455 if ( xParentFrame.is() )
1456 xParentFrame->setActiveFrame( xOwnFrame );
1458 rFrame.GetBindings().HidePopups();
1459 rFrame.GetDispatcher()->Update_Impl( true );
1462 void SfxViewShell::UIDeactivated( SfxInPlaceClient* /*pClient*/ )
1464 if ( !rFrame.GetFrame().IsClosing_Impl() || SfxViewFrame::Current() != &rFrame )
1465 rFrame.GetDispatcher()->Update_Impl( true );
1466 rFrame.GetBindings().HidePopups(false);
1468 rFrame.GetBindings().InvalidateAll(true);
1471 SfxInPlaceClient* SfxViewShell::FindIPClient
1473 const uno::Reference < embed::XEmbeddedObject >& xObj,
1474 vcl::Window* pObjParentWin
1475 ) const
1477 std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
1478 if ( rClients.empty() )
1479 return nullptr;
1481 if( !pObjParentWin )
1482 pObjParentWin = GetWindow();
1483 for (SfxInPlaceClient* pIPClient : rClients)
1485 if ( pIPClient->GetObject() == xObj && pIPClient->GetEditWin() == pObjParentWin )
1486 return pIPClient;
1489 return nullptr;
1493 SfxInPlaceClient* SfxViewShell::GetIPClient() const
1495 return GetUIActiveClient();
1499 SfxInPlaceClient* SfxViewShell::GetUIActiveIPClient_Impl() const
1501 // this method is needed as long as SFX still manages the border space for ChildWindows (see SfxFrame::Resize)
1502 std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
1503 if ( rClients.empty() )
1504 return nullptr;
1506 for (SfxInPlaceClient* pIPClient : rClients)
1508 if ( pIPClient->IsUIActive() )
1509 return pIPClient;
1512 return nullptr;
1515 SfxInPlaceClient* SfxViewShell::GetUIActiveClient() const
1517 std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
1518 if ( rClients.empty() )
1519 return nullptr;
1521 const bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
1523 for (SfxInPlaceClient* pIPClient : rClients)
1525 if ( pIPClient->IsObjectUIActive() || ( bIsTiledRendering && pIPClient->IsObjectInPlaceActive() ) )
1526 return pIPClient;
1529 return nullptr;
1533 void SfxViewShell::Activate( bool bMDI )
1535 if ( bMDI )
1537 SfxObjectShell *pSh = GetViewFrame().GetObjectShell();
1538 if (const auto xModel = pSh->GetModel())
1539 xModel->setCurrentController(GetController());
1541 SetCurrentDocument();
1546 void SfxViewShell::Deactivate(bool /*bMDI*/)
1551 void SfxViewShell::Move()
1553 /* [Description]
1555 This virtual Method is called when the window displayed in the
1556 SfxViewShell gets a StarView-Move() notification.
1558 This base implementation does not have to be called. .
1560 [Note]
1562 This Method can be used to cancel a selection, in order to catch the
1563 mouse movement which is due to moving a window.
1565 For now the notification does not work In-Place.
1572 void SfxViewShell::OuterResizePixel
1574 const Point& /*rToolOffset*/,// Upper left corner Tools in Frame-Window
1575 const Size& /*rSize*/ // All available sizes.
1578 /* [Description]
1580 Override this Method to be able to react to the size-change of
1581 the View. Thus the View is defined as the Edit window and also the
1582 attached Tools are defined (for example the ruler).
1584 The Edit window must not be changed either in size or position.
1586 The Vis-Area of SfxObjectShell, its scale and position can be changed
1587 here. The main use is to change the size of the Vis-Area.
1589 If the Border is changed due to the new calculation then this has to be set
1590 by <SfxViewShell::SetBorderPixel(const SvBorder&)>. The Positioning of Tools
1591 is only allowed after the calling of 'SetBorderPixel'.
1593 [Example]
1595 void AppViewSh::OuterViewResizePixel( const Point &rOfs, const Size &rSz )
1597 // Calculate Tool position and size externally, do not set!
1598 // (due to the following Border calculation)
1599 Point aHLinPos...; Size aHLinSz...;
1602 // Calculate and Set a Border of Tools which matches rSize.
1603 SvBorder aBorder...
1604 SetBorderPixel( aBorder ); // Allow Positioning from here on.
1606 // Arrange Tools
1607 pHLin->SetPosSizePixel( aHLinPos, aHLinSz );
1611 [Cross-reference]
1613 <SfxViewShell::InnerResizePixel(const Point&,const Size& rSize)>
1617 SetBorderPixel( SvBorder() );
1621 void SfxViewShell::InnerResizePixel
1623 const Point& /*rToolOffset*/,// Upper left corner Tools in Frame-Window
1624 const Size& /*rSize*/, // All available sizes.
1625 bool
1628 /* [Description]
1630 Override this Method to be able to react to the size-change of
1631 the Edit window.
1633 The Edit window must not be changed either in size or position.
1634 Neither the Vis-Area of SfxObjectShell nor its scale or position are
1635 allowed to be changed
1637 If the Border is changed due to the new calculation then is has to be set
1638 by <SfxViewShell::SetBorderPixel(const SvBorder&)>.
1639 The Positioning of Tools is only allowed after the calling of
1640 'SetBorderPixel'.
1643 [Note]
1645 void AppViewSh::InnerViewResizePixel( const Point &rOfs, const Size &rSz )
1647 // Calculate Tool position and size internally, do not set!
1648 // (due to the following Border calculation)
1649 Point aHLinPos...; Size aHLinSz...;
1652 // Calculate and Set a Border of Tools which matches rSize.
1653 SvBorder aBorder...
1654 SetBorderPixel( aBorder ); // Allow Positioning from here on.
1656 // Arrange Tools
1657 pHLin->SetPosSizePixel( aHLinPos, aHLinSz );
1661 [Cross-reference]
1663 <SfxViewShell::OuterResizePixel(const Point&,const Size& rSize)>
1667 SetBorderPixel( SvBorder() );
1670 void SfxViewShell::InvalidateBorder()
1672 GetViewFrame().InvalidateBorderImpl( this );
1673 if (pImpl->m_pController.is())
1675 pImpl->m_pController->BorderWidthsChanged_Impl();
1679 void SfxViewShell::SetBorderPixel( const SvBorder &rBorder )
1681 GetViewFrame().SetBorderPixelImpl( this, rBorder );
1683 // notify related controller that border size is changed
1684 if (pImpl->m_pController.is())
1686 pImpl->m_pController->BorderWidthsChanged_Impl();
1690 const SvBorder& SfxViewShell::GetBorderPixel() const
1692 return GetViewFrame().GetBorderPixelImpl();
1695 void SfxViewShell::SetWindow
1697 vcl::Window* pViewPort // For example Null pointer in the Destructor.
1700 /* [Description]
1702 With this method the SfxViewShell is set in the data window. This is
1703 needed for the in-place container and for restoring the proper focus.
1705 Even in-place-active the conversion of the ViewPort Windows is forbidden.
1709 if( pWindow == pViewPort )
1710 return;
1712 // Disconnect existing IP-Clients if possible
1713 DisconnectAllClients();
1715 // Switch View-Port
1716 bool bHadFocus = pWindow && pWindow->HasChildPathFocus( true );
1717 pWindow = pViewPort;
1719 if( pWindow )
1721 // Disable automatic GUI mirroring (right-to-left) for document windows
1722 pWindow->EnableRTL( false );
1725 if ( bHadFocus && pWindow )
1726 pWindow->GrabFocus();
1727 //TODO/CLEANUP
1728 //Do we still need this Method?!
1729 //SfxGetpApp()->GrabFocus( pWindow );
1732 ViewShellDocId SfxViewShell::mnCurrentDocId(0);
1734 SfxViewShell::SfxViewShell
1736 SfxViewFrame& rViewFrame, /* <SfxViewFrame>, which will be
1737 displayed in this View */
1738 SfxViewShellFlags nFlags /* See <SfxViewShell-Flags> */
1741 : SfxShell(this)
1742 , pImpl( new SfxViewShell_Impl(nFlags, SfxViewShell::mnCurrentDocId) )
1743 , rFrame(rViewFrame)
1744 , pWindow(nullptr)
1745 , bNoNewWindow( nFlags & SfxViewShellFlags::NO_NEWWINDOW )
1746 , mbPrinterSettingsModified(false)
1747 , maLOKLanguageTag(LANGUAGE_NONE)
1748 , maLOKLocale(LANGUAGE_NONE)
1749 , maLOKDeviceFormFactor(LOKDeviceFormFactor::UNKNOWN)
1750 , mbLOKAccessibilityEnabled(false)
1752 SetMargin( rViewFrame.GetMargin_Impl() );
1754 SetPool( &rViewFrame.GetObjectShell()->GetPool() );
1755 StartListening(*rViewFrame.GetObjectShell());
1757 // Insert into list
1758 std::vector<SfxViewShell*> &rViewArr = SfxGetpApp()->GetViewShells_Impl();
1759 rViewArr.push_back(this);
1761 if (comphelper::LibreOfficeKit::isActive())
1763 maLOKLanguageTag = SfxLokHelper::getDefaultLanguage();
1764 maLOKLocale = SfxLokHelper::getDefaultLanguage();
1766 const auto [isTimezoneSet, aTimezone] = SfxLokHelper::getDefaultTimezone();
1767 maLOKIsTimezoneSet = isTimezoneSet;
1768 maLOKTimezone = aTimezone;
1770 maLOKDeviceFormFactor = SfxLokHelper::getDeviceFormFactor();
1772 vcl::Window* pFrameWin = rViewFrame.GetWindow().GetFrameWindow();
1773 if (pFrameWin && !pFrameWin->GetLOKNotifier())
1774 pFrameWin->SetLOKNotifier(this, true);
1778 SfxViewShell::~SfxViewShell()
1780 // Remove from list
1781 const SfxViewShell *pThis = this;
1782 std::vector<SfxViewShell*> &rViewArr = SfxGetpApp()->GetViewShells_Impl();
1783 auto it = std::find( rViewArr.begin(), rViewArr.end(), pThis );
1784 rViewArr.erase( it );
1786 if ( pImpl->xClipboardListener.is() )
1788 pImpl->xClipboardListener->DisconnectViewShell();
1789 pImpl->xClipboardListener = nullptr;
1792 if (pImpl->m_pController.is())
1794 pImpl->m_pController->ReleaseShell_Impl();
1795 pImpl->m_pController.clear();
1798 vcl::Window* pFrameWin = GetViewFrame().GetWindow().GetFrameWindow();
1799 if (pFrameWin && pFrameWin->GetLOKNotifier() == this)
1800 pFrameWin->ReleaseLOKNotifier();
1803 OUString SfxViewShell::getA11yFocusedParagraph() const
1805 const LOKDocumentFocusListener& rDocFocusListener = GetLOKDocumentFocusListener();
1806 return rDocFocusListener.getFocusedParagraph();
1809 int SfxViewShell::getA11yCaretPosition() const
1811 const LOKDocumentFocusListener& rDocFocusListener = GetLOKDocumentFocusListener();
1812 return rDocFocusListener.getCaretPosition();
1815 bool SfxViewShell::PrepareClose
1817 bool bUI // TRUE: Allow Dialog and so on, FALSE: silent-mode
1820 if (GetViewFrame().GetWindow().GetLOKNotifier() == this)
1821 GetViewFrame().GetWindow().ReleaseLOKNotifier();
1823 SfxPrinter *pPrinter = GetPrinter();
1824 if ( pPrinter && pPrinter->IsPrinting() )
1826 if ( bUI )
1828 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewFrame().GetFrameWeld(),
1829 VclMessageType::Info, VclButtonsType::Ok,
1830 SfxResId(STR_CANT_CLOSE)));
1831 xBox->run();
1834 return false;
1837 if( GetViewFrame().IsInModalMode() )
1838 return false;
1840 if( bUI && GetViewFrame().GetDispatcher()->IsLocked() )
1841 return false;
1843 return true;
1847 SfxViewShell* SfxViewShell::Current()
1849 SfxViewFrame *pCurrent = SfxViewFrame::Current();
1850 return pCurrent ? pCurrent->GetViewShell() : nullptr;
1854 SfxViewShell* SfxViewShell::Get( const Reference< XController>& i_rController )
1856 if ( !i_rController.is() )
1857 return nullptr;
1859 for ( SfxViewShell* pViewShell = SfxViewShell::GetFirst( false );
1860 pViewShell;
1861 pViewShell = SfxViewShell::GetNext( *pViewShell, false )
1864 if ( pViewShell->GetController() == i_rController )
1865 return pViewShell;
1867 return nullptr;
1871 SdrView* SfxViewShell::GetDrawView() const
1873 /* [Description]
1875 This virtual Method has to be overloaded by the sub classes, to be able
1876 make the Property-Editor available.
1878 The default implementation does always return zero.
1882 return nullptr;
1886 OUString SfxViewShell::GetSelectionText
1888 bool /*bCompleteWords*/, /* FALSE (default)
1889 Only the actual selected text is returned.
1891 TRUE
1892 The selected text is expanded so that only
1893 whole words are returned. As word separators
1894 these are used: white spaces and punctuation
1895 ".,;" and single and double quotes.
1897 bool /*bOnlyASample*/ /* used by some dialogs to avoid constructing monster strings e.g. in calc */
1900 /* [Description]
1902 Override this Method to return a text that
1903 is included in the current selection. This is for example used when
1904 sending emails.
1906 When called with "CompleteWords == TRUE", it is for example sufficient
1907 with having the Cursor positioned somewhere within a URL in-order
1908 to have the entire URL returned.
1912 return OUString();
1916 bool SfxViewShell::HasSelection( bool ) const
1918 /* [Description]
1920 With this virtual Method can a for example a Dialog be queried, to
1921 check if something is selected in the current view. If the Parameter
1922 is <BOOL> TRUE then it is checked whether some text is selected.
1926 return false;
1929 void SfxViewShell::AddSubShell( SfxShell& rShell )
1931 pImpl->aArr.push_back(&rShell);
1932 SfxDispatcher *pDisp = rFrame.GetDispatcher();
1933 if ( pDisp->IsActive(*this) )
1935 pDisp->Push(rShell);
1936 pDisp->Flush();
1940 void SfxViewShell::RemoveSubShell( SfxShell* pShell )
1942 SfxDispatcher *pDisp = rFrame.GetDispatcher();
1943 if ( !pShell )
1945 size_t nCount = pImpl->aArr.size();
1946 if ( pDisp->IsActive(*this) )
1948 for(size_t n = nCount; n > 0; --n)
1949 pDisp->Pop(*pImpl->aArr[n - 1]);
1950 pDisp->Flush();
1952 pImpl->aArr.clear();
1954 else
1956 SfxShellArr_Impl::iterator i = std::find(pImpl->aArr.begin(), pImpl->aArr.end(), pShell);
1957 if(i != pImpl->aArr.end())
1959 pImpl->aArr.erase(i);
1960 if(pDisp->IsActive(*this))
1962 pDisp->RemoveShell_Impl(*pShell);
1963 pDisp->Flush();
1969 SfxShell* SfxViewShell::GetSubShell( sal_uInt16 nNo )
1971 sal_uInt16 nCount = pImpl->aArr.size();
1972 if(nNo < nCount)
1973 return pImpl->aArr[nCount - nNo - 1];
1974 return nullptr;
1977 void SfxViewShell::PushSubShells_Impl( bool bPush )
1979 SfxDispatcher *pDisp = rFrame.GetDispatcher();
1980 if ( bPush )
1982 for (auto const& elem : pImpl->aArr)
1983 pDisp->Push(*elem);
1985 else if(!pImpl->aArr.empty())
1987 SfxShell& rPopUntil = *pImpl->aArr[0];
1988 if ( pDisp->GetShellLevel( rPopUntil ) != USHRT_MAX )
1989 pDisp->Pop( rPopUntil, SfxDispatcherPopFlags::POP_UNTIL );
1992 pDisp->Flush();
1996 void SfxViewShell::WriteUserData( OUString&, bool )
2001 void SfxViewShell::ReadUserData(const OUString&, bool )
2005 void SfxViewShell::ReadUserDataSequence ( const uno::Sequence < beans::PropertyValue >& )
2009 void SfxViewShell::WriteUserDataSequence ( uno::Sequence < beans::PropertyValue >& )
2014 // returns the first shell of spec. type viewing the specified doc.
2015 SfxViewShell* SfxViewShell::GetFirst
2017 bool bOnlyVisible,
2018 const std::function< bool ( const SfxViewShell* ) >& isViewShell
2021 // search for a SfxViewShell of the specified type
2022 std::vector<SfxViewShell*> &rShells = SfxGetpApp()->GetViewShells_Impl();
2023 for (SfxViewShell* pShell : rShells)
2025 if ( pShell )
2027 // This code used to check that the frame exists in the other list,
2028 // because of https://bz.apache.org/ooo/show_bug.cgi?id=62084, with the explanation:
2029 // sometimes dangling SfxViewShells exist that point to a dead SfxViewFrame
2030 // these ViewShells shouldn't be accessible anymore
2031 // a destroyed ViewFrame is not in the ViewFrame array anymore, so checking this array helps
2032 // That doesn't seem to be needed anymore, but keep an assert, just in case.
2033 assert(std::find(SfxGetpApp()->GetViewFrames_Impl().begin(), SfxGetpApp()->GetViewFrames_Impl().end(),
2034 &pShell->GetViewFrame()) != SfxGetpApp()->GetViewFrames_Impl().end());
2035 if ( ( !bOnlyVisible || pShell->GetViewFrame().IsVisible() ) && (!isViewShell || isViewShell(pShell)))
2036 return pShell;
2040 return nullptr;
2043 // returns the next shell of spec. type viewing the specified doc.
2044 SfxViewShell* SfxViewShell::GetNext
2046 const SfxViewShell& rPrev,
2047 bool bOnlyVisible,
2048 const std::function<bool ( const SfxViewShell* )>& isViewShell
2051 std::vector<SfxViewShell*> &rShells = SfxGetpApp()->GetViewShells_Impl();
2052 size_t nPos;
2053 for ( nPos = 0; nPos < rShells.size(); ++nPos )
2054 if ( rShells[nPos] == &rPrev )
2055 break;
2057 for ( ++nPos; nPos < rShells.size(); ++nPos )
2059 SfxViewShell *pShell = rShells[nPos];
2060 if ( pShell )
2062 assert(std::find(SfxGetpApp()->GetViewFrames_Impl().begin(), SfxGetpApp()->GetViewFrames_Impl().end(),
2063 &pShell->GetViewFrame()) != SfxGetpApp()->GetViewFrames_Impl().end());
2064 if ( ( !bOnlyVisible || pShell->GetViewFrame().IsVisible() ) && (!isViewShell || isViewShell(pShell)) )
2065 return pShell;
2069 return nullptr;
2073 void SfxViewShell::Notify( SfxBroadcaster& rBC,
2074 const SfxHint& rHint )
2076 const SfxEventHint* pEventHint = dynamic_cast<const SfxEventHint*>(&rHint);
2077 if ( !(pEventHint && pEventHint->GetEventId() == SfxEventHintId::LoadFinished) )
2078 return;
2080 if ( !GetController().is() )
2081 return;
2083 // avoid access to dangling ViewShells
2084 auto &rFrames = SfxGetpApp()->GetViewFrames_Impl();
2085 for (SfxViewFrame* frame : rFrames)
2087 if ( frame == &GetViewFrame() && &rBC == GetObjectShell() )
2089 SfxItemSet* pSet = GetObjectShell()->GetMedium()->GetItemSet();
2090 const SfxUnoAnyItem* pItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pSet, SID_VIEW_DATA, false);
2091 if ( pItem )
2093 pImpl->m_pController->restoreViewData( pItem->GetValue() );
2094 pSet->ClearItem( SID_VIEW_DATA );
2096 break;
2101 bool SfxViewShell::ExecKey_Impl(const KeyEvent& aKey)
2103 bool setModuleConfig = false; // In case libreofficekit is active, we will re-set the module config class.
2104 if (!pImpl->m_xAccExec)
2106 pImpl->m_xAccExec = ::svt::AcceleratorExecute::createAcceleratorHelper();
2107 pImpl->m_xAccExec->init(::comphelper::getProcessComponentContext(),
2108 rFrame.GetFrame().GetFrameInterface());
2109 setModuleConfig = true;
2112 if (comphelper::LibreOfficeKit::isActive())
2114 // Get the module name.
2115 css::uno::Reference< css::uno::XComponentContext > xContext (::comphelper::getProcessComponentContext());
2116 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager(css::frame::ModuleManager::create(xContext));
2117 OUString sModule = xModuleManager->identify(rFrame.GetFrame().GetFrameInterface());
2119 // Get the language name.
2120 OUString viewLang = GetLOKLanguageTag().getBcp47();
2122 // Merge them & have a key.
2123 OUString key = sModule + viewLang;
2125 // Check it in configurations map. Create a configuration manager if there isn't one for the key.
2126 std::unordered_map<OUString, css::uno::Reference<com::sun::star::ui::XAcceleratorConfiguration>>& acceleratorConfs = SfxApplication::Get()->GetAcceleratorConfs_Impl();
2127 if (acceleratorConfs.find(key) == acceleratorConfs.end())
2129 // Create a new configuration manager for the module.
2131 OUString actualLang = officecfg::Setup::L10N::ooLocale::get();
2133 std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
2134 officecfg::Setup::L10N::ooLocale::set(viewLang, batch);
2135 batch->commit();
2137 // We have set the language. Time to create the config manager.
2138 acceleratorConfs[key] = svt::AcceleratorExecute::lok_createNewAcceleratorConfiguration(::comphelper::getProcessComponentContext(), sModule);
2140 std::shared_ptr<comphelper::ConfigurationChanges> batch2(comphelper::ConfigurationChanges::create());
2141 officecfg::Setup::L10N::ooLocale::set(actualLang, batch2);
2142 batch2->commit();
2145 if (setModuleConfig)
2146 pImpl->m_xAccExec->lok_setModuleConfig(acceleratorConfs[key]);
2149 return pImpl->m_xAccExec->execute(aKey.GetKeyCode());
2152 void SfxViewShell::setLibreOfficeKitViewCallback(SfxLokCallbackInterface* pCallback)
2154 pImpl->m_pLibreOfficeKitViewCallback = pCallback;
2156 afterCallbackRegistered();
2158 if (!pImpl->m_pLibreOfficeKitViewCallback)
2159 return;
2161 // Ask other views to tell us about their cursors.
2162 SfxViewShell* pViewShell = SfxViewShell::GetFirst();
2163 while (pViewShell)
2165 if (pViewShell->GetDocId() == GetDocId())
2166 pViewShell->NotifyCursor(this);
2167 pViewShell = SfxViewShell::GetNext(*pViewShell);
2171 SfxLokCallbackInterface* SfxViewShell::getLibreOfficeKitViewCallback() const
2173 return pImpl->m_pLibreOfficeKitViewCallback;
2176 void SfxViewShell::dumpLibreOfficeKitViewState(rtl::OStringBuffer &rState)
2178 if (pImpl->m_pLibreOfficeKitViewCallback)
2179 pImpl->m_pLibreOfficeKitViewCallback->dumpState(rState);
2182 static bool ignoreLibreOfficeKitViewCallback(int nType, const SfxViewShell_Impl* pImpl)
2184 if (!comphelper::LibreOfficeKit::isActive())
2185 return true;
2187 if (comphelper::LibreOfficeKit::isTiledPainting())
2189 switch (nType)
2191 case LOK_CALLBACK_FORM_FIELD_BUTTON:
2192 case LOK_CALLBACK_TEXT_SELECTION:
2193 case LOK_CALLBACK_COMMENT:
2194 break;
2195 default:
2196 // Reject e.g. invalidate during paint.
2197 return true;
2201 if (pImpl->m_bTiledSearching)
2203 switch (nType)
2205 case LOK_CALLBACK_TEXT_SELECTION:
2206 case LOK_CALLBACK_TEXT_VIEW_SELECTION:
2207 case LOK_CALLBACK_TEXT_SELECTION_START:
2208 case LOK_CALLBACK_TEXT_SELECTION_END:
2209 case LOK_CALLBACK_GRAPHIC_SELECTION:
2210 case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
2211 return true;
2215 return false;
2218 void SfxViewShell::libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart, int nMode) const
2220 if (ignoreLibreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_TILES, pImpl.get()))
2221 return;
2222 if (pImpl->m_pLibreOfficeKitViewCallback)
2223 pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewInvalidateTilesCallback(pRect, nPart, nMode);
2224 else
2225 SAL_INFO(
2226 "sfx.view",
2227 "SfxViewShell::libreOfficeKitViewInvalidateTilesCallback no callback set!");
2230 void SfxViewShell::libreOfficeKitViewCallbackWithViewId(int nType, const OString& pPayload, int nViewId) const
2232 if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
2233 return;
2234 if (pImpl->m_pLibreOfficeKitViewCallback)
2235 pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewCallbackWithViewId(nType, pPayload, nViewId);
2236 else
2237 SAL_INFO(
2238 "sfx.view",
2239 "SfxViewShell::libreOfficeKitViewCallbackWithViewId no callback set! Dropped payload of type "
2240 << lokCallbackTypeToString(nType) << ": [" << pPayload << ']');
2243 void SfxViewShell::libreOfficeKitViewCallback(int nType, const OString& pPayload) const
2245 if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
2246 return;
2247 if (pImpl->m_pLibreOfficeKitViewCallback)
2248 pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewCallback(nType, pPayload);
2249 else
2250 SAL_INFO(
2251 "sfx.view",
2252 "SfxViewShell::libreOfficeKitViewCallback no callback set! Dropped payload of type "
2253 << lokCallbackTypeToString(nType) << ": [" << pPayload << ']');
2256 void SfxViewShell::libreOfficeKitViewUpdatedCallback(int nType) const
2258 if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
2259 return;
2260 if (pImpl->m_pLibreOfficeKitViewCallback)
2261 pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewUpdatedCallback(nType);
2262 else
2263 SAL_INFO(
2264 "sfx.view",
2265 "SfxViewShell::libreOfficeKitViewUpdatedCallback no callback set! Dropped payload of type "
2266 << lokCallbackTypeToString(nType));
2269 void SfxViewShell::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) const
2271 if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
2272 return;
2273 if (pImpl->m_pLibreOfficeKitViewCallback)
2274 pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewUpdatedCallbackPerViewId(nType, nViewId, nSourceViewId);
2275 else
2276 SAL_INFO(
2277 "sfx.view",
2278 "SfxViewShell::libreOfficeKitViewUpdatedCallbackPerViewId no callback set! Dropped payload of type "
2279 << lokCallbackTypeToString(nType));
2282 void SfxViewShell::libreOfficeKitViewAddPendingInvalidateTiles()
2284 if (pImpl->m_pLibreOfficeKitViewCallback)
2285 pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewAddPendingInvalidateTiles();
2286 else
2287 SAL_INFO(
2288 "sfx.view",
2289 "SfxViewShell::libreOfficeKitViewAddPendingInvalidateTiles no callback set!");
2292 void SfxViewShell::afterCallbackRegistered()
2296 void SfxViewShell::flushPendingLOKInvalidateTiles()
2298 // SfxViewShell itself does not delay any tile invalidations.
2301 std::optional<OString> SfxViewShell::getLOKPayload(int nType, int /*nViewId*/) const
2303 // SfxViewShell itself currently doesn't handle any updated-payload types.
2304 SAL_WARN("sfx.view", "SfxViewShell::getLOKPayload unhandled type " << lokCallbackTypeToString(nType));
2305 abort();
2308 vcl::Window* SfxViewShell::GetEditWindowForActiveOLEObj() const
2310 vcl::Window* pEditWin = nullptr;
2311 SfxInPlaceClient* pIPClient = GetIPClient();
2312 if (pIPClient)
2314 pEditWin = pIPClient->GetEditWin();
2316 return pEditWin;
2319 void SfxViewShell::SetLOKLanguageTag(const OUString& rBcp47LanguageTag)
2321 LanguageTag aTag(rBcp47LanguageTag, true);
2323 css::uno::Sequence<OUString> inst(officecfg::Setup::Office::InstalledLocales::get()->getElementNames());
2324 LanguageTag aFallbackTag = LanguageTag(getInstalledLocaleForSystemUILanguage(inst, /* bRequestInstallIfMissing */ false, rBcp47LanguageTag), true).makeFallback();
2326 // If we want de-CH, and the de localisation is available, we don't want to use de-DE as then
2327 // the magic in Translate::get() won't turn ess-zet into double s. Possibly other similar cases?
2328 if (comphelper::LibreOfficeKit::isActive() && aTag.getLanguage() == aFallbackTag.getLanguage())
2329 maLOKLanguageTag = aTag;
2330 else
2331 maLOKLanguageTag = aFallbackTag;
2334 LOKDocumentFocusListener& SfxViewShell::GetLOKDocumentFocusListener()
2336 if (mpLOKDocumentFocusListener)
2337 return *mpLOKDocumentFocusListener;
2339 mpLOKDocumentFocusListener = new LOKDocumentFocusListener(this);
2340 return *mpLOKDocumentFocusListener;
2343 const LOKDocumentFocusListener& SfxViewShell::GetLOKDocumentFocusListener() const
2345 return const_cast<SfxViewShell*>(this)->GetLOKDocumentFocusListener();
2348 void SfxViewShell::SetLOKAccessibilityState(bool bEnabled)
2350 if (bEnabled == mbLOKAccessibilityEnabled)
2351 return;
2352 mbLOKAccessibilityEnabled = bEnabled;
2354 LOKDocumentFocusListener& rDocumentFocusListener = GetLOKDocumentFocusListener();
2356 if (!pWindow)
2357 return;
2359 uno::Reference< accessibility::XAccessible > xAccessible =
2360 pWindow->GetAccessible();
2362 if (!xAccessible.is())
2363 return;
2365 if (mbLOKAccessibilityEnabled)
2369 rDocumentFocusListener.attachRecursive(xAccessible);
2371 catch (const uno::Exception&)
2373 SAL_WARN("lok.a11y", "Exception caught processing LOKDocumentFocusListener::attachRecursive");
2376 else
2380 rDocumentFocusListener.detachRecursive(xAccessible);
2382 catch (const uno::Exception&)
2384 SAL_WARN("lok.a11y", "Exception caught processing LOKDocumentFocusListener::detachRecursive");
2389 void SfxViewShell::SetLOKLocale(const OUString& rBcp47LanguageTag)
2391 maLOKLocale = LanguageTag(rBcp47LanguageTag, true).makeFallback();
2394 void SfxViewShell::NotifyCursor(SfxViewShell* /*pViewShell*/) const
2398 void SfxViewShell::setTiledSearching(bool bTiledSearching)
2400 pImpl->m_bTiledSearching = bTiledSearching;
2403 int SfxViewShell::getPart() const
2405 return 0;
2408 int SfxViewShell::getEditMode() const
2410 return 0;
2413 ViewShellId SfxViewShell::GetViewShellId() const
2415 return pImpl->m_nViewShellId;
2418 void SfxViewShell::SetCurrentDocId(ViewShellDocId nId)
2420 mnCurrentDocId = nId;
2423 ViewShellDocId SfxViewShell::GetDocId() const
2425 assert(pImpl->m_nDocId >= ViewShellDocId(0) && "m_nDocId should have been initialized, but it is invalid.");
2426 return pImpl->m_nDocId;
2429 void SfxViewShell::notifyInvalidation(tools::Rectangle const* pRect) const
2431 SfxLokHelper::notifyInvalidation(this, pRect);
2434 void SfxViewShell::NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload)
2436 SfxLokHelper::notifyOtherViews(this, nType, rKey, rPayload);
2439 void SfxViewShell::NotifyOtherView(OutlinerViewShell* pOther, int nType, const OString& rKey, const OString& rPayload)
2441 auto pOtherShell = dynamic_cast<SfxViewShell*>(pOther);
2442 if (!pOtherShell)
2443 return;
2445 SfxLokHelper::notifyOtherView(this, pOtherShell, nType, rKey, rPayload);
2448 void SfxViewShell::dumpAsXml(xmlTextWriterPtr pWriter) const
2450 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxViewShell"));
2451 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
2452 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("id"), BAD_CAST(OString::number(static_cast<sal_Int32>(GetViewShellId())).getStr()));
2453 (void)xmlTextWriterEndElement(pWriter);
2456 bool SfxViewShell::KeyInput( const KeyEvent &rKeyEvent )
2458 /* [Description]
2460 This Method executes the KeyEvent 'rKeyEvent' of the Keys (Accelerator)
2461 configured either direct or indirect (for example by the Application)
2462 in the SfxViewShell.
2464 [Return value]
2466 bool TRUE
2467 The Key (Accelerator) is configured and the
2468 associated Handler was called
2470 FALSE
2471 The Key (Accelerator) is not configured and
2472 subsequently no Handler was called
2474 [Cross-reference]
2476 <SfxApplication::KeyInput(const KeyEvent&)>
2479 return ExecKey_Impl(rKeyEvent);
2482 bool SfxViewShell::GlobalKeyInput_Impl( const KeyEvent &rKeyEvent )
2484 return ExecKey_Impl(rKeyEvent);
2488 void SfxViewShell::ShowCursor( bool /*bOn*/ )
2490 /* [Description]
2492 Subclasses must override this Method so that SFx can switch the
2493 Cursor on and off, for example while a <SfxProgress> is running.
2500 void SfxViewShell::ResetAllClients_Impl( SfxInPlaceClient const *pIP )
2503 std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
2504 if ( rClients.empty() )
2505 return;
2507 for (SfxInPlaceClient* pIPClient : rClients)
2509 if( pIPClient != pIP )
2510 pIPClient->ResetObject();
2515 void SfxViewShell::DisconnectAllClients()
2517 std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
2518 if ( rClients.empty() )
2519 return;
2521 for ( size_t n = 0; n < rClients.size(); )
2522 // clients will remove themselves from the list
2523 delete rClients.at( n );
2527 void SfxViewShell::QueryObjAreaPixel( tools::Rectangle& ) const
2532 void SfxViewShell::VisAreaChanged()
2534 std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
2535 if ( rClients.empty() )
2536 return;
2538 for (SfxInPlaceClient* pIPClient : rClients)
2540 if ( pIPClient->IsObjectInPlaceActive() )
2541 // client is active, notify client that the VisArea might have changed
2542 pIPClient->VisAreaChanged();
2547 void SfxViewShell::CheckIPClient_Impl(
2548 SfxInPlaceClient const *const pIPClient, const tools::Rectangle& rVisArea)
2550 if ( GetObjectShell()->IsInClose() )
2551 return;
2553 bool bAlwaysActive =
2554 ( ( pIPClient->GetObjectMiscStatus() & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) != 0 );
2555 bool bActiveWhenVisible =
2556 ( pIPClient->GetObjectMiscStatus() & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE ) != 0;
2558 // this method is called when a client is created
2559 if (pIPClient->IsObjectInPlaceActive())
2560 return;
2562 // object in client is currently not active
2563 // check if the object wants to be activated always or when it becomes at least partially visible
2564 // TODO/LATER: maybe we should use the scaled area instead of the ObjArea?!
2565 if (bAlwaysActive || (bActiveWhenVisible && rVisArea.Overlaps(pIPClient->GetObjArea())))
2569 pIPClient->GetObject()->changeState( embed::EmbedStates::INPLACE_ACTIVE );
2571 catch (const uno::Exception&)
2573 TOOLS_WARN_EXCEPTION("sfx.view", "SfxViewShell::CheckIPClient_Impl");
2578 SfxObjectShell* SfxViewShell::GetObjectShell()
2580 return rFrame.GetObjectShell();
2583 Reference< XModel > SfxViewShell::GetCurrentDocument() const
2585 Reference< XModel > xDocument;
2587 const SfxObjectShell* pDocShell( const_cast< SfxViewShell* >( this )->GetObjectShell() );
2588 OSL_ENSURE( pDocShell, "SfxViewFrame::GetCurrentDocument: no DocShell!?" );
2589 if ( pDocShell )
2590 xDocument = pDocShell->GetModel();
2591 return xDocument;
2595 void SfxViewShell::SetCurrentDocument() const
2597 uno::Reference< frame::XModel > xDocument( GetCurrentDocument() );
2598 if ( xDocument.is() )
2599 SfxObjectShell::SetCurrentComponent( xDocument );
2603 const Size& SfxViewShell::GetMargin() const
2605 return pImpl->aMargin;
2609 void SfxViewShell::SetMargin( const Size& rSize )
2611 // the default margin was verified using www.apple.com !!
2612 Size aMargin = rSize;
2613 if ( aMargin.Width() == -1 )
2614 aMargin.setWidth( DEFAULT_MARGIN_WIDTH );
2615 if ( aMargin.Height() == -1 )
2616 aMargin.setHeight( DEFAULT_MARGIN_HEIGHT );
2618 if ( aMargin != pImpl->aMargin )
2620 pImpl->aMargin = aMargin;
2621 MarginChanged();
2625 void SfxViewShell::MarginChanged()
2629 void SfxViewShell::JumpToMark( const OUString& rMark )
2631 SfxStringItem aMarkItem( SID_JUMPTOMARK, rMark );
2632 GetViewFrame().GetDispatcher()->ExecuteList(
2633 SID_JUMPTOMARK,
2634 SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
2635 { &aMarkItem });
2638 void SfxViewShell::SetController( SfxBaseController* pController )
2640 pImpl->m_pController = pController;
2642 // there should be no old listener, but if there is one, it should be disconnected
2643 if ( pImpl->xClipboardListener.is() )
2644 pImpl->xClipboardListener->DisconnectViewShell();
2646 pImpl->xClipboardListener = new SfxClipboardChangeListener( this, GetClipboardNotifier() );
2649 Reference < XController > SfxViewShell::GetController() const
2651 return pImpl->m_pController;
2654 SfxBaseController* SfxViewShell::GetBaseController_Impl() const
2656 return pImpl->m_pController.get();
2659 void SfxViewShell::AddContextMenuInterceptor_Impl( const uno::Reference< ui::XContextMenuInterceptor >& xInterceptor )
2661 std::unique_lock g(pImpl->aMutex);
2662 pImpl->aInterceptorContainer.addInterface( g, xInterceptor );
2665 void SfxViewShell::RemoveContextMenuInterceptor_Impl( const uno::Reference< ui::XContextMenuInterceptor >& xInterceptor )
2667 std::unique_lock g(pImpl->aMutex);
2668 pImpl->aInterceptorContainer.removeInterface( g, xInterceptor );
2671 bool SfxViewShell::TryContextMenuInterception(const rtl::Reference<VCLXPopupMenu>& rIn,
2672 const OUString& rMenuIdentifier,
2673 rtl::Reference<VCLXPopupMenu>& rOut,
2674 ui::ContextMenuExecuteEvent aEvent)
2676 rOut.clear();
2677 bool bModified = false;
2679 // create container from menu
2680 aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
2681 rIn, &rMenuIdentifier);
2683 // get selection from controller
2684 aEvent.Selection.set( GetController(), uno::UNO_QUERY );
2686 // call interceptors
2687 std::unique_lock g(pImpl->aMutex);
2688 std::vector<uno::Reference< ui::XContextMenuInterceptor>> aInterceptors =
2689 pImpl->aInterceptorContainer.getElements(g);
2690 g.unlock();
2691 for (const auto & rListener : aInterceptors )
2695 ui::ContextMenuInterceptorAction eAction;
2697 SolarMutexReleaser rel;
2698 eAction = rListener->notifyContextMenuExecute( aEvent );
2700 switch ( eAction )
2702 case ui::ContextMenuInterceptorAction_CANCELLED :
2703 // interceptor does not want execution
2704 return false;
2705 case ui::ContextMenuInterceptorAction_EXECUTE_MODIFIED :
2706 // interceptor wants his modified menu to be executed
2707 bModified = true;
2708 break;
2709 case ui::ContextMenuInterceptorAction_CONTINUE_MODIFIED :
2710 // interceptor has modified menu, but allows for calling other interceptors
2711 bModified = true;
2712 continue;
2713 case ui::ContextMenuInterceptorAction_IGNORED :
2714 // interceptor is indifferent
2715 continue;
2716 default:
2717 OSL_FAIL("Wrong return value of ContextMenuInterceptor!");
2718 continue;
2721 catch (...)
2723 g.lock();
2724 pImpl->aInterceptorContainer.removeInterface(g, rListener);
2725 g.unlock();
2728 break;
2731 if (bModified)
2733 // container was modified, create a new menu out of it
2734 rOut = new VCLXPopupMenu();
2735 ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer(rOut, aEvent.ActionTriggerContainer);
2738 return true;
2741 bool SfxViewShell::TryContextMenuInterception(const rtl::Reference<VCLXPopupMenu>& rPopupMenu,
2742 const OUString& rMenuIdentifier, css::ui::ContextMenuExecuteEvent aEvent)
2744 bool bModified = false;
2746 // create container from menu
2747 aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
2748 rPopupMenu, &rMenuIdentifier);
2750 // get selection from controller
2751 aEvent.Selection = css::uno::Reference< css::view::XSelectionSupplier >( GetController(), css::uno::UNO_QUERY );
2753 // call interceptors
2754 std::unique_lock g(pImpl->aMutex);
2755 std::vector<uno::Reference< ui::XContextMenuInterceptor>> aInterceptors =
2756 pImpl->aInterceptorContainer.getElements(g);
2757 g.unlock();
2758 for (const auto & rListener : aInterceptors )
2762 css::ui::ContextMenuInterceptorAction eAction;
2764 SolarMutexReleaser rel;
2765 eAction = rListener->notifyContextMenuExecute( aEvent );
2767 switch ( eAction )
2769 case css::ui::ContextMenuInterceptorAction_CANCELLED:
2770 // interceptor does not want execution
2771 return false;
2772 case css::ui::ContextMenuInterceptorAction_EXECUTE_MODIFIED:
2773 // interceptor wants his modified menu to be executed
2774 bModified = true;
2775 break;
2776 case css::ui::ContextMenuInterceptorAction_CONTINUE_MODIFIED:
2777 // interceptor has modified menu, but allows for calling other interceptors
2778 bModified = true;
2779 continue;
2780 case css::ui::ContextMenuInterceptorAction_IGNORED:
2781 // interceptor is indifferent
2782 continue;
2783 default:
2784 SAL_WARN( "sfx.view", "Wrong return value of ContextMenuInterceptor!" );
2785 continue;
2788 catch (...)
2790 g.lock();
2791 pImpl->aInterceptorContainer.removeInterface(g, rListener);
2792 g.unlock();
2795 break;
2798 if ( bModified )
2800 rPopupMenu->clear();
2801 ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer(rPopupMenu, aEvent.ActionTriggerContainer);
2804 return true;
2807 bool SfxViewShell::HandleNotifyEvent_Impl( NotifyEvent const & rEvent )
2809 if (pImpl->m_pController.is())
2810 return pImpl->m_pController->HandleEvent_Impl( rEvent );
2811 return false;
2814 bool SfxViewShell::HasKeyListeners_Impl() const
2816 return (pImpl->m_pController.is())
2817 && pImpl->m_pController->HasKeyListeners_Impl();
2820 bool SfxViewShell::HasMouseClickListeners_Impl() const
2822 return (pImpl->m_pController.is())
2823 && pImpl->m_pController->HasMouseClickListeners_Impl();
2826 bool SfxViewShell::Escape()
2828 return GetViewFrame().GetBindings().Execute(SID_TERMINATE_INPLACEACTIVATION);
2831 Reference< view::XRenderable > SfxViewShell::GetRenderable()
2833 Reference< view::XRenderable >xRender;
2834 SfxObjectShell* pObj = GetObjectShell();
2835 if( pObj )
2837 Reference< frame::XModel > xModel( pObj->GetModel() );
2838 if( xModel.is() )
2839 xRender.set( xModel, UNO_QUERY );
2841 return xRender;
2844 void SfxViewShell::notifyWindow(vcl::LOKWindowId nDialogId, const OUString& rAction, const std::vector<vcl::LOKPayloadItem>& rPayload) const
2846 SfxLokHelper::notifyWindow(this, nDialogId, rAction, rPayload);
2849 uno::Reference< datatransfer::clipboard::XClipboardNotifier > SfxViewShell::GetClipboardNotifier() const
2851 uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClipboardNotifier;
2852 xClipboardNotifier.set(GetViewFrame().GetWindow().GetClipboard(), uno::UNO_QUERY);
2853 return xClipboardNotifier;
2856 void SfxViewShell::AddRemoveClipboardListener( const uno::Reference < datatransfer::clipboard::XClipboardListener >& rClp, bool bAdd )
2860 uno::Reference< datatransfer::clipboard::XClipboard > xClipboard(GetViewFrame().GetWindow().GetClipboard());
2861 if( xClipboard.is() )
2863 uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClpbrdNtfr( xClipboard, uno::UNO_QUERY );
2864 if( xClpbrdNtfr.is() )
2866 if( bAdd )
2867 xClpbrdNtfr->addClipboardListener( rClp );
2868 else
2869 xClpbrdNtfr->removeClipboardListener( rClp );
2873 catch (const uno::Exception&)
2878 weld::Window* SfxViewShell::GetFrameWeld() const
2880 return pWindow ? pWindow->GetFrameWeld() : nullptr;
2883 void SfxViewShell::setBlockedCommandList(const char* blockedCommandList)
2885 if(!mvLOKBlockedCommandList.empty())
2886 return;
2888 OUString BlockedListString(blockedCommandList, strlen(blockedCommandList), RTL_TEXTENCODING_UTF8);
2889 OUString command = BlockedListString.getToken(0, ' ');
2890 for (size_t i = 1; !command.isEmpty(); i++)
2892 mvLOKBlockedCommandList.emplace(command);
2893 command = BlockedListString.getToken(i, ' ');
2897 bool SfxViewShell::isBlockedCommand(OUString command)
2899 return mvLOKBlockedCommandList.find(command) != mvLOKBlockedCommandList.end();
2902 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */