Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/view/viewsh.cxx
Line
Count
Source
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.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <config_features.h>
21
22
#include <boost/property_tree/json_parser.hpp>
23
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/colorcfg.hxx>
34
#include <svtools/langhelp.hxx>
35
#include <com/sun/star/awt/XPopupMenu.hpp>
36
#include <com/sun/star/frame/XLayoutManager.hpp>
37
#include <com/sun/star/frame/ModuleManager.hpp>
38
#include <com/sun/star/io/IOException.hpp>
39
#include <com/sun/star/beans/XPropertySet.hpp>
40
#include <com/sun/star/embed/EmbedStates.hpp>
41
#include <com/sun/star/embed/EmbedMisc.hpp>
42
#include <com/sun/star/embed/XEmbeddedObject.hpp>
43
#include <com/sun/star/container/XContainerQuery.hpp>
44
#include <com/sun/star/frame/XStorable.hpp>
45
#include <com/sun/star/frame/XModel.hpp>
46
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
47
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
48
#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp>
49
#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
50
#include <com/sun/star/drawing/XShapes.hpp>
51
#include <com/sun/star/view/XRenderable.hpp>
52
#include <com/sun/star/uno/Reference.hxx>
53
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
54
#include <com/sun/star/accessibility/XAccessibleContext.hpp>
55
#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
56
#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
57
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
58
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
59
#include <com/sun/star/accessibility/AccessibleRole.hpp>
60
#include <com/sun/star/accessibility/XAccessibleText.hpp>
61
#include <com/sun/star/accessibility/XAccessibleTable.hpp>
62
#include <cppuhelper/implbase.hxx>
63
#include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
64
65
#include <cppuhelper/weakref.hxx>
66
67
#include <com/sun/star/accessibility/XAccessibleTextAttributes.hpp>
68
#include <com/sun/star/accessibility/AccessibleTextType.hpp>
69
#include <com/sun/star/awt/FontSlant.hpp>
70
71
#include <comphelper/OAccessible.hxx>
72
#include <comphelper/diagnose_ex.hxx>
73
#include <editeng/unoprnms.hxx>
74
#include <tools/debug.hxx>
75
#include <tools/urlobj.hxx>
76
#include <unotools/tempfile.hxx>
77
#include <svtools/soerr.hxx>
78
#include <tools/svborder.hxx>
79
80
#include <framework/actiontriggerhelper.hxx>
81
#include <comphelper/lok.hxx>
82
#include <comphelper/processfactory.hxx>
83
#include <comphelper/propertyvalue.hxx>
84
#include <comphelper/sequenceashashmap.hxx>
85
#include <toolkit/helper/vclunohelper.hxx>
86
#include <vcl/settings.hxx>
87
#include <vcl/commandinfoprovider.hxx>
88
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
89
90
#include <officecfg/Setup.hxx>
91
#include <sfx2/app.hxx>
92
#include <sfx2/flatpak.hxx>
93
#include <sfx2/viewsh.hxx>
94
#include "viewimp.hxx"
95
#include <sfx2/sfxresid.hxx>
96
#include <sfx2/request.hxx>
97
#include <sfx2/printer.hxx>
98
#include <sfx2/docfile.hxx>
99
#include <sfx2/dispatch.hxx>
100
#include <sfx2/strings.hrc>
101
#include <sfx2/sfxbasecontroller.hxx>
102
#include <sfx2/mailmodelapi.hxx>
103
#include <bluthsndapi.hxx>
104
#include <sfx2/viewfrm.hxx>
105
#include <sfx2/event.hxx>
106
#include <sfx2/ipclient.hxx>
107
#include <sfx2/sfxsids.hrc>
108
#include <sfx2/objface.hxx>
109
#include <sfx2/lokhelper.hxx>
110
#include <sfx2/lokcallback.hxx>
111
#include <openuriexternally.hxx>
112
#include <iostream>
113
#include <vector>
114
#include <list>
115
#include <libxml/xmlwriter.h>
116
#include <toolkit/awt/vclxmenu.hxx>
117
#include <unordered_map>
118
#include <unordered_set>
119
120
#define ShellClass_SfxViewShell
121
#include <sfxslots.hxx>
122
123
using namespace ::com::sun::star;
124
using namespace ::com::sun::star::uno;
125
using namespace ::com::sun::star::frame;
126
using namespace ::com::sun::star::beans;
127
using namespace ::cppu;
128
129
class SfxClipboardChangeListener : public ::cppu::WeakImplHelper<
130
    datatransfer::clipboard::XClipboardListener >
131
{
132
public:
133
    SfxClipboardChangeListener( SfxViewShell* pView, uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClpbrdNtfr );
134
135
    // XEventListener
136
    virtual void SAL_CALL disposing( const lang::EventObject& rEventObject ) override;
137
138
    // XClipboardListener
139
    virtual void SAL_CALL changedContents( const datatransfer::clipboard::ClipboardEvent& rEventObject ) override;
140
141
4.26k
    void DisconnectViewShell() { m_pViewShell = nullptr; }
142
    void ChangedContents();
143
144
    enum AsyncExecuteCmd
145
    {
146
        ASYNCEXECUTE_CMD_DISPOSING,
147
        ASYNCEXECUTE_CMD_CHANGEDCONTENTS
148
    };
149
150
    struct AsyncExecuteInfo
151
    {
152
        AsyncExecuteInfo( AsyncExecuteCmd eCmd, SfxClipboardChangeListener* pListener ) :
153
4.26k
            m_eCmd( eCmd ), m_xListener( pListener ) {}
154
155
        AsyncExecuteCmd m_eCmd;
156
        rtl::Reference<SfxClipboardChangeListener> m_xListener;
157
    };
158
159
private:
160
    SfxViewShell* m_pViewShell;
161
    uno::Reference< datatransfer::clipboard::XClipboardNotifier > m_xClpbrdNtfr;
162
    uno::Reference< lang::XComponent > m_xCtrl;
163
164
    DECL_STATIC_LINK( SfxClipboardChangeListener, AsyncExecuteHdl_Impl, void*, void );
165
};
166
167
SfxClipboardChangeListener::SfxClipboardChangeListener( SfxViewShell* pView, uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClpbrdNtfr )
168
4.26k
  : m_pViewShell( nullptr ), m_xClpbrdNtfr(std::move( xClpbrdNtfr )), m_xCtrl(pView->GetController())
169
4.26k
{
170
4.26k
    if ( m_xCtrl.is() )
171
4.26k
    {
172
4.26k
        m_xCtrl->addEventListener( uno::Reference < lang::XEventListener > ( static_cast < lang::XEventListener* >( this ) ) );
173
4.26k
        m_pViewShell = pView;
174
4.26k
    }
175
4.26k
    if ( m_xClpbrdNtfr.is() )
176
0
    {
177
0
        m_xClpbrdNtfr->addClipboardListener( uno::Reference< datatransfer::clipboard::XClipboardListener >(
178
0
            static_cast< datatransfer::clipboard::XClipboardListener* >( this )));
179
0
    }
180
4.26k
}
181
182
void SfxClipboardChangeListener::ChangedContents()
183
0
{
184
0
    const SolarMutexGuard aGuard;
185
0
    if (!m_pViewShell)
186
0
        return;
187
188
0
    SfxBindings& rBind = m_pViewShell->GetViewFrame().GetBindings();
189
0
    rBind.Invalidate(SID_PASTE);
190
0
    rBind.Invalidate(SID_PASTE_SPECIAL);
191
0
    rBind.Invalidate(SID_CLIPBOARD_FORMAT_ITEMS);
192
193
0
    if (comphelper::LibreOfficeKit::isActive())
194
0
    {
195
        // In the future we might send the payload as well.
196
0
        SfxLokHelper::notifyAllViews(LOK_CALLBACK_CLIPBOARD_CHANGED, ""_ostr);
197
0
    }
198
0
}
199
200
IMPL_STATIC_LINK( SfxClipboardChangeListener, AsyncExecuteHdl_Impl, void*, p, void )
201
0
{
202
0
    AsyncExecuteInfo* pAsyncExecuteInfo = static_cast<AsyncExecuteInfo*>(p);
203
0
    if ( pAsyncExecuteInfo )
204
0
    {
205
0
        if ( pAsyncExecuteInfo->m_xListener.is() )
206
0
        {
207
0
            if ( pAsyncExecuteInfo->m_eCmd == ASYNCEXECUTE_CMD_DISPOSING )
208
0
                pAsyncExecuteInfo->m_xListener->DisconnectViewShell();
209
0
            else if ( pAsyncExecuteInfo->m_eCmd == ASYNCEXECUTE_CMD_CHANGEDCONTENTS )
210
0
                pAsyncExecuteInfo->m_xListener->ChangedContents();
211
0
        }
212
0
    }
213
0
    delete pAsyncExecuteInfo;
214
0
}
215
216
void SAL_CALL SfxClipboardChangeListener::disposing( const lang::EventObject& /*rEventObject*/ )
217
4.26k
{
218
    // Either clipboard or ViewShell is going to be destroyed -> no interest in listening anymore
219
4.26k
    uno::Reference< lang::XComponent > xCtrl( m_xCtrl );
220
4.26k
    uno::Reference< datatransfer::clipboard::XClipboardNotifier > xNotify( m_xClpbrdNtfr );
221
222
4.26k
    uno::Reference< datatransfer::clipboard::XClipboardListener > xThis( static_cast< datatransfer::clipboard::XClipboardListener* >( this ));
223
4.26k
    if ( xCtrl.is() )
224
4.26k
        xCtrl->removeEventListener( uno::Reference < lang::XEventListener > ( static_cast < lang::XEventListener* >( this )));
225
4.26k
    if ( xNotify.is() )
226
0
        xNotify->removeClipboardListener( xThis );
227
228
    // Make asynchronous call to avoid locking SolarMutex which is the
229
    // root for many deadlocks, especially in conjunction with the "Windows"
230
    // based single thread apartment clipboard code!
231
4.26k
    AsyncExecuteInfo* pInfo = new AsyncExecuteInfo( ASYNCEXECUTE_CMD_DISPOSING, this );
232
4.26k
    if (!Application::PostUserEvent( LINK( nullptr, SfxClipboardChangeListener, AsyncExecuteHdl_Impl ), pInfo ))
233
0
        delete pInfo;
234
4.26k
}
235
236
void SAL_CALL SfxClipboardChangeListener::changedContents( const datatransfer::clipboard::ClipboardEvent& )
237
0
{
238
    // Make asynchronous call to avoid locking SolarMutex which is the
239
    // root for many deadlocks, especially in conjunction with the "Windows"
240
    // based single thread apartment clipboard code!
241
0
    AsyncExecuteInfo* pInfo = new AsyncExecuteInfo( ASYNCEXECUTE_CMD_CHANGEDCONTENTS, this );
242
0
    if (!Application::PostUserEvent( LINK( nullptr, SfxClipboardChangeListener, AsyncExecuteHdl_Impl ), pInfo ))
243
0
        delete pInfo;
244
0
}
245
246
namespace
247
{
248
struct TableSizeType
249
{
250
    sal_Int32 nRowCount;
251
    sal_Int32 nColCount;
252
};
253
}
254
255
typedef std::list<uno::Reference<accessibility::XAccessibleTable>> XAccessibleTableList;
256
257
namespace
258
{
259
constexpr
260
bool isText(sal_Int16 nRole)
261
0
{
262
0
    return nRole == accessibility::AccessibleRole::DOCUMENT_TEXT;
263
0
}
264
265
constexpr
266
bool isSpreadsheet(sal_Int16 nRole)
267
0
{
268
0
    return nRole == accessibility::AccessibleRole::DOCUMENT_SPREADSHEET;
269
0
}
270
271
constexpr
272
bool isPresentation(sal_Int16 nRole)
273
0
{
274
0
    return nRole == accessibility::AccessibleRole::DOCUMENT_PRESENTATION;
275
0
}
276
277
constexpr
278
bool isDocument(sal_Int16 nRole)
279
0
{
280
0
    return isText(nRole) || isSpreadsheet(nRole) || isPresentation(nRole);
281
0
}
282
283
bool hasState(const accessibility::AccessibleEventObject& aEvent, ::sal_Int64 nState)
284
0
{
285
0
    bool res = false;
286
0
    uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
287
0
    if (xContext.is())
288
0
    {
289
0
        ::sal_Int64 nStateSet = xContext->getAccessibleStateSet();
290
0
        res = (nStateSet & nState) != 0;
291
0
    }
292
0
    return res;
293
0
}
294
295
bool isFocused(const accessibility::AccessibleEventObject& aEvent)
296
0
{
297
0
    return hasState(aEvent, accessibility::AccessibleStateType::FOCUSED);
298
0
}
299
300
uno::Reference<accessibility::XAccessibleContext>
301
getParentContext(const uno::Reference<accessibility::XAccessibleContext>& xContext)
302
0
{
303
0
    uno::Reference<accessibility::XAccessibleContext> xParentContext;
304
0
    uno::Reference<accessibility::XAccessible> xParent = xContext->getAccessibleParent();
305
0
    if (xParent.is())
306
0
        xParentContext = uno::Reference<accessibility::XAccessibleContext>(xParent, uno::UNO_QUERY);
307
0
    return xParentContext;
308
0
}
309
310
OUString selectionEventTypeToString(sal_Int16 nEventId)
311
0
{
312
0
    using namespace accessibility;
313
0
    switch(nEventId)
314
0
    {
315
0
        case AccessibleEventId::SELECTION_CHANGED:
316
0
            return u"create"_ustr;
317
0
        case AccessibleEventId::SELECTION_CHANGED_ADD:
318
0
            return u"add"_ustr;
319
0
        case AccessibleEventId::SELECTION_CHANGED_REMOVE:
320
0
            return u"remove"_ustr;
321
0
        default:
322
0
            return u""_ustr;
323
0
    }
324
0
}
325
326
bool selectionHasToBeNotified(const uno::Reference<accessibility::XAccessibleContext>& xContext)
327
0
{
328
0
    sal_Int16 nRole = xContext->getAccessibleRole();
329
0
    return
330
0
        nRole == accessibility::AccessibleRole::GRAPHIC ||
331
0
        nRole == accessibility::AccessibleRole::EMBEDDED_OBJECT ||
332
0
        nRole == accessibility::AccessibleRole::SHAPE;
333
0
}
334
335
bool hasToBeActiveForEditing(sal_Int16 nRole)
336
0
{
337
0
    return
338
0
        nRole == accessibility::AccessibleRole::SHAPE;
339
0
}
340
341
sal_Int16 getParentRole(const uno::Reference<accessibility::XAccessibleContext>& xContext)
342
0
{
343
0
    sal_Int16 nRole = 0;
344
0
    if (xContext.is())
345
0
    {
346
0
        uno::Reference<accessibility::XAccessibleContext> xParentContext = getParentContext(xContext);
347
0
        if (xParentContext.is())
348
0
            nRole = xParentContext->getAccessibleRole();
349
0
    }
350
0
    return nRole;
351
0
}
352
353
sal_Int64 getAccessibleSiblingCount(const Reference<accessibility::XAccessibleContext>& xContext)
354
0
{
355
0
    if (!xContext.is())
356
0
        return -1;
357
358
0
    sal_Int64 nChildCount = 0;
359
0
    Reference<accessibility::XAccessible> xParent = xContext->getAccessibleParent();
360
0
    if (xParent.is())
361
0
    {
362
0
        Reference<accessibility::XAccessibleContext> xParentContext = xParent->getAccessibleContext();
363
0
        if (xParentContext.is())
364
0
        {
365
0
            nChildCount = xParentContext->getAccessibleChildCount();
366
0
        }
367
0
    }
368
0
    return nChildCount - 1;
369
0
}
370
371
// Put in rAncestorList all ancestors of xTable up to xAncestorTable or
372
// up to the first not-a-table ancestor if xAncestorTable is not an ancestor.
373
// xTable is included in the list, xAncestorTable is not included.
374
// The list is ordered from the ancient ancestor to xTable.
375
// Return true if xAncestorTable is an ancestor of xTable.
376
bool getAncestorList(XAccessibleTableList& rAncestorList,
377
                     const uno::Reference<accessibility::XAccessibleTable>& xTable,
378
                     const uno::Reference<accessibility::XAccessibleTable>& xAncestorTable = uno::Reference<accessibility::XAccessibleTable>())
379
0
{
380
0
    uno::Reference<accessibility::XAccessibleTable> xCurrentTable = xTable;
381
0
    while (xCurrentTable.is() && xCurrentTable != xAncestorTable)
382
0
    {
383
0
        rAncestorList.push_front(xCurrentTable);
384
385
0
        uno::Reference<accessibility::XAccessibleContext> xContext(xCurrentTable, uno::UNO_QUERY);
386
0
        xCurrentTable.clear();
387
0
        if (xContext.is())
388
0
        {
389
0
            uno::Reference<accessibility::XAccessible> xParent = xContext->getAccessibleParent();
390
0
            uno::Reference<accessibility::XAccessibleContext> xParentContext(xParent, uno::UNO_QUERY);
391
0
            if (xParentContext.is()
392
0
                    && xParentContext->getAccessibleRole() == accessibility::AccessibleRole::TABLE_CELL)
393
0
            {
394
0
                uno::Reference<accessibility::XAccessible> xCellParent = xParentContext->getAccessibleParent();
395
0
                if (xCellParent.is())
396
0
                {
397
0
                    xCurrentTable = uno::Reference<accessibility::XAccessibleTable>(xCellParent, uno::UNO_QUERY);
398
0
                }
399
0
            }
400
0
        }
401
0
    }
402
403
0
    return xCurrentTable.is() && xCurrentTable == xAncestorTable;
404
0
}
405
406
void lookForParentTable(const uno::Reference<accessibility::XAccessibleContext>& xContext,
407
                        uno::Reference<accessibility::XAccessibleTable>& xTable,
408
                        sal_Int64& nChildIndex)
409
0
{
410
0
    using namespace accessibility;
411
0
    uno::Reference<XAccessibleContext> xParentContext = getParentContext(xContext);
412
0
    if (xParentContext.is() && xParentContext->getAccessibleRole() == AccessibleRole::TABLE_CELL)
413
0
    {
414
0
        uno::Reference<XAccessible> xCellParent = xParentContext->getAccessibleParent();
415
0
        if (xCellParent.is())
416
0
        {
417
0
            xTable = uno::Reference<XAccessibleTable>(xCellParent, uno::UNO_QUERY);
418
0
            if (xTable.is())
419
0
            {
420
0
                nChildIndex = xParentContext->getAccessibleIndexInParent();
421
0
            }
422
0
        }
423
0
    }
424
0
}
425
426
OUString truncateText(std::u16string_view sText, sal_Int32 nNewLength)
427
0
{
428
    // truncate test to given length
429
0
    std::u16string_view sNewText = sText.substr(0, nNewLength);
430
    // try to truncate at a word
431
0
    size_t nLastPos = sNewText.rfind(u" ");
432
0
    if (nLastPos != 0 && nLastPos != std::u16string_view::npos)
433
0
        sNewText = sNewText.substr(0, nLastPos);
434
0
    return OUString(sNewText);
435
0
}
436
437
std::string stateSetToString(::sal_Int64 stateSet)
438
0
{
439
0
    static const std::string states[35] = {
440
0
            "ACTIVE", "ARMED", "BUSY", "CHECKED", "DEFUNC",
441
0
            "EDITABLE", "ENABLED", "EXPANDABLE", "EXPANDED", "FOCUSABLE",
442
0
            "FOCUSED", "HORIZONTAL", "ICONIFIED", "INDETERMINATE", "MANAGES_DESCENDANTS",
443
0
            "MODAL", "MULTI_LINE", "MULTI_SELECTABLE", "OPAQUE", "PRESSED",
444
0
            "RESIZABLE", "SELECTABLE", "SELECTED", "SENSITIVE", "SHOWING",
445
0
            "SINGLE_LINE", "STALE", "TRANSIENT", "VERTICAL", "VISIBLE",
446
0
            "MOVEABLE", "DEFAULT", "OFFSCREEN", "COLLAPSE", "CHECKABLE"
447
0
    };
448
449
0
    if (stateSet == 0)
450
0
        return "INVALID";
451
0
    ::sal_Int64 state = 1;
452
0
    std::string s;
453
0
    for (int i = 0; i < 35; ++i)
454
0
    {
455
0
        if (stateSet & state)
456
0
        {
457
0
            s += states[i];
458
0
            s += "|";
459
0
        }
460
0
        state <<= 1;
461
0
    }
462
0
    return s;
463
0
}
464
465
void aboutView(std::string msg,  const void* pInstance, const SfxViewShell* pViewShell)
466
0
{
467
0
    if (!pViewShell)
468
0
        return;
469
470
0
    SAL_INFO("lok.a11y", ">>> " << msg << ": instance: " << pInstance
471
0
            << ", VIED ID: " <<  pViewShell->GetViewShellId().get() << " <<<");
472
0
}
473
474
void aboutEvent(std::string msg, const accessibility::AccessibleEventObject& aEvent)
475
0
{
476
0
    try
477
0
    {
478
0
        uno::Reference< accessibility::XAccessible > xSource(aEvent.Source, uno::UNO_QUERY);
479
0
        if (xSource.is())
480
0
        {
481
0
            uno::Reference< accessibility::XAccessibleContext > xContext =
482
0
                    xSource->getAccessibleContext();
483
484
0
            if (xContext.is())
485
0
            {
486
0
                SAL_INFO("lok.a11y", msg << ": event id: " << aEvent.EventId
487
0
                        << "\n  xSource: " << xSource.get()
488
0
                        << "\n  role: " << xContext->getAccessibleRole()
489
0
                        << "\n  name: " << xContext->getAccessibleName()
490
0
                        << "\n  index in parent: " << xContext->getAccessibleIndexInParent()
491
0
                        << "\n  state set: " << stateSetToString(xContext->getAccessibleStateSet())
492
0
                        << "\n  parent: " << xContext->getAccessibleParent().get()
493
0
                        << "\n  child count: " << xContext->getAccessibleChildCount());
494
0
            }
495
0
            else
496
0
            {
497
0
                SAL_INFO("lok.a11y", msg << ": event id: " << aEvent.EventId
498
0
                                         << ", no accessible context!");
499
0
            }
500
0
        }
501
0
        else
502
0
        {
503
0
            SAL_INFO("lok.a11y", msg << ": event id: " << aEvent.EventId
504
0
                                     << ", no accessible source!");
505
0
        }
506
0
        uno::Reference< accessibility::XAccessible > xOldValue;
507
0
        aEvent.OldValue >>= xOldValue;
508
0
        if (xOldValue.is())
509
0
        {
510
0
            uno::Reference< accessibility::XAccessibleContext > xContext =
511
0
                    xOldValue->getAccessibleContext();
512
513
0
            if (xContext.is())
514
0
            {
515
0
                SAL_INFO("lok.a11y", msg << ": "
516
0
                           "\n  xOldValue: " << xOldValue.get()
517
0
                        << "\n  role: " << xContext->getAccessibleRole()
518
0
                        << "\n  name: " << xContext->getAccessibleName()
519
0
                        << "\n  index in parent: " << xContext->getAccessibleIndexInParent()
520
0
                        << "\n  state set: " << stateSetToString(xContext->getAccessibleStateSet())
521
0
                        << "\n  parent: " << xContext->getAccessibleParent().get()
522
0
                        << "\n  child count: " << xContext->getAccessibleChildCount());
523
0
            }
524
0
        }
525
0
        uno::Reference< accessibility::XAccessible > xNewValue;
526
0
        aEvent.NewValue >>= xNewValue;
527
0
        if (xNewValue.is())
528
0
        {
529
0
            uno::Reference< accessibility::XAccessibleContext > xContext =
530
0
                    xNewValue->getAccessibleContext();
531
532
0
            if (xContext.is())
533
0
            {
534
0
                SAL_INFO("lok.a11y", msg << ": "
535
0
                           "\n  xNewValue: " << xNewValue.get()
536
0
                        << "\n  role: " << xContext->getAccessibleRole()
537
0
                        << "\n  name: " << xContext->getAccessibleName()
538
0
                        << "\n  index in parent: " << xContext->getAccessibleIndexInParent()
539
0
                        << "\n  state set: " << stateSetToString(xContext->getAccessibleStateSet())
540
0
                        << "\n  parent: " << xContext->getAccessibleParent().get()
541
0
                        << "\n  child count: " << xContext->getAccessibleChildCount());
542
0
            }
543
0
        }
544
0
    }
545
0
    catch( const lang::IndexOutOfBoundsException& /*e*/ )
546
0
    {
547
0
        LOK_WARN("lok.a11y", "Focused object has invalid index in parent");
548
0
    }
549
0
}
550
551
sal_Int32 getListPrefixSize(const uno::Reference<css::accessibility::XAccessibleText>& xAccText)
552
0
{
553
0
    if (!xAccText.is())
554
0
        return 0;
555
556
0
    OUString sText = xAccText->getText();
557
0
    sal_Int32 nLength = sText.getLength();
558
0
    if (nLength <= 0)
559
0
        return 0;
560
561
0
    css::uno::Sequence< css::beans::PropertyValue > aRunAttributeList;
562
0
    css::uno::Sequence< OUString > aRequestedAttributes = {UNO_NAME_NUMBERING_LEVEL, UNO_NAME_NUMBERING};
563
0
    aRunAttributeList = xAccText->getCharacterAttributes(0, aRequestedAttributes);
564
565
0
    sal_Int16 nLevel = -1;
566
0
    bool bIsCounted = false;
567
0
    for (const auto& attribute: aRunAttributeList)
568
0
    {
569
0
        if (attribute.Name.isEmpty())
570
0
            continue;
571
0
        if (attribute.Name == UNO_NAME_NUMBERING_LEVEL)
572
0
           attribute.Value >>= nLevel;
573
0
        else if (attribute.Name == UNO_NAME_NUMBERING)
574
0
           attribute.Value >>= bIsCounted;
575
0
    }
576
0
    if (nLevel < 0 || !bIsCounted)
577
0
        return 0;
578
579
0
    css::accessibility::TextSegment aTextSegment =
580
0
        xAccText->getTextAtIndex(0, css::accessibility::AccessibleTextType::ATTRIBUTE_RUN);
581
582
0
    SAL_INFO("lok.a11y", "getListPrefixSize: prefix: " << aTextSegment.SegmentText << ", level: " << nLevel);
583
584
0
    return aTextSegment.SegmentEnd;
585
0
}
586
587
void aboutTextFormatting(std::string msg, const uno::Reference<css::accessibility::XAccessibleText>& xAccText)
588
0
{
589
0
    if (!xAccText.is())
590
0
        return;
591
592
0
    OUString sText = xAccText->getText();
593
0
    sal_Int32 nLength = sText.getLength();
594
0
    if (nLength <= 0)
595
0
        return;
596
597
0
    css::uno::Reference<css::accessibility::XAccessibleTextAttributes>
598
0
        xAccTextAttr(xAccText, uno::UNO_QUERY);
599
0
    css::uno::Sequence< OUString > aRequestedAttributes;
600
601
0
    sal_Int32 nPos = 0;
602
0
    while (nPos < nLength)
603
0
    {
604
0
        css::accessibility::TextSegment aTextSegment =
605
0
                xAccText->getTextAtIndex(nPos, css::accessibility::AccessibleTextType::ATTRIBUTE_RUN);
606
0
        SAL_INFO("lok.a11y", msg << ": "
607
0
                "text segment: '" << aTextSegment.SegmentText
608
0
                << "', start: " << aTextSegment.SegmentStart
609
0
                << ", end: " << aTextSegment.SegmentEnd);
610
611
0
        css::uno::Sequence< css::beans::PropertyValue > aRunAttributeList;
612
0
        if (xAccTextAttr.is())
613
0
        {
614
0
            aRunAttributeList = xAccTextAttr->getRunAttributes(nPos, aRequestedAttributes);
615
0
        }
616
0
        else
617
0
        {
618
0
            aRunAttributeList = xAccText->getCharacterAttributes(nPos, aRequestedAttributes);
619
0
        }
620
621
0
        sal_Int32 nSize = aRunAttributeList.getLength();
622
0
        SAL_INFO("lok.a11y",
623
0
                 msg << ": attribute list size: " << nSize);
624
0
        if (nSize)
625
0
        {
626
0
            OUString sValue;
627
0
            OUString sAttributes = u"{ "_ustr;
628
0
            for (const auto& attribute: aRunAttributeList)
629
0
            {
630
0
                if (attribute.Name.isEmpty())
631
0
                    continue;
632
633
0
                if (attribute.Name == "CharHeight" || attribute.Name == "CharWeight")
634
0
                {
635
0
                    float fValue = 0;
636
0
                    attribute.Value >>= fValue;
637
0
                    sValue = OUString::number(fValue);
638
0
                }
639
0
                else if (attribute.Name == "CharPosture")
640
0
                {
641
0
                    awt::FontSlant nValue = awt::FontSlant_NONE;
642
0
                    attribute.Value >>= nValue;
643
0
                    sValue = OUString::number(static_cast<unsigned int>(nValue));
644
0
                }
645
0
                else if (attribute.Name == "CharUnderline")
646
0
                {
647
0
                    sal_Int16 nValue = 0;
648
0
                    attribute.Value >>= nValue;
649
0
                    sValue = OUString::number(nValue);
650
0
                }
651
0
                else if (attribute.Name == "CharFontName")
652
0
                {
653
0
                    attribute.Value >>= sValue;
654
0
                }
655
0
                else if (attribute.Name == "Rsid")
656
0
                {
657
0
                    sal_uInt32 nValue = 0;
658
0
                    attribute.Value >>= nValue;
659
0
                    sValue = OUString::number(nValue);
660
0
                }
661
0
                else if (attribute.Name == UNO_NAME_NUMBERING_LEVEL)
662
0
                {
663
0
                    sal_Int16 nValue(-1);
664
0
                    attribute.Value >>= nValue;
665
0
                    sValue = OUString::number(nValue);
666
0
                }
667
0
                else if (attribute.Name == UNO_NAME_NUMBERING)
668
0
                {
669
0
                    bool bValue(false);
670
0
                    attribute.Value >>= bValue;
671
0
                    sValue = OUString::boolean(bValue);
672
0
                }
673
0
                else if (attribute.Name == UNO_NAME_NUMBERING_RULES)
674
0
                {
675
0
                    attribute.Value >>= sValue;
676
0
                }
677
678
0
                if (!sValue.isEmpty())
679
0
                {
680
0
                    if (sAttributes != "{ ")
681
0
                        sAttributes += ", ";
682
0
                    sAttributes += attribute.Name + ": " + sValue;
683
0
                    sValue = "";
684
0
                }
685
0
            }
686
0
            sAttributes += " }";
687
0
            SAL_INFO("lok.a11y",
688
0
                     msg << ": " << sAttributes);
689
0
        }
690
0
        nPos = aTextSegment.SegmentEnd + 1;
691
0
    }
692
0
}
693
694
void aboutParagraph(const std::string& msg, const OUString& rsParagraphContent, sal_Int32 nCaretPosition,
695
                    sal_Int32 nSelectionStart, sal_Int32 nSelectionEnd, sal_Int32 nListPrefixLength,
696
                    bool force = false)
697
0
{
698
0
    SAL_INFO("lok.a11y", msg << ": "
699
0
            "\n text content: \"" << rsParagraphContent << "\""
700
0
            "\n caret pos: " << nCaretPosition
701
0
            << "\n selection: start: " << nSelectionStart << ", end: " << nSelectionEnd
702
0
            << "\n list prefix length: " << nListPrefixLength
703
0
            << "\n force: " << force
704
0
            );
705
0
}
706
707
void aboutParagraph(const std::string& msg, const uno::Reference<css::accessibility::XAccessibleText>& xAccText,
708
                    bool force = false)
709
0
{
710
0
    if (!xAccText.is())
711
0
        return;
712
713
0
    OUString sText = xAccText->getText();
714
0
    sal_Int32 nCaretPosition = xAccText->getCaretPosition();
715
0
    sal_Int32 nSelectionStart = xAccText->getSelectionStart();
716
0
    sal_Int32 nSelectionEnd = xAccText->getSelectionEnd();
717
0
    sal_Int32 nListPrefixLength = getListPrefixSize(xAccText);
718
0
    aboutParagraph(msg, sText, nCaretPosition, nSelectionStart, nSelectionEnd, nListPrefixLength, force);
719
0
}
720
721
void aboutFocusedCellChanged(sal_Int32 nOutCount, const std::vector<TableSizeType>& aInList,
722
                             sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nRowSpan, sal_Int32 nColSpan)
723
0
{
724
0
    std::stringstream inListStream;
725
0
    inListStream << "[ ";
726
0
    for (const auto& rTableSize: aInList)
727
0
    {
728
0
        inListStream << "{ rowCount: " << rTableSize.nRowCount << " colCount: " << rTableSize.nColCount << " } ";
729
0
    }
730
0
    inListStream << "]";
731
732
0
    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyFocusedCellChanged: "
733
0
            "\n outCount: " << nOutCount
734
0
            << "\n inList: " << inListStream.str()
735
0
            << "\n row: " << nRow
736
0
            << "\n column: " << nCol
737
0
            << "\n rowSpan: " << nRowSpan
738
0
            << "\n colSpan: " << nColSpan
739
0
            );
740
0
}
741
} // anonymous namespace
742
743
class LOKDocumentFocusListener :
744
    public ::cppu::WeakImplHelper< accessibility::XAccessibleEventListener >
745
{
746
    static constexpr sal_Int64 MAX_ATTACHABLE_CHILDREN = 100;
747
748
    const SfxViewShell* m_pViewShell;
749
    sal_Int16 m_nDocumentType;
750
    std::unordered_set<uno::Reference<uno::XInterface>> m_aRefList;
751
    OUString m_sFocusedParagraph;
752
    sal_Int32 m_nCaretPosition;
753
    sal_Int32 m_nSelectionStart;
754
    sal_Int32 m_nSelectionEnd;
755
    sal_Int32 m_nListPrefixLength;
756
    uno::Reference<accessibility::XAccessibleTable> m_xLastTable;
757
    OUString m_sSelectedText;
758
    bool m_bIsEditingCell;
759
    // used for text content of a shape
760
    bool m_bIsEditingInSelection;
761
    OUString m_sSelectedCellAddress;
762
    uno::Reference<accessibility::XAccessible> m_xSelectedObject;
763
764
public:
765
    explicit LOKDocumentFocusListener(const SfxViewShell* pViewShell);
766
767
    /// @throws lang::IndexOutOfBoundsException
768
    /// @throws uno::RuntimeException
769
    void attachRecursive(
770
        const uno::Reference< accessibility::XAccessible >& xAccessible
771
    );
772
773
    /// @throws lang::IndexOutOfBoundsException
774
    /// @throws uno::RuntimeException
775
    void attachRecursive(
776
        const uno::Reference< accessibility::XAccessible >& xAccessible,
777
        const uno::Reference< accessibility::XAccessibleContext >& xContext
778
    );
779
780
    /// @throws lang::IndexOutOfBoundsException
781
    /// @throws uno::RuntimeException
782
    void attachRecursive(
783
        const uno::Reference< accessibility::XAccessible >& xAccessible,
784
        const uno::Reference< accessibility::XAccessibleContext >& xContext,
785
        const sal_Int64 nStateSet
786
    );
787
788
    /// @throws lang::IndexOutOfBoundsException
789
    /// @throws uno::RuntimeException
790
    void detachRecursive(
791
        const uno::Reference< accessibility::XAccessible >& xAccessible,
792
        bool bForce = false
793
    );
794
795
    /// @throws lang::IndexOutOfBoundsException
796
    /// @throws uno::RuntimeException
797
    void detachRecursive(
798
        const uno::Reference< accessibility::XAccessibleContext >& xContext,
799
        bool bForce = false
800
    );
801
802
    /// @throws lang::IndexOutOfBoundsException
803
    /// @throws uno::RuntimeException
804
    void detachRecursive(
805
        const uno::Reference< accessibility::XAccessibleContext >& xContext,
806
        const sal_Int64 nStateSet,
807
        bool bForce = false
808
    );
809
810
    /// @throws lang::IndexOutOfBoundsException
811
    /// @throws uno::RuntimeException
812
    static uno::Reference< accessibility::XAccessible > getAccessible(const lang::EventObject& aEvent );
813
814
    // XEventListener
815
    virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
816
817
    // XAccessibleEventListener
818
    virtual void SAL_CALL notifyEvent( const accessibility::AccessibleEventObject& aEvent ) override;
819
820
    void notifyEditingInSelectionState(bool bParagraph = true);
821
    void notifyFocusedParagraphChanged(bool force = false);
822
    void notifyCaretChanged();
823
    void notifyTextSelectionChanged();
824
    void notifyFocusedCellChanged(sal_Int32 nOutCount, const std::vector<TableSizeType>& aInList, sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nRowSpan, sal_Int32 nColSpan);
825
    void notifySelectionChanged(const uno::Reference<accessibility::XAccessible>& xAccObj, const OUString& sAction);
826
827
    OUString getFocusedParagraph() const;
828
    int getCaretPosition() const;
829
830
private:
831
    void paragraphPropertiesToTree(boost::property_tree::ptree& aPayloadTree, bool force = false) const;
832
    void paragraphPropertiesToJson(std::string& aPayload, bool force = false) const;
833
    bool updateParagraphInfo(const uno::Reference<css::accessibility::XAccessibleText>& xAccText,
834
                             bool force, const std::string& msg = "");
835
    void updateAndNotifyParagraph(const uno::Reference<css::accessibility::XAccessibleText>& xAccText,
836
                                  bool force, const std::string& msg = "");
837
    void resetParagraphInfo();
838
    void onFocusedParagraphInWriterTable(const uno::Reference<accessibility::XAccessibleTable>& xTable,
839
                                         sal_Int64 nChildIndex,
840
                                         const uno::Reference<accessibility::XAccessibleText>& xAccText);
841
    uno::Reference< accessibility::XAccessible >
842
    getSelectedObject(const accessibility::AccessibleEventObject& aEvent) const;
843
    void onShapeSelectionChanged(const Reference<accessibility::XAccessible>& xSelectedObject,
844
                                 const OUString& sAction);
845
};
846
847
LOKDocumentFocusListener::LOKDocumentFocusListener(const SfxViewShell* pViewShell)
848
0
    : m_pViewShell(pViewShell)
849
0
    , m_nDocumentType(0)
850
0
    , m_nCaretPosition(0)
851
0
    , m_nSelectionStart(0)
852
0
    , m_nSelectionEnd(0)
853
0
    , m_nListPrefixLength(0)
854
0
    , m_bIsEditingCell(false)
855
0
    , m_bIsEditingInSelection(false)
856
0
{
857
0
}
858
859
void LOKDocumentFocusListener::paragraphPropertiesToTree(boost::property_tree::ptree& aPayloadTree, bool force) const
860
0
{
861
0
    bool bLeftToRight = m_nCaretPosition == m_nSelectionEnd;
862
0
    aPayloadTree.put("content", m_sFocusedParagraph.toUtf8().getStr());
863
0
    aPayloadTree.put("position", m_nCaretPosition);
864
0
    aPayloadTree.put("start", bLeftToRight ? m_nSelectionStart : m_nSelectionEnd);
865
0
    aPayloadTree.put("end", bLeftToRight ? m_nSelectionEnd : m_nSelectionStart);
866
0
    if (m_nListPrefixLength > 0)
867
0
        aPayloadTree.put("listPrefixLength", m_nListPrefixLength);
868
0
    if (force)
869
0
        aPayloadTree.put("force", 1);
870
0
}
871
872
void LOKDocumentFocusListener::paragraphPropertiesToJson(std::string& aPayload, bool force) const
873
0
{
874
0
    boost::property_tree::ptree aPayloadTree;
875
0
    paragraphPropertiesToTree(aPayloadTree, force);
876
0
    std::stringstream aStream;
877
0
    boost::property_tree::write_json(aStream, aPayloadTree);
878
0
    aPayload = aStream.str();
879
0
}
880
881
OUString LOKDocumentFocusListener::getFocusedParagraph() const
882
0
{
883
0
    aboutView("LOKDocumentFocusListener::getFocusedParagraph", this, m_pViewShell);
884
0
    aboutParagraph("LOKDocumentFocusListener::getFocusedParagraph",
885
0
                   m_sFocusedParagraph, m_nCaretPosition,
886
0
                   m_nSelectionStart, m_nSelectionEnd, m_nListPrefixLength);
887
888
0
    std::string aPayload;
889
0
    paragraphPropertiesToJson(aPayload);
890
0
    OUString sRet = OUString::fromUtf8(aPayload);
891
0
    return sRet;
892
0
}
893
894
int LOKDocumentFocusListener::getCaretPosition() const
895
0
{
896
0
    aboutView("LOKDocumentFocusListener::getCaretPosition", this, m_pViewShell);
897
0
    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::getCaretPosition: " << m_nCaretPosition);
898
0
    return m_nCaretPosition;
899
0
}
900
901
// notifyEditingInSelectionState
902
// Used for notifying when editing becomes active/disabled for a shape
903
// bParagraph: should we append currently focused paragraph ?
904
// The problem is that the initially focused paragraph could not be the one user has clicked on,
905
// when there are more than a single paragraph.
906
// So in some case sending the focused paragraph could be misleading.
907
void LOKDocumentFocusListener::notifyEditingInSelectionState(bool bParagraph)
908
0
{
909
0
    aboutView("LOKDocumentFocusListener::notifyEditingInSelectionState", this, m_pViewShell);
910
911
0
    boost::property_tree::ptree aPayloadTree;
912
0
    bool bIsCell = !m_sSelectedCellAddress.isEmpty();
913
0
    aPayloadTree.put("cell", bIsCell ? 1 : 0);
914
0
    if (bIsCell)
915
0
    {
916
0
        aPayloadTree.put("enabled", m_bIsEditingCell ? 1 : 0);
917
0
        if (m_bIsEditingCell)
918
0
        {
919
0
            aPayloadTree.put("selection", m_sSelectedCellAddress);
920
0
            if (bParagraph)
921
0
                aPayloadTree.put("paragraph", m_sFocusedParagraph);
922
0
        }
923
0
    }
924
0
    else
925
0
    {
926
0
        aPayloadTree.put("enabled", m_bIsEditingInSelection ? 1 : 0);
927
0
        if (m_bIsEditingInSelection && m_xSelectedObject.is())
928
0
        {
929
0
            uno::Reference<accessibility::XAccessibleContext> xContext = m_xSelectedObject->getAccessibleContext();
930
0
            if (xContext.is())
931
0
            {
932
0
                OUString sSelectionDescr = xContext->getAccessibleName();
933
0
                sSelectionDescr = sSelectionDescr.trim();
934
0
                aPayloadTree.put("selection", sSelectionDescr);
935
0
                if (bParagraph)
936
0
                    aPayloadTree.put("paragraph", m_sFocusedParagraph);
937
0
            }
938
0
        }
939
0
    }
940
941
0
    std::stringstream aStream;
942
0
    boost::property_tree::write_json(aStream, aPayloadTree);
943
0
    std::string aPayload = aStream.str();
944
0
    if (m_pViewShell)
945
0
    {
946
0
        SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEditingInSelectionState: payload: \n" << aPayload);
947
0
        m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_EDITING_IN_SELECTION_STATE, aPayload.c_str());
948
0
    }
949
0
}
950
951
/// notifyFocusedParagraphChanged
952
//
953
//  Notify content, caret position and text selection start/end for the focused paragraph
954
//  in current view.
955
//  For focused we don't mean to be necessarily the currently focused accessibility node.
956
//  It's enough that the caret is present in the paragraph (position != -1).
957
//  In fact each view has its own accessibility node per each text paragraph.
958
//  Anyway there can be only one focused accessibility node at time.
959
//  So when text changes are performed in one view, both accessibility nodes emit
960
//  a text changed event, anyway only the accessibility node belonging to the view
961
//  where the text change has occurred is the focused one.
962
//
963
//  force: when true update the clipboard content even if client is composing.
964
//
965
//  Usually when editing on the client involves composing the clipboard area updating
966
//  is skipped until the composition is over.
967
//  On the contrary the composition would be aborted, making dictation not possible.
968
//  Anyway when the text change has been performed by another view we are in due
969
//  to update the clipboard content even if the user is in the middle of a composition.
970
void LOKDocumentFocusListener::notifyFocusedParagraphChanged(bool force)
971
0
{
972
0
    aboutView("LOKDocumentFocusListener::notifyFocusedParagraphChanged", this, m_pViewShell);
973
0
    std::string aPayload;
974
0
    paragraphPropertiesToJson(aPayload, force);
975
0
    if (m_pViewShell)
976
0
    {
977
0
        aboutParagraph("LOKDocumentFocusListener::notifyFocusedParagraphChanged",
978
0
                       m_sFocusedParagraph, m_nCaretPosition,
979
0
                       m_nSelectionStart, m_nSelectionEnd, m_nListPrefixLength, force);
980
981
0
        m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_FOCUS_CHANGED, aPayload.c_str());
982
0
    }
983
0
}
984
985
void LOKDocumentFocusListener::notifyCaretChanged()
986
0
{
987
0
    aboutView("LOKDocumentFocusListener::notifyCaretChanged", this, m_pViewShell);
988
0
    boost::property_tree::ptree aPayloadTree;
989
0
    aPayloadTree.put("position", m_nCaretPosition);
990
0
    std::stringstream aStream;
991
0
    boost::property_tree::write_json(aStream, aPayloadTree);
992
0
    std::string aPayload = aStream.str();
993
0
    if (m_pViewShell)
994
0
    {
995
0
        SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyCaretChanged: " << m_nCaretPosition);
996
0
        m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_CARET_CHANGED, aPayload.c_str());
997
0
    }
