Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / uibase / uiview / viewling.cxx
blob6e6225980e29ffa6329e0dceea854db11d729de0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <hintids.hxx>
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 <vcl/weld.hxx>
34 #include <svtools/ehdl.hxx>
35 #include <sfx2/dispatch.hxx>
36 #include <sfx2/viewfrm.hxx>
37 #include <sfx2/request.hxx>
38 #include <svx/dialmgr.hxx>
39 #include <svx/svxerr.hxx>
40 #include <svx/svxdlg.hxx>
41 #include <osl/diagnose.h>
42 #include <swwait.hxx>
43 #include <uitool.hxx>
44 #include <view.hxx>
45 #include <wrtsh.hxx>
46 #include <viewopt.hxx>
47 #include <swundo.hxx>
48 #include <hyp.hxx>
49 #include <olmenu.hxx>
50 #include <pam.hxx>
51 #include <edtwin.hxx>
52 #include <ndtxt.hxx>
53 #include <txtfrm.hxx>
54 #include <cmdid.h>
55 #include <strings.hrc>
56 #include <hhcwrp.hxx>
58 #include <boost/property_tree/json_parser.hpp>
60 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
61 #include <com/sun/star/ui/ContextMenuExecuteEvent.hpp>
62 #include <com/sun/star/lang/XInitialization.hpp>
63 #include <com/sun/star/frame/XDispatch.hpp>
64 #include <com/sun/star/frame/XDispatchProvider.hpp>
65 #include <com/sun/star/frame/XFrame.hpp>
66 #include <com/sun/star/frame/XPopupMenuController.hpp>
67 #include <com/sun/star/awt/PopupMenuDirection.hpp>
68 #include <com/sun/star/awt/XVclWindowPeer.hpp>
69 #include <com/sun/star/util/URL.hpp>
70 #include <com/sun/star/beans/PropertyValue.hpp>
71 #include <com/sun/star/beans/XPropertySet.hpp>
72 #include <com/sun/star/util/URLTransformer.hpp>
73 #include <com/sun/star/util/XURLTransformer.hpp>
75 #include <vcl/svapp.hxx>
76 #include <rtl/ustring.hxx>
78 #include <cppuhelper/bootstrap.hxx>
79 #include <svtools/langtab.hxx>
81 #include <editeng/editerr.hxx>
82 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
84 #include <memory>
86 using namespace sw::mark;
87 using namespace ::com::sun::star;
88 using namespace ::com::sun::star::beans;
89 using namespace ::com::sun::star::uno;
90 using namespace ::com::sun::star::linguistic2;
92 // Lingu-Dispatcher
94 void SwView::ExecLingu(SfxRequest &rReq)
96 switch(rReq.GetSlot())
98 case SID_THESAURUS:
99 StartThesaurus();
100 rReq.Ignore();
101 break;
102 case SID_HANGUL_HANJA_CONVERSION:
103 StartTextConversion( LANGUAGE_KOREAN, LANGUAGE_KOREAN, nullptr,
104 i18n::TextConversionOption::CHARACTER_BY_CHARACTER, true );
105 break;
106 case SID_CHINESE_CONVERSION:
108 //open ChineseTranslationDialog
109 Reference< XComponentContext > xContext(
110 ::cppu::defaultBootstrap_InitialComponentContext() ); //@todo get context from calc if that has one
111 if(xContext.is())
113 Reference< lang::XMultiComponentFactory > xMCF( xContext->getServiceManager() );
114 if(xMCF.is())
116 Reference< ui::dialogs::XExecutableDialog > xDialog(
117 xMCF->createInstanceWithContext(
118 "com.sun.star.linguistic2.ChineseTranslationDialog", xContext),
119 UNO_QUERY);
120 Reference< lang::XInitialization > xInit( xDialog, UNO_QUERY );
121 if( xInit.is() )
123 Reference<awt::XWindow> xParentWindow;
124 if (weld::Window* pParentWindow = rReq.GetFrameWeld())
125 xParentWindow = pParentWindow->GetXWindow();
126 // initialize dialog
127 uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence(
129 {"ParentWindow", uno::Any(xParentWindow)}
130 }));
131 xInit->initialize( aSeq );
133 //execute dialog
134 sal_Int16 nDialogRet = xDialog->execute();
135 if( RET_OK == nDialogRet )
137 //get some parameters from the dialog
138 bool bToSimplified = true;
139 bool bUseVariants = true;
140 bool bCommonTerms = true;
141 Reference< beans::XPropertySet > xProp( xDialog, UNO_QUERY );
142 if( xProp.is() )
146 xProp->getPropertyValue( "IsDirectionToSimplified" ) >>= bToSimplified;
147 xProp->getPropertyValue( "IsUseCharacterVariants" ) >>= bUseVariants;
148 xProp->getPropertyValue( "IsTranslateCommonTerms" ) >>= bCommonTerms;
150 catch (const Exception&)
155 //execute translation
156 LanguageType nSourceLang = bToSimplified ? LANGUAGE_CHINESE_TRADITIONAL : LANGUAGE_CHINESE_SIMPLIFIED;
157 LanguageType nTargetLang = bToSimplified ? LANGUAGE_CHINESE_SIMPLIFIED : LANGUAGE_CHINESE_TRADITIONAL;
158 sal_Int32 nOptions = bUseVariants ? i18n::TextConversionOption::USE_CHARACTER_VARIANTS : 0;
159 if( !bCommonTerms )
160 nOptions = nOptions | i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
162 vcl::Font aTargetFont = OutputDevice::GetDefaultFont( DefaultFontType::CJK_TEXT,
163 nTargetLang, GetDefaultFontFlags::OnlyOne );
165 // disallow formatting, updating the view, ... while
166 // converting the document. (saves time)
167 // Also remember the current view and cursor position for later
168 m_pWrtShell->StartAction();
170 // remember cursor position data for later restoration of the cursor
171 const SwPosition *pPoint = m_pWrtShell->GetCursor()->GetPoint();
172 bool bRestoreCursor = pPoint->GetNode().IsTextNode();
173 const SwNodeIndex aPointNodeIndex( pPoint->GetNode() );
174 sal_Int32 nPointIndex = pPoint->GetContentIndex();
176 // since this conversion is not interactive the whole converted
177 // document should be undone in a single undo step.
178 m_pWrtShell->StartUndo( SwUndoId::OVERWRITE );
180 StartTextConversion( nSourceLang, nTargetLang, &aTargetFont, nOptions, false );
182 m_pWrtShell->EndUndo( SwUndoId::OVERWRITE );
184 if (bRestoreCursor)
186 SwTextNode *pTextNode = aPointNodeIndex.GetNode().GetTextNode();
187 // check for unexpected error case
188 OSL_ENSURE(pTextNode && pTextNode->GetText().getLength() >= nPointIndex,
189 "text missing: corrupted node?" );
190 // restore cursor to its original position
191 if (!pTextNode || pTextNode->GetText().getLength() < nPointIndex)
192 m_pWrtShell->GetCursor()->GetPoint()->Assign( aPointNodeIndex );
193 else
194 m_pWrtShell->GetCursor()->GetPoint()->Assign( *pTextNode, nPointIndex );
197 // enable all, restore view and cursor position
198 m_pWrtShell->EndAction();
201 Reference< lang::XComponent > xComponent( xDialog, UNO_QUERY );
202 if( xComponent.is() )
203 xComponent->dispose();
206 break;
208 case FN_HYPHENATE_OPT_DLG:
209 HyphenateDocument();
210 break;
211 default:
212 OSL_ENSURE(false, "wrong Dispatcher");
213 return;
217 // start language specific text conversion
219 void SwView::StartTextConversion(
220 LanguageType nSourceLang,
221 LanguageType nTargetLang,
222 const vcl::Font *pTargetFont,
223 sal_Int32 nOptions,
224 bool bIsInteractive )
226 // do not do text conversion if it is active elsewhere
227 if (SwEditShell::HasConvIter())
229 return;
232 SpellContext();
234 const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions();
235 const bool bOldIdle = pVOpt->IsIdle();
236 pVOpt->SetIdle( false );
238 bool bOldIns = m_pWrtShell->IsInsMode();
239 m_pWrtShell->SetInsMode();
241 const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() ||
242 m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext();
244 const bool bStart = bSelection || m_pWrtShell->IsStartOfDoc();
245 const bool bOther = !bSelection && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY);
248 const uno::Reference< uno::XComponentContext > xContext(
249 comphelper::getProcessComponentContext() );
250 SwHHCWrapper aWrap( this, xContext, nSourceLang, nTargetLang, pTargetFont,
251 nOptions, bIsInteractive,
252 bStart, bOther, bSelection );
253 aWrap.Convert();
256 m_pWrtShell->SetInsMode( bOldIns );
257 pVOpt->SetIdle( bOldIdle );
258 SpellContext(false);
261 // spellcheck and text conversion related stuff
263 void SwView::SpellStart( SvxSpellArea eWhich,
264 bool bStartDone, bool bEndDone,
265 SwConversionArgs *pConvArgs )
267 Reference< XLinguProperties > xProp = ::GetLinguPropertySet();
268 bool bIsWrapReverse = !pConvArgs && xProp.is() && xProp->getIsWrapReverse();
270 SwDocPositions eStart = SwDocPositions::Start;
271 SwDocPositions eEnd = SwDocPositions::End;
272 SwDocPositions eCurr = SwDocPositions::Curr;
273 switch ( eWhich )
275 case SvxSpellArea::Body:
276 if( bIsWrapReverse )
277 eCurr = SwDocPositions::End;
278 else
279 eCurr = SwDocPositions::Start;
280 break;
281 case SvxSpellArea::BodyEnd:
282 if( bIsWrapReverse )
284 if( bStartDone )
285 eStart = SwDocPositions::Curr;
286 eCurr = SwDocPositions::End;
288 else if( bStartDone )
289 eCurr = SwDocPositions::Start;
290 break;
291 case SvxSpellArea::BodyStart:
292 if( !bIsWrapReverse )
294 if( bEndDone )
295 eEnd = SwDocPositions::Curr;
296 eCurr = SwDocPositions::Start;
298 else if( bEndDone )
299 eCurr = SwDocPositions::End;
300 break;
301 case SvxSpellArea::Other:
302 if( bIsWrapReverse )
304 eStart = SwDocPositions::OtherStart;
305 eEnd = SwDocPositions::OtherEnd;
306 eCurr = SwDocPositions::OtherEnd;
308 else
310 eStart = SwDocPositions::OtherStart;
311 eEnd = SwDocPositions::OtherEnd;
312 eCurr = SwDocPositions::OtherStart;
314 break;
315 default:
316 OSL_ENSURE( false, "SpellStart with unknown Area" );
318 m_pWrtShell->SpellStart( eStart, eEnd, eCurr, pConvArgs );
321 // Error message while Spelling
323 // The passed pointer nlang is itself the value
324 void SwView::SpellError(LanguageType eLang)
326 int nPend = 0;
328 if ( m_pWrtShell->ActionPend() )
330 m_pWrtShell->Push();
331 m_pWrtShell->ClearMark();
334 m_pWrtShell->EndAction();
335 ++nPend;
337 while( m_pWrtShell->ActionPend() );
339 OUString aErr(SvtLanguageTable::GetLanguageString( eLang ) );
341 SwEditWin &rEditWin = GetEditWin();
342 int nWaitCnt = 0;
343 while( rEditWin.IsWait() )
345 rEditWin.LeaveWait();
346 ++nWaitCnt;
348 if ( LANGUAGE_NONE == eLang )
349 ErrorHandler::HandleError( ERRCODE_SVX_LINGU_NOLANGUAGE );
350 else
351 ErrorHandler::HandleError( *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
353 while( nWaitCnt )
355 rEditWin.EnterWait();
356 --nWaitCnt;
359 if ( nPend )
361 while( nPend-- )
362 m_pWrtShell->StartAction();
363 m_pWrtShell->Combine();
367 // Finish spelling and restore cursor
369 void SwView::SpellEnd( SwConversionArgs const *pConvArgs )
371 m_pWrtShell->SpellEnd( pConvArgs );
372 if( m_pWrtShell->IsExtMode() )
373 m_pWrtShell->SetMark();
376 void SwView::HyphStart( SvxSpellArea eWhich )
378 switch ( eWhich )
380 case SvxSpellArea::Body:
381 m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::End );
382 break;
383 case SvxSpellArea::BodyEnd:
384 m_pWrtShell->HyphStart( SwDocPositions::Curr, SwDocPositions::End );
385 break;
386 case SvxSpellArea::BodyStart:
387 m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::Curr );
388 break;
389 case SvxSpellArea::Other:
390 m_pWrtShell->HyphStart( SwDocPositions::OtherStart, SwDocPositions::OtherEnd );
391 break;
392 default:
393 OSL_ENSURE( false, "HyphStart with unknown Area" );
397 // Interactive separation
399 void SwView::HyphenateDocument()
401 // do not hyphenate if interactive hyphenation is active elsewhere
402 if (SwEditShell::HasHyphIter())
404 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(),
405 VclMessageType::Warning, VclButtonsType::Ok, SwResId(STR_MULT_INTERACT_HYPH_WARN)));
406 xBox->set_title(SwResId(STR_HYPH_TITLE));
407 xBox->run();
408 return;
411 SfxErrorContext aContext( ERRCTX_SVX_LINGU_HYPHENATION, OUString(), m_pEditWin->GetFrameWeld(),
412 RID_SVXERRCTX, SvxResLocale() );
414 Reference< XHyphenator > xHyph( ::GetHyphenator() );
415 if (!xHyph.is())
417 ErrorHandler::HandleError( ERRCODE_SVX_LINGU_LINGUNOTEXISTS );
418 return;
421 if (m_pWrtShell->GetSelectionType() & (SelectionType::DrawObjectEditMode|SelectionType::DrawObject))
423 // Hyphenation in a Draw object
424 HyphenateDrawText();
426 else
428 SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions());
429 bool bOldIdle = pVOpt->IsIdle();
430 pVOpt->SetIdle( false );
432 Reference< XLinguProperties > xProp( ::GetLinguPropertySet() );
434 m_pWrtShell->StartUndo(SwUndoId::INSATTR); // valid later
436 bool bHyphSpecial = xProp.is() && xProp->getIsHyphSpecial();
437 bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() ||
438 m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext();
439 bool bOther = m_pWrtShell->HasOtherCnt() && bHyphSpecial && !bSelection;
440 bool bStart = bSelection || ( !bOther && m_pWrtShell->IsStartOfDoc() );
441 bool bStop = false;
442 if( !bOther && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY) && !bSelection )
443 // turned on no special area
445 // I want also in special areas hyphenation
446 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(),
447 VclMessageType::Question, VclButtonsType::YesNo,
448 SwResId(STR_QUERY_SPECIAL_FORCED)));
449 if (xBox->run() == RET_YES)
451 bOther = true;
452 if (xProp.is())
454 xProp->setIsHyphSpecial( true );
457 else
458 bStop = true; // No hyphenation
461 if( !bStop )
463 SwHyphWrapper aWrap( this, xHyph, bStart, bOther, bSelection );
464 aWrap.SpellDocument();
465 m_pWrtShell->EndUndo(SwUndoId::INSATTR);
467 pVOpt->SetIdle( bOldIdle );
471 bool SwView::IsValidSelectionForThesaurus() const
473 // must not be a multi-selection, and if it is a selection it needs
474 // to be within a single paragraph
476 const bool bMultiSel = m_pWrtShell->GetCursor()->IsMultiSelection();
477 const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection();
478 return !bMultiSel && (!bSelection || m_pWrtShell->IsSelOnePara() );
481 OUString SwView::GetThesaurusLookUpText( bool bSelection ) const
483 return bSelection ? m_pWrtShell->GetSelText() : m_pWrtShell->GetCurWord();
486 void SwView::InsertThesaurusSynonym( const OUString &rSynonmText, const OUString &rLookUpText, bool bSelection )
488 bool bOldIns = m_pWrtShell->IsInsMode();
489 m_pWrtShell->SetInsMode();
491 m_pWrtShell->StartAllAction();
492 m_pWrtShell->StartUndo(SwUndoId::DELETE);
494 if( !bSelection )
496 if(m_pWrtShell->IsEndWrd())
497 m_pWrtShell->Left(SwCursorSkipMode::Cells, false, 1, false );
499 m_pWrtShell->SelWrd();
501 // make sure the selection build later from the data below does not
502 // include "in word" character to the left and right in order to
503 // preserve those. Therefore count those "in words" in order to modify
504 // the selection accordingly.
505 const sal_Unicode* pChar = rLookUpText.getStr();
506 sal_Int32 nLeft = 0;
507 while (*pChar++ == CH_TXTATR_INWORD)
508 ++nLeft;
509 pChar = rLookUpText.getLength() ? rLookUpText.getStr() + rLookUpText.getLength() - 1 : nullptr;
510 sal_Int32 nRight = 0;
511 while (pChar && *pChar-- == CH_TXTATR_INWORD)
512 ++nRight;
514 // adjust existing selection
515 SwPaM *pCursor = m_pWrtShell->GetCursor();
516 pCursor->GetPoint()->AdjustContent(-nRight);
517 pCursor->GetMark()->AdjustContent(nLeft);
520 m_pWrtShell->Insert( rSynonmText );
522 m_pWrtShell->EndUndo(SwUndoId::DELETE);
523 m_pWrtShell->EndAllAction();
525 m_pWrtShell->SetInsMode( bOldIns );
528 // Start thesaurus
530 void SwView::StartThesaurus()
532 if (!IsValidSelectionForThesaurus())
533 return;
535 SfxErrorContext aContext( ERRCTX_SVX_LINGU_THESAURUS, OUString(), m_pEditWin->GetFrameWeld(),
536 RID_SVXERRCTX, SvxResLocale() );
538 // Determine language
539 LanguageType eLang = m_pWrtShell->GetCurLang();
540 if( LANGUAGE_SYSTEM == eLang )
541 eLang = GetAppLanguage();
543 if( eLang == LANGUAGE_DONTKNOW || eLang == LANGUAGE_NONE )
545 SpellError( LANGUAGE_NONE );
546 return;
549 SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions());
550 const bool bOldIdle = pVOpt->IsIdle();
551 pVOpt->SetIdle( false );
552 comphelper::ScopeGuard guard([&]() { pVOpt->SetIdle(bOldIdle); }); // restore when leaving scope
554 // get initial LookUp text
555 const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection();
556 OUString aTmp = GetThesaurusLookUpText( bSelection );
558 Reference< XThesaurus > xThes( ::GetThesaurus() );
560 if ( !xThes.is() || !xThes->hasLocale( LanguageTag::convertToLocale( eLang ) ) )
561 SpellError( eLang );
562 else
564 VclPtr<AbstractThesaurusDialog> pDlg;
565 // create dialog
566 { //Scope for SwWait-Object
567 SwWait aWait( *GetDocShell(), true );
568 // load library with dialog only on demand ...
569 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
570 pDlg.reset(pFact->CreateThesaurusDialog(GetEditWin().GetFrameWeld(), xThes, aTmp, eLang));
573 if (pDlg)
575 guard.dismiss(); // ignore, we'll call SetIdle() explicitly after the dialog ends
577 pDlg->StartExecuteAsync([aTmp, bSelection, bOldIdle, pDlg, pVOpt, this](sal_Int32 nResult){
578 if (nResult == RET_OK )
579 InsertThesaurusSynonym(pDlg->GetWord(), aTmp, bSelection);
581 pVOpt->SetIdle(bOldIdle);
582 pDlg->disposeOnce();
588 // Offer online suggestions
590 namespace {
592 //!! Start of extra code for context menu modifying extensions
593 struct ExecuteInfo
595 uno::Reference< frame::XDispatch > xDispatch;
596 util::URL aTargetURL;
597 uno::Sequence< PropertyValue > aArgs;
600 class AsyncExecute
602 public:
603 DECL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, void );
608 IMPL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, p, void )
610 ExecuteInfo* pExecuteInfo = static_cast<ExecuteInfo*>(p);
611 SolarMutexReleaser aReleaser;
614 // Asynchronous execution as this can lead to our own destruction!
615 // Framework can recycle our current frame and the layout manager disposes all user interface
616 // elements if a component gets detached from its frame!
617 pExecuteInfo->xDispatch->dispatch( pExecuteInfo->aTargetURL, pExecuteInfo->aArgs );
619 catch (const Exception&)
623 delete pExecuteInfo;
625 //!! End of extra code for context menu modifying extensions
627 bool SwView::ExecSpellPopup(const Point& rPt)
629 bool bRet = false;
630 const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions();
631 if( pVOpt->IsOnlineSpell() &&
632 !m_pWrtShell->IsSelection())
634 if (m_pWrtShell->GetSelectionType() & SelectionType::DrawObjectEditMode)
635 bRet = ExecDrwTextSpellPopup(rPt);
636 else if (!m_pWrtShell->IsSelFrameMode())
638 const bool bOldViewLock = m_pWrtShell->IsViewLocked();
639 m_pWrtShell->LockView( true );
640 if (!comphelper::LibreOfficeKit::isActive())
641 m_pWrtShell->Push();
642 SwRect aToFill;
644 SwCursorShell *pCursorShell = m_pWrtShell.get();
645 SwPaM *pCursor = pCursorShell->GetCursor();
646 SwPosition aPoint(*pCursor->GetPoint());
647 const SwTextNode *pNode = aPoint.GetNode().GetTextNode();
649 // Spell-check in case the idle jobs haven't had a chance to kick in.
650 // This makes it possible to suggest spelling corrections for
651 // wrong words independent of the spell-checking idle job.
652 if (pNode && pNode->IsWrongDirty() &&
653 !pCursorShell->IsTableMode() &&
654 !pCursor->HasMark() && !pCursor->IsMultiSelection())
656 std::pair<Point, bool> const tmp(rPt, false);
657 SwContentFrame *const pContentFrame = pCursor->GetPointContentNode()->getLayoutFrame(
658 pCursorShell->GetLayout(),
659 &aPoint, &tmp);
660 if (pContentFrame)
662 SwRect aRepaint(static_cast<SwTextFrame*>(pContentFrame)->AutoSpell_(
663 *pCursor->GetPointContentNode()->GetTextNode(), 0));
664 if (aRepaint.HasArea())
665 m_pWrtShell->InvalidateWindows(aRepaint);
669 // decide which variant of the context menu to use...
670 // if neither spell checking nor grammar checking provides suggestions use the
671 // default context menu.
672 bool bUseGrammarContext = false;
673 Reference< XSpellAlternatives > xAlt( m_pWrtShell->GetCorrection(&rPt, aToFill) );
674 ProofreadingResult aGrammarCheckRes;
675 sal_Int32 nErrorInResult = -1;
676 uno::Sequence< OUString > aSuggestions;
677 bool bCorrectionRes = false;
678 if (!xAlt.is() || !xAlt->getAlternatives().hasElements())
680 sal_Int32 nErrorPosInText = -1;
681 bCorrectionRes = m_pWrtShell->GetGrammarCorrection( aGrammarCheckRes, nErrorPosInText, nErrorInResult, aSuggestions, &rPt, aToFill );
682 OUString aMessageText;
683 if (nErrorInResult >= 0)
684 aMessageText = aGrammarCheckRes.aErrors[ nErrorInResult ].aShortComment;
685 // we like to use the grammar checking context menu if we either get
686 // some suggestions or at least a comment about the error found...
687 bUseGrammarContext = bCorrectionRes &&
688 (aSuggestions.hasElements() || !aMessageText.isEmpty());
691 // open respective context menu for spell check or grammar errors with correction suggestions...
692 if ((!bUseGrammarContext && xAlt.is()) ||
693 (bUseGrammarContext && bCorrectionRes && aGrammarCheckRes.aErrors.hasElements()))
695 // get paragraph text
696 OUString aParaText;
697 if (pNode)
699 pCursorShell->Push();
700 if (!pCursorShell->IsSttPara())
702 pCursorShell->MovePara(GoCurrPara, fnParaStart);
704 pCursorShell->SetMark();
705 if (!pCursorShell->IsEndPara())
707 pCursorShell->MovePara(GoCurrPara, fnParaEnd);
709 aParaText = pCursorShell->GetSelText();
710 pCursorShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
712 else
714 OSL_FAIL("text node expected but not found" );
717 bRet = true;
718 m_pWrtShell->SttSelect();
719 std::unique_ptr<SwSpellPopup> xPopup(bUseGrammarContext ?
720 new SwSpellPopup(m_pWrtShell.get(), aGrammarCheckRes, nErrorInResult, aSuggestions, aParaText) :
721 new SwSpellPopup(m_pWrtShell.get(), xAlt, aParaText));
722 ui::ContextMenuExecuteEvent aEvent;
723 const Point aPixPos = GetEditWin().LogicToPixel( rPt );
725 aEvent.SourceWindow = VCLUnoHelper::GetInterface( m_pEditWin );
726 aEvent.ExecutePosition.X = aPixPos.X();
727 aEvent.ExecutePosition.Y = aPixPos.Y();
728 rtl::Reference<VCLXPopupMenu> xMenu;
730 OUString sMenuName = bUseGrammarContext ?
731 OUString("private:resource/GrammarContextMenu") : OUString("private:resource/SpellContextMenu");
732 rtl::Reference<VCLXPopupMenu> xMenuInterface = xPopup->CreateMenuInterface();
733 if (TryContextMenuInterception(xMenuInterface, sMenuName, xMenu, aEvent))
735 //! happy hacking for context menu modifying extensions of this
736 //! 'custom made' menu... *sigh* (code copied from sfx2 and framework)
737 if (xMenu.is())
739 css::uno::Reference<css::awt::XWindowPeer> xParent(aEvent.SourceWindow, css::uno::UNO_QUERY);
740 const sal_uInt16 nId = xMenu->execute(xParent, css::awt::Rectangle(aPixPos.X(), aPixPos.Y(), 1, 1),
741 css::awt::PopupMenuDirection::EXECUTE_DOWN);
742 OUString aCommand = xMenu->getCommand(nId);
743 if (aCommand.isEmpty() )
745 if (!ExecuteMenuCommand(xMenu, GetViewFrame(), nId))
746 xPopup->Execute(nId);
748 else
750 SfxViewFrame& rSfxViewFrame = GetViewFrame();
751 uno::Reference<frame::XFrame> xFrame = rSfxViewFrame.GetFrame().GetFrameInterface();
752 css::util::URL aURL;
753 uno::Reference< frame::XDispatchProvider > xDispatchProvider( xFrame, UNO_QUERY );
757 uno::Reference< frame::XDispatch > xDispatch;
758 uno::Reference< util::XURLTransformer > xURLTransformer = util::URLTransformer::create(comphelper::getProcessComponentContext());
760 aURL.Complete = aCommand;
761 xURLTransformer->parseStrict(aURL);
762 uno::Sequence< beans::PropertyValue > aArgs;
763 xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 );
765 if (xDispatch.is())
767 // Execute dispatch asynchronously
768 ExecuteInfo* pExecuteInfo = new ExecuteInfo;
769 pExecuteInfo->xDispatch = xDispatch;
770 pExecuteInfo->aTargetURL = aURL;
771 pExecuteInfo->aArgs = aArgs;
772 Application::PostUserEvent( LINK(nullptr, AsyncExecute , ExecuteHdl_Impl), pExecuteInfo );
775 catch (const Exception&)
780 else
782 if (comphelper::LibreOfficeKit::isActive())
784 if (SfxViewShell* pViewShell = SfxViewShell::Current())
786 boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(xMenuInterface);
787 boost::property_tree::ptree aRoot;
788 aRoot.add_child("menu", aMenu);
790 std::stringstream aStream;
791 boost::property_tree::write_json(aStream, aRoot, true);
792 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, OString(aStream.str()));
795 else
797 xPopup->Execute(aToFill.SVRect(), m_pEditWin);
803 if (!comphelper::LibreOfficeKit::isActive())
804 m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
805 m_pWrtShell->LockView( bOldViewLock );
808 return bRet;
811 /** Function: ExecSmartTagPopup
813 This function shows the popup menu for smarttag
814 actions.
816 void SwView::ExecSmartTagPopup( const Point& rPt )
818 const bool bOldViewLock = m_pWrtShell->IsViewLocked();
819 m_pWrtShell->LockView( true );
820 m_pWrtShell->Push();
822 css::uno::Sequence< css::uno::Any > aArgs{
823 css::uno::Any(comphelper::makePropertyValue( "Frame", GetDispatcher().GetFrame()->GetFrame().GetFrameInterface() )),
824 css::uno::Any(comphelper::makePropertyValue( "CommandURL", OUString( ".uno:OpenSmartTagMenuOnCursor" ) ))
827 css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
828 css::uno::Reference< css::frame::XPopupMenuController > xPopupController(
829 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
830 "com.sun.star.comp.svx.SmartTagMenuController", aArgs, xContext ), css::uno::UNO_QUERY );
832 css::uno::Reference< css::awt::XPopupMenu > xPopupMenu( xContext->getServiceManager()->createInstanceWithContext(
833 "com.sun.star.awt.PopupMenu", xContext ), css::uno::UNO_QUERY );
835 if ( xPopupController.is() && xPopupMenu.is() )
837 xPopupController->setPopupMenu( xPopupMenu );
839 SwRect aToFill;
840 m_pWrtShell->GetSmartTagRect( rPt, aToFill );
841 m_pWrtShell->SttSelect();
843 if ( aToFill.HasArea() )
844 xPopupMenu->execute( m_pEditWin->GetComponentInterface(),
845 VCLUnoHelper::ConvertToAWTRect( m_pEditWin->LogicToPixel( aToFill.SVRect() ) ), css::awt::PopupMenuDirection::EXECUTE_DOWN );
847 css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY );
848 if ( xComponent.is() )
849 xComponent->dispose();
852 m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
853 m_pWrtShell->LockView( bOldViewLock );
856 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */