Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sw/source/uibase/uiview/viewling.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <hintids.hxx>
21
22
#include <com/sun/star/lang/Locale.hpp>
23
#include <com/sun/star/linguistic2/XThesaurus.hpp>
24
#include <com/sun/star/linguistic2/ProofreadingResult.hpp>
25
#include <com/sun/star/linguistic2/XLinguProperties.hpp>
26
#include <com/sun/star/i18n/TextConversionOption.hpp>
27
#include <comphelper/lok.hxx>
28
#include <comphelper/processfactory.hxx>
29
#include <comphelper/propertyvalue.hxx>
30
#include <comphelper/propertysequence.hxx>
31
#include <comphelper/scopeguard.hxx>
32
#include <toolkit/helper/vclunohelper.hxx>
33
#include <unotools/fontdefs.hxx>
34
#include <vcl/rendercontext/GetDefaultFontFlags.hxx>
35
#include <vcl/weld/MessageDialog.hxx>
36
#include <vcl/weld/weld.hxx>
37
#include <sfx2/dispatch.hxx>
38
#include <sfx2/viewfrm.hxx>
39
#include <sfx2/request.hxx>
40
#include <svx/dialmgr.hxx>
41
#include <svx/ehdl.hxx>
42
#include <svx/svxerr.hxx>
43
#include <svx/svxdlg.hxx>
44
#include <svx/chinese_translation_unodialog.hxx>
45
#include <osl/diagnose.h>
46
#include <swwait.hxx>
47
#include <uitool.hxx>
48
#include <view.hxx>
49
#include <wrtsh.hxx>
50
#include <viewopt.hxx>
51
#include <swundo.hxx>
52
#include <hyp.hxx>
53
#include <olmenu.hxx>
54
#include <pam.hxx>
55
#include <edtwin.hxx>
56
#include <ndtxt.hxx>
57
#include <txtfrm.hxx>
58
#include <cmdid.h>
59
#include <strings.hrc>
60
#include <hhcwrp.hxx>
61
62
#include <boost/property_tree/json_parser.hpp>
63
64
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
65
#include <com/sun/star/ui/ContextMenuExecuteEvent.hpp>
66
#include <com/sun/star/lang/XInitialization.hpp>
67
#include <com/sun/star/frame/XDispatch.hpp>
68
#include <com/sun/star/frame/XDispatchProvider.hpp>
69
#include <com/sun/star/frame/XFrame.hpp>
70
#include <com/sun/star/frame/XPopupMenuController.hpp>
71
#include <com/sun/star/awt/PopupMenuDirection.hpp>
72
#include <com/sun/star/awt/XVclWindowPeer.hpp>
73
#include <com/sun/star/util/URL.hpp>
74
#include <com/sun/star/beans/PropertyValue.hpp>
75
#include <com/sun/star/beans/XPropertySet.hpp>
76
#include <com/sun/star/util/URLTransformer.hpp>
77
#include <com/sun/star/util/XURLTransformer.hpp>
78
79
#include <vcl/svapp.hxx>
80
#include <vcl/unohelp.hxx>
81
#include <rtl/ustring.hxx>
82
83
#include <svtools/langtab.hxx>
84
85
#include <editeng/editerr.hxx>
86
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
87
88
#include <memory>
89
90
using namespace sw::mark;
91
using namespace ::com::sun::star;
92
using namespace ::com::sun::star::beans;
93
using namespace ::com::sun::star::uno;
94
using namespace ::com::sun::star::linguistic2;
95
96
// Lingu-Dispatcher
97
98
void SwView::ExecLingu(SfxRequest &rReq)
99
0
{
100
0
    switch(rReq.GetSlot())
101
0
    {
102
0
        case SID_THESAURUS:
103
0
            StartThesaurus();
104
0
            rReq.Ignore();
105
0
            break;
106
0
        case SID_HANGUL_HANJA_CONVERSION:
107
0
            StartTextConversion( LANGUAGE_KOREAN, LANGUAGE_KOREAN, nullptr,
108
0
                    i18n::TextConversionOption::CHARACTER_BY_CHARACTER, true );
109
0
            break;
110
0
        case SID_CHINESE_CONVERSION:
111
0
        {
112
            //open ChineseTranslationDialog
113
0
            Reference<awt::XWindow> xParentWindow;
114
0
            if (weld::Window* pParentWindow = rReq.GetFrameWeld())
115
0
                xParentWindow = pParentWindow->GetXWindow();
116
0
            rtl::Reference< textconversiondlgs::ChineseTranslation_UnoDialog > xDialog(new textconversiondlgs::ChineseTranslation_UnoDialog(xParentWindow));
117
118
            //execute dialog
119
0
            sal_Int16 nDialogRet = xDialog->execute();
120
0
            if( RET_OK == nDialogRet )
121
0
            {
122
                //get some parameters from the dialog
123
0
                bool bToSimplified = xDialog->getIsDirectionToSimplified();
124
0
                bool bCommonTerms = xDialog->getIsTranslateCommonTerms();
125
126
                //execute translation
127
0
                LanguageType nSourceLang = bToSimplified ? LANGUAGE_CHINESE_TRADITIONAL : LANGUAGE_CHINESE_SIMPLIFIED;
128
0
                LanguageType nTargetLang = bToSimplified ? LANGUAGE_CHINESE_SIMPLIFIED : LANGUAGE_CHINESE_TRADITIONAL;
129
0
                sal_Int32 nOptions       = !bCommonTerms ? i18n::TextConversionOption::CHARACTER_BY_CHARACTER : 0;
130
131
0
                vcl::Font aTargetFont = OutputDevice::GetDefaultFont( DefaultFontType::CJK_TEXT,
132
0
                                        nTargetLang, GetDefaultFontFlags::OnlyOne );
133
134
                // disallow formatting, updating the view, ... while
135
                // converting the document. (saves time)
136
                // Also remember the current view and cursor position for later
137
0
                m_pWrtShell->StartAction();
138
139
                // remember cursor position data for later restoration of the cursor
140
0
                const SwPosition *pPoint = m_pWrtShell->GetCursor()->GetPoint();
141
0
                bool bRestoreCursor = pPoint->GetNode().IsTextNode();
142
0
                const SwNodeIndex aPointNodeIndex( pPoint->GetNode() );
143
0
                sal_Int32 nPointIndex = pPoint->GetContentIndex();
144
145
                // since this conversion is not interactive the whole converted
146
                // document should be undone in a single undo step.
147
0
                m_pWrtShell->StartUndo( SwUndoId::OVERWRITE );
148
149
0
                StartTextConversion( nSourceLang, nTargetLang, &aTargetFont, nOptions, false );
150
151
0
                m_pWrtShell->EndUndo( SwUndoId::OVERWRITE );
152
153
0
                if (bRestoreCursor)
154
0
                {
155
0
                    SwTextNode *pTextNode = aPointNodeIndex.GetNode().GetTextNode();
156
                    // check for unexpected error case
157
0
                    OSL_ENSURE(pTextNode && pTextNode->GetText().getLength() >= nPointIndex,
158
0
                        "text missing: corrupted node?" );
159
                    // restore cursor to its original position
160
0
                    if (!pTextNode || pTextNode->GetText().getLength() < nPointIndex)
161
0
                        m_pWrtShell->GetCursor()->GetPoint()->Assign( aPointNodeIndex );
162
0
                    else
163
0
                        m_pWrtShell->GetCursor()->GetPoint()->Assign( *pTextNode, nPointIndex );
164
0
                }
165
166
                // enable all, restore view and cursor position
167
0
                m_pWrtShell->EndAction();
168
0
            }
169
0
            break;
170
0
        }
171
0
        case FN_HYPHENATE_OPT_DLG:
172
0
            HyphenateDocument();
173
0
            break;
174
0
        default:
175
0
            OSL_ENSURE(false, "wrong Dispatcher");
176
0
            return;
177
0
    }
178
0
}
179
180
// start language specific text conversion
181
182
void SwView::StartTextConversion(
183
        LanguageType nSourceLang,
184
        LanguageType nTargetLang,
185
        const vcl::Font *pTargetFont,
186
        sal_Int32 nOptions,
187
        bool bIsInteractive )
188
0
{
189
    // do not do text conversion if it is active elsewhere
190
0
    if (SwEditShell::HasConvIter())
191
0
    {
192
0
        return;
193
0
    }
194
195
0
    SpellContext();
196
197
0
    const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions();
198
0
    const bool bOldIdle = pVOpt->IsIdle();
199
0
    pVOpt->SetIdle( false );
200
201
0
    bool bOldIns = m_pWrtShell->IsInsMode();
202
0
    m_pWrtShell->SetInsMode();
203
204
0
    const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() ||
205
0
        m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext();
206
207
0
    const bool  bStart = bSelection || m_pWrtShell->IsStartOfDoc();
208
0
    const bool  bOther = !bSelection && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY);
209
210
0
    {
211
0
        const uno::Reference< uno::XComponentContext >& xContext(
212
0
                    comphelper::getProcessComponentContext() );
213
0
        SwHHCWrapper aWrap( *this, xContext, nSourceLang, nTargetLang, pTargetFont,
214
0
                            nOptions, bIsInteractive,
215
0
                            bStart, bOther, bSelection );
216
0
        aWrap.Convert();
217
0
    }
218
219
0
    m_pWrtShell->SetInsMode( bOldIns );
220
0
    pVOpt->SetIdle( bOldIdle );