998
0
}
999
1000
void LOKDocumentFocusListener::notifyTextSelectionChanged()
1001
0
{
1002
0
    aboutView("LOKDocumentFocusListener::notifyTextSelectionChanged", this, m_pViewShell);
1003
0
    bool bLeftToRight = m_nCaretPosition == m_nSelectionEnd;
1004
0
    boost::property_tree::ptree aPayloadTree;
1005
0
    aPayloadTree.put("start", bLeftToRight ? m_nSelectionStart : m_nSelectionEnd);
1006
0
    aPayloadTree.put("end", bLeftToRight ? m_nSelectionEnd : m_nSelectionStart);
1007
0
    std::stringstream aStream;
1008
0
    boost::property_tree::write_json(aStream, aPayloadTree);
1009
0
    std::string aPayload = aStream.str();
1010
0
    if (m_pViewShell)
1011
0
    {
1012
0
        SAL_INFO("lok.a11y",  "LOKDocumentFocusListener::notifyTextSelectionChanged: "
1013
0
                "start: " << m_nSelectionStart << ", end: " << m_nSelectionEnd);
1014
0
        m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_TEXT_SELECTION_CHANGED, aPayload.c_str());
1015
0
    }
1016
0
}
1017
1018
void LOKDocumentFocusListener::notifyFocusedCellChanged(
1019
        sal_Int32 nOutCount, const std::vector<TableSizeType>& aInList,
1020
        sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nRowSpan, sal_Int32 nColSpan)
1021
0
{
1022
0
    aboutView("LOKDocumentFocusListener::notifyTablePositionChanged", this, m_pViewShell);
1023
0
    boost::property_tree::ptree aPayloadTree;
1024
0
    if (nOutCount > 0)
1025
0
    {
1026
0
        aPayloadTree.put("outCount", nOutCount);
1027
0
    }
1028
0
    if (!aInList.empty())
1029
0
    {
1030
0
        boost::property_tree::ptree aInListNode;
1031
0
        for (const auto& rTableSize: aInList)
1032
0
        {
1033
0
            boost::property_tree::ptree aTableSizeNode;
1034
0
            aTableSizeNode.put("rowCount", rTableSize.nRowCount);
1035
0
            aTableSizeNode.put("colCount", rTableSize.nColCount);
1036
1037
0
            aInListNode.push_back(std::make_pair(std::string(), aTableSizeNode));
1038
0
        }
1039
0
        aPayloadTree.add_child("inList", aInListNode);
1040
0
    }
1041
1042
0
    aPayloadTree.put("row", nRow);
1043
0
    aPayloadTree.put("col", nCol);
1044
1045
0
    if (nRowSpan > 1)
1046
0
    {
1047
0
        aPayloadTree.put("rowSpan", nRowSpan);
1048
0
    }
1049
0
    if (nColSpan > 1)
1050
0
    {
1051
0
        aPayloadTree.put("colSpan", nColSpan);
1052
0
    }
1053
1054
0
    boost::property_tree::ptree aContentNode;
1055
0
    paragraphPropertiesToTree(aContentNode);
1056
0
    aPayloadTree.add_child("paragraph", aContentNode);
1057
1058
0
    std::stringstream aStream;
1059
0
    boost::property_tree::write_json(aStream, aPayloadTree);
1060
0
    std::string aPayload = aStream.str();
1061
0
    if (m_pViewShell)
1062
0
    {
1063
0
        aboutFocusedCellChanged(nOutCount, aInList, nRow, nCol, nRowSpan, nColSpan);
1064
0
        aboutParagraph("LOKDocumentFocusListener::notifyFocusedCellChanged: paragraph: ",
1065
0
                       m_sFocusedParagraph, m_nCaretPosition, m_nSelectionStart, m_nSelectionEnd,
1066
0
                       m_nListPrefixLength, false);
1067
1068
0
        m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_FOCUSED_CELL_CHANGED, aPayload.c_str());
1069
0
    }
1070
0
}
1071
1072
void LOKDocumentFocusListener::notifySelectionChanged(const uno::Reference<accessibility::XAccessible>& xAccObj,
1073
                                                      const OUString& sAction)
1074
0
{
1075
0
    using namespace accessibility;
1076
0
    if (!xAccObj.is())
1077
0
        return;
1078
1079
0
    aboutView("LOKDocumentFocusListener::notifySelectionChanged", this, m_pViewShell);
1080
0
    uno::Reference<XAccessibleContext> xContext = xAccObj->getAccessibleContext();
1081
0
    if (xContext.is())
1082
0
    {
1083
0
        OUString sName = xContext->getAccessibleName();
1084
0
        sName = sName.trim();
1085
0
        if (sName == "GraphicObjectShape")
1086
0
            sName = "Graphic";
1087
1088
        // check for text content and send it with some limitations:
1089
        // no more than 10 paragraphs, no more than 1000 chars
1090
0
        bool bIsCell = xContext->getAccessibleRole() == AccessibleRole::TABLE_CELL;
1091
0
        OUString sTextContent;
1092
0
        if (sAction == "create" || sAction == "add")
1093
0
        {
1094
0
            const sal_Int64 nMaxJoinedParagraphs = 10;
1095
0
            const sal_Int32 nMaxTextContentLength = 1000;
1096
0
            if (bIsCell)
1097
0
            {
1098
0
                uno::Reference<XAccessibleText> xAccText(xAccObj, uno::UNO_QUERY);
1099
0
                if (xAccText.is())
1100
0
                {
1101
0
                    sTextContent = xAccText->getText();
1102
0
                    sal_Int32 nTextLength = sTextContent.getLength();
1103
0
                    if (nTextLength > nMaxTextContentLength)
1104
0
                    {
1105
0
                        sTextContent = truncateText(sTextContent, nMaxTextContentLength);
1106
0
                    }
1107
0
                }
1108
0
            }
1109
0
            else
1110
0
            {
1111
0
                sal_Int32 nTotalTextLength = 0;
1112
0
                sal_Int64 nChildCount = xContext->getAccessibleChildCount();
1113
0
                if (nChildCount > nMaxJoinedParagraphs)
1114
0
                    nChildCount = nMaxJoinedParagraphs;
1115
0
                for (sal_Int64 i = 0; i < nChildCount; ++i)
1116
0
                {
1117
0
                    uno::Reference<XAccessible> xChild = xContext->getAccessibleChild(i);
1118
0
                    uno::Reference<XAccessibleText> xAccText(xChild, uno::UNO_QUERY);
1119
0
                    if (!xAccText.is())
1120
0
                        continue;
1121
0
                    OUString sText = xAccText->getText();
1122
0
                    sal_Int32 nTextLength = sText.getLength();
1123
0
                    if (nTextLength < 1)
1124
0
                        continue;
1125
0
                    if (nTotalTextLength + nTextLength < nMaxTextContentLength)
1126
0
                    {
1127
0
                        nTotalTextLength += nTextLength;
1128
0
                        sTextContent += sText + " \n";
1129
0
                    }
1130
0
                    else
1131
0
                    {
1132
                        // truncate paragraph
1133
0
                        sal_Int32 nNewLength = nMaxTextContentLength - nTotalTextLength;
1134
0
                        sTextContent += truncateText(sText, nNewLength);
1135
0
                        break;
1136
0
                    }
1137
0
                }
1138
0
            }
1139
0
        }
1140
1141
0
        boost::property_tree::ptree aPayloadTree;
1142
0
        aPayloadTree.put("cell", bIsCell ? 1 : 0);
1143
0
        aPayloadTree.put("action", sAction);
1144
0
        aPayloadTree.put("name", sName);
1145
0
        if (!sTextContent.isEmpty())
1146
0
            aPayloadTree.put("text", sTextContent);
1147
0
        std::stringstream aStream;
1148
0
        boost::property_tree::write_json(aStream, aPayloadTree);
1149
0
        std::string aPayload = aStream.str();
1150
0
        if (m_pViewShell)
1151
0
        {
1152
0
            SAL_INFO("lok.a11y",  "LOKDocumentFocusListener::notifySelectionChanged: "
1153
0
                                     "action: " << sAction << ", name: " << sName);
1154
0
            m_pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_A11Y_SELECTION_CHANGED, aPayload.c_str());
1155
0
        }
1156
0
    }
1157
0
}
1158
1159
void LOKDocumentFocusListener::disposing( const lang::EventObject& aEvent )
1160
0
{
1161
    // Unref the object here, but do not remove as listener since the object
1162
    // might no longer be in a state that safely allows this.
1163
0
    if( aEvent.Source.is() )
1164
0
        m_aRefList.erase(aEvent.Source);
1165
1166
0
}
1167
1168
bool LOKDocumentFocusListener::updateParagraphInfo(const uno::Reference<css::accessibility::XAccessibleText>& xAccText,
1169
                                                   bool force, const std::string& msg)
1170
0
{
1171
0
    if (!xAccText.is())
1172
0
        return false;
1173
1174
0
    bool bNotify = false;
1175
    // If caret is present inside the paragraph (pos != -1), it means that paragraph has focus in the current view.
1176
0
    sal_Int32 nCaretPosition = xAccText->getCaretPosition();
1177
0
    if (nCaretPosition >= 0)
1178
0
    {
1179
0
        OUString sText = xAccText->getText();
1180
0
        m_nCaretPosition = nCaretPosition;
1181
0
        m_nSelectionStart = xAccText->getSelectionStart();
1182
0
        m_nSelectionEnd = xAccText->getSelectionEnd();
1183
0
        m_nListPrefixLength = getListPrefixSize(xAccText);
1184
1185
        // Inside a text shape when there is no selection, selection-start and selection-end are
1186
        // set to current caret position instead of -1. Moreover, inside a text shape pressing
1187
        // delete or backspace with an empty selection really deletes text and not only the empty
1188
        // selection as it occurs in a text paragraph in Writer.
1189
        // So whenever selection-start == selection-end, and we are inside a shape we need
1190
        // to set these parameters to -1 in order to have the client to handle delete and
1191
        // backspace properly.
1192
0
        if (m_nSelectionStart == m_nSelectionEnd && m_nSelectionStart != -1)
1193
0
        {
1194
0
            uno::Reference<accessibility::XAccessibleContext> xContext(xAccText, uno::UNO_QUERY);
1195
0
            sal_Int16 nParentRole = getParentRole(xContext);
1196
0
            if (nParentRole == accessibility::AccessibleRole::SHAPE ||
1197
0
                nParentRole == accessibility::AccessibleRole::TEXT_FRAME) // spreadsheet cell editing
1198
0
                m_nSelectionStart = m_nSelectionEnd = -1;
1199
0
        }
1200
1201
        // In case only caret position or text selection are different we can rely on specific events.
1202
0
        if (m_sFocusedParagraph != sText)
1203
0
        {
1204
0
            m_sFocusedParagraph = sText;
1205
0
            bNotify = true;
1206
0
        }
1207
0
    }
1208
0
    else
1209
0
    {
1210
0
        SAL_WARN("lok.a11y",
1211
0
                 "LOKDocumentFocusListener::updateParagraphInfo: skipped since no caret is present");
1212
0
    }
1213
1214
0
    std::string header = "LOKDocumentFocusListener::updateParagraphInfo";
1215
0
    if (msg.size())
1216
0
        header += ": " + msg;
1217
0
    aboutParagraph(header, xAccText, force);
1218
0
    return bNotify;
1219
1220
0
}
1221
1222
void LOKDocumentFocusListener::updateAndNotifyParagraph(
1223
        const uno::Reference<css::accessibility::XAccessibleText>& xAccText,
1224
        bool force, const std::string& msg)
1225
0
{
1226
0
    if (updateParagraphInfo(xAccText, force, msg))
1227
0
        notifyFocusedParagraphChanged(force);
1228
0
}
1229
1230
void LOKDocumentFocusListener::resetParagraphInfo()
1231
0
{
1232
0
    m_sFocusedParagraph = "";
1233
0
    m_nCaretPosition = 0;
1234
0
    m_nSelectionStart = -1;
1235
0
    m_nSelectionEnd = -1;
1236
0
    m_nListPrefixLength = 0;
1237
0
}
1238
1239
// For a presentation document when an accessible event of type SELECTION_CHANGED_XXX occurs
1240
// the selected (or unselected) object is put in NewValue, instead for a text document
1241
// the selected object is put in Source.
1242
// The following function helps to retrieve the selected object independently on where it has been put.
1243
uno::Reference< accessibility::XAccessible >
1244
LOKDocumentFocusListener::getSelectedObject(const accessibility::AccessibleEventObject& aEvent) const
1245
0
{
1246
0
    uno::Reference< accessibility::XAccessible > xSelectedObject;
1247
0
    if (isText(m_nDocumentType))
1248
0
    {
1249
0
        xSelectedObject.set(aEvent.Source, uno::UNO_QUERY);
1250
0
    }
1251
0
    else
1252
0
    {
1253
0
        aEvent.NewValue >>= xSelectedObject;
1254
0
    }
1255
0
    return xSelectedObject;
1256
0
}
1257
1258
void LOKDocumentFocusListener::onShapeSelectionChanged(
1259
    const uno::Reference<accessibility::XAccessible>& xSelectedObject,
1260
    const OUString& sAction)
1261
0
{
1262
    // when a shape is selected or unselected we could need to notify that text content editing
1263
    // is no more active, that allows on the client side to prevent default input.
1264
0
    resetParagraphInfo();
1265
0
    if (m_bIsEditingInSelection)
1266
0
    {
1267
0
        m_bIsEditingInSelection = false;
1268
0
        notifyEditingInSelectionState();
1269
0
    }
1270
0
    notifySelectionChanged(xSelectedObject, sAction);
1271
0
}
1272
1273
void LOKDocumentFocusListener::onFocusedParagraphInWriterTable(
1274
    const uno::Reference<accessibility::XAccessibleTable>& xTable,
1275
    sal_Int64 nChildIndex,
1276
    const uno::Reference<accessibility::XAccessibleText>& xAccText
1277
)
1278
0
{
1279
0
    std::vector<TableSizeType> aInList;
1280
0
    sal_Int32 nOutCount = 0;
1281
1282
0
    if (m_xLastTable.is())
1283
0
    {
1284
0
        if (xTable != m_xLastTable)
1285
0
        {
1286
            // do we get in one or more nested tables ?
1287
            // check if xTable is a descendant of m_xLastTable
1288
0
            XAccessibleTableList newTableAncestorList;
1289
0
            bool isLastAncestorOfNew = getAncestorList(newTableAncestorList, xTable, m_xLastTable);
1290
0
            bool isNewAncestorOfLast = false;
1291
0
            if (!isLastAncestorOfNew)
1292
0
            {
1293
                // do we get out of one or more nested tables ?
1294
                // check if m_xLastTable is a descendant of xTable
1295
0
                XAccessibleTableList lastTableAncestorList;
1296
0
                isNewAncestorOfLast = getAncestorList(lastTableAncestorList, m_xLastTable, xTable);
1297
                // we have to notify "out of table" for all  m_xLastTable ancestors up to xTable
1298
                // or the first not-a-table ancestor
1299
0
                nOutCount = lastTableAncestorList.size();
1300
0
            }
1301
0
            if (isLastAncestorOfNew || !isNewAncestorOfLast)
1302
0
            {
1303
                // we have to notify row/col count for all xTable ancestors starting from the ancestor
1304
                // which is a child of m_xLastTable (isLastAncestorOfNew) or the first not-a-table ancestor
1305
0
                for (const auto& ancestor: newTableAncestorList)
1306
0
                {
1307
0
                    TableSizeType aTableSize{ancestor->getAccessibleRowCount(),
1308
0
                                              ancestor->getAccessibleColumnCount()};
1309
0
                    aInList.push_back(aTableSize);
1310
0
                }
1311
0
            }
1312
0
        }
1313
0
    }
1314
0
    else
1315
0
    {
1316
        // cursor was not inside any table and gets inside one or more tables
1317
        // we have to notify row/col count for all xTable ancestors starting from first not-a-table ancestor
1318
0
        XAccessibleTableList newTableAncestorList;
1319
0
        getAncestorList(newTableAncestorList, xTable);
1320
0
        for (const auto& ancestor: newTableAncestorList)
1321
0
        {
1322
0
            TableSizeType aTableSize{ancestor->getAccessibleRowCount(),
1323
0
                                      ancestor->getAccessibleColumnCount()};
1324
0
            aInList.push_back(aTableSize);
1325
0
        }
1326
0
    }
1327
1328
    // we have to notify current row/col of xTable and related row/col span
1329
0
    sal_Int32 nRow = xTable->getAccessibleRow(nChildIndex);
1330
0
    sal_Int32 nCol = xTable->getAccessibleColumn(nChildIndex);
1331
0
    sal_Int32 nRowSpan = xTable->getAccessibleRowExtentAt(nRow, nCol);
1332
0
    sal_Int32 nColSpan = xTable->getAccessibleColumnExtentAt(nRow, nCol);
1333
1334
0
    m_xLastTable = xTable;
1335
0
    updateParagraphInfo(xAccText, false, "STATE_CHANGED: FOCUSED");
1336
0
    notifyFocusedCellChanged(nOutCount, aInList, nRow, nCol, nRowSpan, nColSpan);
1337
0
}
1338
1339
void LOKDocumentFocusListener::notifyEvent(const accessibility::AccessibleEventObject& aEvent)
1340
0
{
1341
0
    using namespace accessibility;
1342
0
    aboutView("LOKDocumentFocusListener::notifyEvent", this, m_pViewShell);
1343
1344
0
    try
1345
0
    {
1346
0
        aboutEvent("LOKDocumentFocusListener::notifyEvent", aEvent);
1347
1348
0
        switch (aEvent.EventId)
1349
0
        {
1350
0
            case AccessibleEventId::STATE_CHANGED:
1351
0
            {
1352
                // logging
1353
0
                sal_Int64 nState = accessibility::AccessibleStateType::INVALID;
1354
0
                aEvent.NewValue >>= nState;
1355
0
                sal_Int64 nOldState = accessibility::AccessibleStateType::INVALID;
1356
0
                aEvent.OldValue >>= nOldState;
1357
0
                SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: STATE_CHANGED: "
1358
0
                                        " New State: " << stateSetToString(nState)
1359
0
                                     << ", Old State: " << stateSetToString(nOldState));
1360
1361
                // check validity
1362
0
                uno::Reference< XAccessible > xAccessibleObject = getAccessible(aEvent);
1363
0
                if (!xAccessibleObject.is())
1364
0
                    return;
1365
0
                uno::Reference<XAccessibleContext> xContext(aEvent.Source, uno::UNO_QUERY);
1366
0
                if (!xContext)
1367
0
                    return;
1368
1369
0
                sal_Int16 nRole = xContext->getAccessibleRole();
1370
1371
0
                if (nRole == AccessibleRole::PARAGRAPH)
1372
0
                {
1373
0
                    uno::Reference<XAccessibleText> xAccText(xAccessibleObject, uno::UNO_QUERY);
1374
0
                    if (!xAccText.is())
1375
0
                        return;
1376
1377
0
                    switch (nState)
1378
0
                    {
1379
0
                        case AccessibleStateType::ACTIVE:
1380
0
                        {
1381
0
                            if (!m_bIsEditingInSelection && hasToBeActiveForEditing(getParentRole(xContext)))
1382
0
                            {
1383
0
                                m_bIsEditingInSelection = true;
1384
0
                            }
1385
0
                            break;
1386
0
                        }
1387
0
                        case AccessibleStateType::FOCUSED:
1388
0
                        {
1389
0
                            if (m_bIsEditingInSelection && m_xSelectedObject.is())
1390
0
                            {
1391
0
                                updateParagraphInfo(xAccText, true, "STATE_CHANGED: FOCUSED");
1392
0
                                notifyEditingInSelectionState(getAccessibleSiblingCount(xContext) == 0);
1393
0
                                notifyFocusedParagraphChanged(true);
1394
                                // we clear selected object so when editing is over but shape is
1395
                                // still selected, the selection event is notified the same to the client
1396
0
                                m_xSelectedObject.clear();
1397
0
                                return;
1398
0
                            }
1399
0
                            if (isText(m_nDocumentType))
1400
0
                            {
1401
                                // check if we are inside a table: in case notify table and current cell info
1402
0
                                bool isInsideTable = false;
1403
0
                                uno::Reference<XAccessibleTable> xTable;
1404
0
                                sal_Int64 nChildIndex = 0;
1405
0
                                lookForParentTable(xContext, xTable, nChildIndex);
1406
0
                                if (xTable.is())
1407
0
                                {
1408
0
                                    onFocusedParagraphInWriterTable(xTable, nChildIndex, xAccText);
1409
0
                                    isInsideTable = true;
1410
0
                                }
1411
                                // paragraph is not inside any table
1412
0
                                if (!isInsideTable)
1413
0
                                {
1414
0
                                    if (m_xLastTable.is())
1415
0
                                    {
1416
                                        // we get out one or more tables
1417
                                        // we have to notify "out of table" for all m_xLastTable ancestors
1418
                                        // up to the first not-a-table ancestor
1419
0
                                        XAccessibleTableList lastTableAncestorList;
1420
0
                                        getAncestorList(lastTableAncestorList, m_xLastTable);
1421
0
                                        sal_Int32 nOutCount = lastTableAncestorList.size();
1422
                                        // no more inside a table
1423
0
                                        m_xLastTable.clear();
1424
                                        // notify
1425
0
                                        std::vector<TableSizeType> aInList;
1426
0
                                        updateParagraphInfo(xAccText, false, "STATE_CHANGED: FOCUSED");
1427
0
                                        notifyFocusedCellChanged(nOutCount, aInList, -1, -1, 1, 1);
1428
0
                                    }
1429
0
                                    else
1430
0
                                    {
1431
0
                                        updateAndNotifyParagraph(xAccText, false, "STATE_CHANGED: FOCUSED");
1432
0
                                    }
1433
0
                                }
1434
0
                            }
1435
0
                            else if (isSpreadsheet(m_nDocumentType))
1436
0
                            {
1437
0
                                if (m_bIsEditingCell)
1438
0
                                {
1439
0
                                    if (!hasState(aEvent, AccessibleStateType::ACTIVE))
1440
0
                                    {
1441
0
                                        SAL_WARN("lok.a11y",
1442
0
                                                 "LOKDocumentFocusListener::notifyEvent: FOCUSED: "
1443
0
                                                 "cell not ACTIVE for editing yet");
1444
0
                                        return;
1445
0
                                    }
1446
0
                                    else if (m_xSelectedObject.is())
1447
0
                                    {
1448
0
                                        updateParagraphInfo(xAccText, true, "STATE_CHANGED: ACTIVE");
1449
0
                                        notifyEditingInSelectionState(getAccessibleSiblingCount(xContext) == 0);
1450
0
                                        notifyFocusedParagraphChanged(true);
1451
0
                                        m_xSelectedObject.clear();
1452
0
                                        return;
1453
0
                                    }
1454
1455
0
                                    updateAndNotifyParagraph(xAccText, false, "STATE_CHANGED: FOCUSED");
1456
0
                                }
1457
0
                            }
1458
0
                            else if (isPresentation(m_nDocumentType))
1459
0
                            {
1460
0
                                updateAndNotifyParagraph(xAccText, false, "STATE_CHANGED: FOCUSED");
1461
0
                            }
1462
0
                            aboutTextFormatting("LOKDocumentFocusListener::notifyEvent: STATE_CHANGED: FOCUSED", xAccText);
1463
1464
0
                            break;
1465
0
                        }
1466
0
                        default:
1467
0
                            break;
1468
0
                    }
1469
0
                }
1470
0
                break;
1471
0
            }
1472
0
            case AccessibleEventId::CARET_CHANGED:
1473
0
            {
1474
0
                sal_Int32 nNewPos = -1;
1475
0
                aEvent.NewValue >>= nNewPos;
1476
0
                sal_Int32 nOldPos = -1;
1477
0
                aEvent.OldValue >>= nOldPos;
1478
1479
0
                if (nNewPos >= 0)
1480
0
                {
1481
0
                    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: CARET_CHANGED: "
1482
0
                                         "new pos: " << nNewPos << ", nOldPos: " << nOldPos);
1483
1484
0
                    uno::Reference<XAccessibleText> xAccText(getAccessible(aEvent), uno::UNO_QUERY);
1485
0
                    if (xAccText.is())
1486
0
                    {
1487
0
                        m_nCaretPosition = nNewPos;
1488
                        // Let's say we are in the following case: 'Hello wor|ld',
1489
                        // where '|' is the cursor position for the current view.
1490
                        // Suppose that in another view it's typed <enter> soon before 'world'.
1491
                        // Now the new paragraph content and caret position is: 'wor|ld'.
1492
                        // Anyway no new paragraph focused event is emitted for current view.
1493
                        // Only a new caret position event is emitted.
1494
                        // So we could need to notify a new focused paragraph changed message.
1495
0
                        if (!isFocused(aEvent))
1496
0
                        {
1497
0
                            if (updateParagraphInfo(xAccText, false, "CARET_CHANGED"))
1498
0
                                notifyFocusedParagraphChanged(true);
1499
0
                        }
1500
0
                        else
1501
0
                        {
1502
0
                            notifyCaretChanged();
1503
0
                        }
1504
0
                        aboutParagraph("LOKDocumentFocusListener::notifyEvent: CARET_CHANGED", xAccText);
1505
0
                    }
1506
0
                }
1507
0
                break;
1508
0
            }
1509
0
            case AccessibleEventId::TEXT_CHANGED:
1510
0
            {
1511
0
                TextSegment aDeletedText;
1512
0
                TextSegment aInsertedText;
1513
1514
0
                if (aEvent.OldValue >>= aDeletedText)
1515
0
                {
1516
0
                    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: TEXT_CHANGED: "
1517
0
                                             "deleted text: >" << aDeletedText.SegmentText << "<");
1518
0
                }
1519
0
                if (aEvent.NewValue >>= aInsertedText)
1520
0
                {
1521
0
                    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: TEXT_CHANGED: "
1522
0
                                             "inserted text: >" << aInsertedText.SegmentText << "<");
1523
0
                }
1524
0
                uno::Reference<XAccessibleText> xAccText(getAccessible(aEvent), uno::UNO_QUERY);
1525
1526
                // When the change has been performed in another view we need to force
1527
                // paragraph content updating on the client, even if current editing involves composing.
1528
                // We make a guess that if the paragraph accessibility node is not focused,
1529
                // it means that the text change has been performed in another view.
1530
0
                updateAndNotifyParagraph(xAccText, !isFocused(aEvent), "TEXT_CHANGED");
1531
1532
0
                break;
1533
0
            }
1534
0
            case AccessibleEventId::TEXT_SELECTION_CHANGED:
1535
0
            {
1536
0
                if (!isFocused(aEvent))
1537
0
                {
1538
0
                    SAL_WARN("lok.a11y",
1539
0
                             "LOKDocumentFocusListener::notifyEvent: TEXT_SELECTION_CHANGED: "
1540
0
                             "skip non focused paragraph");
1541
0
                    return;
1542
0
                }
1543
1544
0
                uno::Reference<XAccessibleText> xAccText(getAccessible(aEvent), uno::UNO_QUERY);
1545
0
                if (xAccText.is())
1546
0
                {
1547
                    // We send a message to client also when start/end are -1, in this way the client knows
1548
                    // if a text selection object exists or not. That's needed because of the odd behavior
1549
                    // occurring when <backspace>/<delete> are hit and a text selection is empty,
1550
                    // but it still exists.
1551
                    // Such keys delete the empty selection instead of the previous/next char.
1552
0
                    updateParagraphInfo(xAccText, false, "TEXT_SELECTION_CHANGED");
1553
1554
0
                    m_sSelectedText = xAccText->getSelectedText();
1555
0
                    SAL_INFO("lok.a11y",
1556
0
                             "LOKDocumentFocusListener::notifyEvent: TEXT_SELECTION_CHANGED: selected text: >"
1557
0
                              << m_sSelectedText << "<");
1558
1559
                    // Calc: when editing a formula send the update content
1560
0
                    if (m_bIsEditingCell)
1561
0
                    {
1562
0
                        OUString sText = xAccText->getText();
1563
0
                        if (!m_sSelectedCellAddress.isEmpty() &&
1564
0
                            !m_sSelectedText.isEmpty() && sText.startsWith("="))
1565
0
                        {
1566
0
                            notifyFocusedParagraphChanged();
1567
0
                        }
1568
0
                    }
1569
0
                    notifyTextSelectionChanged();
1570
0
                }
1571
0
                break;
1572
0
            }
1573
0
            case AccessibleEventId::SELECTION_CHANGED:
1574
0
            case AccessibleEventId::SELECTION_CHANGED_REMOVE:
1575
0
            {
1576
0
                uno::Reference< XAccessible > xSelectedObject = getSelectedObject(aEvent);
1577
0
                if (!xSelectedObject.is())
1578
0
                    return;
1579
0
                uno::Reference< XAccessibleContext > xContext = xSelectedObject->getAccessibleContext();
1580
0
                if (!xContext.is())
1581
0
                    return;
1582
1583
0
                if (aEvent.EventId == AccessibleEventId::SELECTION_CHANGED_REMOVE)
1584
0
                    m_xSelectedObject.clear();
1585
0
                else if (m_xSelectedObject.is() && m_xSelectedObject == xSelectedObject)
1586
0
                        return; // selecting the same object; note: on editing selected object is cleared
1587
0
                else
1588
0
                    m_xSelectedObject = xSelectedObject;
1589
0
                SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: SELECTION_CHANGED: "
1590
0
                                         "m_xSelectedObject.is(): " << m_xSelectedObject.is());
1591
1592
0
                OUString sAction = selectionEventTypeToString(aEvent.EventId);
1593
0
                sal_Int16 nRole = xContext->getAccessibleRole();
1594
0
                switch(nRole)
1595
0
                {
1596
0
                    case AccessibleRole::GRAPHIC:
1597
0
                    case AccessibleRole::EMBEDDED_OBJECT:
1598
0
                    case AccessibleRole::SHAPE:
1599
0
                    {
1600
0
                        onShapeSelectionChanged(xSelectedObject, sAction);
1601
0
                        break;
1602
0
                    }
1603
0
                    case AccessibleRole::TABLE_CELL:
1604
0
                    {
1605
0
                        notifySelectionChanged(xSelectedObject, sAction);
1606
1607
0
                        if (aEvent.EventId == AccessibleEventId::SELECTION_CHANGED)
1608
0
                        {
1609
0
                            m_sSelectedCellAddress = xContext->getAccessibleName();
1610
0
                            if (m_bIsEditingCell && !m_sSelectedCellAddress.isEmpty())
1611
0
                            {
1612
                                // Check cell address: "$Sheet1.A10".
1613
                                // On cell editing SELECTION_CHANGED is not emitted when selection is expanded.
1614
                                // So selection can't be a cell range.
1615
0
                                sal_Int32 nDotIndex = m_sSelectedText.indexOf('.');
1616
0
                                OUString sCellAddress = m_sSelectedText.copy(nDotIndex + 1);
1617
0
                                SAL_INFO("lok.a11y", "LOKDocumentFocusListener::notifyEvent: SELECTION_CHANGED: "
1618
0
                                                         "cell address: >" << sCellAddress << "<");
1619
0
                                if (m_sSelectedCellAddress == sCellAddress)
1620
0
                                {
1621
0
                                    notifyFocusedParagraphChanged();
1622
0
                                    notifyTextSelectionChanged();
1623
0
                                }
1624
0
                            }
1625
0
                        }
1626
0
                        break;
1627
0
                    }
1628
0
                    default:
1629
0
                        break;
1630
0
                }
1631
0
                break;
1632
0
            }
1633
0
            case AccessibleEventId::CHILD:
1634
0
            {
1635
0
                uno::Reference< accessibility::XAccessible > xChild;
1636
0
                if( (aEvent.OldValue >>= xChild) && xChild.is() )
1637
0
                    detachRecursive(xChild);
1638
1639
0
                if( (aEvent.NewValue >>= xChild) && xChild.is() )
1640
0
                    attachRecursive(xChild);
1641
1642
0
                break;
1643
0
            }
1644
0
            case AccessibleEventId::INVALIDATE_ALL_CHILDREN:
1645
0
            {
1646
0
                SAL_INFO("lok.a11y", "Invalidate all children called");
1647
0
                break;
1648
0
            }
1649
0
            default:
1650
0
                break;
1651
0
        }
1652
0
    }
1653
0
    catch( const lang::IndexOutOfBoundsException& )
1654
0
    {
1655
0
        LOK_WARN("lok.a11y",
1656
0
                 "LOKDocumentFocusListener::notifyEvent:Focused object has invalid index in parent");
1657
0
    }
1658
0
}
1659
1660
uno::Reference< accessibility::XAccessible > LOKDocumentFocusListener::getAccessible(const lang::EventObject& aEvent )
1661
0
{
1662
0
    uno::Reference< accessibility::XAccessible > xAccessible(aEvent.Source, uno::UNO_QUERY);
1663
1664
0
    if( xAccessible.is() )
1665
0
        return xAccessible;
1666
1667
0
    SAL_WARN("lok.a11y",
1668
0
             "LOKDocumentFocusListener::getAccessible: Event source doesn't implement XAccessible.");
1669
1670
0
    uno::Reference< accessibility::XAccessibleContext > xContext(aEvent.Source, uno::UNO_QUERY);
1671
1672
0
    if( xContext.is() )
1673
0
    {
1674
0
        uno::Reference< accessibility::XAccessible > xParent( xContext->getAccessibleParent() );
1675
0
        if( xParent.is() )
1676
0
        {
1677
0
            uno::Reference< accessibility::XAccessibleContext > xParentContext( xParent->getAccessibleContext() );
1678
0
            if( xParentContext.is() )
1679
0
            {
1680
0
                return xParentContext->getAccessibleChild( xContext->getAccessibleIndexInParent() );
1681
0
            }
1682
0
        }
1683
0
    }
1684
1685
0
    LOK_WARN("lok.a11y",
1686
0
             "LOKDocumentFocusListener::getAccessible: Can't get any accessible object from event source.");
1687
1688
0
    return uno::Reference< accessibility::XAccessible >();
1689
0
}
1690
1691
void LOKDocumentFocusListener::attachRecursive(
1692
    const uno::Reference< accessibility::XAccessible >& xAccessible
1693
)
1694
0
{
1695
0
    LOK_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(1): xAccessible: " << xAccessible.get());
1696
1697
0
    uno::Reference< accessibility::XAccessibleContext > xContext =
1698
0
        xAccessible->getAccessibleContext();
1699
1700
0
    if( xContext.is() )
1701
0
        attachRecursive(xAccessible, xContext);
1702
0
}
1703
1704
void LOKDocumentFocusListener::attachRecursive(
1705
    const uno::Reference< accessibility::XAccessible >& xAccessible,
1706
    const uno::Reference< accessibility::XAccessibleContext >& xContext
1707
)
1708
0
{
1709
0
    try
1710
0
    {
1711
0
        LOK_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(2): xAccessible: "
1712
0
                                 << xAccessible.get() << ", role: " << xContext->getAccessibleRole()
1713
0
                                 << ", name: " << xContext->getAccessibleName()
1714
0
                                 << ", parent: " << xContext->getAccessibleParent().get()
1715
0
                                 << ", child count: " << xContext->getAccessibleChildCount());
1716
1717
0
        sal_Int64 nStateSet = xContext->getAccessibleStateSet();
1718
1719
0
        if (!m_bIsEditingCell)
1720
0
        {
1721
0
            ::rtl::OUString sName = xContext->getAccessibleName();
1722
0
            m_bIsEditingCell = sName.startsWith("Cell");
1723
0
        }
1724
1725
0
        attachRecursive(xAccessible, xContext, nStateSet);
1726
0
    }
1727
0
    catch (const uno::Exception& e)
1728
0
    {
1729
0
        LOK_WARN("lok.a11y", "LOKDocumentFocusListener::attachRecursive(2): raised exception: " << e.Message);
1730
0
    }
1731
0
}
1732
1733
void LOKDocumentFocusListener::attachRecursive(
1734
    const uno::Reference< accessibility::XAccessible >& xAccessible,
1735
    const uno::Reference< accessibility::XAccessibleContext >& xContext,
1736
    const sal_Int64 nStateSet
1737
)
1738
0
{
1739
0
    aboutView("LOKDocumentFocusListener::attachRecursive (3)", this, m_pViewShell);
1740
0
    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #1: this: " << this
1741
0
            << ", xAccessible: " << xAccessible.get()
1742
0
            << ", role: " << xContext->getAccessibleRole()
1743
0
            << ", name: " << xContext->getAccessibleName()
1744
0
            << ", index in parent: " << xContext->getAccessibleIndexInParent()
1745
0
            << ", state: " << stateSetToString(nStateSet)
1746
0
            << ", parent: " << xContext->getAccessibleParent().get()
1747
0
            << ", child count: " << xContext->getAccessibleChildCount());
1748
1749
0
    uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
1750
1751
0
    if (!xBroadcaster.is())
1752
0
        return;
1753
0
    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #2: xBroadcaster.is()");
1754
    // If not already done, add the broadcaster to the list and attach as listener.
1755
0
    const uno::Reference< uno::XInterface >& xInterface = xBroadcaster;
1756
0
    if( m_aRefList.insert(xInterface).second )
1757
0
    {
1758
0
        SAL_INFO("lok.a11y", "LOKDocumentFocusListener::attachRecursive(3) #3: m_aRefList.insert(xInterface).second");
1759
0
        xBroadcaster->addAccessibleEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
1760
1761
0
        if (isDocument(xContext->getAccessibleRole()))
1762
0
        {
1763
0
            m_nDocumentType = xContext->getAccessibleRole();
1764
0
        }
1765
1766
0
        if (!(nStateSet & accessibility::AccessibleStateType::MANAGES_DESCENDANTS))
1767
0
        {
1768
0
            if ((nStateSet & accessibility::AccessibleStateType::SELECTED) &&
1769
0
                selectionHasToBeNotified(xContext))
1770
0
            {
1771
0
                uno::Reference< accessibility::XAccessible > xAccObj(xContext, uno::UNO_QUERY);
1772
0
                onShapeSelectionChanged(xAccObj, u"create"_ustr);
1773
0
            }
1774
1775
0
            sal_Int64 nmax = xContext->getAccessibleChildCount();
1776
0
            if( nmax > MAX_ATTACHABLE_CHILDREN )
1777
0
                nmax = MAX_ATTACHABLE_CHILDREN;
1778
1779
0
            for( sal_Int64 n = 0; n < nmax; n++ )
1780
0
            {
1781
0
                uno::Reference< accessibility::XAccessible > xChild( xContext->getAccessibleChild( n ) );
1782
1783
0
                if( xChild.is() )
1784
0
                    attachRecursive(xChild);
1785
0
            }
1786
0
        }
1787
0
        else
1788
0
        {
1789
            // Usually, when the document is loaded, a CARET_CHANGED accessibility event is automatically emitted
1790
            // for the first paragraph. That allows to notify the paragraph content to the client, even if no input
1791
            // event occurred yet. However, when switching to a11y enabled in the client and in Cypress tests
1792
            // no accessibility event is automatically emitted until some input event occurs.
1793
            // So we use the following workaround to notify the content of the focused paragraph,
1794
            // without waiting for an input event.
1795
            // Here we update the paragraph info related to the focused paragraph,
1796
            // later when afterCallbackRegistered is executed we notify the paragraph content.
1797
0
            sal_Int64 nChildCount = xContext->getAccessibleChildCount();
1798
0
            if (nChildCount > 0 && nChildCount < 10)
1799
0
            {
1800
0
                for (sal_Int64 n = 0; n < nChildCount; ++n)
1801
0
                {
1802
0
                    uno::Reference< accessibility::XAccessible > xChild(xContext->getAccessibleChild(n));
1803
0
                    if (xChild.is())
1804
0
                    {
1805
0
                        uno::Reference<css::accessibility::XAccessibleText> xAccText(xChild, uno::UNO_QUERY);
1806
0
                        if (xAccText.is())
1807
0
                        {
1808
0
                            sal_Int32 nPos = xAccText->getCaretPosition();
1809
0
                            if (nPos >= 0)
1810
0
                            {
1811
0
                                attachRecursive(xChild);
1812
0
                                updateParagraphInfo(xAccText, false, "LOKDocumentFocusListener::attachRecursive(3)");
1813
0
                                break;
1814
0
                            }
1815
0
                        }
1816
0
                    }
1817
0
                }
1818
0
            }
1819
0
        }
1820
0
    }
1821
0
}
1822
1823
void LOKDocumentFocusListener::detachRecursive(
1824
    const uno::Reference< accessibility::XAccessible >& xAccessible,
1825
    bool bForce
1826
)
1827
0
{
1828
0
    uno::Reference< accessibility::XAccessibleContext > xContext =
1829
0
        xAccessible->getAccessibleContext();
1830
1831
0
    if( xContext.is() )
1832
0
        detachRecursive(xContext, bForce);
1833
0
}
1834
1835
void LOKDocumentFocusListener::detachRecursive(
1836
    const uno::Reference< accessibility::XAccessibleContext >& xContext,
1837
    bool bForce
1838
)
1839
0
{
1840
0
    aboutView("LOKDocumentFocusListener::detachRecursive (2)", this, m_pViewShell);
1841
0
    sal_Int64 nStateSet = xContext->getAccessibleStateSet();
1842
1843
0
    SAL_INFO("lok.a11y", "LOKDocumentFocusListener::detachRecursive(2): this: " << this
1844
0
            << ", name: " << xContext->getAccessibleName()
1845
0
            << ", parent: " << xContext->getAccessibleParent().get()
1846
0
            << ", child count: " << xContext->getAccessibleChildCount());
1847
1848
0
    if (m_bIsEditingCell)
1849
0
    {
1850
0
        ::rtl::OUString sName = xContext->getAccessibleName();
1851
0
        m_bIsEditingCell = !sName.startsWith("Cell");
1852
0
        if (!m_bIsEditingCell)
1853
0
        {
1854
0
            m_sFocusedParagraph = "";
1855
0
            m_nCaretPosition = 0;
1856
0
            notifyFocusedParagraphChanged();
1857
0
        }
1858
0
    }
1859
1860
0
    detachRecursive(xContext, nStateSet, bForce);
1861
0
}
1862
1863
void LOKDocumentFocusListener::detachRecursive(
1864
    const uno::Reference< accessibility::XAccessibleContext >& xContext,
1865
    const sal_Int64 nStateSet,
1866
    bool bForce
1867
)
1868
0
{
1869
0
    uno::Reference< accessibility::XAccessibleEventBroadcaster > xBroadcaster(xContext, uno::UNO_QUERY);
1870
1871
0
    if (xBroadcaster.is() && 0 < m_aRefList.erase(xBroadcaster))
1872
0
    {
1873
0
        xBroadcaster->removeAccessibleEventListener(static_cast< accessibility::XAccessibleEventListener *>(this));
1874
1875
0
        if ((nStateSet & accessibility::AccessibleStateType::SELECTED) &&
1876
0
            selectionHasToBeNotified(xContext))
1877
0
        {
1878
0
            uno::Reference< accessibility::XAccessible > xAccObj(xContext, uno::UNO_QUERY);
1879
0
            onShapeSelectionChanged(xAccObj, u"delete"_ustr);
1880
0
        }
1881
1882
0
        if (bForce || !(nStateSet & accessibility::AccessibleStateType::MANAGES_DESCENDANTS))
1883
0
        {
1884
0
            sal_Int64 nmax = xContext->getAccessibleChildCount();
1885
0
            if (nmax > MAX_ATTACHABLE_CHILDREN)
1886
0
                nmax = MAX_ATTACHABLE_CHILDREN;
1887
0
            for (sal_Int64 n = 0; n < nmax; n++)
1888
0
            {
1889
0
                uno::Reference< accessibility::XAccessible > xChild(xContext->getAccessibleChild(n));
1890
1891
0
                if (xChild.is())
1892
0
                    detachRecursive(xChild);
1893
0
            }
1894
0
        }
1895
0
    }
1896
0
}
1897
1898
sal_uInt32 SfxViewShell_Impl::m_nLastViewShellId = 0;
1899
1900
SfxViewShell_Impl::SfxViewShell_Impl(SfxViewShellFlags const nFlags, ViewShellDocId nDocId)
1901
4.26k
:   m_bHasPrintOptions(nFlags & SfxViewShellFlags::HAS_PRINTOPTIONS)
1902
4.26k
,   m_nFamily(0xFFFF)   // undefined, default set by TemplateDialog
1903
4.26k
,   m_pLibreOfficeKitViewCallback(nullptr)
1904
4.26k
,   m_bTiledSearching(false)
1905
4.26k
,   m_nViewShellId(SfxViewShell_Impl::m_nLastViewShellId++)
1906
4.26k
,   m_nDocId(nDocId)
1907
4.26k
{
1908
4.26k
}
1909
1910
SfxViewShell_Impl::~SfxViewShell_Impl()
1911
4.26k
{
1912
4.26k
}
1913
1914
std::vector< SfxInPlaceClient* >& SfxViewShell_Impl::GetIPClients_Impl()
1915
42.7k
{
1916
42.7k
    return maIPClients;
1917
42.7k
}
1918
1919
SFX_IMPL_SUPERCLASS_INTERFACE(SfxViewShell,SfxShell)
1920
1921
void SfxViewShell::InitInterface_Impl()
1922
27
{
1923
27
}
1924
1925
1926
/** search for a filter name dependent on type and module
1927
 */
1928
static OUString impl_retrieveFilterNameFromTypeAndModule(
1929
    const css::uno::Reference< css::container::XContainerQuery >& rContainerQuery,
1930
    const OUString& rType,
1931
    const OUString& rModuleIdentifier,
1932
    const sal_Int32 nFlags )
1933
0
{
1934
    // Retrieve filter from type
1935
0
    css::uno::Sequence< css::beans::NamedValue > aQuery {
1936
0
        { u"Type"_ustr, css::uno::Any( rType ) },
1937
0
        { u"DocumentService"_ustr, css::uno::Any( rModuleIdentifier ) }
1938
0
    };
1939
1940
0
    css::uno::Reference< css::container::XEnumeration > xEnumeration =
1941
0
        rContainerQuery->createSubSetEnumerationByProperties( aQuery );
1942
1943
0
    OUString aFoundFilterName;
1944
0
    while ( xEnumeration->hasMoreElements() )
1945
0
    {
1946
0
        ::comphelper::SequenceAsHashMap aFilterPropsHM( xEnumeration->nextElement() );
1947
0
        sal_Int32 nFilterFlags = aFilterPropsHM.getUnpackedValueOrDefault(
1948
0
            u"Flags"_ustr,
1949
0
            sal_Int32( 0 ) );
1950
1951
0
        if ( nFilterFlags & nFlags )
1952
0
        {
1953
0
            aFoundFilterName = aFilterPropsHM.getUnpackedValueOrDefault(u"Name"_ustr, OUString());
1954
0
            break;
1955
0
        }
1956
0
    }
1957
1958
0
    return aFoundFilterName;
1959
0
}
1960
1961
namespace {
1962
1963
/** search for an internal typename, which map to the current app module
1964
    and map also to a "family" of file formats as e.g. PDF/MS Doc/OOo Doc.
1965
 */
1966
enum ETypeFamily
1967
{
1968
    E_MS_DOC,
1969
    E_OOO_DOC
1970
};
1971
1972
}
1973
1974
static OUString impl_searchFormatTypeForApp(const css::uno::Reference< css::frame::XFrame >& xFrame     ,
1975
                                                  ETypeFamily                                eTypeFamily)
1976
0
{
1977
0
    try
1978
0
    {
1979
0
        const css::uno::Reference< css::uno::XComponentContext >&  xContext      (::comphelper::getProcessComponentContext());
1980
0
        css::uno::Reference< css::frame::XModuleManager2 >  xModuleManager(css::frame::ModuleManager::create(xContext));
1981
1982
0
        OUString sModule = xModuleManager->identify(xFrame);
1983
0
        OUString sType   ;
1984
1985
0
        switch(eTypeFamily)
1986
0
        {
1987
0
            case E_MS_DOC:
1988
0
            {
1989
0
                if ( sModule == "com.sun.star.text.TextDocument" )
1990
0
                    sType = "writer_MS_Word_2007";
1991
0
                else
1992
0
                if ( sModule == "com.sun.star.sheet.SpreadsheetDocument" )
1993
0
                    sType = "MS Excel 2007 XML";
1994
0
                else
1995
0
                if ( sModule == "com.sun.star.presentation.PresentationDocument" )
1996
0
                    sType = "MS PowerPoint 2007 XML";
1997
0
            }
1998
0
            break;
1999
2000
0
            case E_OOO_DOC:
2001
0
            {
2002
0
                if ( sModule == "com.sun.star.text.TextDocument" )
2003
0
                    sType = "writer8";
2004
0
                else
2005
0
                if ( sModule == "com.sun.star.sheet.SpreadsheetDocument" )
2006
0
                    sType = "calc8";
2007
0
                else
2008
0
                if ( sModule == "com.sun.star.drawing.DrawingDocument" )
2009
0
                    sType = "draw8";
2010
0
                else
2011
0
                if ( sModule == "com.sun.star.presentation.PresentationDocument" )
2012
0
                    sType = "impress8";
2013
0
            }
2014
0
            break;
2015
0
        }
2016
2017
0
        return sType;
2018
0
    }
2019
0
    catch (const css::uno::RuntimeException&)
2020
0
    {
2021
0
        throw;
2022
0
    }
2023
0
    catch (const css::uno::Exception&)
2024
0
    {
2025
0
    }
2026
2027
0
    return OUString();
2028
0
}
2029
2030
void SfxViewShell::NewIPClient_Impl( SfxInPlaceClient *pIPClient )
2031
0
{
2032
0
    pImpl->GetIPClients_Impl().push_back(pIPClient);
2033
0
}
2034
2035
void SfxViewShell::IPClientGone_Impl( SfxInPlaceClient const *pIPClient )
2036
0
{
2037
0
    std::vector< SfxInPlaceClient* >& pClients = pImpl->GetIPClients_Impl();
2038
2039
0
    auto it = std::find(pClients.begin(), pClients.end(), pIPClient);
2040
0
    if (it != pClients.end())
2041
0
        pClients.erase( it );
2042
0
}
2043
2044
2045
void SfxViewShell::ExecMisc_Impl( SfxRequest &rReq )
2046
0
{
2047
0
    const sal_uInt16 nId = rReq.GetSlot();
2048
0
    switch( nId )
2049
0
    {
2050
0
        case SID_STYLE_FAMILY :
2051
0
        {
2052
0
            const SfxUInt16Item* pItem = rReq.GetArg<SfxUInt16Item>(nId);
2053
0
            if (pItem)
2054
0
            {
2055
0
                pImpl->m_nFamily = pItem->GetValue();
2056
0
            }
2057
0
            break;
2058
0
        }
2059
0
        case SID_ACTIVATE_STYLE_APPLY:
2060
0
        {
2061
0
            uno::Reference< frame::XFrame > xFrame =
2062
0
                GetViewFrame().GetFrame().GetFrameInterface();
2063
2064
0
            Reference< beans::XPropertySet > xPropSet( xFrame, UNO_QUERY );
2065
0
            Reference< frame::XLayoutManager > xLayoutManager;
2066
0
            if ( xPropSet.is() )
2067
0
            {
2068
0
                try
2069
0
                {
2070
0
                    Any aValue = xPropSet->getPropertyValue(u"LayoutManager"_ustr);
2071
0
                    aValue >>= xLayoutManager;
2072
0
                    if ( xLayoutManager.is() )
2073
0
                    {
2074
0
                        uno::Reference< ui::XUIElement > xElement = xLayoutManager->getElement( u"private:resource/toolbar/textobjectbar"_ustr );
2075
0
                        if(!xElement.is())
2076
0
                        {
2077
0
                            xElement = xLayoutManager->getElement( u"private:resource/toolbar/frameobjectbar"_ustr );
2078
0
                        }
2079
0
                        if(!xElement.is())
2080
0
                        {
2081
0
                            xElement = xLayoutManager->getElement( u"private:resource/toolbar/oleobjectbar"_ustr );
2082
0
                        }
2083
0
                        if(xElement.is())
2084
0
                        {
2085
0
                            uno::Reference< awt::XWindow > xWin( xElement->getRealInterface(), uno::UNO_QUERY_THROW );
2086
0
                            VclPtr<vcl::Window> pWin = VCLUnoHelper::GetWindow( xWin );
2087
0
                            ToolBox* pTextToolbox = dynamic_cast< ToolBox* >( pWin.get() );
2088
0
                            if( pTextToolbox )
2089
0
                            {
2090
0
                                ToolBox::ImplToolItems::size_type nItemCount = pTextToolbox->GetItemCount();
2091
0
                                for( ToolBox::ImplToolItems::size_type nItem = 0; nItem < nItemCount; ++nItem )
2092
0
                                {
2093
0
                                    ToolBoxItemId nItemId = pTextToolbox->GetItemId( nItem );
2094
0
                                    const OUString aCommand = pTextToolbox->GetItemCommand( nItemId );
2095
0
                                    if (aCommand == ".uno:StyleApply")
2096
0
                                    {
2097
0
                                        vcl::Window* pItemWin = pTextToolbox->GetItemWindow( nItemId );
2098
0
                                        if( pItemWin )
2099
0
                                            pItemWin->GrabFocus();
2100
0
                                        break;
2101
0
                                    }
2102
0
                                }
2103
0
                            }
2104
0
                        }
2105
0
                    }
2106
0
                }
2107
0
                catch (const Exception&)
2108
0
                {
2109
0
                }
2110
0
            }
2111
0
            rReq.Done();
2112
0
        }
2113
0
        break;
2114
2115
0
        case SID_MAIL_SENDDOCASMS:
2116
0
        case SID_MAIL_SENDDOCASOOO:
2117
0
        case SID_MAIL_SENDDOCASPDF:
2118
0
        case SID_MAIL_SENDDOC:
2119
0
        case SID_MAIL_SENDDOCASFORMAT:
2120
0
        {
2121
0
            SfxObjectShell* pDoc = GetObjectShell();
2122
0
            if (!pDoc)
2123
0
                break;
2124
0
            pDoc->QueryHiddenInformation(HiddenWarningFact::WhenSaving);
2125
0
            SfxMailModel  aModel;
2126
0
            OUString aDocType;
2127
2128
0
            const SfxStringItem* pMailRecipient = rReq.GetArg<SfxStringItem>(SID_MAIL_RECIPIENT);
2129
0
            if ( pMailRecipient )
2130
0
            {
2131
0
                OUString aRecipient( pMailRecipient->GetValue() );
2132
0
                OUString aMailToStr(u"mailto:"_ustr);
2133
2134
0
                if ( aRecipient.startsWith( aMailToStr ) )
2135
0
                    aRecipient = aRecipient.copy( aMailToStr.getLength() );
2136
0
                aModel.AddToAddress( aRecipient );
2137
0
            }
2138
0
            const SfxStringItem* pMailDocType = rReq.GetArg(SID_TYPE_NAME);
2139
0
            if ( pMailDocType )
2140
0
                aDocType = pMailDocType->GetValue();
2141
2142
0
            uno::Reference < frame::XFrame > xFrame( rFrame.GetFrame().GetFrameInterface() );
2143
0
            SfxMailModel::SendMailResult eResult = SfxMailModel::SEND_MAIL_ERROR;
2144
2145
0
            if ( nId == SID_MAIL_SENDDOC )
2146
0
                eResult = aModel.SaveAndSend( xFrame, OUString() );
2147
0
            else if ( nId == SID_MAIL_SENDDOCASPDF )
2148
0
                eResult = aModel.SaveAndSend( xFrame, u"pdf_Portable_Document_Format"_ustr);
2149
0
            else if ( nId == SID_MAIL_SENDDOCASMS )
2150
0
            {
2151
0
                aDocType = impl_searchFormatTypeForApp(xFrame, E_MS_DOC);
2152
0
                if (!aDocType.isEmpty())
2153
0
                    eResult = aModel.SaveAndSend( xFrame, aDocType );
2154
0
            }
2155
0
            else if ( nId == SID_MAIL_SENDDOCASOOO )
2156
0
            {
2157
0
                aDocType = impl_searchFormatTypeForApp(xFrame, E_OOO_DOC);
2158
0
                if (!aDocType.isEmpty())
2159
0
                    eResult = aModel.SaveAndSend( xFrame, aDocType );
2160
0
            }
2161
2162
0
            if ( eResult == SfxMailModel::SEND_MAIL_ERROR )
2163
0
            {
2164
0
                weld::Window* pWin = SfxGetpApp()->GetTopWindow();
2165
0
                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
2166
0
                                                                         VclMessageType::Info, VclButtonsType::Ok,
2167
0
                                                                         SfxResId(STR_ERROR_SEND_MAIL)));
2168
0
                xBox->run();
2169
0
                rReq.Ignore();
2170
0
            }
2171
0
            else
2172
0
                rReq.Done();
2173
0
        }
2174
0
        break;
2175
2176
0
        case SID_BLUETOOTH_SENDDOC:
2177
0
        {
2178
0
            SfxBluetoothModel aModel;
2179
0
            SfxObjectShell* pDoc = GetObjectShell();
2180
0
            if (!pDoc)
2181
0
                break;
2182
0
            pDoc->QueryHiddenInformation(HiddenWarningFact::WhenSaving);
2183
0
            uno::Reference < frame::XFrame > xFrame( rFrame.GetFrame().GetFrameInterface() );
2184
0
            SfxMailModel::SendMailResult eResult = aModel.SaveAndSend( xFrame );
2185
0
            if( eResult == SfxMailModel::SEND_MAIL_ERROR )
2186
0
            {
2187
0
                weld::Window* pWin = SfxGetpApp()->GetTopWindow();
2188
0
                std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
2189
0
                                                                         VclMessageType::Info, VclButtonsType::Ok,
2190
0
                                                                         SfxResId(STR_ERROR_SEND_MAIL)));
2191
0
                xBox->run();
2192
0
                rReq.Ignore();
2193
0
            }
2194
0
            else
2195
0
                rReq.Done();
2196
0
        }
2197
0
        break;
2198
2199
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2200
0
        case SID_WEBHTML:
2201
0
        {
2202
0
            css::uno::Reference< lang::XMultiServiceFactory > xSMGR(::comphelper::getProcessServiceFactory(), css::uno::UNO_SET_THROW);
2203
0
            css::uno::Reference< uno::XComponentContext >     xContext(::comphelper::getProcessComponentContext(), css::uno::UNO_SET_THROW);
2204
0
            css::uno::Reference< css::frame::XFrame >         xFrame( rFrame.GetFrame().GetFrameInterface() );
2205
0
            css::uno::Reference< css::frame::XModel >         xModel;
2206
2207
0
            css::uno::Reference< css::frame::XModuleManager2 > xModuleManager( css::frame::ModuleManager::create(xContext) );
2208
2209
0
            OUString aModule;
2210
0
            try
2211
0
            {
2212
0
                aModule = xModuleManager->identify( xFrame );
2213
0
            }
2214
0
            catch (const css::uno::RuntimeException&)
2215
0
            {
2216
0
                throw;
2217
0
            }
2218
0
            catch (const css::uno::Exception&)
2219
0
            {
2220
0
            }
2221
2222
0
            if ( xFrame.is() )
2223
0
            {
2224
0
                css::uno::Reference< css::frame::XController > xController = xFrame->getController();
2225
0
                if ( xController.is() )
2226
0
                    xModel = xController->getModel();
2227
0
            }
2228
2229
            // We need at least a valid module name and model reference
2230
0
            css::uno::Reference< css::frame::XStorable > xStorable( xModel, css::uno::UNO_QUERY );
2231
0
            if ( xModel.is() && xStorable.is() )
2232
0
            {
2233
0
                OUString aFilterName;
2234
0
                OUString aTypeName( u"generic_HTML"_ustr );
2235
0
                OUString aFileName;
2236
2237
0
                OUString aLocation = xStorable->getLocation();
2238
0
                INetURLObject aFileObj( aLocation );
2239
2240
0
                bool bPrivateProtocol = ( aFileObj.GetProtocol() == INetProtocol::PrivSoffice );
2241
0
                bool bHasLocation = !aLocation.isEmpty() && !bPrivateProtocol;
2242
2243
0
                css::uno::Reference< css::container::XContainerQuery > xContainerQuery(
2244
0
                    xSMGR->createInstance( u"com.sun.star.document.FilterFactory"_ustr ),
2245
0
                    css::uno::UNO_QUERY_THROW );
2246
2247
                // Retrieve filter from type
2248
2249
0
                sal_Int32 nFilterFlags = 0x00000002; // export
2250
0
                aFilterName = impl_retrieveFilterNameFromTypeAndModule( xContainerQuery, aTypeName, aModule, nFilterFlags );
2251
0
                if ( aFilterName.isEmpty() )
2252
0
                {
2253
                    // Draw/Impress uses a different type. 2nd chance try to use alternative type name
2254
0
                    aFilterName = impl_retrieveFilterNameFromTypeAndModule(
2255
0
                        xContainerQuery, u"graphic_HTML"_ustr, aModule, nFilterFlags );
2256
0
                }
2257
2258
                // No filter found => error
2259
                // No type and no location => error
2260
0
                if ( aFilterName.isEmpty() ||  aTypeName.isEmpty())
2261
0
                {
2262
0
                    rReq.Done();
2263
0
                    return;
2264
0
                }
2265
2266
                // Use provided save file name. If empty determine file name
2267
0
                if ( !bHasLocation )
2268
0
                {
2269
                    // Create a default file name with the correct extension
2270
0
                    aFileName = "webpreview";
2271
0
                }
2272
0
                else
2273
0
                {
2274
                    // Determine file name from model
2275
0
                    INetURLObject aFObj( xStorable->getLocation() );
2276
0
                    aFileName = aFObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::NONE );
2277
0
                }
2278
2279
0
                OSL_ASSERT( !aFilterName.isEmpty() );
2280
0
                OSL_ASSERT( !aFileName.isEmpty() );
2281
2282
                // Creates a temporary directory to store our predefined file into it (for the
2283
                // flatpak case, create it in XDG_CACHE_HOME instead of /tmp for technical reasons,
2284
                // so that it can be accessed by the browser running outside the sandbox):
2285
0
                OUString * parent = nullptr;
2286
0
                if (flatpak::isFlatpak() && !flatpak::createTemporaryHtmlDirectory(&parent))
2287
0
                {
2288
0
                    SAL_WARN("sfx.view", "cannot create Flatpak html temp dir");
2289
0
                }
2290
2291
0
                INetURLObject aFilePathObj( ::utl::CreateTempURL(parent, true) );
2292
0
                aFilePathObj.insertName( aFileName );
2293
0
                aFilePathObj.setExtension( u"htm" );
2294
2295
0
                OUString aFileURL = aFilePathObj.GetMainURL( INetURLObject::DecodeMechanism::NONE );
2296
2297
0
                css::uno::Sequence< css::beans::PropertyValue > aArgs{
2298
0
                    comphelper::makePropertyValue(u"FilterName"_ustr, aFilterName)
2299
0
                };
2300
2301
                // Store document in the html format
2302
0
                try
2303
0
                {
2304
0
                    xStorable->storeToURL( aFileURL, aArgs );
2305
0
                }
2306
0
                catch (const io::IOException&)
2307
0
                {
2308
0
                    rReq.Done();
2309
0
                    return;
2310
0
                }
2311
2312
0
                sfx2::openUriExternally(aFileURL, true, rReq.GetFrameWeld());
2313
0
                rReq.Done(true);
2314
0
                break;
2315
0
            }
2316
0
            else
2317
0
            {
2318
0
                rReq.Done();
2319
0
                return;
2320
0
            }
2321
0
        }
2322
0
    }
2323
0
}
2324
2325
2326
void SfxViewShell::GetState_Impl( SfxItemSet &rSet )
2327
0
{
2328
2329
0
    SfxWhichIter aIter( rSet );
2330
0
    SfxObjectShell *pSh = GetViewFrame().GetObjectShell();
2331
0
    for ( sal_uInt16 nSID = aIter.FirstWhich(); nSID; nSID = aIter.NextWhich() )
2332
0
    {
2333
0
        switch ( nSID )
2334
0
        {
2335
2336
0
            case SID_BLUETOOTH_SENDDOC:
2337
0
            case SID_MAIL_SENDDOC:
2338
0
            case SID_MAIL_SENDDOCASFORMAT:
2339
0
            case SID_MAIL_SENDDOCASMS:
2340
0
            case SID_MAIL_SENDDOCASOOO:
2341
0
            case SID_MAIL_SENDDOCASPDF:
2342
0
            {
2343
#if HAVE_FEATURE_MACOSX_SANDBOX
2344
                rSet.DisableItem(nSID);
2345
#endif
2346
0
                if (pSh && pSh->isExportLocked())
2347
0
                    rSet.DisableItem(nSID);
2348
0
                break;
2349
0
            }
2350
0
            case SID_WEBHTML:
2351
0
            {
2352
0
                if (pSh && pSh->isExportLocked())
2353
0
                    rSet.DisableItem(nSID);
2354
0
                break;
2355
0
            }
2356
            // Printer functions
2357
0
            case SID_PRINTDOC:
2358
0
            case SID_PRINTDOCDIRECT:
2359
0
            case SID_SETUPPRINTER:
2360
0
            case SID_PRINTER_NAME:
2361
0
            {
2362
0
                if (Application::GetSettings().GetMiscSettings().GetDisablePrinting()
2363
0
                    || (pSh && pSh->isPrintLocked()))
2364
0
                {
2365
0
                    rSet.DisableItem(nSID);
2366
0
                    break;
2367
0
                }
2368
2369
0
                SfxPrinter *pPrinter = GetPrinter();
2370
2371
0
                if ( SID_PRINTDOCDIRECT == nSID )
2372
0
                {
2373
0
                    OUString aPrinterName;
2374
0
                    if ( pPrinter != nullptr )
2375
0
                        aPrinterName = pPrinter->GetName();
2376
0
                    else
2377
0
                    {
2378
                        // tdf#109149 don't poll the Default Printer Name on every query.
2379
                        // We are queried on every change, so on every
2380
                        // keystroke, and we are only using this to fill in the
2381
                        // printername inside the label of "Print Directly (printer-name)"
2382
                        // On Printer::GetDefaultPrinterName() is implemented with
2383
                        // GetDefaultPrinter so don't call this excessively. 5 mins
2384
                        // seems a reasonable refresh time.
2385
0
                        std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
2386
0
                        std::chrono::minutes five_mins(5);
2387
0
                        if (now > pImpl->m_nDefaultPrinterNameFetchTime + five_mins)
2388
0
                        {
2389
0
                            pImpl->m_sDefaultPrinterName = Printer::GetDefaultPrinterName();
2390
0
                            pImpl->m_nDefaultPrinterNameFetchTime = now;
2391
0
                        }
2392
0
                        aPrinterName = pImpl->m_sDefaultPrinterName;
2393
0
                    }
2394
0
                    if ( !aPrinterName.isEmpty() )
2395
0
                    {
2396
0
                        uno::Reference < frame::XFrame > xFrame( rFrame.GetFrame().GetFrameInterface() );
2397
2398
0
                        auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(u".uno:PrintDefault"_ustr,
2399
0
                            vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
2400
0
                        OUString val = vcl::CommandInfoProvider::GetLabelForCommand(aProperties) +
2401
0
                                        " (" + aPrinterName + ")";
2402
2403
0
                        rSet.Put( SfxStringItem( SID_PRINTDOCDIRECT, val ) );
2404
0
                    }
2405
0
                }
2406
0
                break;
2407
0
            }
2408
0
            case SID_STYLE_FAMILY :
2409
0
            {
2410
0
                rSet.Put( SfxUInt16Item( SID_STYLE_FAMILY, pImpl->m_nFamily ) );
2411
0
                break;
2412
0
            }
2413
0
        }
2414
0
    }
2415
0
}
2416
2417
void SfxViewShell::SetZoomFactor( const Fraction &rZoomX,
2418
    const Fraction &rZoomY )
2419
0
{
2420
0
    DBG_ASSERT( GetWindow(), "no window" );
2421
0
    MapMode aMap( GetWindow()->GetMapMode() );
2422
0
    aMap.SetScaleX( rZoomX );
2423
0
    aMap.SetScaleY( rZoomY );
2424
0
    GetWindow()->SetMapMode( aMap );
2425
0
}
2426
2427
ErrCode SfxViewShell::DoVerb(sal_Int32 /*nVerb*/)
2428
2429
/*  [Description]
2430
2431
    Virtual Method used to perform a Verb on a selected Object.
2432
    Since this Object is only known by the derived classes, they must override
2433
    DoVerb.
2434
*/
2435
2436
0
{
2437
0
    return ERRCODE_SO_NOVERBS;
2438
0
}
2439
2440
void SfxViewShell::OutplaceActivated( bool bActive )
2441
0
{
2442
0
    if ( !bActive )
2443
0
    {
2444
0
        if (SfxViewFrame* pFrame = GetFrame())
2445
0
            pFrame->GetFrame().Appear();
2446
0
    }
2447
0
}
2448
2449
void SfxViewShell::UIActivating( SfxInPlaceClient* /*pClient*/ )
2450
0
{
2451
0
    uno::Reference < frame::XFrame > xOwnFrame( rFrame.GetFrame().GetFrameInterface() );
2452
0
    uno::Reference < frame::XFramesSupplier > xParentFrame = xOwnFrame->getCreator();
2453
0
    if ( xParentFrame.is() )
2454
0
        xParentFrame->setActiveFrame( xOwnFrame );
2455
2456
0
    rFrame.GetBindings().HidePopups();
2457
0
    rFrame.GetDispatcher()->Update_Impl( true );
2458
0
}
2459
2460
void SfxViewShell::UIDeactivated( SfxInPlaceClient* /*pClient*/ )
2461
0
{
2462
0
    if ( !rFrame.GetFrame().IsClosing_Impl() || SfxViewFrame::Current() != &rFrame )
2463
0
        rFrame.GetDispatcher()->Update_Impl( true );
2464
0
    rFrame.GetBindings().HidePopups(false);
2465
2466
0
    rFrame.GetBindings().InvalidateAll(true);
2467
0
}
2468
2469
SfxInPlaceClient* SfxViewShell::FindIPClient
2470
(
2471
    const uno::Reference < embed::XEmbeddedObject >& xObj,
2472
    vcl::Window*             pObjParentWin
2473
)   const
2474
0
{
2475
0
    std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
2476
0
    if ( rClients.empty() )
2477
0
        return nullptr;
2478
2479
0
    if( !pObjParentWin )
2480
0
        pObjParentWin = GetWindow();
2481
0
    for (SfxInPlaceClient* pIPClient : rClients)
2482
0
    {
2483
0
        if ( pIPClient->GetObject() == xObj && pIPClient->GetEditWin() == pObjParentWin )
2484
0
            return pIPClient;
2485
0
    }
2486
2487
0
    return nullptr;
2488
0
}
2489
2490
2491
SfxInPlaceClient* SfxViewShell::GetIPClient() const
2492
8.52k
{
2493
8.52k
    return GetUIActiveClient();
2494
8.52k
}
2495
2496
2497
SfxInPlaceClient* SfxViewShell::GetUIActiveIPClient_Impl() const
2498
0
{
2499
    // this method is needed as long as SFX still manages the border space for ChildWindows (see SfxFrame::Resize)
2500
0
    std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
2501
0
    if ( rClients.empty() )
2502
0
        return nullptr;
2503
2504
0
    for (SfxInPlaceClient* pIPClient : rClients)
2505
0
    {
2506
0
        if ( pIPClient->IsUIActive() )
2507
0
            return pIPClient;
2508
0
    }
2509
2510
0
    return nullptr;
2511
0
}
2512
2513
SfxInPlaceClient* SfxViewShell::GetUIActiveClient() const
2514
21.3k
{
2515
21.3k
    std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
2516
21.3k
    if ( rClients.empty() )
2517
21.3k
        return nullptr;
2518
2519
0
    const bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
2520
2521
0
    for (SfxInPlaceClient* pIPClient : rClients)
2522
0
    {
2523
0
        if ( pIPClient->IsObjectUIActive() || ( bIsTiledRendering && pIPClient->IsObjectInPlaceActive() ) )
2524
0
            return pIPClient;
2525
0
    }
2526
2527
0
    return nullptr;
2528
0
}
2529
2530
2531
void SfxViewShell::Activate( bool bMDI )
2532
4.26k
{
2533
4.26k
    if ( bMDI )
2534
4.26k
    {
2535
4.26k
        SfxObjectShell *pSh = GetViewFrame().GetObjectShell();
2536
4.26k
        if (const auto xModel = pSh->GetModel())
2537
4.26k
            xModel->setCurrentController(GetController());
2538
2539
4.26k
        SetCurrentDocument();
2540
4.26k
    }
2541
4.26k
}
2542
2543
2544
void SfxViewShell::Deactivate(bool /*bMDI*/)
2545
4.26k
{
2546
4.26k
}
2547
2548
2549
void SfxViewShell::Move()
2550
2551
/*  [Description]
2552
2553
    This virtual Method is called when the window displayed in the
2554
    SfxViewShell gets a StarView-Move() notification.
2555
2556
    This base implementation does not have to be called.     .
2557
2558
    [Note]
2559
2560
    This Method can be used to cancel a selection, in order to catch the
2561
    mouse movement which is due to moving a window.
2562
2563
    For now the notification does not work In-Place.
2564
*/
2565
2566
0
{
2567
0
}
2568
2569
2570
void SfxViewShell::OuterResizePixel
2571
(
2572
    const Point&    /*rToolOffset*/,// Upper left corner Tools in Frame-Window
2573
    const Size&     /*rSize*/       // All available sizes.
2574
)
2575
2576
/*  [Description]
2577
2578
    Override this Method to be able to react to the size-change of
2579
    the View. Thus the View is defined as the Edit window and also the
2580
    attached Tools are defined (for example the ruler).
2581
2582
    The Edit window must not be changed either in size or position.
2583
2584
    The Vis-Area of SfxObjectShell, its scale and position can be changed
2585
    here. The main use is to change the size of the Vis-Area.
2586
2587
    If the Border is changed due to the new calculation then this has to be set
2588
    by <SfxViewShell::SetBorderPixel(const SvBorder&)>. The Positioning of Tools
2589
    is only allowed after the calling of 'SetBorderPixel'.
2590
2591
    [Example]
2592
2593
    void AppViewSh::OuterViewResizePixel( const Point &rOfs, const Size &rSz )
2594
    {
2595
        // Calculate Tool position and size externally, do not set!
2596
        // (due to the following Border calculation)
2597
        Point aHLinPos...; Size aHLinSz...;
2598
        ...
2599
2600
        // Calculate and Set a Border of Tools which matches rSize.
2601
        SvBorder aBorder...
2602
        SetBorderPixel( aBorder ); // Allow Positioning from here on.
2603
2604
        // Arrange Tools
2605
        pHLin->SetPosSizePixel( aHLinPos, aHLinSz );
2606
        ...
2607
    }
2608
2609
    [Cross-reference]
2610
2611
        <SfxViewShell::InnerResizePixel(const Point&,const Size& rSize)>
2612
*/
2613
2614
0
{
2615
0
    SetBorderPixel( SvBorder() );
2616
0
}
2617
2618
2619
void SfxViewShell::InnerResizePixel
2620
(
2621
    const Point&    /*rToolOffset*/,// Upper left corner Tools in Frame-Window
2622
    const Size&     /*rSize*/,      // All available sizes.
2623
    bool
2624
)
2625
2626
/*  [Description]
2627
2628
    Override this Method to be able to react to the size-change of
2629
    the Edit window.
2630
2631
    The Edit window must not be changed either in size or position.
2632
    Neither the Vis-Area of SfxObjectShell nor its scale or position are
2633
    allowed to be changed
2634
2635
    If the Border is changed due to the new calculation then is has to be set
2636
    by <SfxViewShell::SetBorderPixel(const SvBorder&)>.
2637
    The Positioning of Tools is only allowed after the calling of
2638
    'SetBorderPixel'.
2639
2640
2641
    [Note]
2642
2643
    void AppViewSh::InnerViewResizePixel( const Point &rOfs, const Size &rSz )
2644
    {
2645
        // Calculate Tool position and size internally, do not set!
2646
        // (due to the following Border calculation)
2647
        Point aHLinPos...; Size aHLinSz...;
2648
        ...
2649
2650
        // Calculate and Set a Border of Tools which matches rSize.
2651
        SvBorder aBorder...
2652
        SetBorderPixel( aBorder ); // Allow Positioning from here on.
2653
2654
        // Arrange Tools
2655
        pHLin->SetPosSizePixel( aHLinPos, aHLinSz );
2656
        ...
2657
    }
2658
2659
    [Cross-reference]
2660
2661
        <SfxViewShell::OuterResizePixel(const Point&,const Size& rSize)>
2662
*/
2663
2664
0
{
2665
0
    SetBorderPixel( SvBorder() );
2666
0
}
2667
2668
void SfxViewShell::InvalidateBorder()
2669
4.59k
{
2670
4.59k
    GetViewFrame().InvalidateBorderImpl( this );
2671
4.59k
    if (pImpl->m_pController.is())
2672
4.59k
    {
2673
4.59k
        pImpl->m_pController->BorderWidthsChanged_Impl();
2674
4.59k
    }
2675
4.59k
}
2676
2677
void SfxViewShell::SetBorderPixel( const SvBorder &rBorder )
2678
0
{
2679
0
    GetViewFrame().SetBorderPixelImpl( this, rBorder );
2680
2681
    // notify related controller that border size is changed
2682
0
    if (pImpl->m_pController.is())
2683
0
    {
2684
0
        pImpl->m_pController->BorderWidthsChanged_Impl();
2685
0
    }
2686
0
}
2687
2688
const SvBorder& SfxViewShell::GetBorderPixel() const
2689
0
{
2690
0
    return GetViewFrame().GetBorderPixelImpl();
2691
0
}
2692
2693
void SfxViewShell::SetWindow
2694
(
2695
    vcl::Window*     pViewPort   // For example Null pointer in the Destructor.
2696
)
2697
2698
/*  [Description]
2699
2700
    With this method the SfxViewShell is set in the data window. This is
2701
    needed for the in-place container and for restoring the proper focus.
2702
2703
    Even in-place-active the conversion of the ViewPort Windows is forbidden.
2704
*/
2705
2706
8.52k
{
2707
8.52k
    if( pWindow == pViewPort )
2708
0
        return;
2709
2710
    // Disconnect existing IP-Clients if possible
2711
8.52k
    DisconnectAllClients();
2712
2713
    // Switch View-Port
2714
8.52k
    bool bHadFocus = pWindow && pWindow->HasChildPathFocus( true );
2715
8.52k
    pWindow = pViewPort;
2716
2717
8.52k
    if( pWindow )
2718
4.26k
    {
2719
        // Disable automatic GUI mirroring (right-to-left) for document windows
2720
4.26k
        pWindow->EnableRTL( false );
2721
4.26k
    }
2722
2723
8.52k
    if ( bHadFocus && pWindow )
2724
0
        pWindow->GrabFocus();
2725
    //TODO/CLEANUP
2726
    //Do we still need this Method?!
2727
    //SfxGetpApp()->GrabFocus( pWindow );
2728
8.52k
}
2729
2730
SfxViewShell::SfxViewShell
2731
(
2732
    SfxViewFrame&     rViewFrame,     /*  <SfxViewFrame>, which will be
2733
                                          displayed in this View */
2734
    SfxViewShellFlags nFlags          /*  See <SfxViewShell-Flags> */
2735
)
2736
2737
4.26k
:   SfxShell(this)
2738
4.26k
,   pImpl( new SfxViewShell_Impl(nFlags, comphelper::LibreOfficeKit::getDocId()) )
2739
4.26k
,   rFrame(rViewFrame)
2740
4.26k
,   pWindow(nullptr)
2741
4.26k
,   bNoNewWindow( nFlags & SfxViewShellFlags::NO_NEWWINDOW )
2742
4.26k
,   mbPrinterSettingsModified(false)
2743
4.26k
,   maLOKLanguageTag(LANGUAGE_NONE)
2744
4.26k
,   maLOKLocale(LANGUAGE_NONE)
2745
4.26k
,   maLOKDeviceFormFactor(LOKDeviceFormFactor::UNKNOWN)
2746
4.26k
,   mbLOKAccessibilityEnabled(false)
2747
4.26k
,   mbLOKColorPreviewEnabled(false)
2748
4.26k
{
2749
4.26k
    SetMargin( rViewFrame.GetMargin_Impl() );
2750
2751
4.26k
    SetPool( &rViewFrame.GetObjectShell()->GetPool() );
2752
4.26k
    StartListening(*rViewFrame.GetObjectShell());
2753
2754
    // Insert into list
2755
4.26k
    std::vector<SfxViewShell*> &rViewArr = SfxGetpApp()->GetViewShells_Impl();
2756
4.26k
    rViewArr.push_back(this);
2757
2758
4.26k
    if (comphelper::LibreOfficeKit::isActive())
2759
0
    {
2760
0
        maLOKLanguageTag = SfxLokHelper::getDefaultLanguage();
2761
0
        maLOKLocale = SfxLokHelper::getDefaultLanguage();
2762
2763
0
        const auto [isTimezoneSet, aTimezone] = SfxLokHelper::getDefaultTimezone();
2764
0
        maLOKIsTimezoneSet = isTimezoneSet;
2765
0
        maLOKTimezone = aTimezone;
2766
2767
0
        maLOKDeviceFormFactor = SfxLokHelper::getDeviceFormFactor();
2768
2769
0
        vcl::Window* pFrameWin = rViewFrame.GetWindow().GetFrameWindow();
2770
0
        if (pFrameWin && !pFrameWin->GetLOKNotifier())
2771
0
            pFrameWin->SetLOKNotifier(this, true);
2772
0
    }
2773
4.26k
}
2774
2775
SfxViewShell::~SfxViewShell()
2776
4.26k
{
2777
    // Remove from list
2778
4.26k
    const SfxViewShell *pThis = this;
2779
4.26k
    std::vector<SfxViewShell*> &rViewArr = SfxGetpApp()->GetViewShells_Impl();
2780
4.26k
    auto it = std::find( rViewArr.begin(), rViewArr.end(), pThis );
2781
4.26k
    rViewArr.erase( it );
2782
2783
4.26k
    if ( pImpl->xClipboardListener.is() )
2784
4.26k
    {
2785
4.26k
        pImpl->xClipboardListener->DisconnectViewShell();
2786
4.26k
        pImpl->xClipboardListener = nullptr;
2787
4.26k
    }
2788
2789
4.26k
    if (pImpl->m_pController.is())
2790
4.26k
    {
2791
4.26k
        pImpl->m_pController->ReleaseShell_Impl();
2792
4.26k
        pImpl->m_pController.clear();
2793
4.26k
    }
2794
2795
4.26k
    vcl::Window* pFrameWin = GetViewFrame().GetWindow().GetFrameWindow();
2796
4.26k
    if (pFrameWin && pFrameWin->GetLOKNotifier() == this)
2797
0
        pFrameWin->ReleaseLOKNotifier();
2798
4.26k
}
2799
2800
OUString SfxViewShell::getA11yFocusedParagraph() const
2801
0
{
2802
0
    const LOKDocumentFocusListener& rDocFocusListener = GetLOKDocumentFocusListener();
2803
0
    return rDocFocusListener.getFocusedParagraph();
2804
0
}
2805
2806
int SfxViewShell::getA11yCaretPosition() const
2807
0
{
2808
0
    const LOKDocumentFocusListener& rDocFocusListener = GetLOKDocumentFocusListener();
2809
0
    return rDocFocusListener.getCaretPosition();
2810
0
}
2811
2812
void SfxViewShell::SetSigningCertificate(const svl::crypto::CertificateOrName& rCertificate)
2813
0
{
2814
0
    pImpl->m_aSigningCertificate = rCertificate;
2815
0
}
2816
2817
svl::crypto::CertificateOrName SfxViewShell::GetSigningCertificate() const
2818
0
{
2819
0
    return pImpl->m_aSigningCertificate;
2820
0
}
2821
2822
namespace
2823
{
2824
uno::Reference<beans::XPropertySet>
2825
GetSelectedShapeOfView(const uno::Reference<frame::XController>& xController)
2826
0
{
2827
0
    uno::Reference<view::XSelectionSupplier> xSelectionSupplier(xController, uno::UNO_QUERY);
2828
0
    if (!xSelectionSupplier)
2829
0
    {
2830
0
        return {};
2831
0
    }
2832
0
    uno::Reference<drawing::XShapes> xShapes(xSelectionSupplier->getSelection(), uno::UNO_QUERY);
2833
0
    if (!xShapes.is() || xShapes->getCount() != 1)
2834
0
    {
2835
0
        return {};
2836
0
    }
2837
2838
0
    return uno::Reference<beans::XPropertySet>(xShapes->getByIndex(0), uno::UNO_QUERY);
2839
0
}
2840
}
2841
2842
void SfxViewShell::SetSignPDFCertificate(const svl::crypto::CertificateOrName& rCertificateOrName)
2843
0
{
2844
0
    uno::Reference<beans::XPropertySet> xShape = GetSelectedShapeOfView(GetController());
2845
0
    if (!xShape.is() || !xShape->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
2846
0
    {
2847
0
        return;
2848
0
    }
2849
2850
0
    comphelper::SequenceAsHashMap aMap(xShape->getPropertyValue("InteropGrabBag"));
2851
2852
0
    auto it = aMap.find("SignatureCertificate");
2853
0
    if (rCertificateOrName.Is())
2854
0
    {
2855
0
        if (rCertificateOrName.m_xCertificate.is())
2856
0
        {
2857
0
            aMap["SignatureCertificate"] <<= rCertificateOrName.m_xCertificate;
2858
0
        }
2859
0
        else
2860
0
        {
2861
0
            aMap["SignatureCertificate"] <<= rCertificateOrName.m_aName;
2862
0
        }
2863
0
    }
2864
0
    else if (it != aMap.end())
2865
0
    {
2866
0
        aMap.erase(it);
2867
0
    }
2868
0
    xShape->setPropertyValue("InteropGrabBag", uno::Any(aMap.getAsConstPropertyValueList()));
2869
0
    if (!rCertificateOrName.Is())
2870
0
    {
2871
        // The shape's property is now reset, so the doc model is no longer modified.
2872
0
        GetObjectShell()->SetModified(false);
2873
0
    }
2874
0
}
2875
2876
svl::crypto::CertificateOrName SfxViewShell::GetSignPDFCertificate() const
2877
0
{
2878
0
    uno::Reference<beans::XPropertySet> xShape = GetSelectedShapeOfView(GetController());
2879
0
    if (!xShape.is() || !xShape->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
2880
0
    {
2881
0
        return {};
2882
0
    }
2883
2884
0
    comphelper::SequenceAsHashMap aMap(xShape->getPropertyValue("InteropGrabBag"));
2885
0
    auto it = aMap.find("SignatureCertificate");
2886
0
    if (it == aMap.end())
2887
0
    {
2888
0
        return {};
2889
0
    }
2890
2891
0
    svl::crypto::CertificateOrName aCertificateOrName;
2892
0
    if (it->second.has<uno::Reference<security::XCertificate>>())
2893
0
    {
2894
0
        it->second >>= aCertificateOrName.m_xCertificate;
2895
0
    }
2896
0
    else
2897
0
    {
2898
0
        it->second >>= aCertificateOrName.m_aName;
2899
0
    }
2900
0
    return aCertificateOrName;
2901
0
}
2902
2903
bool SfxViewShell::PrepareClose
2904
(
2905
    bool bUI     // TRUE: Allow Dialog and so on, FALSE: silent-mode
2906
)
2907
8.52k
{
2908
8.52k
    if (GetViewFrame().GetWindow().GetLOKNotifier() == this)
2909
0
        GetViewFrame().GetWindow().ReleaseLOKNotifier();
2910
2911
8.52k
    SfxPrinter *pPrinter = GetPrinter();
2912
8.52k
    if ( pPrinter && pPrinter->IsPrinting() )
2913
0
    {
2914
0
        if ( bUI )
2915
0
        {
2916
0
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewFrame().GetFrameWeld(),
2917
0
                                                                     VclMessageType::Info, VclButtonsType::Ok,
2918
0
                                                                     SfxResId(STR_CANT_CLOSE)));
2919
0
            xBox->run();
2920
0
        }
2921
2922
0
        return false;
2923
0
    }
2924
2925
8.52k
    if( GetViewFrame().IsInModalMode() )
2926
0
        return false;
2927
2928
8.52k
    if( bUI && GetViewFrame().GetDispatcher()->IsLocked() )
2929
0
        return false;
2930
2931
8.52k
    return true;
2932
8.52k
}
2933
2934
SfxViewShell* SfxViewShell::Current()
2935
12.4M
{
2936
12.4M
    SfxViewFrame *pCurrent = SfxViewFrame::Current();
2937
12.4M
    return pCurrent ? pCurrent->GetViewShell() : nullptr;
2938
12.4M
}
2939
2940
bool SfxViewShell::IsCurrentLokViewReadOnly()
2941
362k
{
2942
362k
    if (!comphelper::LibreOfficeKit::isActive())
2943
362k
        return false;
2944
0
    SfxViewShell* pCurrent = Current();
2945
0
    return pCurrent && pCurrent->IsLokReadOnlyView();
2946
362k
}
2947
2948
SfxViewShell* SfxViewShell::Get( const Reference< XController>& i_rController )
2949
4.26k
{
2950
4.26k
    if ( !i_rController.is() )
2951
4.26k
        return nullptr;
2952
2953
0
    for (   SfxViewShell* pViewShell = SfxViewShell::GetFirst( false );
2954
0
            pViewShell;
2955
0
            pViewShell = SfxViewShell::GetNext( *pViewShell, false )
2956
0
        )
2957
0
    {
2958
0
        if ( pViewShell->GetController() == i_rController )
2959
0
            return pViewShell;
2960
0
    }
2961
0
    return nullptr;
2962
0
}
2963
2964
SdrView* SfxViewShell::GetDrawView() const
2965
2966
/*  [Description]
2967
2968
    This virtual Method has to be overloaded by the sub classes, to be able
2969
    make the Property-Editor available.
2970
2971
    The default implementation does always return zero.
2972
*/
2973
2974
0
{
2975
0
    return nullptr;
2976
0
}
2977
2978
2979
OUString SfxViewShell::GetSelectionText
2980
(
2981
    bool /*bCompleteWords*/, /*  FALSE (default)
2982
                                Only the actual selected text is returned.
2983
2984
                                TRUE
2985
                                The selected text is expanded so that only
2986
                                whole words are returned. As word separators
2987
                                these are used: white spaces and punctuation
2988
                                ".,;" and single and double quotes.
2989
                            */
2990
    bool /*bOnlyASample*/ /* used by some dialogs to avoid constructing monster strings e.g. in calc */
2991
)
2992
2993
/*  [Description]
2994
2995
    Override this Method to return a text that
2996
    is included in the current selection. This is for example used when
2997
    sending emails.
2998
2999
    When called with "CompleteWords == TRUE", it is for example sufficient
3000
    with having the Cursor positioned somewhere within a URL in-order
3001
    to have the entire URL returned.
3002
*/
3003
3004
0
{
3005
0
    return OUString();
3006
0
}
3007
3008
3009
bool SfxViewShell::HasSelection( bool ) const
3010
3011
/*  [Description]
3012
3013
    With this virtual Method can a for example a Dialog be queried, to
3014
    check if something is selected in the current view. If the Parameter
3015
    is <BOOL> TRUE then it is checked whether some text is selected.
3016
*/
3017
3018
0
{
3019
0
    return false;
3020
0
}
3021
3022
void SfxViewShell::AddSubShell( SfxShell& rShell )
3023
0
{
3024
0
    pImpl->aArr.push_back(&rShell);
3025
0
    SfxDispatcher *pDisp = rFrame.GetDispatcher();
3026
0
    if ( pDisp->IsActive(*this) )
3027
0
    {
3028
0
        pDisp->Push(rShell);
3029
0
        pDisp->Flush();
3030
0
    }
3031
0
}
3032
3033
void SfxViewShell::RemoveSubShell( SfxShell* pShell )
3034
0
{
3035
0
    SfxDispatcher *pDisp = rFrame.GetDispatcher();
3036
0
    if ( !pShell )
3037
0
    {
3038
0
        size_t nCount = pImpl->aArr.size();
3039
0
        if ( pDisp->IsActive(*this) )
3040
0
        {
3041
0
            for(size_t n = nCount; n > 0; --n)
3042
0
                pDisp->Pop(*pImpl->aArr[n - 1]);
3043
0
            pDisp->Flush();
3044
0
        }
3045
0
        pImpl->aArr.clear();
3046
0
    }
3047
0
    else
3048
0
    {
3049
0
        SfxShellArr_Impl::iterator i = std::find(pImpl->aArr.begin(), pImpl->aArr.end(), pShell);
3050
0
        if(i != pImpl->aArr.end())
3051
0
        {
3052
0
            pImpl->aArr.erase(i);
3053
0
            if(pDisp->IsActive(*this))
3054
0
            {
3055
0
                pDisp->RemoveShell_Impl(*pShell);
3056
0
                pDisp->Flush();
3057
0
            }
3058
0
        }
3059
0
    }
3060
0
}
3061
3062
SfxShell* SfxViewShell::GetSubShell( sal_uInt16 nNo )
3063
0
{
3064
0
    sal_uInt16 nCount = pImpl->aArr.size();
3065
0
    if(nNo < nCount)
3066
0
        return pImpl->aArr[nCount - nNo - 1];
3067
0
    return nullptr;
3068
0
}
3069
3070
void SfxViewShell::PushSubShells_Impl( bool bPush )
3071
8.52k
{
3072
8.52k
    SfxDispatcher *pDisp = rFrame.GetDispatcher();
3073
8.52k
    if ( bPush )
3074
4.26k
    {
3075
4.26k
        for (auto const& elem : pImpl->aArr)
3076
0
            pDisp->Push(*elem);
3077
4.26k
    }
3078
4.26k
    else if(!pImpl->aArr.empty())
3079
0
    {
3080
0
        SfxShell& rPopUntil = *pImpl->aArr[0];
3081
0
        if ( pDisp->GetShellLevel( rPopUntil ) != USHRT_MAX )
3082
0
            pDisp->Pop( rPopUntil, SfxDispatcherPopFlags::POP_UNTIL );
3083
0
    }
3084
3085
8.52k
    pDisp->Flush();
3086
8.52k
}
3087
3088
3089
void SfxViewShell::WriteUserData( OUString&, bool )
3090
0
{
3091
0
}
3092
3093
3094
void SfxViewShell::ReadUserData(const OUString&, bool )
3095
0
{
3096
0
}
3097
3098
void SfxViewShell::ReadUserDataSequence ( const uno::Sequence < beans::PropertyValue >& )
3099
0
{
3100
0
}
3101
3102
void SfxViewShell::WriteUserDataSequence ( uno::Sequence < beans::PropertyValue >& )
3103
0
{
3104
0
}
3105
3106
3107
// returns the first shell of spec. type viewing the specified doc.
3108
SfxViewShell* SfxViewShell::GetFirst
3109
(
3110
    bool          bOnlyVisible,
3111
    const std::function< bool ( const SfxViewShell& ) >& isViewShell
3112
)
3113
7.40M
{
3114
    // search for a SfxViewShell of the specified type
3115
7.40M
    std::vector<SfxViewShell*> &rShells = SfxGetpApp()->GetViewShells_Impl();
3116
7.40M
    for (SfxViewShell* pShell : rShells)
3117
0
    {
3118
0
        if ( pShell )
3119
0
        {
3120
            // This code used to check that the frame exists in the other list,
3121
            // because of https://bz.apache.org/ooo/show_bug.cgi?id=62084, with the explanation:
3122
            // sometimes dangling SfxViewShells exist that point to a dead SfxViewFrame
3123
            // these ViewShells shouldn't be accessible anymore
3124
            // a destroyed ViewFrame is not in the ViewFrame array anymore, so checking this array helps
3125
            // That doesn't seem to be needed anymore, but keep an assert, just in case.
3126
0
            assert(std::find(SfxGetpApp()->GetViewFrames_Impl().begin(), SfxGetpApp()->GetViewFrames_Impl().end(),
3127
0
                &pShell->GetViewFrame()) != SfxGetpApp()->GetViewFrames_Impl().end());
3128
0
            if ( ( !bOnlyVisible || pShell->GetViewFrame().IsVisible() ) && (!isViewShell || isViewShell(*pShell)))
3129
0
                return pShell;
3130
0
        }
3131
0
    }
3132
3133
7.40M
    return nullptr;
3134
7.40M
}
3135
3136
// returns the next shell of spec. type viewing the specified doc.
3137
SfxViewShell* SfxViewShell::GetNext
3138
(
3139
    const SfxViewShell& rPrev,
3140
    bool                bOnlyVisible,
3141
    const std::function<bool ( const SfxViewShell& )>& isViewShell
3142
)
3143
0
{
3144
0
    std::vector<SfxViewShell*> &rShells = SfxGetpApp()->GetViewShells_Impl();
3145
0
    size_t nPos;
3146
0
    for ( nPos = 0; nPos < rShells.size(); ++nPos )
3147
0
        if ( rShells[nPos] == &rPrev )
3148
0
            break;
3149
3150
0
    for ( ++nPos; nPos < rShells.size(); ++nPos )
3151
0
    {
3152
0
        SfxViewShell *pShell = rShells[nPos];
3153
0
        if ( pShell )
3154
0
        {
3155
0
            assert(std::find(SfxGetpApp()->GetViewFrames_Impl().begin(), SfxGetpApp()->GetViewFrames_Impl().end(),
3156
0
                &pShell->GetViewFrame()) != SfxGetpApp()->GetViewFrames_Impl().end());
3157
0
            if ( ( !bOnlyVisible || pShell->GetViewFrame().IsVisible() ) && (!isViewShell || isViewShell(*pShell)) )
3158
0
                return pShell;
3159
0
        }
3160
0
    }
3161
3162
0
    return nullptr;
3163
0
}
3164
3165
void SfxViewShell::Notify( SfxBroadcaster& rBC,
3166
                            const SfxHint& rHint )
3167
135k
{
3168
135k
    if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint ||
3169
21.3k
        static_cast<const SfxEventHint&>(rHint).GetEventId() != SfxEventHintId::LoadFinished)
3170
135k
    {
3171
135k
        return;
3172
135k
    }
3173
3174
0
    if ( !GetController().is() )
3175
0
        return;
3176
3177
    // avoid access to dangling ViewShells
3178
0
    auto &rFrames = SfxGetpApp()->GetViewFrames_Impl();
3179
0
    for (SfxViewFrame* frame : rFrames)
3180
0
    {
3181
0
        if ( frame == &GetViewFrame() && &rBC == GetObjectShell() )
3182
0
        {
3183
0
            SfxItemSet& rSet = GetObjectShell()->GetMedium()->GetItemSet();
3184
0
            const SfxUnoAnyItem* pItem = rSet.GetItem(SID_VIEW_DATA, false);
3185
0
            if ( pItem )
3186
0
            {
3187
0
                pImpl->m_pController->restoreViewData( pItem->GetValue() );
3188
0
                rSet.ClearItem( SID_VIEW_DATA );
3189
0
            }
3190
0
            break;
3191
0
        }
3192
0
    }
3193
0
}
3194
3195
bool SfxViewShell::ExecKey_Impl(const KeyEvent& aKey)
3196
0
{
3197
0
    bool setModuleConfig = false; // In case libreofficekit is active, we will re-set the module config class.
3198
0
    if (!pImpl->m_xAccExec)
3199
0
    {
3200
0
        pImpl->m_xAccExec = ::svt::AcceleratorExecute::createAcceleratorHelper();
3201
0
        pImpl->m_xAccExec->init(::comphelper::getProcessComponentContext(),
3202
0
            rFrame.GetFrame().GetFrameInterface());
3203
0
        setModuleConfig = true;
3204
0
    }
3205
3206
0
    if (comphelper::LibreOfficeKit::isActive())
3207
0
    {
3208
        // Get the module name.
3209
0
        const css::uno::Reference< css::uno::XComponentContext >&  xContext      (::comphelper::getProcessComponentContext());
3210
0
        css::uno::Reference< css::frame::XModuleManager2 >  xModuleManager(css::frame::ModuleManager::create(xContext));
3211
0
        OUString sModule = xModuleManager->identify(rFrame.GetFrame().GetFrameInterface());
3212
3213
        // Get the language name.
3214
0
        OUString viewLang = GetLOKLanguageTag().getBcp47();
3215
3216
        // Merge them & have a key.
3217
0
        OUString key = sModule + viewLang;
3218
3219
        // Check it in configurations map. Create a configuration manager if there isn't one for the key.
3220
0
        std::unordered_map<OUString, css::uno::Reference<css::ui::XAcceleratorConfiguration>>& acceleratorConfs = SfxApplication::Get()->GetAcceleratorConfs_Impl();
3221
0
        if (acceleratorConfs.find(key) == acceleratorConfs.end())
3222
0
        {
3223
            // Create a new configuration manager for the module.
3224
3225
0
            OUString actualLang = officecfg::Setup::L10N::ooLocale::get();
3226
3227
0
            std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
3228
0
            officecfg::Setup::L10N::ooLocale::set(viewLang, batch);
3229
0
            batch->commit();
3230
3231
            // We have set the language. Time to create the config manager.
3232
0
            acceleratorConfs[key] = svt::AcceleratorExecute::lok_createNewAcceleratorConfiguration(::comphelper::getProcessComponentContext(), sModule);
3233
3234
0
            std::shared_ptr<comphelper::ConfigurationChanges> batch2(comphelper::ConfigurationChanges::create());
3235
0
            officecfg::Setup::L10N::ooLocale::set(actualLang, batch2);
3236
0
            batch2->commit();
3237
0
        }
3238
3239
0
        if (setModuleConfig)
3240
0
            pImpl->m_xAccExec->lok_setModuleConfig(acceleratorConfs[key]);
3241
0
    }
3242
3243
0
    return pImpl->m_xAccExec->execute(aKey.GetKeyCode());
3244
0
}
3245
3246
void SfxViewShell::setLibreOfficeKitViewCallback(SfxLokCallbackInterface* pCallback)
3247
0
{
3248
0
    pImpl->m_pLibreOfficeKitViewCallback = pCallback;
3249
3250
0
    afterCallbackRegistered();
3251
3252
0
    if (!pImpl->m_pLibreOfficeKitViewCallback)
3253
0
        return;
3254
3255
    // Ask other views to tell us about their cursors.
3256
0
    SfxViewShell* pViewShell = SfxViewShell::GetFirst();
3257
0
    while (pViewShell)
3258
0
    {
3259
0
        if (pViewShell->GetDocId() == GetDocId())
3260
0
            pViewShell->NotifyCursor(this);
3261
0
        pViewShell = SfxViewShell::GetNext(*pViewShell);
3262
0
    }
3263
0
}
3264
3265
SfxLokCallbackInterface* SfxViewShell::getLibreOfficeKitViewCallback() const
3266
0
{
3267
0
    return pImpl->m_pLibreOfficeKitViewCallback;
3268
0
}
3269
3270
void SfxViewShell::dumpLibreOfficeKitViewState(rtl::OStringBuffer &rState)
3271
0
{
3272
0
    rState.append("\n    SfxViewShell: ");
3273
0
    rState.append(OString::number(reinterpret_cast<sal_uInt64>(this), 16));
3274
0
    rState.append("\n\tDocId:\t");
3275
0
    auto nDocId = static_cast<int>(GetDocId());
3276
0
    rState.append(static_cast<sal_Int32>(nDocId));
3277
0
    rState.append("\n\tViewId:\t");
3278
0
    rState.append(static_cast<sal_Int32>(GetViewShellId()));
3279
0
    rState.append("\n\tPart:\t");
3280
0
    rState.append(static_cast<sal_Int32>(getPart()));
3281
0
    rState.append("\n\tLang:\t");
3282
0
    rState.append(OUStringToOString(GetLOKLanguageTag().getBcp47(), RTL_TEXTENCODING_UTF8));
3283
0
    rState.append("\n\tA11y:\t");
3284
0
    rState.append(GetLOKAccessibilityState() ? "enabled" : "disabled");
3285
3286
0
    if (pImpl->m_pLibreOfficeKitViewCallback)
3287
0
        pImpl->m_pLibreOfficeKitViewCallback->dumpState(rState);
3288
0
}
3289
3290
static bool ignoreLibreOfficeKitViewCallback(int nType, const SfxViewShell_Impl* pImpl)
3291
8.90k
{
3292
8.90k
    if (!comphelper::LibreOfficeKit::isActive())
3293
8.90k
        return true;
3294
3295
0
    if (comphelper::LibreOfficeKit::isTiledPainting())
3296
0
    {
3297
0
        switch (nType)
3298
0
        {
3299
0
        case LOK_CALLBACK_FORM_FIELD_BUTTON:
3300
0
        case LOK_CALLBACK_TEXT_SELECTION:
3301
0
        case LOK_CALLBACK_COMMENT:
3302
0
        case LOK_CALLBACK_DOCUMENT_SIZE_CHANGED:
3303
0
            break;
3304
0
        default:
3305
            // Reject e.g. invalidate during paint.
3306
0
            return true;
3307
0
        }
3308
0
    }
3309
3310
0
    if (pImpl->m_bTiledSearching)
3311
0
    {
3312
0
        switch (nType)
3313
0
        {
3314
0
        case LOK_CALLBACK_TEXT_SELECTION:
3315
0
        case LOK_CALLBACK_TEXT_VIEW_SELECTION:
3316
0
        case LOK_CALLBACK_TEXT_SELECTION_START:
3317
0
        case LOK_CALLBACK_TEXT_SELECTION_END:
3318
0
        case LOK_CALLBACK_GRAPHIC_SELECTION:
3319
0
        case LOK_CALLBACK_GRAPHIC_VIEW_SELECTION:
3320
0
            return true;
3321
0
        }
3322
0
    }
3323
3324
0
    return false;
3325
0
}
3326
3327
void SfxViewShell::libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart, int nMode) const
3328
0
{
3329
0
    if (ignoreLibreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_TILES, pImpl.get()))
3330
0
        return;
3331
0
    if (pImpl->m_pLibreOfficeKitViewCallback)
3332
0
        pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewInvalidateTilesCallback(pRect, nPart, nMode);
3333
0
    else
3334
0
        SAL_INFO(
3335
0
            "sfx.view",
3336
0
            "SfxViewShell::libreOfficeKitViewInvalidateTilesCallback no callback set!");
3337
0
}
3338
3339
void SfxViewShell::libreOfficeKitViewCallbackWithViewId(int nType, const OString& pPayload, int nViewId) const
3340
0
{
3341
0
    if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
3342
0
        return;
3343
0
    if (pImpl->m_pLibreOfficeKitViewCallback)
3344
0
        pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewCallbackWithViewId(nType, pPayload, nViewId);
3345
0
    else
3346
0
        SAL_INFO(
3347
0
            "sfx.view",
3348
0
            "SfxViewShell::libreOfficeKitViewCallbackWithViewId no callback set! Dropped payload of type "
3349
0
            << lokCallbackTypeToString(nType) << ": [" << pPayload << ']');
3350
0
}
3351
3352
void SfxViewShell::libreOfficeKitViewCallback(int nType, const OString& pPayload) const
3353
8.90k
{
3354
8.90k
    if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
3355
8.90k
        return;
3356
0
    if (pImpl->m_pLibreOfficeKitViewCallback)
3357
0
        pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewCallback(nType, pPayload);
3358
0
    else
3359
0
        SAL_INFO(
3360
0
            "sfx.view",
3361
0
            "SfxViewShell::libreOfficeKitViewCallback no callback set! Dropped payload of type "
3362
0
            << lokCallbackTypeToString(nType) << ": [" << pPayload << ']');
3363
0
}
3364
3365
void SfxViewShell::libreOfficeKitViewUpdatedCallback(int nType) const
3366
0
{
3367
0
    if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
3368
0
        return;
3369
0
    if (pImpl->m_pLibreOfficeKitViewCallback)
3370
0
        pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewUpdatedCallback(nType);
3371
0
    else
3372
0
        SAL_INFO(
3373
0
            "sfx.view",
3374
0
            "SfxViewShell::libreOfficeKitViewUpdatedCallback no callback set! Dropped payload of type "
3375
0
            << lokCallbackTypeToString(nType));
3376
0
}
3377
3378
void SfxViewShell::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) const
3379
0
{
3380
0
    if (ignoreLibreOfficeKitViewCallback(nType, pImpl.get()))
3381
0
        return;
3382
0
    if (pImpl->m_pLibreOfficeKitViewCallback)
3383
0
        pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewUpdatedCallbackPerViewId(nType, nViewId, nSourceViewId);
3384
0
    else
3385
0
        SAL_INFO(
3386
0
            "sfx.view",
3387
0
            "SfxViewShell::libreOfficeKitViewUpdatedCallbackPerViewId no callback set! Dropped payload of type "
3388
0
            << lokCallbackTypeToString(nType));
3389
0
}
3390
3391
void SfxViewShell::libreOfficeKitViewAddPendingInvalidateTiles()
3392
0
{
3393
0
    if (pImpl->m_pLibreOfficeKitViewCallback)
3394
0
        pImpl->m_pLibreOfficeKitViewCallback->libreOfficeKitViewAddPendingInvalidateTiles();
3395
0
    else
3396
0
        SAL_INFO(
3397
0
            "sfx.view",
3398
0
            "SfxViewShell::libreOfficeKitViewAddPendingInvalidateTiles no callback set!");
3399
0
}
3400
3401
void SfxViewShell::afterCallbackRegistered()
3402
0
{
3403
0
    LOK_INFO("sfx.view", "SfxViewShell::afterCallbackRegistered invoked");
3404
0
    if (GetLOKAccessibilityState())
3405
0
    {
3406
0
        LOKDocumentFocusListener& rDocFocusListener = GetLOKDocumentFocusListener();
3407
0
        rDocFocusListener.notifyFocusedParagraphChanged();
3408
0
    }
3409
0
}
3410
3411
void SfxViewShell::flushPendingLOKInvalidateTiles()
3412
0
{
3413
    // SfxViewShell itself does not delay any tile invalidations.
3414
0
}
3415
3416
std::optional<OString> SfxViewShell::getLOKPayload(int nType, int /*nViewId*/) const
3417
0
{
3418
    // SfxViewShell itself currently doesn't handle any updated-payload types.
3419
0
    SAL_WARN("sfx.view", "SfxViewShell::getLOKPayload unhandled type " << lokCallbackTypeToString(nType));
3420
0
    abort();
3421
0
}
3422
3423
vcl::Window* SfxViewShell::GetEditWindowForActiveOLEObj() const
3424
0
{
3425
0
    vcl::Window* pEditWin = nullptr;
3426
0
    SfxInPlaceClient* pIPClient = GetIPClient();
3427
0
    if (pIPClient)
3428
0
    {
3429
0
        pEditWin = pIPClient->GetEditWin();
3430
0
    }
3431
0
    return pEditWin;
3432
0
}
3433
3434
::Color SfxViewShell::GetColorConfigColor(svtools::ColorConfigEntry eEntry) const
3435
0
{
3436
0
    SAL_WARN("sfx.view", "SfxViewShell::GetColorConfigColor not overridden!");
3437
0
    svtools::ColorConfig aColorConfig;
3438
0
    return aColorConfig.GetColorValue(eEntry).nColor;
3439
0
}
3440
3441
void SfxViewShell::SetLOKLanguageTag(const OUString& rBcp47LanguageTag)
3442
0
{
3443
0
    LanguageTag aTag(rBcp47LanguageTag, true);
3444
3445
0
    css::uno::Sequence<OUString> inst(officecfg::Setup::Office::InstalledLocales::get()->getElementNames());
3446
0
    LanguageTag aFallbackTag = LanguageTag(getInstalledLocaleForSystemUILanguage(inst, /* bRequestInstallIfMissing */ false, rBcp47LanguageTag), true).makeFallback();
3447
3448
    // If we want de-CH, and the de localisation is available, we don't want to use de-DE as then
3449
    // the magic in Translate::get() won't turn ess-zet into double s.
3450
0
    if (rBcp47LanguageTag == "de-CH")
3451
0
        maLOKLanguageTag = std::move(aTag);
3452
0
    else
3453
0
        maLOKLanguageTag = std::move(aFallbackTag);
3454
0
}
3455
3456
LOKDocumentFocusListener& SfxViewShell::GetLOKDocumentFocusListener()
3457
0
{
3458
0
    if (mpLOKDocumentFocusListener)
3459
0
        return *mpLOKDocumentFocusListener;
3460
3461
0
    mpLOKDocumentFocusListener = new LOKDocumentFocusListener(this);
3462
0
    return *mpLOKDocumentFocusListener;
3463
0
}
3464
3465
const LOKDocumentFocusListener& SfxViewShell::GetLOKDocumentFocusListener() const
3466
0
{
3467
0
    return const_cast<SfxViewShell*>(this)->GetLOKDocumentFocusListener();
3468
0
}
3469
3470
void SfxViewShell::SetLOKAccessibilityState(bool bEnabled)
3471
0
{
3472
0
    if (bEnabled == mbLOKAccessibilityEnabled)
3473
0
        return;
3474
0
    mbLOKAccessibilityEnabled = bEnabled;
3475
3476
0
    LOKDocumentFocusListener& rDocumentFocusListener = GetLOKDocumentFocusListener();
3477
3478
0
    if (!pWindow)
3479
0
        return;
3480
3481
0
    uno::Reference< accessibility::XAccessible > xAccessible =
3482
0
        pWindow->GetAccessible();
3483
3484
0
    if (!xAccessible.is())
3485
0
        return;
3486
3487
0
    if (mbLOKAccessibilityEnabled)
3488
0
    {
3489
0
        try
3490
0
        {
3491
0
            rDocumentFocusListener.attachRecursive(xAccessible);
3492
0
        }
3493
0
        catch (const uno::Exception&)
3494
0
        {
3495
0
            LOK_WARN("SetLOKAccessibilityState", "Exception caught processing LOKDocumentFocusListener::attachRecursive");
3496
0
        }
3497
0
    }
3498
0
    else
3499
0
    {
3500
0
        try
3501
0
        {
3502
0
            rDocumentFocusListener.detachRecursive(xAccessible, /*bForce*/ true);
3503
0
        }
3504
0
        catch (const uno::Exception&)
3505
0
        {
3506
0
            LOK_WARN("SetLOKAccessibilityState", "Exception caught processing LOKDocumentFocusListener::detachRecursive");
3507
0
        }
3508
0
    }
3509
0
}
3510
3511
void SfxViewShell::SetLOKColorPreviewState(bool bEnabled)
3512
0
{
3513
0
    mbLOKColorPreviewEnabled = bEnabled;
3514
0
}
3515
3516
void SfxViewShell::SetLOKLocale(const OUString& rBcp47LanguageTag)
3517
0
{
3518
0
    maLOKLocale = LanguageTag(rBcp47LanguageTag, true).makeFallback();
3519
0
    if (this == Current())
3520
0
    {
3521
        // update the current LOK language and locale for the dialog tunneling
3522
0
        comphelper::LibreOfficeKit::setLanguageTag(GetLOKLanguageTag());
3523
0
        comphelper::LibreOfficeKit::setLocale(GetLOKLocale());
3524
0
    }
3525
0
}
3526
3527
void SfxViewShell::NotifyCursor(SfxViewShell* /*pViewShell*/) const
3528
0
{
3529
0
}
3530
3531
void SfxViewShell::setTiledSearching(bool bTiledSearching)
3532
0
{
3533
0
    pImpl->m_bTiledSearching = bTiledSearching;
3534
0
}
3535
3536
int SfxViewShell::getPart() const
3537
0
{
3538
0
    return 0;
3539
0
}
3540
3541
int SfxViewShell::getEditMode() const
3542
0
{
3543
0
    return 0;
3544
0
}
3545
3546
ViewShellId SfxViewShell::GetViewShellId() const
3547
0
{
3548
0
    return pImpl->m_nViewShellId;
3549
0
}
3550
3551
ViewShellDocId SfxViewShell::GetDocId() const
3552
0
{
3553
0
    assert(pImpl->m_nDocId >= ViewShellDocId(0) && "m_nDocId should have been initialized, but it is invalid.");
3554
0
    return pImpl->m_nDocId;
3555
0
}
3556
3557
void SfxViewShell::notifyInvalidation(tools::Rectangle const* pRect) const
3558
0
{
3559
0
    SfxLokHelper::notifyInvalidation(this, pRect);
3560
0
}
3561
3562
void SfxViewShell::notifyCursorInvalidation(tools::Rectangle const* pRect, bool bControlEvent) const
3563
0
{
3564
0
    SfxLokHelper::notifyCursorInvalidation(this, pRect, bControlEvent);
3565
0
}
3566
3567
void SfxViewShell::NotifyOtherViews(int nType, const OString& rKey, const OString& rPayload)
3568
0
{
3569
0
    SfxLokHelper::notifyOtherViews(this, nType, rKey, rPayload);
3570
0
}
3571
3572
void SfxViewShell::NotifyOtherView(OutlinerViewShell* pOther, int nType, const OString& rKey, const OString& rPayload)
3573
0
{
3574
0
    auto pOtherShell = dynamic_cast<SfxViewShell*>(pOther);
3575
0
    if (!pOtherShell)
3576
0
        return;
3577
3578
0
    SfxLokHelper::notifyOtherView(*this, pOtherShell, nType, rKey, rPayload);
3579
0
}
3580
3581
void SfxViewShell::dumpAsXml(xmlTextWriterPtr pWriter) const
3582
0
{
3583
0
    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxViewShell"));
3584
0
    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
3585
0
    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("id"), BAD_CAST(OString::number(static_cast<sal_Int32>(GetViewShellId())).getStr()));
3586
0
    (void)xmlTextWriterEndElement(pWriter);
3587
0
}
3588
3589
bool SfxViewShell::KeyInput( const KeyEvent &rKeyEvent )
3590
3591
/*  [Description]
3592
3593
    This Method executes the KeyEvent 'rKeyEvent' of the Keys (Accelerator)
3594
    configured either direct or indirect (for example by the Application)
3595
    in the SfxViewShell.
3596
3597
    [Return value]
3598
3599
    bool                    TRUE
3600
                            The Key (Accelerator) is configured and the
3601
                            associated Handler was called
3602
3603
                            FALSE
3604
                            The Key (Accelerator) is not configured and
3605
                            subsequently no Handler was called
3606
3607
    [Cross-reference]
3608
3609
    <SfxApplication::KeyInput(const KeyEvent&)>
3610
*/
3611
0
{
3612
0
    return ExecKey_Impl(rKeyEvent);
3613
0
}
3614
3615
bool SfxViewShell::GlobalKeyInput_Impl( const KeyEvent &rKeyEvent )
3616
0
{
3617
0
    return ExecKey_Impl(rKeyEvent);
3618
0
}
3619
3620
3621
void SfxViewShell::ShowCursor( bool /*bOn*/ )
3622
3623
/*  [Description]
3624
3625
    Subclasses must override this Method so that SFx can switch the
3626
    Cursor on and off, for example while a <SfxProgress> is running.
3627
*/
3628
3629
0
{
3630
0
}
3631
3632
3633
void SfxViewShell::ResetAllClients_Impl( SfxInPlaceClient const *pIP )
3634
0
{
3635
3636
0
    std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
3637
0
    if ( rClients.empty() )
3638
0
        return;
3639
3640
0
    for (SfxInPlaceClient* pIPClient : rClients)
3641
0
    {
3642
0
        if( pIPClient != pIP )
3643
0
            pIPClient->ResetObject();
3644
0
    }
3645
0
}
3646
3647
3648
void SfxViewShell::DisconnectAllClients()
3649
21.3k
{
3650
21.3k
    std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
3651
21.3k
    if ( rClients.empty() )
3652
21.3k
        return;
3653
3654
0
    for ( size_t n = 0; n < rClients.size(); )
3655
        // clients will remove themselves from the list
3656
0
        delete rClients.at( n );
3657
0
}
3658
3659
3660
void SfxViewShell::QueryObjAreaPixel( tools::Rectangle& ) const
3661
0
{
3662
0
}
3663
3664
3665
void SfxViewShell::VisAreaChanged()
3666
154
{
3667
154
    std::vector< SfxInPlaceClient* >& rClients = pImpl->GetIPClients_Impl();
3668
154
    if ( rClients.empty() )
3669
154
        return;
3670
3671
0
    for (SfxInPlaceClient* pIPClient : rClients)
3672
0
    {
3673
0
        if ( pIPClient->IsObjectInPlaceActive() )
3674
            // client is active, notify client that the VisArea might have changed
3675
0
            pIPClient->VisAreaChanged();
3676
0
    }
3677
0
}
3678
3679
3680
void SfxViewShell::CheckIPClient_Impl(
3681
        SfxInPlaceClient const *const pIPClient, const tools::Rectangle& rVisArea)
3682
0
{
3683
0
    if ( GetObjectShell()->IsInClose() )
3684
0
        return;
3685
3686
0
    bool bAlwaysActive =
3687
0
        ( ( pIPClient->GetObjectMiscStatus() & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) != 0 );
3688
0
    bool bActiveWhenVisible =
3689
0
        ( pIPClient->GetObjectMiscStatus() & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE ) != 0;
3690
3691
    // this method is called when a client is created
3692
0
    if (pIPClient->IsObjectInPlaceActive())
3693
0
        return;
3694
3695
    // object in client is currently not active
3696
    // check if the object wants to be activated always or when it becomes at least partially visible
3697
    // TODO/LATER: maybe we should use the scaled area instead of the ObjArea?!
3698
0
    if (bAlwaysActive || (bActiveWhenVisible && rVisArea.Overlaps(pIPClient->GetObjArea())))
3699
0
    {
3700
0
        try
3701
0
        {
3702
0
            pIPClient->GetObject()->changeState( embed::EmbedStates::INPLACE_ACTIVE );
3703
0
        }
3704
0
        catch (const uno::Exception&)
3705
0
        {
3706
0
            TOOLS_WARN_EXCEPTION("sfx.view", "SfxViewShell::CheckIPClient_Impl");
3707
0
        }
3708
0
    }
3709
0
}
3710
3711
SfxObjectShell* SfxViewShell::GetObjectShell()
3712
290k
{
3713
290k
    return rFrame.GetObjectShell();
3714
290k
}
3715
3716
Reference< XModel > SfxViewShell::GetCurrentDocument() const
3717
17.4k
{
3718
17.4k
    Reference< XModel > xDocument;
3719
3720
17.4k
    const SfxObjectShell* pDocShell( const_cast< SfxViewShell* >( this )->GetObjectShell() );
3721
17.4k
    OSL_ENSURE( pDocShell, "SfxViewFrame::GetCurrentDocument: no DocShell!?" );
3722
17.4k
    if ( pDocShell )
3723
17.4k
        xDocument = pDocShell->GetModel();
3724
17.4k
    return xDocument;
3725
17.4k
}
3726
3727
3728
void SfxViewShell::SetCurrentDocument() const
3729
8.52k
{
3730
8.52k
    uno::Reference< frame::XModel > xDocument( GetCurrentDocument() );
3731
8.52k
    if ( xDocument.is() )
3732
8.52k
        SfxObjectShell::SetCurrentComponent( xDocument );
3733
8.52k
}
3734
3735
3736
const Size& SfxViewShell::GetMargin() const
3737
4.26k
{
3738
4.26k
    return pImpl->aMargin;
3739
4.26k
}
3740
3741
3742
void SfxViewShell::SetMargin( const Size& rSize )
3743
4.26k
{
3744
    // the default margin was verified using www.apple.com !!
3745
4.26k
    Size aMargin = rSize;
3746
4.26k
    if ( aMargin.Width() == -1 )
3747
4.26k
        aMargin.setWidth( DEFAULT_MARGIN_WIDTH );
3748
4.26k
    if ( aMargin.Height() == -1 )
3749
4.26k
        aMargin.setHeight( DEFAULT_MARGIN_HEIGHT );
3750
3751
4.26k
    if ( aMargin != pImpl->aMargin )
3752
4.26k
    {
3753
4.26k
        pImpl->aMargin = aMargin;
3754
4.26k
        MarginChanged();
3755
4.26k
    }
3756
4.26k
}
3757
3758
void SfxViewShell::MarginChanged()
3759
4.26k
{
3760
4.26k
}
3761
3762
void SfxViewShell::JumpToMark( const OUString& rMark )
3763
0
{
3764
0
    SfxStringItem aMarkItem( SID_JUMPTOMARK, rMark );
3765
0
    GetViewFrame().GetDispatcher()->ExecuteList(
3766
0
        SID_JUMPTOMARK,
3767
0
        SfxCallMode::SYNCHRON|SfxCallMode::RECORD,
3768
0
        { &aMarkItem });
3769
0
}
3770
3771
void SfxViewShell::SetController( SfxBaseController* pController )
3772
4.26k
{
3773
4.26k
    pImpl->m_pController = pController;
3774
3775
    // there should be no old listener, but if there is one, it should be disconnected
3776
4.26k
    if (  pImpl->xClipboardListener.is() )
3777
0
        pImpl->xClipboardListener->DisconnectViewShell();
3778
3779
4.26k
    pImpl->xClipboardListener = new SfxClipboardChangeListener( this, GetClipboardNotifier() );
3780
4.26k
}
3781
3782
Reference < XController > SfxViewShell::GetController() const
3783
25.5k
{
3784
25.5k
    return pImpl->m_pController;
3785
25.5k
}
3786
3787
SfxBaseController* SfxViewShell::GetBaseController_Impl() const
3788
4.26k
{
3789
4.26k
    return pImpl->m_pController.get();
3790
4.26k
}
3791
3792
void SfxViewShell::AddContextMenuInterceptor_Impl( const uno::Reference< ui::XContextMenuInterceptor >& xInterceptor )
3793
0
{
3794
0
    std::unique_lock g(pImpl->aMutex);
3795
0
    pImpl->aInterceptorContainer.addInterface( g, xInterceptor );
3796
0
}
3797
3798
void SfxViewShell::RemoveContextMenuInterceptor_Impl( const uno::Reference< ui::XContextMenuInterceptor >& xInterceptor )
3799
0
{
3800
0
    std::unique_lock g(pImpl->aMutex);
3801
0
    pImpl->aInterceptorContainer.removeInterface( g, xInterceptor );
3802
0
}
3803
3804
bool SfxViewShell::TryContextMenuInterception(const rtl::Reference<VCLXPopupMenu>& rIn,
3805
                                              const OUString& rMenuIdentifier,
3806
                                              rtl::Reference<VCLXPopupMenu>& rOut,
3807
                                              ui::ContextMenuExecuteEvent aEvent)
3808
0
{
3809
0
    rOut.clear();
3810
0
    bool bModified = false;
3811
3812
    // create container from menu
3813
0
    aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
3814
0
        rIn, &rMenuIdentifier);
3815
3816
    // get selection from controller
3817
0
    aEvent.Selection.set( GetController(), uno::UNO_QUERY );
3818
3819
    // call interceptors
3820
0
    std::unique_lock g(pImpl->aMutex);
3821
0
    std::vector<uno::Reference< ui::XContextMenuInterceptor>> aInterceptors =
3822
0
        pImpl->aInterceptorContainer.getElements(g);
3823
0
    g.unlock();
3824
0
    for (const auto & rListener : aInterceptors )
3825
0
    {
3826
0
        try
3827
0
        {
3828
0
            ui::ContextMenuInterceptorAction eAction;
3829
0
            {
3830
0
                SolarMutexReleaser rel;
3831
0
                eAction = rListener->notifyContextMenuExecute( aEvent );
3832
0
            }
3833
0
            switch ( eAction )
3834
0
            {
3835
0
                case ui::ContextMenuInterceptorAction_CANCELLED :
3836
                    // interceptor does not want execution
3837
0
                    return false;
3838
0
                case ui::ContextMenuInterceptorAction_EXECUTE_MODIFIED :
3839
                    // interceptor wants his modified menu to be executed
3840
0
                    bModified = true;
3841
0
                    break;
3842
0
                case ui::ContextMenuInterceptorAction_CONTINUE_MODIFIED :
3843
                    // interceptor has modified menu, but allows for calling other interceptors
3844
0
                    bModified = true;
3845
0
                    continue;
3846
0
                case ui::ContextMenuInterceptorAction_IGNORED :
3847
                    // interceptor is indifferent
3848
0
                    continue;
3849
0
                default:
3850
0
                    OSL_FAIL("Wrong return value of ContextMenuInterceptor!");
3851
0
                    continue;
3852
0
            }
3853
0
        }
3854
0
        catch (...)
3855
0
        {
3856
0
            g.lock();
3857
0
            pImpl->aInterceptorContainer.removeInterface(g, rListener);
3858
0
            g.unlock();
3859
0
        }
3860
3861
0
        break;
3862
0
    }
3863
3864
0
    if (bModified)
3865
0
    {
3866
        // container was modified, create a new menu out of it
3867
0
        rOut = new VCLXPopupMenu();
3868
0
        ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer(rOut, aEvent.ActionTriggerContainer);
3869
0
    }
3870
3871
0
    return true;
3872
0
}
3873
3874
bool SfxViewShell::TryContextMenuInterception(const rtl::Reference<VCLXPopupMenu>& rPopupMenu,
3875
                                              const OUString& rMenuIdentifier, css::ui::ContextMenuExecuteEvent aEvent)
3876
0
{
3877
0
    bool bModified = false;
3878
3879
    // create container from menu
3880
0
    aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu(
3881
0
        rPopupMenu, &rMenuIdentifier);
3882
3883
    // get selection from controller
3884
0
    aEvent.Selection = css::uno::Reference< css::view::XSelectionSupplier >( GetController(), css::uno::UNO_QUERY );
3885
3886
    // call interceptors
3887
0
    std::unique_lock g(pImpl->aMutex);
3888
0
    std::vector<uno::Reference< ui::XContextMenuInterceptor>> aInterceptors =
3889
0
        pImpl->aInterceptorContainer.getElements(g);
3890
0
    g.unlock();
3891
0
    for (const auto & rListener : aInterceptors )
3892
0
    {
3893
0
        try
3894
0
        {
3895
0
            css::ui::ContextMenuInterceptorAction eAction;
3896
0
            {
3897
0
                SolarMutexReleaser rel;
3898
0
                eAction = rListener->notifyContextMenuExecute( aEvent );
3899
0
            }
3900
0
            switch ( eAction )
3901
0
            {
3902
0
                case css::ui::ContextMenuInterceptorAction_CANCELLED:
3903
                    // interceptor does not want execution
3904
0
                    return false;
3905
0
                case css::ui::ContextMenuInterceptorAction_EXECUTE_MODIFIED:
3906
                    // interceptor wants his modified menu to be executed
3907
0
                    bModified = true;
3908
0
                    break;
3909
0
                case css::ui::ContextMenuInterceptorAction_CONTINUE_MODIFIED:
3910
                    // interceptor has modified menu, but allows for calling other interceptors
3911
0
                    bModified = true;
3912
0
                    continue;
3913
0
                case css::ui::ContextMenuInterceptorAction_IGNORED:
3914
                    // interceptor is indifferent
3915
0
                    continue;
3916
0
                default:
3917
0
                    SAL_WARN( "sfx.view", "Wrong return value of ContextMenuInterceptor!" );
3918
0
                    continue;
3919
0
            }
3920
0
        }
3921
0
        catch (...)
3922
0
        {
3923
0
            g.lock();
3924
0
            pImpl->aInterceptorContainer.removeInterface(g, rListener);
3925
0
            g.unlock();
3926
0
        }
3927
3928
0
        break;
3929
0
    }
3930
3931
0
    if ( bModified )
3932
0
    {
3933
0
        rPopupMenu->clear();
3934
0
        ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer(rPopupMenu, aEvent.ActionTriggerContainer);
3935
0
    }
3936
3937
0
    return true;
3938
0
}
3939
3940
bool SfxViewShell::HandleNotifyEvent_Impl( NotifyEvent const & rEvent )
3941
0
{
3942
0
    if (pImpl->m_pController.is())
3943
0
        return pImpl->m_pController->HandleEvent_Impl( rEvent );
3944
0
    return false;
3945
0
}
3946
3947
bool SfxViewShell::HasKeyListeners_Impl() const
3948
0
{
3949
0
    return (pImpl->m_pController.is())
3950
0
        && pImpl->m_pController->HasKeyListeners_Impl();
3951
0
}
3952
3953
bool SfxViewShell::HasMouseClickListeners_Impl() const
3954
0
{
3955
0
    return (pImpl->m_pController.is())
3956
0
        && pImpl->m_pController->HasMouseClickListeners_Impl();
3957
0
}
3958
3959
bool SfxViewShell::Escape()
3960
0
{
3961
0
    return GetViewFrame().GetBindings().Execute(SID_TERMINATE_INPLACEACTIVATION).is();
3962
0
}
3963
3964
Reference< view::XRenderable > SfxViewShell::GetRenderable()
3965
0
{
3966
0
    Reference< view::XRenderable >xRender;
3967
0
    SfxObjectShell* pObj = GetObjectShell();
3968
0
    if( pObj )
3969
0
    {
3970
0
        Reference< frame::XModel > xModel( pObj->GetModel() );
3971
0
        if( xModel.is() )
3972
0
            xRender.set( xModel, UNO_QUERY );
3973
0
    }
3974
0
    return xRender;
3975
0
}
3976
3977
void SfxViewShell::notifyWindow(vcl::LOKWindowId nDialogId, const OUString& rAction, const std::vector<vcl::LOKPayloadItem>& rPayload) const
3978
0
{
3979
0
    SfxLokHelper::notifyWindow(this, nDialogId, rAction, rPayload);
3980
0
}
3981
3982
OString SfxViewShell::dumpNotifyState() const
3983
0
{
3984
0
    return OString("sfxviewsh: " +
3985
0
                   OString::number(reinterpret_cast<sal_uInt64>(this), 16) +
3986
0
                   " doc: " + OString::number(static_cast<sal_Int32>(static_cast<int>(GetDocId()))) +
3987
0
                   " view: " +
3988
0
                   OString::number(static_cast<sal_Int32>(GetViewShellId())));
3989
0
}
3990
3991
uno::Reference< datatransfer::clipboard::XClipboardNotifier > SfxViewShell::GetClipboardNotifier() const
3992
4.26k
{
3993
4.26k
    uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClipboardNotifier;
3994
4.26k
    xClipboardNotifier.set(GetViewFrame().GetWindow().GetClipboard(), uno::UNO_QUERY);
3995
4.26k
    return xClipboardNotifier;
3996
4.26k
}
3997
3998
void SfxViewShell::AddRemoveClipboardListener( const uno::Reference < datatransfer::clipboard::XClipboardListener >& rClp, bool bAdd )
3999
0
{
4000
0
    try
4001
0
    {
4002
0
        uno::Reference< datatransfer::clipboard::XClipboard > xClipboard(GetViewFrame().GetWindow().GetClipboard());
4003
0
        if( xClipboard.is() )
4004
0
        {
4005
0
            uno::Reference< datatransfer::clipboard::XClipboardNotifier > xClpbrdNtfr( xClipboard, uno::UNO_QUERY );
4006
0
            if( xClpbrdNtfr.is() )
4007
0
            {
4008
0
                if( bAdd )
4009
0
                    xClpbrdNtfr->addClipboardListener( rClp );
4010
0
                else
4011
0
                    xClpbrdNtfr->removeClipboardListener( rClp );
4012
0
            }
4013
0
        }
4014
0
    }
4015
0
    catch (const uno::Exception&)
4016
0
    {
4017
0
    }
4018
0
}
4019
4020
weld::Window* SfxViewShell::GetFrameWeld() const
4021
154
{
4022
154
    return pWindow ? pWindow->GetFrameWeld() : nullptr;
4023
154
}
4024
4025
void SfxViewShell::setBlockedCommandList(const char* blockedCommandList)
4026
0
{
4027
0
    if(!mvLOKBlockedCommandList.empty())
4028
0
        return;
4029
4030
0
    OUString BlockedListString(blockedCommandList, strlen(blockedCommandList), RTL_TEXTENCODING_UTF8);
4031
0
    OUString command = BlockedListString.getToken(0, ' ');
4032
0
    for (size_t i = 1; !command.isEmpty(); i++)
4033
0
    {
4034
0
        mvLOKBlockedCommandList.emplace(command);
4035
0
        command = BlockedListString.getToken(i, ' ');
4036
0
    }
4037
0
}
4038
4039
bool SfxViewShell::isBlockedCommand(const OUString & command) const
4040
0
{
4041
0
    return mvLOKBlockedCommandList.find(command) != mvLOKBlockedCommandList.end();
4042
0
}
4043
4044
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */