LibreOffice Module sw (master)  1
viewling.cxx
Go to the documentation of this file.
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>
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>
57 
58 #include <boost/property_tree/json_parser.hpp>
59 
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/util/URL.hpp>
69 #include <com/sun/star/beans/PropertyValue.hpp>
70 #include <com/sun/star/beans/XPropertySet.hpp>
71 #include <com/sun/star/util/URLTransformer.hpp>
72 #include <com/sun/star/util/XURLTransformer.hpp>
73 
74 #include <vcl/svapp.hxx>
75 #include <rtl/ustring.hxx>
76 
77 #include <cppuhelper/bootstrap.hxx>
78 #include <svtools/langtab.hxx>
79 
80 #include <editeng/editerr.hxx>
81 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
82 
83 #include <memory>
84 
85 using namespace sw::mark;
86 using namespace ::com::sun::star;
87 using namespace ::com::sun::star::beans;
88 using namespace ::com::sun::star::uno;
89 using namespace ::com::sun::star::linguistic2;
90 
91 // Lingu-Dispatcher
92 
94 {
95  switch(rReq.GetSlot())
96  {
97  case SID_THESAURUS:
98  StartThesaurus();
99  rReq.Ignore();
100  break;
101  case SID_HANGUL_HANJA_CONVERSION:
102  StartTextConversion( LANGUAGE_KOREAN, LANGUAGE_KOREAN, nullptr,
103  i18n::TextConversionOption::CHARACTER_BY_CHARACTER, true );
104  break;
105  case SID_CHINESE_CONVERSION:
106  {
107  //open ChineseTranslationDialog
109  ::cppu::defaultBootstrap_InitialComponentContext() ); //@todo get context from calc if that has one
110  if(xContext.is())
111  {
112  Reference< lang::XMultiComponentFactory > xMCF( xContext->getServiceManager() );
113  if(xMCF.is())
114  {
115  Reference< ui::dialogs::XExecutableDialog > xDialog(
116  xMCF->createInstanceWithContext(
117  "com.sun.star.linguistic2.ChineseTranslationDialog", xContext),
118  UNO_QUERY);
119  Reference< lang::XInitialization > xInit( xDialog, UNO_QUERY );
120  if( xInit.is() )
121  {
122  Reference<awt::XWindow> xParentWindow;
123  if (weld::Window* pParentWindow = rReq.GetFrameWeld())
124  xParentWindow = pParentWindow->GetXWindow();
125  // initialize dialog
126  uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence(
127  {
128  {"ParentWindow", uno::Any(xParentWindow)}
129  }));
130  xInit->initialize( aSeq );
131 
132  //execute dialog
133  sal_Int16 nDialogRet = xDialog->execute();
134  if( RET_OK == nDialogRet )
135  {
136  //get some parameters from the dialog
137  bool bToSimplified = true;
138  bool bUseVariants = true;
139  bool bCommonTerms = true;
140  Reference< beans::XPropertySet > xProp( xDialog, UNO_QUERY );
141  if( xProp.is() )
142  {
143  try
144  {
145  xProp->getPropertyValue( "IsDirectionToSimplified" ) >>= bToSimplified;
146  xProp->getPropertyValue( "IsUseCharacterVariants" ) >>= bUseVariants;
147  xProp->getPropertyValue( "IsTranslateCommonTerms" ) >>= bCommonTerms;
148  }
149  catch (const Exception&)
150  {
151  }
152  }
153 
154  //execute translation
157  sal_Int32 nOptions = bUseVariants ? i18n::TextConversionOption::USE_CHARACTER_VARIANTS : 0;
158  if( !bCommonTerms )
159  nOptions = nOptions | i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
160 
161  vcl::Font aTargetFont = OutputDevice::GetDefaultFont( DefaultFontType::CJK_TEXT,
162  nTargetLang, GetDefaultFontFlags::OnlyOne );
163 
164  // disallow formatting, updating the view, ... while
165  // converting the document. (saves time)
166  // Also remember the current view and cursor position for later
167  m_pWrtShell->StartAction();
168 
169  // remember cursor position data for later restoration of the cursor
170  const SwPosition *pPoint = m_pWrtShell->GetCursor()->GetPoint();
171  bool bRestoreCursor = pPoint->nNode.GetNode().IsTextNode();
172  const SwNodeIndex aPointNodeIndex( pPoint->nNode );
173  sal_Int32 nPointIndex = pPoint->nContent.GetIndex();
174 
175  // since this conversion is not interactive the whole converted
176  // document should be undone in a single undo step.
177  m_pWrtShell->StartUndo( SwUndoId::OVERWRITE );
178 
179  StartTextConversion( nSourceLang, nTargetLang, &aTargetFont, nOptions, false );
180 
181  m_pWrtShell->EndUndo( SwUndoId::OVERWRITE );
182 
183  if (bRestoreCursor)
184  {
185  SwTextNode *pTextNode = aPointNodeIndex.GetNode().GetTextNode();
186  // check for unexpected error case
187  OSL_ENSURE(pTextNode && pTextNode->GetText().getLength() >= nPointIndex,
188  "text missing: corrupted node?" );
189  if (!pTextNode || pTextNode->GetText().getLength() < nPointIndex)
190  nPointIndex = 0;
191  // restore cursor to its original position
192  m_pWrtShell->GetCursor()->GetPoint()->nContent.Assign( pTextNode, nPointIndex );
193  }
194 
195  // enable all, restore view and cursor position
196  m_pWrtShell->EndAction();
197  }
198  }
199  Reference< lang::XComponent > xComponent( xDialog, UNO_QUERY );
200  if( xComponent.is() )
201  xComponent->dispose();
202  }
203  }
204  break;
205  }
207  HyphenateDocument();
208  break;
209  default:
210  OSL_ENSURE(false, "wrong Dispatcher");
211  return;
212  }
213 }
214 
215 // start language specific text conversion
216 
218  LanguageType nSourceLang,
219  LanguageType nTargetLang,
220  const vcl::Font *pTargetFont,
221  sal_Int32 nOptions,
222  bool bIsInteractive )
223 {
224  // do not do text conversion if it is active elsewhere
226  {
227  return;
228  }
229 
230  SpellContext();
231 
232  const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions();
233  const bool bOldIdle = pVOpt->IsIdle();
234  pVOpt->SetIdle( false );
235 
236  bool bOldIns = m_pWrtShell->IsInsMode();
237  m_pWrtShell->SetInsMode();
238 
239  const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() ||
240  m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext();
241 
242  const bool bStart = bSelection || m_pWrtShell->IsStartOfDoc();
243  const bool bOther = !bSelection && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY);
244 
245  {
246  const uno::Reference< uno::XComponentContext > xContext(
248  SwHHCWrapper aWrap( this, xContext, nSourceLang, nTargetLang, pTargetFont,
249  nOptions, bIsInteractive,
250  bStart, bOther, bSelection );
251  aWrap.Convert();
252  }
253 
254  m_pWrtShell->SetInsMode( bOldIns );
255  pVOpt->SetIdle( bOldIdle );
256  SpellContext(false);
257 }
258 
259 // spellcheck and text conversion related stuff
260 
262  bool bStartDone, bool bEndDone,
263  SwConversionArgs *pConvArgs )
264 {
265  Reference< XLinguProperties > xProp = ::GetLinguPropertySet();
266  bool bIsWrapReverse = !pConvArgs && xProp.is() && xProp->getIsWrapReverse();
267 
271  switch ( eWhich )
272  {
273  case SvxSpellArea::Body:
274  if( bIsWrapReverse )
275  eCurr = SwDocPositions::End;
276  else
277  eCurr = SwDocPositions::Start;
278  break;
279  case SvxSpellArea::BodyEnd:
280  if( bIsWrapReverse )
281  {
282  if( bStartDone )
283  eStart = SwDocPositions::Curr;
284  eCurr = SwDocPositions::End;
285  }
286  else if( bStartDone )
287  eCurr = SwDocPositions::Start;
288  break;
289  case SvxSpellArea::BodyStart:
290  if( !bIsWrapReverse )
291  {
292  if( bEndDone )
293  eEnd = SwDocPositions::Curr;
294  eCurr = SwDocPositions::Start;
295  }
296  else if( bEndDone )
297  eCurr = SwDocPositions::End;
298  break;
299  case SvxSpellArea::Other:
300  if( bIsWrapReverse )
301  {
304  eCurr = SwDocPositions::OtherEnd;
305  }
306  else
307  {
311  }
312  break;
313  default:
314  OSL_ENSURE( false, "SpellStart with unknown Area" );
315  }
316  m_pWrtShell->SpellStart( eStart, eEnd, eCurr, pConvArgs );
317 }
318 
319 // Error message while Spelling
320 
321 // The passed pointer nlang is itself the value
323 {
324  int nPend = 0;
325 
326  if ( m_pWrtShell->ActionPend() )
327  {
328  m_pWrtShell->Push();
329  m_pWrtShell->ClearMark();
330  do
331  {
332  m_pWrtShell->EndAction();
333  ++nPend;
334  }
335  while( m_pWrtShell->ActionPend() );
336  }
337  OUString aErr(SvtLanguageTable::GetLanguageString( eLang ) );
338 
339  SwEditWin &rEditWin = GetEditWin();
340  int nWaitCnt = 0;
341  while( rEditWin.IsWait() )
342  {
343  rEditWin.LeaveWait();
344  ++nWaitCnt;
345  }
346  if ( LANGUAGE_NONE == eLang )
348  else
350 
351  while( nWaitCnt )
352  {
353  rEditWin.EnterWait();
354  --nWaitCnt;
355  }
356 
357  if ( nPend )
358  {
359  while( nPend-- )
360  m_pWrtShell->StartAction();
361  m_pWrtShell->Combine();
362  }
363 }
364 
365 // Finish spelling and restore cursor
366 
367 void SwView::SpellEnd( SwConversionArgs const *pConvArgs )
368 {
369  m_pWrtShell->SpellEnd( pConvArgs );
370  if( m_pWrtShell->IsExtMode() )
371  m_pWrtShell->SetMark();
372 }
373 
375 {
376  switch ( eWhich )
377  {
378  case SvxSpellArea::Body:
379  m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::End );
380  break;
381  case SvxSpellArea::BodyEnd:
382  m_pWrtShell->HyphStart( SwDocPositions::Curr, SwDocPositions::End );
383  break;
384  case SvxSpellArea::BodyStart:
385  m_pWrtShell->HyphStart( SwDocPositions::Start, SwDocPositions::Curr );
386  break;
387  case SvxSpellArea::Other:
388  m_pWrtShell->HyphStart( SwDocPositions::OtherStart, SwDocPositions::OtherEnd );
389  break;
390  default:
391  OSL_ENSURE( false, "HyphStart with unknown Area" );
392  }
393 }
394 
395 // Interactive separation
396 
398 {
399  // do not hyphenate if interactive hyphenation is active elsewhere
401  {
402  std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(),
403  VclMessageType::Warning, VclButtonsType::Ok, SwResId(STR_MULT_INTERACT_HYPH_WARN)));
404  xBox->set_title(SwResId(STR_HYPH_TITLE));
405  xBox->run();
406  return;
407  }
408 
409  SfxErrorContext aContext( ERRCTX_SVX_LINGU_HYPHENATION, OUString(), m_pEditWin->GetFrameWeld(),
411 
412  Reference< XHyphenator > xHyph( ::GetHyphenator() );
413  if (!xHyph.is())
414  {
416  return;
417  }
418 
419  if (m_pWrtShell->GetSelectionType() & (SelectionType::DrawObjectEditMode|SelectionType::DrawObject))
420  {
421  // Hyphenation in a Draw object
422  HyphenateDrawText();
423  }
424  else
425  {
426  SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions());
427  bool bOldIdle = pVOpt->IsIdle();
428  pVOpt->SetIdle( false );
429 
430  Reference< XLinguProperties > xProp( ::GetLinguPropertySet() );
431 
432  m_pWrtShell->StartUndo(SwUndoId::INSATTR); // valid later
433 
434  bool bHyphSpecial = xProp.is() && xProp->getIsHyphSpecial();
435  bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection() ||
436  m_pWrtShell->GetCursor() != m_pWrtShell->GetCursor()->GetNext();
437  bool bOther = m_pWrtShell->HasOtherCnt() && bHyphSpecial && !bSelection;
438  bool bStart = bSelection || ( !bOther && m_pWrtShell->IsStartOfDoc() );
439  bool bStop = false;
440  if( !bOther && !(m_pWrtShell->GetFrameType(nullptr,true) & FrameTypeFlags::BODY) && !bSelection )
441  // turned on no special area
442  {
443  // I want also in special areas hyphenation
444  std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetEditWin().GetFrameWeld(),
445  VclMessageType::Question, VclButtonsType::YesNo,
446  SwResId(STR_QUERY_SPECIAL_FORCED)));
447  if (xBox->run() == RET_YES)
448  {
449  bOther = true;
450  if (xProp.is())
451  {
452  xProp->setIsHyphSpecial( true );
453  }
454  }
455  else
456  bStop = true; // No hyphenation
457  }
458 
459  if( !bStop )
460  {
461  SwHyphWrapper aWrap( this, xHyph, bStart, bOther, bSelection );
462  aWrap.SpellDocument();
463  m_pWrtShell->EndUndo(SwUndoId::INSATTR);
464  }
465  pVOpt->SetIdle( bOldIdle );
466  }
467 }
468 
470 {
471  // must not be a multi-selection, and if it is a selection it needs
472  // to be within a single paragraph
473 
474  const bool bMultiSel = m_pWrtShell->GetCursor()->IsMultiSelection();
475  const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection();
476  return !bMultiSel && (!bSelection || m_pWrtShell->IsSelOnePara() );
477 }
478 
479 OUString SwView::GetThesaurusLookUpText( bool bSelection ) const
480 {
481  return bSelection ? m_pWrtShell->GetSelText() : m_pWrtShell->GetCurWord();
482 }
483 
484 void SwView::InsertThesaurusSynonym( const OUString &rSynonmText, const OUString &rLookUpText, bool bSelection )
485 {
486  bool bOldIns = m_pWrtShell->IsInsMode();
487  m_pWrtShell->SetInsMode();
488 
489  m_pWrtShell->StartAllAction();
490  m_pWrtShell->StartUndo(SwUndoId::DELETE);
491 
492  if( !bSelection )
493  {
494  if(m_pWrtShell->IsEndWrd())
495  m_pWrtShell->Left(CRSR_SKIP_CELLS, false, 1, false );
496 
497  m_pWrtShell->SelWrd();
498 
499  // make sure the selection build later from the data below does not
500  // include "in word" character to the left and right in order to
501  // preserve those. Therefore count those "in words" in order to modify
502  // the selection accordingly.
503  const sal_Unicode* pChar = rLookUpText.getStr();
504  sal_Int32 nLeft = 0;
505  while (*pChar++ == CH_TXTATR_INWORD)
506  ++nLeft;
507  pChar = rLookUpText.getLength() ? rLookUpText.getStr() + rLookUpText.getLength() - 1 : nullptr;
508  sal_Int32 nRight = 0;
509  while (pChar && *pChar-- == CH_TXTATR_INWORD)
510  ++nRight;
511 
512  // adjust existing selection
513  SwPaM *pCursor = m_pWrtShell->GetCursor();
514  pCursor->GetPoint()->nContent -= nRight;
515  pCursor->GetMark()->nContent += nLeft;
516  }
517 
518  m_pWrtShell->Insert( rSynonmText );
519 
520  m_pWrtShell->EndUndo(SwUndoId::DELETE);
521  m_pWrtShell->EndAllAction();
522 
523  m_pWrtShell->SetInsMode( bOldIns );
524 }
525 
526 // Start thesaurus
527 
529 {
530  if (!IsValidSelectionForThesaurus())
531  return;
532 
533  SfxErrorContext aContext( ERRCTX_SVX_LINGU_THESAURUS, OUString(), m_pEditWin->GetFrameWeld(),
535 
536  // Determine language
537  LanguageType eLang = m_pWrtShell->GetCurLang();
538  if( LANGUAGE_SYSTEM == eLang )
539  eLang = GetAppLanguage();
540 
541  if( eLang == LANGUAGE_DONTKNOW || eLang == LANGUAGE_NONE )
542  {
543  SpellError( LANGUAGE_NONE );
544  return;
545  }
546 
547  SwViewOption* pVOpt = const_cast<SwViewOption*>(m_pWrtShell->GetViewOptions());
548  const bool bOldIdle = pVOpt->IsIdle();
549  pVOpt->SetIdle( false );
550  comphelper::ScopeGuard guard([&]() { pVOpt->SetIdle(bOldIdle); }); // restore when leaving scope
551 
552  // get initial LookUp text
553  const bool bSelection = static_cast<SwCursorShell*>(m_pWrtShell.get())->HasSelection();
554  OUString aTmp = GetThesaurusLookUpText( bSelection );
555 
556  Reference< XThesaurus > xThes( ::GetThesaurus() );
557 
558  if ( !xThes.is() || !xThes->hasLocale( LanguageTag::convertToLocale( eLang ) ) )
559  SpellError( eLang );
560  else
561  {
563  // create dialog
564  { //Scope for SwWait-Object
565  SwWait aWait( *GetDocShell(), true );
566  // load library with dialog only on demand ...
568  pDlg.reset(pFact->CreateThesaurusDialog(GetEditWin().GetFrameWeld(), xThes, aTmp, eLang));
569  }
570 
571  if (pDlg)
572  {
573  guard.dismiss(); // ignore, we'll call SetIdle() explicitly after the dialog ends
574 
575  pDlg->StartExecuteAsync([aTmp, bSelection, bOldIdle, pDlg, pVOpt, this](sal_Int32 nResult){
576  if (nResult == RET_OK )
577  InsertThesaurusSynonym(pDlg->GetWord(), aTmp, bSelection);
578 
579  pVOpt->SetIdle(bOldIdle);
580  pDlg->disposeOnce();
581  });
582  }
583  }
584 }
585 
586 // Offer online suggestions
587 
588 namespace {
589 
591 struct ExecuteInfo
592 {
593  uno::Reference< frame::XDispatch > xDispatch;
594  util::URL aTargetURL;
595  uno::Sequence< PropertyValue > aArgs;
596 };
597 
598 class AsyncExecute
599 {
600 public:
601  DECL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, void );
602 };
603 
604 }
605 
606 IMPL_STATIC_LINK( AsyncExecute, ExecuteHdl_Impl, void*, p, void )
607 {
608  ExecuteInfo* pExecuteInfo = static_cast<ExecuteInfo*>(p);
609  SolarMutexReleaser aReleaser;
610  try
611  {
612  // Asynchronous execution as this can lead to our own destruction!
613  // Framework can recycle our current frame and the layout manager disposes all user interface
614  // elements if a component gets detached from its frame!
615  pExecuteInfo->xDispatch->dispatch( pExecuteInfo->aTargetURL, pExecuteInfo->aArgs );
616  }
617  catch (const Exception&)
618  {
619  }
620 
621  delete pExecuteInfo;
622 }
624 
625 bool SwView::ExecSpellPopup(const Point& rPt)
626 {
627  bool bRet = false;
628  const SwViewOption* pVOpt = m_pWrtShell->GetViewOptions();
629  if( pVOpt->IsOnlineSpell() &&
630  !m_pWrtShell->IsSelection())
631  {
632  if (m_pWrtShell->GetSelectionType() & SelectionType::DrawObjectEditMode)
633  bRet = ExecDrwTextSpellPopup(rPt);
634  else if (!m_pWrtShell->IsSelFrameMode())
635  {
636  const bool bOldViewLock = m_pWrtShell->IsViewLocked();
637  m_pWrtShell->LockView( true );
638  m_pWrtShell->Push();
639  SwRect aToFill;
640 
641  SwCursorShell *pCursorShell = m_pWrtShell.get();
642  SwPaM *pCursor = pCursorShell->GetCursor();
643  SwPosition aPoint(*pCursor->GetPoint());
644  const SwTextNode *pNode = aPoint.nNode.GetNode().GetTextNode();
645 
646  // Spell-check in case the idle jobs haven't had a chance to kick in.
647  // This makes it possible to suggest spelling corrections for
648  // wrong words independent of the spell-checking idle job.
649  if (pNode && pNode->IsWrongDirty() &&
650  !pCursorShell->IsTableMode() &&
651  !pCursor->HasMark() && !pCursor->IsMultiSelection())
652  {
653  std::pair<Point, bool> const tmp(rPt, false);
654  SwContentFrame *const pContentFrame = pCursor->GetContentNode()->getLayoutFrame(
655  pCursorShell->GetLayout(),
656  &aPoint, &tmp);
657  if (pContentFrame)
658  {
659  SwRect aRepaint(static_cast<SwTextFrame*>(pContentFrame)->AutoSpell_(
660  *pCursor->GetContentNode()->GetTextNode(), 0));
661  if (aRepaint.HasArea())
662  m_pWrtShell->InvalidateWindows(aRepaint);
663  }
664  }
665 
666  // decide which variant of the context menu to use...
667  // if neither spell checking nor grammar checking provides suggestions use the
668  // default context menu.
669  bool bUseGrammarContext = false;
670  Reference< XSpellAlternatives > xAlt( m_pWrtShell->GetCorrection(&rPt, aToFill) );
671  ProofreadingResult aGrammarCheckRes;
672  sal_Int32 nErrorInResult = -1;
673  uno::Sequence< OUString > aSuggestions;
674  bool bCorrectionRes = false;
675  if (!xAlt.is() || !xAlt->getAlternatives().hasElements())
676  {
677  sal_Int32 nErrorPosInText = -1;
678  bCorrectionRes = m_pWrtShell->GetGrammarCorrection( aGrammarCheckRes, nErrorPosInText, nErrorInResult, aSuggestions, &rPt, aToFill );
679  OUString aMessageText;
680  if (nErrorInResult >= 0)
681  aMessageText = aGrammarCheckRes.aErrors[ nErrorInResult ].aShortComment;
682  // we like to use the grammar checking context menu if we either get
683  // some suggestions or at least a comment about the error found...
684  bUseGrammarContext = bCorrectionRes &&
685  (aSuggestions.hasElements() || !aMessageText.isEmpty());
686  }
687 
688  // open respective context menu for spell check or grammar errors with correction suggestions...
689  if ((!bUseGrammarContext && xAlt.is()) ||
690  (bUseGrammarContext && bCorrectionRes && aGrammarCheckRes.aErrors.hasElements()))
691  {
692  // get paragraph text
693  OUString aParaText;
694  if (pNode)
695  aParaText = pNode->GetText(); // this may include hidden text but that should be Ok
696  else
697  {
698  OSL_FAIL("text node expected but not found" );
699  }
700 
701  bRet = true;
702  m_pWrtShell->SttSelect();
703  std::unique_ptr<SwSpellPopup> xPopup(bUseGrammarContext ?
704  new SwSpellPopup(m_pWrtShell.get(), aGrammarCheckRes, nErrorInResult, aSuggestions, aParaText) :
705  new SwSpellPopup(m_pWrtShell.get(), xAlt, aParaText));
706  ui::ContextMenuExecuteEvent aEvent;
707  const Point aPixPos = GetEditWin().LogicToPixel( rPt );
708 
709  aEvent.SourceWindow = VCLUnoHelper::GetInterface( m_pEditWin );
710  aEvent.ExecutePosition.X = aPixPos.X();
711  aEvent.ExecutePosition.Y = aPixPos.Y();
712  ScopedVclPtr<Menu> pMenu;
713 
714  OUString sMenuName = bUseGrammarContext ?
715  OUString("private:resource/GrammarContextMenu") : OUString("private:resource/SpellContextMenu");
716  if (TryContextMenuInterception(xPopup->GetMenu(), sMenuName, pMenu, aEvent))
717  {
720  if ( pMenu )
721  {
722  const sal_uInt16 nId = static_cast<PopupMenu*>(pMenu.get())->Execute(m_pEditWin, aPixPos);
723  OUString aCommand = static_cast<PopupMenu*>(pMenu.get())->GetItemCommand(nId);
724  if (aCommand.isEmpty() )
725  {
726  if (!ExecuteMenuCommand(dynamic_cast<PopupMenu&>(*pMenu), *GetViewFrame(), nId))
727  xPopup->Execute(nId);
728  }
729  else
730  {
731  SfxViewFrame *pSfxViewFrame = GetViewFrame();
732  uno::Reference< frame::XFrame > xFrame;
733  if ( pSfxViewFrame )
734  xFrame = pSfxViewFrame->GetFrame().GetFrameInterface();
735  css::util::URL aURL;
736  uno::Reference< frame::XDispatchProvider > xDispatchProvider( xFrame, UNO_QUERY );
737 
738  try
739  {
740  uno::Reference< frame::XDispatch > xDispatch;
741  uno::Reference< util::XURLTransformer > xURLTransformer = util::URLTransformer::create(comphelper::getProcessComponentContext());
742 
743  aURL.Complete = aCommand;
744  xURLTransformer->parseStrict(aURL);
745  uno::Sequence< beans::PropertyValue > aArgs;
746  xDispatch = xDispatchProvider->queryDispatch( aURL, OUString(), 0 );
747 
748  if (xDispatch.is())
749  {
750  // Execute dispatch asynchronously
751  ExecuteInfo* pExecuteInfo = new ExecuteInfo;
752  pExecuteInfo->xDispatch = xDispatch;
753  pExecuteInfo->aTargetURL = aURL;
754  pExecuteInfo->aArgs = aArgs;
755  Application::PostUserEvent( LINK(nullptr, AsyncExecute , ExecuteHdl_Impl), pExecuteInfo );
756  }
757  }
758  catch (const Exception&)
759  {
760  }
761  }
762  }
763  else
764  {
766  {
767  if (SfxViewShell* pViewShell = SfxViewShell::Current())
768  {
769  boost::property_tree::ptree aMenu = SfxDispatcher::fillPopupMenu(&xPopup->GetMenu());
770  boost::property_tree::ptree aRoot;
771  aRoot.add_child("menu", aMenu);
772 
773  std::stringstream aStream;
774  boost::property_tree::write_json(aStream, aRoot, true);
775  pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CONTEXT_MENU, aStream.str().c_str());
776  }
777  }
778  else
779  {
780  xPopup->Execute(aToFill.SVRect(), m_pEditWin);
781  }
782  }
783  }
784  }
785 
787  m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
788  m_pWrtShell->LockView( bOldViewLock );
789  }
790  }
791  return bRet;
792 }
793 
799 void SwView::ExecSmartTagPopup( const Point& rPt )
800 {
801  const bool bOldViewLock = m_pWrtShell->IsViewLocked();
802  m_pWrtShell->LockView( true );
803  m_pWrtShell->Push();
804 
805  css::uno::Sequence< css::uno::Any > aArgs( 2 );
806  aArgs[0] <<= comphelper::makePropertyValue( "Frame", GetDispatcher().GetFrame()->GetFrame().GetFrameInterface() );
807  aArgs[1] <<= comphelper::makePropertyValue( "CommandURL", OUString( ".uno:OpenSmartTagMenuOnCursor" ) );
808 
809  css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
810  css::uno::Reference< css::frame::XPopupMenuController > xPopupController(
811  xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
812  "com.sun.star.comp.svx.SmartTagMenuController", aArgs, xContext ), css::uno::UNO_QUERY );
813 
814  css::uno::Reference< css::awt::XPopupMenu > xPopupMenu( xContext->getServiceManager()->createInstanceWithContext(
815  "com.sun.star.awt.PopupMenu", xContext ), css::uno::UNO_QUERY );
816 
817  if ( xPopupController.is() && xPopupMenu.is() )
818  {
819  xPopupController->setPopupMenu( xPopupMenu );
820 
821  SwRect aToFill;
822  m_pWrtShell->GetSmartTagRect( rPt, aToFill );
823  m_pWrtShell->SttSelect();
824 
825  if ( aToFill.HasArea() )
826  xPopupMenu->execute( m_pEditWin->GetComponentInterface(),
827  VCLUnoHelper::ConvertToAWTRect( m_pEditWin->LogicToPixel( aToFill.SVRect() ) ), css::awt::PopupMenuDirection::EXECUTE_DOWN );
828 
829  css::uno::Reference< css::lang::XComponent > xComponent( xPopupController, css::uno::UNO_QUERY );
830  if ( xComponent.is() )
831  xComponent->dispose();
832  }
833 
834  m_pWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
835  m_pWrtShell->LockView( bOldViewLock );
836 }
837 
838 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsWait() const
#define LANGUAGE_NONE
static vcl::Font GetDefaultFont(DefaultFontType nType, LanguageType eLang, GetDefaultFontFlags nFlags, const OutputDevice *pOutDev=nullptr)
URL aURL
void SpellDocument()
SAL_DLLPRIVATE void HyphenateDocument()
Definition: viewling.cxx:397
void ExecLingu(SfxRequest &)
Definition: viewling.cxx:93
Marks a position in the document model.
Definition: pam.hxx:35
bool IsMultiSelection() const
Definition: pam.hxx:272
SwPaM * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:194
const OUString & GetText() const
Definition: ndtxt.hxx:210
static bool HasConvIter()
Is text conversion active somewhere else?
Definition: edlingu.cxx:616
#define FN_HYPHENATE_OPT_DLG
Definition: cmdid.h:487
SwNodeIndex nNode
Definition: pam.hxx:37
bool IsTableMode() const
Definition: crsrsh.hxx:643
SAL_DLLPRIVATE void SpellStart(SvxSpellArea eSpell, bool bStartDone, bool bEndDone, SwConversionArgs *pConvArgs)
Definition: viewling.cxx:261
static SvxAbstractDialogFactory * Create()
void EnterWait()
Reference< XFrame > xFrame
const SwPosition * GetMark() const
Definition: pam.hxx:209
#define LANGUAGE_KOREAN
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1212
sal_Int16 nId
static ImplSVEvent * PostUserEvent(const Link< void *, void > &rLink, void *pCaller=nullptr, bool bReferenceLink=false)
SwNode & GetNode() const
Definition: ndindex.hxx:119
sal_uInt16 Execute(vcl::Window *pWindow, const Point &rPopupPos)
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
static bool HasHyphIter()
Is hyphenation active somewhere else?
Definition: edlingu.cxx:621
virtual OUString GetWord()=0
SwDocPositions
Definition: cshtyp.hxx:103
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
static boost::property_tree::ptree fillPopupMenu(Menu *pMenu)
sal_uInt16 sal_Unicode
#define CH_TXTATR_INWORD
Definition: hintids.hxx:170
RET_YES
SwIndex nContent
Definition: pam.hxx:38
SfxFrame & GetFrame() const
static SfxViewShell * Current()
SwPaM * GetNext()
Definition: pam.hxx:264
bool ExecSpellPopup(const Point &rPt)
! End of extra code for context menu modifying extensions
Definition: viewling.cxx:625
weld::Window * GetFrameWeld(const SfxFrame *pFrame)
Definition: dialoghelp.cxx:19
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
const SwPosition * GetPoint() const
Definition: pam.hxx:207
css::uno::Sequence< css::uno::Any > InitAnyPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Window class for the Writer edit area, this is the one handling mouse and keyboard events and doing t...
Definition: edtwin.hxx:58
SVX_DLLPUBLIC const ErrMsgCode RID_SVXERRCTX[]
#define LANGUAGE_SYSTEM
static DialogMask HandleError(ErrCode nId, weld::Window *pParent=nullptr, DialogMask nMask=DialogMask::MAX)
void ExecSmartTagPopup(const Point &rPt)
Function: ExecSmartTagPopup.
Definition: viewling.cxx:799
bool IsIdle() const
Definition: viewopt.hxx:209
void SpellError(LanguageType eLang)
Definition: viewling.cxx:322
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
bool HasArea() const
Definition: swrect.hxx:288
#define ERRCTX_SVX_LINGU_THESAURUS
#define LANGUAGE_DONTKNOW
#define LANGUAGE_CHINESE_SIMPLIFIED
void InsertThesaurusSynonym(const OUString &rSynonmText, const OUString &rLookUpText, bool bValidSelection)
Definition: viewling.cxx:484
CPPUHELPER_DLLPUBLIC css::uno::Reference< css::uno::XComponentContext > SAL_CALL defaultBootstrap_InitialComponentContext()
Marks a node in the document model.
Definition: ndindex.hxx:31
IMPL_STATIC_LINK(AsyncExecute, ExecuteHdl_Impl, void *, p, void)
Definition: viewling.cxx:606
OUString SwResId(const char *pId)
Definition: swmodule.cxx:166
bool IsOnlineSpell() const
Definition: viewopt.hxx:371
OUString GetThesaurusLookUpText(bool bSelection) const
Definition: viewling.cxx:479
#define ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS
static css::awt::Rectangle ConvertToAWTRect(::tools::Rectangle const &_rRect)
const css::uno::Reference< css::frame::XFrame > & GetFrameInterface() const
#define ERRCODE_SVX_LINGU_LINGUNOTEXISTS
void reset(reference_type *pBody)
uno::Reference< linguistic2::XThesaurus > GetThesaurus()
Definition: swtypes.cxx:59
weld::Window * GetFrameWeld() const
SAL_DLLPRIVATE void StartTextConversion(LanguageType nSourceLang, LanguageType nTargetLang, const vcl::Font *pTargetFont, sal_Int32 nOptions, bool bIsInteractive)
Definition: viewling.cxx:217
void Convert()
Definition: hhcwrp.cxx:510
const sal_uInt16 CRSR_SKIP_CELLS
Definition: swcrsr.hxx:66
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
sal_uInt16 GetSlot() const
Reference< XDispatch > xDispatch
SfxDispatcher * GetDispatcher()
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
tools::Rectangle SVRect() const
Definition: swrect.hxx:280
SAL_DLLPRIVATE void HyphStart(SvxSpellArea eSpell)
Definition: viewling.cxx:374
bool IsValidSelectionForThesaurus() const
Definition: viewling.cxx:469
SvxSpellArea
void SetIdle(bool b) const
Definition: viewopt.hxx:216
SAL_DLLPRIVATE void StartThesaurus()
Definition: viewling.cxx:528
sal_Int32 GetIndex() const
Definition: index.hxx:91
LanguageType GetAppLanguage()
Definition: init.cxx:732
RET_OK
bool ExecuteMenuCommand(PopupMenu const &rMenu, SfxViewFrame const &rViewFrame, sal_uInt16 nId)
Definition: uitool.cxx:853
void * p
Reference< XComponentContext > getProcessComponentContext()
Sequence< sal_Int8 > aSeq
const char * pChar
#define ERRCTX_SVX_LINGU_HYPHENATION
static OUString GetLanguageString(const LanguageType eType)
uno::Reference< linguistic2::XHyphenator > GetHyphenator()
Definition: swtypes.cxx:57
#define LANGUAGE_CHINESE_TRADITIONAL
OUString aCommand
SAL_DLLPRIVATE void SpellEnd(SwConversionArgs const *pConvArgs)
Definition: viewling.cxx:367
OUString aTargetURL
void LeaveWait()
static css::uno::Reference< css::awt::XWindow > GetInterface(vcl::Window *pWindow)
#define ERRCODE_SVX_LINGU_NOLANGUAGE
SwRootFrame * GetLayout() const
Definition: viewsh.cxx:2067
void Ignore()
bool IsTextNode() const
Definition: node.hxx:640
std::locale SvxResLocale()
uno::Reference< linguistic2::XLinguProperties > GetLinguPropertySet()
Definition: swtypes.cxx:61
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, bool bMobile=false)
AnyEventRef aEvent
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:845
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)