221
0
    SpellContext(false);
222
0
}
223
224
// spellcheck and text conversion related stuff
225
226
void SwView::SpellStart( SvxSpellArea eWhich,
227
        bool bStartDone, bool bEndDone,
228
        SwConversionArgs *pConvArgs )
229
0
{
230
0
    Reference< XLinguProperties >  xProp = ::GetLinguPropertySet();
231
0
    bool bIsWrapReverse = !pConvArgs && xProp.is() && xProp->getIsWrapReverse();
232
233
0
    SwDocPositions eStart = SwDocPositions::Start;
234
0
    SwDocPositions eEnd   = SwDocPositions::End;
235
0
    SwDocPositions eCurr  = SwDocPositions::Curr;
236
0
    switch ( eWhich )
237
0
    {
238
0
        case SvxSpellArea::Body:
239
0
            if( bIsWrapReverse )
240
0
                eCurr = SwDocPositions::End;
241
0
            else
242
0
                eCurr = SwDocPositions::Start;
243
0
            break;
244
0
        case SvxSpellArea::BodyEnd:
245
0
            if( bIsWrapReverse )
246
0
            {
247
0
                if( bStartDone )
248
0
                    eStart = SwDocPositions::Curr;
249
0
                eCurr = SwDocPositions::End;
250
0
            }
251
0
            else if( bStartDone )
252
0
                eCurr = SwDocPositions::Start;
253
0
            break;
254
0
        case SvxSpellArea::BodyStart:
255
0
            if( !bIsWrapReverse )
256
0
            {
257
0
                if( bEndDone )
258
0
                    eEnd = SwDocPositions::Curr;
259
0
                eCurr = SwDocPositions::Start;
260
0
            }
261
0
            else if( bEndDone )
262
0
                eCurr = SwDocPositions::End;
263
0
            break;
264
0
        case SvxSpellArea::Other:
265
0
            if( bIsWrapReverse )
266
0
            {
267
0
                eStart = SwDocPositions::OtherStart;
268
0
                eEnd  = SwDocPositions::OtherEnd;
269
0
                eCurr = SwDocPositions::OtherEnd;
270
0
            }
271
0
            else
272
0
            {
273
0
                eStart = SwDocPositions::OtherStart;
274
0
                eEnd  = SwDocPositions::OtherEnd;
275
0
                eCurr = SwDocPositions::OtherStart;
276
0
            }
277
0
            break;
278
0
        default:
279
0
            OSL_ENSURE( false, "SpellStart with unknown Area" );
280
0
    }
281
0
    m_pWrtShell->SpellStart( eStart, eEnd, eCurr, pConvArgs );
282
0
}
283
284
// Error message while Spelling
285
286
// The passed pointer nlang is itself the value
287
void SwView::SpellError(LanguageType eLang)
288
0
{
289
0
    int nPend = 0;
290
291
0
    if ( m_pWrtShell->ActionPend() )
292
0
    {
293
0
        m_pWrtShell->Push();
294
0
        m_pWrtShell->ClearMark();
295
0
        do
296
0
        {
297
0
            m_pWrtShell->EndAction();
298
0
            ++nPend;
299
0
        }
300
0
        while( m_pWrtShell->ActionPend() );
301
0
    }
302
0
    OUString aErr(SvtLanguageTable::GetLanguageString( eLang ) );
303
304
0
    SwEditWin &rEditWin = GetEditWin();
305
0
    int nWaitCnt = 0;
306
0
    while( rEditWin.IsWait() )
307
0
    {
308
0
        rEditWin.LeaveWait();
309
0
        ++nWaitCnt;
310
0
    }
311
0
    if ( LANGUAGE_NONE == eLang )
312
0
        ErrorHandler::HandleError( ERRCODE_SVX_LINGU_NOLANGUAGE );
313
0
    else
314
0
        ErrorHandler::HandleError( ErrCodeMsg( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
315
316
0
    while( nWaitCnt )
317
0
    {
318
0
        rEditWin.EnterWait();
319
0
        --nWaitCnt;
320
0
    }
321
322
0
    if ( nPend )
323
0
    {
324
0
        while( nPend-- )
325
0
            m_pWrtShell->StartAction();
326
0
        m_pWrtShell->Combine();
327
0
    }
328
0
}
329
330
// Finish spelling and restore cursor
331
332
void SwView::SpellEnd( SwConversionArgs const *pConvArgs )
333
0
{
334
0
    m_pWrtShell->SpellEnd( pConvArgs );
335
0
    if( m_pWrtShell->IsExtMode() )
336
0
        m_pWrtShell->SetMark();
337
0
}
338
339
void SwView::HyphStart( SvxSpellArea eWhich )
340
0
{
341
0
    switch ( eWhich )
342
0
    {
343
0
        case SvxSpellArea::Body:
344
0
            m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::End );
345
0
            break;
346
0
        case SvxSpellArea::BodyEnd:
347
0
            m_pWrtShell->HyphStart( SwDocPositions::Curr, SwDocPositions::End );
348
0
            break;
349
0
        case SvxSpellArea::BodyStart:
350
0
            m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::Curr );
351
0
            break;
352
0
        case SvxSpellArea::Other:
353
0
            m_pWrtShell->HyphStart( SwDocPositions::OtherStart, SwDocPositions::OtherEnd );
354
0
            break;
355
0
        default:
356
0
            OSL_ENSURE( false, "HyphStart with unknown Area" );
357
0
    }
358
0
}
359
360
// Interactive separation
361
362
void SwView::HyphenateDocument()
363
0
{
364
    // do not hyphenate if interactive hyphenation is active elsewhere
365
0
    if (SwEditShell::HasHyphIter())
366
0
    {
367
0
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(),
368
0
            VclMessageType::Warning, VclButtonsType::Ok, SwResId(STR_MULT_INTERACT_HYPH_WARN)));
369
0
        xBox->set_title(SwResId(STR_HYPH_TITLE));
370
0
        xBox->run();
371
0
        return;
372
0
    }
373
374
0
    SvxErrorContext aContext(ERRCTX_SVX_LINGU_HYPHENATION, OUString(), m_pEditWin->GetFrameWeld());
375
376
0
    Reference< XHyphenator >  xHyph( ::GetHyphenator() );
377
0
    if (!xHyph.is())
378
0
    {
379
0
        ErrorHandler::HandleError( ERRCODE_SVX_LINGU_LINGUNOTEXISTS );
380
0
        return;
381
0
    }
382
383
0
    if (m_pWrtShell->GetSelectionType() & (SelectionType::DrawObjectEditMode|SelectionType::DrawObject))
384
0
    {
385
        // Hyphenation in a Draw object
386
0
        HyphenateDrawText();
387
0
    }
388
0
    else
389
0
    {
390
0
        SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions());
391
0
        bool bOldIdle = pVOpt->IsIdle();
392
0
        pVOpt->SetIdle( false );
393
394
0
        Reference< XLinguProperties >  xProp( ::GetLinguPropertySet() );
395
396
0
        m_pWrtShell->StartUndo(SwUndoId::INSATTR);         // valid later
397
398
0
        bool bHyphSpecial = xProp.is() && xProp->getIsHyphSpecial();
399
0
        bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() ||
400
0
            m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext();
401
0
        bool bOther = m_pWrtShell->HasOtherCnt() && bHyphSpecial && !bSelection;
402
0
        bool bStart = bSelection || ( !bOther && m_pWrtShell->IsStartOfDoc() );
403
0
        bool bStop = false;
404
0
        if( !bOther && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY) && !bSelection )
405
        // turned on no special area
406
0
        {
407
            // I want also in special areas hyphenation
408
0
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(),
409
0
                                                      VclMessageType::Question, VclButtonsType::YesNo,
410
0
                                                      SwResId(STR_QUERY_SPECIAL_FORCED)));
411
0
            if (xBox->run() == RET_YES)
412
0
            {
413
0
                bOther = true;
414
0
                if (xProp.is())
415
0
                {
416
0
                    xProp->setIsHyphSpecial( true );
417
0
                }
418
0
            }
419
0
            else
420
0
                bStop = true; // No hyphenation
421
0
        }
422
423
0
        if( !bStop )
424
0
        {
425
0
            SwHyphWrapper aWrap( *this, xHyph, bStart, bOther, bSelection );
426
0
            aWrap.SpellDocument();
427
0
            m_pWrtShell->EndUndo(SwUndoId::INSATTR);
428
0
        }
429
0
        pVOpt->SetIdle( bOldIdle );
430
0
    }
431
0
}
432
433
bool SwView::IsValidSelectionForThesaurus() const
434
0
{
435
    // must not be a multi-selection, and if it is a selection it needs
436
    // to be within a single paragraph
437
438
0
    const bool bMultiSel = m_pWrtShell->GetCursor()->IsMultiSelection();
439
0
    const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection();
440
0
    return !bMultiSel && (!bSelection || m_pWrtShell->IsSelOnePara() );
441
0
}
442
443
OUString SwView::GetThesaurusLookUpText( bool bSelection ) const
444
0
{
445
0
    return bSelection ? m_pWrtShell->GetSelText() : m_pWrtShell->GetCurWord();
446
0
}
447
448
void SwView::InsertThesaurusSynonym( const OUString &rSynonmText, const OUString &rLookUpText, bool bSelection )
449
0
{
450
0
    bool bOldIns = m_pWrtShell->IsInsMode();
451
0
    m_pWrtShell->SetInsMode();
452
453
0
    m_pWrtShell->StartAllAction();
454
0
    m_pWrtShell->StartUndo(SwUndoId::DELETE);
455
456
0
    if( !bSelection )
457
0
    {
458
0
        if(m_pWrtShell->IsEndWrd())
459
0
            m_pWrtShell->Left(SwCursorSkipMode::Cells, false, 1, false );
460
461
0
        m_pWrtShell->SelWrd();
462
463
        // make sure the selection build later from the data below does not
464
        // include "in word" character to the left and right in order to
465
        // preserve those. Therefore count those "in words" in order to modify
466
        // the selection accordingly.
467
0
        const sal_Unicode* pChar = rLookUpText.getStr();
468
0
        sal_Int32 nLeft = 0;
469
0
        while (*pChar++ == CH_TXTATR_INWORD)
470
0
            ++nLeft;
471
0
        pChar = rLookUpText.getLength() ? rLookUpText.getStr() + rLookUpText.getLength() - 1 : nullptr;
472
0
        sal_Int32 nRight = 0;
473
0
        while (pChar && *pChar-- == CH_TXTATR_INWORD)
474
0
            ++nRight;
475
476
        // adjust existing selection
477
0
        SwPaM *pCursor = m_pWrtShell->GetCursor();
478
0
        pCursor->GetPoint()->AdjustContent(-nRight);
479
0
        pCursor->GetMark()->AdjustContent(nLeft);
480
0
    }
481
482
0
    m_pWrtShell->Insert( rSynonmText );
483
484
0
    m_pWrtShell->EndUndo(SwUndoId::DELETE);
485
0
    m_pWrtShell->EndAllAction();
486
487
0
    m_pWrtShell->SetInsMode( bOldIns );
488
0
}
489
490
// Start thesaurus
491
492
void SwView::StartThesaurus()
493
0
{
494
0
    if (!IsValidSelectionForThesaurus())
495
0
        return;
496
497
0
    SvxErrorContext aContext(ERRCTX_SVX_LINGU_THESAURUS, OUString(), m_pEditWin->GetFrameWeld());
498
499
    // Determine language
500
0
    LanguageType eLang = m_pWrtShell->GetCurLang();
501
0
    if( LANGUAGE_SYSTEM == eLang )
502
0
       eLang = GetAppLanguage();
503
504
0
    if( eLang == LANGUAGE_DONTKNOW || eLang == LANGUAGE_NONE )
505
0
    {
506
0
        SpellError( LANGUAGE_NONE );
507
0
        return;
508
0
    }
509
510
0
    SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions());
511
0
    const bool bOldIdle = pVOpt->IsIdle();
512
0
    pVOpt->SetIdle( false );
513
0
    comphelper::ScopeGuard guard([&]() { pVOpt->SetIdle(bOldIdle); }); // restore when leaving scope
514
515
    // get initial LookUp text
516
0
    const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection();
517
0
    OUString aTmp = GetThesaurusLookUpText( bSelection );
518
519
0
    Reference< XThesaurus >  xThes( ::GetThesaurus() );
520
521
0
    if ( !xThes.is() || !xThes->hasLocale( LanguageTag::convertToLocale( eLang ) ) )
522
0
        SpellError( eLang );
523
0
    else
524
0
    {
525
0
        VclPtr<AbstractThesaurusDialog> pDlg;
526
        // create dialog
527
0
        {   //Scope for SwWait-Object
528
0
            SwWait aWait( *GetDocShell(), true );
529
            // load library with dialog only on demand ...
530
0
            SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
531
0
            pDlg.reset(pFact->CreateThesaurusDialog(GetEditWin().GetFrameWeld(), xThes, aTmp, eLang));
532
0
        }
533
534
0
        if (pDlg)
535
0
        {
536
0
            guard.dismiss(); // ignore, we'll call SetIdle() explicitly after the dialog ends
537
538
0
            pDlg->StartExecuteAsync([aTmp, bSelection, bOldIdle, pDlg, pVOpt, this](sal_Int32 nResult){
539
0
                if (nResult == RET_OK )
540
0
                    InsertThesaurusSynonym(pDlg->GetWord(), aTmp, bSelection);
541
542
0
                pVOpt->SetIdle(bOldIdle);
543
0
                pDlg->disposeOnce();
544
0
            });
545
0
        }
546
0
    }
547
0
}
548
549
// Offer online suggestions
550
551
namespace {
552
553
//!! Start of extra code for context menu modifying extensions
554
struct ExecuteInfo
555
{
556
    uno::Reference< frame::XDispatch >  xDispatch;
557
    util::URL                           aTargetURL;
558
};
559
560
class AsyncExecute
561
{
562
public:
563
    DECL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, void );
564
};
565
566
}
567
568
IMPL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, p, void )
569
0
{
570
0
    ExecuteInfo* pExecuteInfo = static_cast<ExecuteInfo*>(p);
571
0
    SolarMutexReleaser aReleaser;
572
0
    try
573
0
    {
574
        // Asynchronous execution as this can lead to our own destruction!
575
        // Framework can recycle our current frame and the layout manager disposes all user interface
576
        // elements if a component gets detached from its frame!
577
0
        pExecuteInfo->xDispatch->dispatch(pExecuteInfo->aTargetURL, uno::Sequence<beans::PropertyValue>());
578
0
    }
579
0
    catch (const Exception&)
580
0
    {
581
0
    }
582
583
0
    delete pExecuteInfo;
584
0
}
585
//!! End of extra code for context menu modifying extensions
586
587
bool SwView::ExecSpellPopup(const Point& rPt, bool bIsMouseEvent)
588
0
{
589
0
    bool bRet = false;
590
0
    const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions();
591
0
    if( pVOpt->IsOnlineSpell() &&
592
0
        !m_pWrtShell->IsSelection())
593
0
    {
594
0
        if (m_pWrtShell->GetSelectionType() & SelectionType::DrawObjectEditMode)
595
0
            bRet = ExecDrwTextSpellPopup(rPt);
596
0
        else if (!m_pWrtShell->IsSelFrameMode())
597
0
        {
598
0
            const bool bOldViewLock = m_pWrtShell->IsViewLocked();
599
0
            m_pWrtShell->LockView( true );
600
0
            if (!comphelper::LibreOfficeKit::isActive())
601
0
                m_pWrtShell->Push();
602
0
            SwRect aToFill;
603
604
0
            SwCursorShell *pCursorShell = m_pWrtShell.get();
605
0
            SwPaM *pCursor = pCursorShell->GetCursor();
606
0
            SwPosition aPoint(*pCursor->GetPoint());
607
0
            const SwTextNode *pNode = aPoint.GetNode().GetTextNode();
608
609
            // Spell-check in case the idle jobs haven't had a chance to kick in.
610
            // This makes it possible to suggest spelling corrections for
611
            // wrong words independent of the spell-checking idle job.
612
0
            if (pNode && pNode->IsWrongDirty() &&
613
0
                !pCursorShell->IsTableMode() &&
614
0
                !pCursor->HasMark() && !pCursor->IsMultiSelection())
615
0
            {
616
0
                std::pair<Point, bool> const tmp(rPt, false);
617
0
                SwContentFrame *const pContentFrame = pCursor->GetPointContentNode()->getLayoutFrame(
618
0
                                        pCursorShell->GetLayout(),
619
0
                                        &aPoint, &tmp);
620
0
                if (pContentFrame)
621
0
                {
622
0
                    SwRect aRepaint(static_cast<SwTextFrame*>(pContentFrame)->AutoSpell_(
623
0
                        *pCursor->GetPointContentNode()->GetTextNode(), 0));
624
0
                    if (aRepaint.HasArea())
625
0
                        m_pWrtShell->InvalidateWindows(aRepaint);
626
0
                }
627
0
            }
628
629
            // decide which variant of the context menu to use...
630
            // if neither spell checking nor grammar checking provides suggestions use the
631
            // default context menu.
632
0
            bool bUseGrammarContext = false;
633
0
            Reference<XSpellAlternatives> xAlt(
634
0
                m_pWrtShell->GetCorrection(bIsMouseEvent ? &rPt : nullptr, aToFill));
635
0
            ProofreadingResult aGrammarCheckRes;
636
0
            sal_Int32 nErrorInResult = -1;
637
0
            uno::Sequence< OUString > aSuggestions;
638
0
            bool bCorrectionRes = false;
639
0
            if (!xAlt.is() || !xAlt->getAlternatives().hasElements())
640
0
            {
641
0
                sal_Int32 nErrorPosInText = -1;
642
0
                bCorrectionRes = m_pWrtShell->GetGrammarCorrection(
643
0
                    aGrammarCheckRes, nErrorPosInText, nErrorInResult, aSuggestions,
644
0
                    bIsMouseEvent ? &rPt : nullptr, aToFill);
645
0
                OUString aMessageText;
646
0
                if (nErrorInResult >= 0)
647
0
                    aMessageText = aGrammarCheckRes.aErrors[ nErrorInResult ].aShortComment;
648
                // we like to use the grammar checking context menu if we either get
649
                // some suggestions or at least a comment about the error found...
650
0
                bUseGrammarContext = bCorrectionRes &&
651
0
                        (aSuggestions.hasElements() || !aMessageText.isEmpty());
652
0
            }
653
654
            // open respective context menu for spell check or grammar errors with correction suggestions...
655
0
            if ((!bUseGrammarContext && xAlt.is()) ||
656
0
                (bUseGrammarContext && bCorrectionRes && aGrammarCheckRes.aErrors.hasElements()))
657
0
            {
658
                // get paragraph text
659
0
                OUString aParaText;
660
0
                if (pNode)
661
0
                {
662
0
                    pCursorShell->Push();
663
0
                    if (!pCursorShell->IsSttPara())
664
0
                    {
665
0
                        pCursorShell->MovePara(GoCurrPara, fnParaStart);
666
0
                    }
667
0
                    pCursorShell->SetMark();
668
0
                    if (!pCursorShell->IsEndPara())
669
0
                    {
670
0
                        pCursorShell->MovePara(GoCurrPara, fnParaEnd);
671
0
                    }
672
0
                    aParaText = pCursorShell->GetSelText();
673
0
                    pCursorShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
674
0
                }
675
0
                else
676
0
                {
677
0
                    OSL_FAIL("text node expected but not found" );
678
0
                }
679
680
0
                bRet = true;
681
0
                m_pWrtShell->SttSelect();
682
0
                std::unique_ptr<SwSpellPopup> xPopup(bUseGrammarContext ?
683
0
                    new SwSpellPopup(m_pWrtShell.get(), aGrammarCheckRes, nErrorInResult, aSuggestions, aParaText) :
684
0
                    new SwSpellPopup(m_pWrtShell.get(), xAlt, aParaText));
685
0
                ui::ContextMenuExecuteEvent aEvent;
686
0
                const Point aPixPos = GetEditWin().LogicToPixel( rPt );
687
688
0
                aEvent.SourceWindow = VCLUnoHelper::GetInterface( m_pEditWin );
689
0
                aEvent.ExecutePosition.X = aPixPos.X();
690
0
                aEvent.ExecutePosition.Y = aPixPos.Y();
691
0
                rtl::Reference<VCLXPopupMenu> xMenu;
692
693
0
                OUString sMenuName = bUseGrammarContext ?
694
0
                    u"private:resource/GrammarContextMenu"_ustr : u"private:resource/SpellContextMenu"_ustr;
695
0
                rtl::Reference<VCLXPopupMenu> xMenuInterface = xPopup->CreateMenuInterface();
696
0
                if (TryContextMenuInterception(xMenuInterface, sMenuName, xMenu, aEvent))
697
0
                {
698
                    //! happy hacking for context menu modifying extensions of this
699
                    //! 'custom made' menu... *sigh* (code copied from sfx2 and framework)
700
0
                    if (xMenu.is())
701
0
                    {
702
0
                        css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY);
703
0
                        const sal_uInt16 nId = xMenu->execute(xParent, css::awt::Rectangle(aPixPos.X(), aPixPos.Y(), 1, 1),
704
0
                                                              css::awt::PopupMenuDirection::EXECUTE_DOWN);
705
0
                        OUString aCommand = xMenu->getCommand(nId);
706
0
                        if (aCommand.isEmpty() )
707
0
                        {
708
0
                            if (!ExecuteMenuCommand(xMenu, GetViewFrame(), nId))
709
0
                                xPopup->Execute(nId);
710
0
                        }
711
0
                        else
712
0
                        {
713
0
                            SfxViewFrame& rSfxViewFrame = GetViewFrame();
714
0
                            uno::Reference<frame::XFrame> xFrame = rSfxViewFrame.GetFrame().GetFrameInterface();
715
0
                            css::util::URL aURL;
716
0
                            uno::Reference< frame::XDispatchProvider > xDispatchProvider( xFrame, UNO_QUERY );
717
718
0
                            try
719
0
                            {
720
0
                                uno::Reference< frame::XDispatch > xDispatch;
721
0
                                uno::Reference< util::XURLTransformer > xURLTransformer = util::URLTransformer::create(comphelper::getProcessComponentContext());
722
723
0
                                aURL.Complete = aCommand;
724
0
                                xURLTransformer->parseStrict(aURL);
725
0
                                xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 );
726
727
0
                                if (xDispatch.is())
728
0
                                {
729
                                    // Execute dispatch asynchronously
730
0
                                    ExecuteInfo* pExecuteInfo   = new ExecuteInfo;
731
0
                                    pExecuteInfo->xDispatch     = std::move(xDispatch);
732
0
                                    pExecuteInfo->aTargetURL    = std::move(aURL);
733
0
                                    Application::PostUserEvent( LINK(nullptr, AsyncExecute , ExecuteHdl_Impl), pExecuteInfo );
734
0
                                }
735
0
                            }
736
0
                            catch (const Exception&)
737
0
                            {
738
0
                            }
739
0
                        }
740
0
                    }
741
0
                    else
742
0
                    {
743
0
                        if (comphelper::LibreOfficeKit::isActive())
744
0
                        {
745
0
                            if (SfxViewShell* pViewShell = SfxViewShell::Current())
746
0
                            {
747
0
                                boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(xMenuInterface);
748
0
                                boost::property_tree::ptree aRoot;
749
0
                                aRoot.add_child("menu", aMenu);
750
751
0
                                std::stringstream aStream;
752
0
                                boost::property_tree::write_json(aStream, aRoot, true);
753
0
                                pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, OString(aStream.str()));
754
0
                            }
755
0
                        }
756
0
                        else
757
0
                        {
758
0
                            xPopup->Execute(aToFill.SVRect(), m_pEditWin);
759
0
                        }
760
0
                    }
761
0
                }
762
0
            }
763
764
0
            if (!comphelper::LibreOfficeKit::isActive())
765
0
                m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
766
0
            m_pWrtShell->LockView( bOldViewLock );
767
0
        }
768
0
    }
769
0
    return bRet;
770
0
}
771
772
/** Function: ExecSmartTagPopup
773
774
   This function shows the popup menu for smarttag
775
   actions.
776
*/
777
void SwView::ExecSmartTagPopup( const Point& rPt )
778
0
{
779
0
    const bool bOldViewLock = m_pWrtShell->IsViewLocked();
780
0
    m_pWrtShell->LockView( true );
781
0
    m_pWrtShell->Push();
782
783
0
    css::uno::Sequence< css::uno::Any > aArgs{
784
0
        css::uno::Any(comphelper::makePropertyValue( u"Frame"_ustr, GetDispatcher().GetFrame()->GetFrame().GetFrameInterface() )),
785
0
        css::uno::Any(comphelper::makePropertyValue( u"CommandURL"_ustr, u".uno:OpenSmartTagMenuOnCursor"_ustr ))
786
0
    };
787
788
0
    const css::uno::Reference< css::uno::XComponentContext >& xContext = comphelper::getProcessComponentContext();
789
0
    css::uno::Reference< css::frame::XPopupMenuController > xPopupController(
790
0
        xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
791
0
        u"com.sun.star.comp.svx.SmartTagMenuController"_ustr, aArgs, xContext ), css::uno::UNO_QUERY );
792
793
0
    rtl::Reference< VCLXPopupMenu > xPopupMenu( new VCLXPopupMenu() );
794
795
0
    if ( xPopupController.is() )
796
0
    {
797
0
        xPopupController->setPopupMenu( xPopupMenu );
798
799
0
        SwRect aToFill;
800
0
        m_pWrtShell->GetSmartTagRect( rPt, aToFill );
801
0
        m_pWrtShell->SttSelect();
802
803
0
        if ( aToFill.HasArea() )
804
0
            xPopupMenu->execute( m_pEditWin->GetComponentInterface(),
805
0
                                 vcl::unohelper::ConvertToAWTRect( m_pEditWin->LogicToPixel( aToFill.SVRect() ) ), css::awt::PopupMenuDirection::EXECUTE_DOWN );
806
807
0
        css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY );
808
0
        if ( xComponent.is() )
809
0
            xComponent->dispose();
810
0
    }
811
812
0
    m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
813
0
    m_pWrtShell->LockView( bOldViewLock );
814
0
}
815
816
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */