LibreOffice Module sc (master)  1
gridwin.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 <scitems.hxx>
21 
22 #include <cstdlib>
23 #include <memory>
24 #include <editeng/adjustitem.hxx>
25 #include <sot/storage.hxx>
26 #include <editeng/eeitem.hxx>
27 #include <editeng/editview.hxx>
28 #include <editeng/editstat.hxx>
29 #include <editeng/flditem.hxx>
30 #include <editeng/justifyitem.hxx>
32 #include <editeng/editobj.hxx>
33 #include <o3tl/unit_conversion.hxx>
34 #include <sfx2/dispatch.hxx>
35 #include <sfx2/viewfrm.hxx>
36 #include <sfx2/docfile.hxx>
37 #include <sfx2/ipclient.hxx>
38 #include <svl/stritem.hxx>
39 #include <svl/sharedstringpool.hxx>
40 #include <vcl/canvastools.hxx>
41 #include <vcl/commandevent.hxx>
42 #include <vcl/cursor.hxx>
43 #include <vcl/inputctx.hxx>
44 #include <vcl/menu.hxx>
45 #include <vcl/settings.hxx>
46 #include <vcl/weldutils.hxx>
47 #include <sot/formats.hxx>
48 #include <comphelper/classids.hxx>
49 
50 #include <svx/svdview.hxx>
51 #include <editeng/outliner.hxx>
52 #include <svx/svdocapt.hxx>
53 #include <svx/svdpagv.hxx>
54 
55 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
56 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
57 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
58 #include <com/sun/star/sheet/MemberResultFlags.hpp>
59 #include <com/sun/star/sheet/TableValidationVisibility.hpp>
60 #include <com/sun/star/awt/KeyModifier.hpp>
61 #include <com/sun/star/awt/MouseButton.hpp>
62 #include <com/sun/star/script/vba/VBAEventId.hpp>
63 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
64 #include <com/sun/star/text/textfield/Type.hpp>
65 
66 #include <gridwin.hxx>
67 #include <tabvwsh.hxx>
68 #include <docsh.hxx>
69 #include <viewdata.hxx>
70 #include <tabview.hxx>
71 #include <select.hxx>
72 #include <scmod.hxx>
73 #include <document.hxx>
74 #include <attrib.hxx>
75 #include <dbdata.hxx>
76 #include <stlpool.hxx>
77 #include <printfun.hxx>
78 #include <cbutton.hxx>
79 #include <sc.hrc>
80 #include <helpids.h>
81 #include <globstr.hrc>
82 #include <strings.hrc>
83 #include <editutil.hxx>
84 #include <scresid.hxx>
85 #include <inputhdl.hxx>
86 #include <uiitems.hxx>
87 #include <formulacell.hxx>
88 #include <patattr.hxx>
89 #include <notemark.hxx>
90 #include <rfindlst.hxx>
91 #include <output.hxx>
92 #include <docfunc.hxx>
93 #include <dbdocfun.hxx>
94 #include <dpobject.hxx>
95 #include <transobj.hxx>
96 #include <drwtrans.hxx>
97 #include <seltrans.hxx>
98 #include <sizedev.hxx>
99 #include <AccessibilityHints.hxx>
100 #include <dpsave.hxx>
101 #include <viewuno.hxx>
102 #include <compiler.hxx>
103 #include <editable.hxx>
104 #include <fillinfo.hxx>
105 #include <filterentries.hxx>
106 #include <drwlayer.hxx>
107 #include <validat.hxx>
108 #include <tabprotection.hxx>
109 #include <postit.hxx>
110 #include <dpcontrol.hxx>
111 #include <checklistmenu.hxx>
112 #include <clipparam.hxx>
113 #include <overlayobject.hxx>
114 #include <cellsuno.hxx>
115 #include <drawview.hxx>
116 #include <dragdata.hxx>
117 #include <cliputil.hxx>
118 #include <queryentry.hxx>
119 #include <markdata.hxx>
120 #include <externalrefmgr.hxx>
121 #include <spellcheckcontext.hxx>
122 #include <uiobject.hxx>
123 #include <undoblk.hxx>
124 #include <datamapper.hxx>
125 #include <inputopt.hxx>
126 #include <queryparam.hxx>
127 
128 #include <svx/sdrpagewindow.hxx>
130 #include <vcl/svapp.hxx>
131 #include <vcl/uitest/logger.hxx>
134 #include <comphelper/lok.hxx>
135 #include <sfx2/lokhelper.hxx>
136 
137 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
138 
139 #include <vector>
140 #include <boost/property_tree/json_parser.hpp>
141 
142 #include <FilterListBox.hxx>
143 
144 using namespace css;
145 using namespace css::uno;
146 
148 {
150 
152  mbActivatePart(false)
153  {}
154 };
155 
156 #define SC_FILTERLISTBOX_LINES 12
157 
159  : mnCol1(0)
160  , mnCol2(rDoc.MaxCol())
161  , mnRow1(0)
162  , mnRow2(rDoc.MaxRow())
163 {
164 }
165 
167 {
168  return mnCol1 <= nCol && nCol <= mnCol2 && mnRow1 <= nRow && nRow <= mnRow2;
169 }
170 
171 bool ScGridWindow::VisibleRange::set(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
172 {
173  bool bChanged = mnCol1 != nCol1 || mnRow1 != nRow1 || mnCol2 != nCol2 || mnRow2 != nRow2;
174 
175  mnCol1 = nCol1;
176  mnRow1 = nRow1;
177  mnCol2 = nCol2;
178  mnRow2 = nRow2;
179 
180  return bChanged;
181 }
182 
183 // ListBox in a FloatingWindow (pParent)
185  SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode)
186  : xBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/filterlist.ui"))
187  , xPopover(xBuilder->weld_popover("FilterList"))
188  , xTreeView(xBuilder->weld_tree_view("list"))
189  , pGridWin(pGrid)
190  , nCol(nNewCol)
191  , nRow(nNewRow)
192  , bInit(true)
193  , bCancelled(false)
194  , bGridHadMouseCaptured(pGrid->IsMouseCaptured())
195  , nSel(0)
196  , eMode(eNewMode)
197  , nAsyncSelectHdl(nullptr)
198 {
199  xTreeView->connect_row_activated(LINK(this, ScFilterListBox, SelectHdl));
200  xTreeView->connect_key_press(LINK(this, ScFilterListBox, KeyInputHdl));
201 }
202 
204 {
205  if (nAsyncSelectHdl)
206  {
208  nAsyncSelectHdl = nullptr;
209  }
210 }
211 
213 {
214  sal_Int32 nPos = xTreeView->get_selected_index();
215  if (nPos == -1)
216  nSel = 0;
217  else
218  nSel = nPos;
219 
220  bInit = false;
221 }
222 
223 IMPL_LINK(ScFilterListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
224 {
225  bool bDone = false;
226 
227  vcl::KeyCode aCode = rKeyEvent.GetKeyCode();
228  // esc with no modifiers
229  if (!aCode.GetModifier() && aCode.GetCode() == KEY_ESCAPE)
230  {
231  pGridWin->ClickExtern(); // clears the listbox
232  bDone = true;
233  }
234 
235  // nowhere to tab to
236  if (aCode.GetCode() == KEY_TAB)
237  bDone = true;
238 
239  return bDone;
240 }
241 
243 {
244  if (!bInit && !bCancelled && !nAsyncSelectHdl)
245  {
246  int nPos = xTreeView->get_selected_index();
247  if (nPos != -1)
248  {
249  nSel = nPos;
250  // #i81298# launch async so the box isn't deleted from modifications within FilterSelect
251  nAsyncSelectHdl = Application::PostUserEvent(LINK(this, ScFilterListBox, AsyncSelectHdl));
252  }
253  }
254  return true;
255 }
256 
257 IMPL_LINK_NOARG(ScFilterListBox, AsyncSelectHdl, void*, void)
258 {
259  nAsyncSelectHdl = nullptr;
260 
261  //tdf#133971 hold self-ref until we return
262  auto xThis(shared_from_this());
263  pGridWin->FilterSelect(nSel);
264  if (xThis.use_count() == 1)
265  {
266  // tdf#133855 we got disposed by FilterSelect
267  return;
268  }
269  pGridWin->ClickExtern();
270 }
271 
272 static bool lcl_IsEditableMatrix( ScDocument& rDoc, const ScRange& rRange )
273 {
274  // If it is an editable range and if there is a Matrix cell at the bottom right with an
275  // origin top left then the range will be set to contain the exact matrix.
277  if ( !rDoc.IsBlockEditable( rRange.aStart.Tab(), rRange.aStart.Col(),rRange.aStart.Row(),
278  rRange.aEnd.Col(),rRange.aEnd.Row() ) )
279  return false;
280 
281  ScRefCellValue aCell(rDoc, rRange.aEnd);
282  ScAddress aPos;
283  return (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->GetMatrixOrigin(rDoc, aPos) && aPos == rRange.aStart);
284 }
285 
286 static void lcl_UnLockComment( ScDrawView* pView, const Point& rPos, const ScViewData& rViewData )
287 {
288  if (!pView)
289  return;
290 
291  ScDocument& rDoc = rViewData.GetDocument();
292  ScAddress aCellPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
293  ScPostIt* pNote = rDoc.GetNote( aCellPos );
294  SdrObject* pObj = pNote ? pNote->GetCaption() : nullptr;
295  if( pObj && pObj->GetLogicRect().IsInside( rPos ) && ScDrawLayer::IsNoteCaption( pObj ) )
296  {
297  const ScProtectionAttr* pProtAttr = rDoc.GetAttr( aCellPos, ATTR_PROTECTION );
298  bool bProtectAttr = pProtAttr->GetProtection() || pProtAttr->GetHideCell() ;
299  bool bProtectDoc = rDoc.IsTabProtected( aCellPos.Tab() ) || rViewData.GetSfxDocShell()->IsReadOnly() ;
300  // unlock internal layer (if not protected), will be relocked in ScDrawView::MarkListHasChanged()
301  pView->LockInternalLayer( bProtectDoc && bProtectAttr );
302  }
303 }
304 
306  ScDocument& rDoc, SCCOL& rPosX, SCROW nPosY, SCTAB nTab, ScRefCellValue& rCell, OUString& rURL )
307 {
308  bool bFound = false;
309  do
310  {
311  ScAddress aPos(rPosX, nPosY, nTab);
312  rCell.assign(rDoc, aPos);
313  if (rCell.isEmpty())
314  {
315  if ( rPosX <= 0 )
316  return false; // everything empty to the links
317  else
318  --rPosX; // continue search
319  }
320  else
321  {
322  const ScPatternAttr* pPattern = rDoc.GetPattern(aPos);
323  if ( !pPattern->GetItem(ATTR_HYPERLINK).GetValue().isEmpty() )
324  {
325  rURL = pPattern->GetItem(ATTR_HYPERLINK).GetValue();
326  bFound = true;
327  }
328  else if (rCell.meType == CELLTYPE_EDIT)
329  bFound = true;
330  else if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->IsHyperLinkCell())
331  bFound = true;
332  else
333  return false; // other cell
334  }
335  }
336  while ( !bFound );
337 
338  return bFound;
339 }
340 
341 // WB_DIALOGCONTROL needed for UNO-Controls
343 : Window( pParent, WB_CLIPCHILDREN | WB_DIALOGCONTROL ),
344  DropTargetHelper( this ),
345  DragSourceHelper( this ),
346  mpOOCursors(),
347  mpOOSelection(),
348  mpOOSelectionBorder(),
349  mpOOAutoFill(),
350  mpOODragRect(),
351  mpOOHeader(),
352  mpOOShrink(),
353  maVisibleRange(rData.GetDocument()),
354  mrViewData( rData ),
355  eWhich( eWhichPos ),
356  mpNoteMarker(),
357  mpFilterBox(),
358  mpAutoFilterPopup(),
359  mpDPFieldPopup(),
360  mpFilterButton(),
361  nCursorHideCount( 0 ),
362  nButtonDown( 0 ),
363  nMouseStatus( SC_GM_NONE ),
364  nNestedButtonState( ScNestedButtonState::NONE ),
365  nDPField( 0 ),
366  pDragDPObj( nullptr ),
367  nRFIndex( 0 ),
368  nRFAddX( 0 ),
369  nRFAddY( 0 ),
370  nPagebreakMouse( SC_PD_NONE ),
371  nPagebreakBreak( 0 ),
372  nPagebreakPrev( 0 ),
373  nPageScript( SvtScriptType::NONE ),
374  nDragStartX( -1 ),
375  nDragStartY( -1 ),
376  nDragEndX( -1 ),
377  nDragEndY( -1 ),
378  meDragInsertMode( INS_NONE ),
379  aComboButton( GetOutDev() ),
380  aCurMousePos( 0,0 ),
381  nPaintCount( 0 ),
382  aRFSelectedCorned( NONE ),
383  bEEMouse( false ),
384  bDPMouse( false ),
385  bRFMouse( false ),
386  bRFSize( false ),
387  bPagebreakDrawn( false ),
388  bDragRect( false ),
389  bIsInPaint( false ),
390  bNeedsRepaint( false ),
391  bAutoMarkVisible( false ),
392  bListValButton( false )
393 {
394  set_id("grid_window");
395  switch(eWhich)
396  {
397  case SC_SPLIT_TOPLEFT:
400  break;
401  case SC_SPLIT_TOPRIGHT:
404  break;
405  case SC_SPLIT_BOTTOMLEFT:
408  break;
412  break;
413  default:
414  OSL_FAIL("GridWindow: wrong position");
415  }
416 
417  SetBackground();
418 
421  SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus );
422 
424 
425  GetOutDev()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
426  EnableRTL( false );
427 
428  bInitialPageBreaks = true;
429  maShowPageBreaksTimer.SetInvokeHandler(LINK(this, ScGridWindow, InitiatePageBreaksTimer));
431 }
432 
434 {
435  disposeOnce();
436 }
437 
439 {
441 
443 
444  mpFilterBox.reset();
445  mpNoteMarker.reset();
448  aComboButton.SetOutputDevice(nullptr);
449 
450  if (mpSpellCheckCxt)
451  mpSpellCheckCxt->reset();
452  mpSpellCheckCxt.reset();
453 
455 }
456 
458 {
459  do
460  {
461  // #i84277# when initializing the filter box, a Basic error can deactivate the view
462  if (mpFilterBox && mpFilterBox->IsInInit())
463  break;
464  mpFilterBox.reset();
465  }
466  while (false);
467 
468  if (mpDPFieldPopup)
469  {
470  mpDPFieldPopup->get_widget().close(false);
472  }
473 }
474 
475 IMPL_LINK_NOARG(ScGridWindow, PopupModeEndHdl, weld::Popover&, void)
476 {
477  if (mpFilterBox)
478  {
479  bool bMouseWasCaptured = mpFilterBox->MouseWasCaptured();
480  mpFilterBox->SetCancelled(); // cancel select
481  // restore the mouse capture state of the GridWindow to
482  // what it was at initial popup time
483  if (bMouseWasCaptured)
484  CaptureMouse();
485  }
486  GrabFocus();
487 }
488 
489 IMPL_LINK( ScGridWindow, PopupSpellingHdl, SpellCallbackInfo&, rInfo, void )
490 {
491  if( rInfo.nCommand == SpellCallbackCommand::STARTSPELLDLG )
492  mrViewData.GetDispatcher().Execute( SID_SPELL_DIALOG, SfxCallMode::ASYNCHRON );
493  else if (rInfo.nCommand == SpellCallbackCommand::AUTOCORRECT_OPTIONS)
494  mrViewData.GetDispatcher().Execute( SID_AUTO_CORRECT_DLG, SfxCallMode::ASYNCHRON );
495 }
496 
497 namespace {
498 
499 struct AutoFilterData : public ScCheckListMenuControl::ExtendedData
500 {
501  ScAddress maPos;
502  ScDBData* mpData;
503 };
504 
505 class AutoFilterAction : public ScCheckListMenuControl::Action
506 {
509 public:
510  AutoFilterAction(ScGridWindow* p, ScGridWindow::AutoFilterMode eMode) :
511  mpWindow(p), meMode(eMode) {}
512  virtual void execute() override
513  {
514  mpWindow->UpdateAutoFilterFromMenu(meMode);
515  }
516 };
517 
518 class AutoFilterPopupEndAction : public ScCheckListMenuControl::Action
519 {
520  VclPtr<ScGridWindow> mpWindow;
521  ScAddress maPos;
522 public:
523  AutoFilterPopupEndAction(ScGridWindow* p, const ScAddress& rPos) :
524  mpWindow(p), maPos(rPos) {}
525  virtual void execute() override
526  {
527  mpWindow->RefreshAutoFilterButton(maPos);
528  }
529 };
530 
531 class AddItemToEntry
532 {
534  svl::SharedStringPool& mrPool;
535 public:
536  AddItemToEntry(ScQueryEntry::QueryItemsType& rItems, svl::SharedStringPool& rPool) :
537  mrItems(rItems), mrPool(rPool) {}
538  void operator() (const ScCheckListMenuControl::ResultEntry& rEntry)
539  {
540  if (rEntry.bValid)
541  {
542  ScQueryEntry::Item aNew;
543  aNew.maString = mrPool.intern(rEntry.aName);
544  // set the filter type to ByValue, if the filter condition is value
546  aNew.mfVal = rEntry.nValue;
547  mrItems.push_back(aNew);
548  }
549  }
550 };
551 
552 class AddSelectedItemString
553 {
554  std::unordered_set<OUString>& mrSetString;
555  std::unordered_set<double>& mrSetValue;
556 public:
557  explicit AddSelectedItemString(std::unordered_set<OUString>& rString, std::unordered_set<double>& rValue) :
558  mrSetString(rString), mrSetValue(rValue) {}
559 
560  void operator() (const ScQueryEntry::Item& rItem)
561  {
562  if( rItem.meType == ScQueryEntry::QueryType::ByValue )
563  mrSetValue.insert(rItem.mfVal);
564  else
565  mrSetString.insert(rItem.maString.getString());
566  }
567 };
568 
569 void collectUIInformation(const OUString& aRow, const OUString& aCol , const OUString& aevent)
570 {
571  EventDescription aDescription;
572  aDescription.aAction = "LAUNCH";
573  aDescription.aID = "grid_window";
574  aDescription.aParameters = {{aevent, ""},
575  {"ROW", aRow}, {"COL", aCol}};
576  aDescription.aParent = "MainWindow";
577  aDescription.aKeyWord = "ScGridWinUIObject";
578 
579  UITestLogger::getInstance().logEvent(aDescription);
580 }
581 
582 }
583 
585 {
586  SCTAB nTab = mrViewData.GetTabNo();
588  bool bLOKActive = comphelper::LibreOfficeKit::isActive();
589 
591 
592  // Estimate the width (in pixels) of the longest text in the list
593  ScFilterEntries aFilterEntries;
594  rDoc.GetFilterEntries(nCol, nRow, nTab, aFilterEntries);
595 
596  vcl::ILibreOfficeKitNotifier* pNotifier = nullptr;
597  if (bLOKActive)
598  pNotifier = SfxViewShell::Current();
599 
600  int nColWidth = ScViewData::ToPixel(rDoc.GetColWidth(nCol, nTab), mrViewData.GetPPTX());
602  aFilterEntries.mbHasDates, nColWidth,
603  nullptr, pNotifier));
605 
606  int nMaxTextWidth = 0;
607  if (aFilterEntries.size() <= 10)
608  {
609  // do pixel calculation for all elements of short lists
610  for (const auto& rEntry : aFilterEntries)
611  {
612  const OUString& aText = rEntry.GetString();
613  nMaxTextWidth = std::max<int>(nMaxTextWidth, rControl.GetTextWidth(aText) + aText.getLength() * 2);
614  }
615  }
616  else
617  {
618  // find the longest string, probably it will be the longest rendered text, too
619  // (performance optimization for long lists)
620  auto itMax = aFilterEntries.begin();
621  for (auto it = itMax; it != aFilterEntries.end(); ++it)
622  {
623  int nTextWidth = it->GetString().getLength();
624  if (nMaxTextWidth < nTextWidth)
625  {
626  nMaxTextWidth = nTextWidth;
627  itMax = it;
628  }
629  }
630  nMaxTextWidth = rControl.GetTextWidth(itMax->GetString()) + nMaxTextWidth * 2;
631  }
632 
633  // window should be at least as wide as the column, or the longest text + checkbox, scrollbar ... (it is estimated with 70 pixel now)
634  // window should be maximum 1024 pixel wide.
635  int nWindowWidth = std::min<int>(1024, nMaxTextWidth + 70);
636  nWindowWidth = rControl.IncreaseWindowWidthToFitText(nWindowWidth);
637  nMaxTextWidth = std::max<int>(nMaxTextWidth, nWindowWidth - 70);
638 
639  rControl.setOKAction(new AutoFilterAction(this, AutoFilterMode::Normal));
640  rControl.setPopupEndAction(
641  new AutoFilterPopupEndAction(this, ScAddress(nCol, nRow, nTab)));
642  std::unique_ptr<AutoFilterData> pData(new AutoFilterData);
643  pData->maPos = ScAddress(nCol, nRow, nTab);
644 
645  Point aPos = mrViewData.GetScrPos(nCol, nRow, eWhich);
646  tools::Long nSizeX = 0;
647  tools::Long nSizeY = 0;
648  mrViewData.GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
649  if (bLOKActive)
650  {
651  // Reverse the zoom factor from aPos and nSize[X|Y]
652  // before letting the autofilter window convert the to twips
653  // with no zoom information.
654  double fZoomX(mrViewData.GetZoomX());
655  double fZoomY(mrViewData.GetZoomY());
656  aPos.setX(aPos.getX() / fZoomX);
657  aPos.setY(aPos.getY() / fZoomY);
658  nSizeX = nSizeX / fZoomX;
659  nSizeY = nSizeY / fZoomY;
660  }
661  tools::Rectangle aCellRect(OutputToScreenPixel(aPos), Size(nSizeX, nSizeY));
662 
663  ScDBData* pDBData = rDoc.GetDBAtCursor(nCol, nRow, nTab, ScDBDataPortion::AREA);
664  if (!pDBData)
665  return;
666 
667  pData->mpData = pDBData;
668  rControl.setExtendedData(std::move(pData));
669 
670  ScQueryParam aParam;
671  pDBData->GetQueryParam(aParam);
672  std::vector<ScQueryEntry*> aEntries = aParam.FindAllEntriesByField(nCol);
673  std::unordered_set<OUString> aSelectedString;
674  std::unordered_set<double> aSelectedValue;
675  bool bQueryByNonEmpty = aEntries.size() == 1 && aEntries[0]->IsQueryByNonEmpty();
676 
677  if (!bQueryByNonEmpty)
678  {
679  for (ScQueryEntry* pEntry : aEntries)
680  {
681  if (pEntry && pEntry->eOp == SC_EQUAL)
682  {
683  ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
684  std::for_each(rItems.begin(), rItems.end(), AddSelectedItemString(aSelectedString, aSelectedValue));
685  }
686  }
687  }
688 
689  // Populate the check box list.
690  rControl.setMemberSize(aFilterEntries.size());
691  for (auto it = aFilterEntries.begin(); it != aFilterEntries.end(); ++it)
692  {
693  // tdf#140745 show (empty) entry on top of the checkbox list
694  if (it->GetString().isEmpty())
695  {
696  const OUString& aStringVal = it->GetString();
697  const double aDoubleVal = it->GetValue();
698  bool bSelected = true;
699  if (!aSelectedValue.empty() || !aSelectedString.empty())
700  bSelected = aSelectedString.count(aStringVal) > 0;
701  else if (bQueryByNonEmpty)
702  bSelected = false;
703  rControl.addMember(aStringVal, aDoubleVal, bSelected);
704  aFilterEntries.maStrData.erase(it);
705  break;
706  }
707  }
708  for (const auto& rEntry : aFilterEntries)
709  {
710  const OUString& aStringVal = rEntry.GetString();
711  const double aDoubleVal = rEntry.GetValue();
712  const double aRDoubleVal = rEntry.GetRoundedValue();
713  bool bSelected = true;
714 
715  if (!aSelectedValue.empty() || !aSelectedString.empty())
716  {
717  if (aDoubleVal == aRDoubleVal)
718  bSelected = aSelectedValue.count(aDoubleVal) > 0 || aSelectedString.count(aStringVal) > 0;
719  else
720  bSelected = aSelectedValue.count(aDoubleVal) > 0 || aSelectedValue.count(aRDoubleVal) > 0 || aSelectedString.count(aStringVal) > 0;
721  }
722 
723  if ( rEntry.IsDate() )
724  rControl.addDateMember( aStringVal, rEntry.GetValue(), bSelected );
725  else
726  rControl.addMember( aStringVal, aRDoubleVal, bSelected, rEntry.GetStringType() == ScTypedStrData::Value );
727  }
728 
729  // Populate the menu.
730  rControl.addMenuItem(
731  ScResId(STR_MENU_SORT_ASC),
732  new AutoFilterAction(this, AutoFilterMode::SortAscending));
733  rControl.addMenuItem(
734  ScResId(STR_MENU_SORT_DESC),
735  new AutoFilterAction(this, AutoFilterMode::SortDescending));
736  rControl.addSeparator();
737  rControl.addMenuItem(
738  ScResId(SCSTR_TOP10FILTER), new AutoFilterAction(this, AutoFilterMode::Top10));
739  rControl.addMenuItem(
740  ScResId(SCSTR_FILTER_EMPTY), new AutoFilterAction(this, AutoFilterMode::Empty));
741  rControl.addMenuItem(
742  ScResId(SCSTR_FILTER_NOTEMPTY), new AutoFilterAction(this, AutoFilterMode::NonEmpty));
743  rControl.addSeparator();
744  rControl.addMenuItem(
745  ScResId(SCSTR_FILTER_TEXT_COLOR), new AutoFilterAction(this, AutoFilterMode::TextColor));
746  rControl.addMenuItem(
747  ScResId(SCSTR_FILTER_BACKGROUND_COLOR), new AutoFilterAction(this, AutoFilterMode::BackgroundColor));
748  rControl.addSeparator();
749  rControl.addMenuItem(
750  ScResId(SCSTR_STDFILTER), new AutoFilterAction(this, AutoFilterMode::Custom));
751  if (aEntries.size())
752  rControl.addMenuItem(
753  ScResId(SCSTR_CLEAR_FILTER), new AutoFilterAction(this, AutoFilterMode::Clear));
754 
755  rControl.initMembers(nMaxTextWidth + 20); // 20 pixel estimated for the checkbox
756 
758  aConfig.mbAllowEmptySet = false;
760  rControl.setConfig(aConfig);
761  if (IsMouseCaptured())
762  ReleaseMouse();
763  rControl.launch(aCellRect);
764 
765  // remember filter rules before modification
767 
768  collectUIInformation(OUString::number(nRow), OUString::number(nCol),"AUTOFILTER");
769 }
770 
772 {
773  if (mpFilterButton)
774  {
775  bool bFilterActive = IsAutoFilterActive(rPos.Col(), rPos.Row(), rPos.Tab());
776  mpFilterButton->setHasHiddenMember(bFilterActive);
777  mpFilterButton->setPopupPressed(false);
778  mpFilterButton->draw();
779  }
780 }
781 
783 {
785 
786  // Terminate autofilter popup now when there is no further user input needed
787  bool bColorMode = eMode == AutoFilterMode::TextColor || eMode == AutoFilterMode::BackgroundColor;
788  if (!bColorMode)
789  rControl.terminateAllPopupMenus();
790 
791  const AutoFilterData* pData =
792  static_cast<const AutoFilterData*>(rControl.getExtendedData());
793 
794  if (!pData)
795  return;
796 
797  const ScAddress& rPos = pData->maPos;
798  ScDBData* pDBData = pData->mpData;
799  if (!pDBData)
800  return;
801 
804  switch (eMode)
805  {
808  {
809  SCCOL nCol = rPos.Col();
810  ScSortParam aSortParam;
811  pDBData->GetSortParam(aSortParam);
812  if (nCol < aSortParam.nCol1 || nCol > aSortParam.nCol2)
813  // out of bound
814  return;
815 
816  bool bHasHeader = pDBData->HasHeader();
817 
818  aSortParam.bHasHeader = bHasHeader;
819  aSortParam.bByRow = true;
820  aSortParam.bCaseSens = false;
821  aSortParam.bNaturalSort = false;
822  aSortParam.bIncludeComments = false;
823  aSortParam.bIncludeGraphicObjects = true;
824  aSortParam.bIncludePattern = true;
825  aSortParam.bInplace = true;
826  aSortParam.maKeyState[0].bDoSort = true;
827  aSortParam.maKeyState[0].nField = nCol;
828  aSortParam.maKeyState[0].bAscending = (eMode == AutoFilterMode::SortAscending);
829 
830  for (size_t i = 1; i < aSortParam.GetSortKeyCount(); ++i)
831  aSortParam.maKeyState[i].bDoSort = false;
832 
833  mrViewData.GetViewShell()->UISort(aSortParam);
834  return;
835  }
837  {
838  ScRange aRange;
839  pDBData->GetArea(aRange);
840  mrViewData.GetView()->MarkRange(aRange);
841  mrViewData.GetView()->SetCursor(rPos.Col(), rPos.Row());
842  mrViewData.GetDispatcher().Execute(SID_FILTER, SfxCallMode::SLOT | SfxCallMode::RECORD);
843  return;
844  }
845  default:
846  ;
847  }
848 
849  ScQueryParam aParam;
850  pDBData->GetQueryParam(aParam);
851 
852  if (eMode == AutoFilterMode::Normal)
853  {
854  // Do not recreate autofilter rules if there are no changes from the user
856  rControl.getResult(aResult);
857 
858  if (aResult == aSaveAutoFilterResult)
859  {
860  SAL_INFO("sc.ui", "Apply autofilter to data when entries are the same");
861 
862  if (!rControl.isAllSelected())
863  {
864  // Apply autofilter to data
865  ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
866  pEntry->bDoQuery = true;
867  pEntry->nField = rPos.Col();
868  pEntry->eConnect = SC_AND;
869  pEntry->eOp = SC_EQUAL;
870  mrViewData.GetView()->Query(aParam, nullptr, true);
871  }
872 
873  return;
874  }
875  }
876 
877  // Remove old entries in auto-filter rules
878  if (!bColorMode)
879  {
880  aParam.RemoveAllEntriesByField(rPos.Col());
881 
882  // tdf#46184 reset filter options to default values
884  aParam.bCaseSens = false;
885  aParam.bDuplicate = true;
886  aParam.bInplace = true;
887  }
888 
889  if (eMode != AutoFilterMode::Clear
890  && !(eMode == AutoFilterMode::Normal && rControl.isAllSelected()))
891  {
892  // Try to use the existing entry for the column (if one exists).
893  ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
894 
895  if (!pEntry)
896  // Something went terribly wrong!
897  return;
898 
899  if (ScTabViewShell::isAnyEditViewInRange(mrViewData.GetViewShell(), /*bColumns*/ false, aParam.nRow1, aParam.nRow2))
900  return;
901 
902  pEntry->bDoQuery = true;
903  pEntry->nField = rPos.Col();
904  pEntry->eConnect = SC_AND;
905 
906  switch (eMode)
907  {
909  {
910  pEntry->eOp = SC_EQUAL;
911 
913  rControl.getResult(aResult);
914 
915  ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
916  rItems.clear();
917  std::for_each(aResult.begin(), aResult.end(), AddItemToEntry(rItems, rPool));
918  }
919  break;
921  pEntry->eOp = SC_TOPVAL;
923  pEntry->GetQueryItem().maString = rPool.intern("10");
924  break;
926  pEntry->SetQueryByEmpty();
927  break;
929  pEntry->SetQueryByNonEmpty();
930  break;
933  {
934  ScFilterEntries aFilterEntries;
935  rDoc.GetFilterEntries(rPos.Col(), rPos.Row(), rPos.Tab(), aFilterEntries);
936 
938  std::set<Color> aColors = eMode == AutoFilterMode::TextColor
939  ? aFilterEntries.getTextColors()
940  : aFilterEntries.getBackgroundColors();
941 
942  sal_Int32 i = 1;
943  sal_Int32 nActive = -1;
944  for (auto& rColor : aColors)
945  {
946  pColorMenu->InsertItem(i, OUString(), MenuItemBits::CHECKABLE);
947  pColorMenu->SetItemColor(i, rColor);
948  auto aItem = pEntry->GetQueryItem();
949  if (aItem.maColor == rColor
950  && ((eMode == AutoFilterMode::TextColor
951  && aItem.meType == ScQueryEntry::ByTextColor)
953  && aItem.meType == ScQueryEntry::ByBackgroundColor)))
954  {
955  nActive = i;
956  pColorMenu->CheckItem(i, true);
957  }
958  i++;
959  }
961  sal_uInt16 nSelected = pColorMenu->Execute(this, pos);
962  pColorMenu.disposeAndClear();
963  rControl.terminateAllPopupMenus();
964 
965  if (nSelected == 0)
966  return;
967 
968  // Disable color filter when active color was selected
969  if (nSelected == nActive)
970  {
971  aParam.RemoveAllEntriesByField(rPos.Col());
972 
973  // tdf#46184 reset filter options to default values
975  aParam.bCaseSens = false;
976  aParam.bDuplicate = true;
977  aParam.bInplace = true;
978  }
979 
980  // Get selected color from set
981  std::set<Color>::iterator it = aColors.begin();
982  std::advance(it, nSelected - 1);
983  Color selectedColor = *it;
984 
985  if (eMode == AutoFilterMode::TextColor)
986  pEntry->SetQueryByTextColor(selectedColor);
987  else
988  pEntry->SetQueryByBackgroundColor(selectedColor);
989  }
990 
991  break;
992  default:
993  // We don't know how to handle this!
994  return;
995  }
996  }
997 
998  mrViewData.GetView()->Query(aParam, nullptr, true);
999  pDBData->SetQueryParam(aParam);
1000 }
1001 
1002 namespace {
1003 
1004 void getCellGeometry(Point& rScrPos, Size& rScrSize, const ScViewData& rViewData, SCCOL nCol, SCROW nRow, ScSplitPos eWhich)
1005 {
1006  // Get the screen position of the cell.
1007  rScrPos = rViewData.GetScrPos(nCol, nRow, eWhich);
1008 
1009  // Get the screen size of the cell.
1010  tools::Long nSizeX, nSizeY;
1011  rViewData.GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
1012  rScrSize = Size(nSizeX-1, nSizeY-1);
1013 }
1014 
1015 }
1016 
1018 {
1019  if (nCol == 0)
1020  // We assume that the page field button is located in cell to the immediate left.
1021  return;
1022 
1023  SCTAB nTab = mrViewData.GetTabNo();
1024  ScDPObject* pDPObj = mrViewData.GetDocument().GetDPAtCursor(nCol, nRow, nTab);
1025  if (!pDPObj)
1026  return;
1027 
1028  Point aScrPos;
1029  Size aScrSize;
1030  getCellGeometry(aScrPos, aScrSize, mrViewData, nCol, nRow, eWhich);
1031  DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol-1, nRow, nTab), pDPObj);
1032 }
1033 
1035 {
1036  SCTAB nTab = mrViewData.GetTabNo();
1037  ScDPObject* pDPObj = mrViewData.GetDocument().GetDPAtCursor(nCol, nRow, nTab);
1038  if (!pDPObj)
1039  return;
1040 
1041  Point aScrPos;
1042  Size aScrSize;
1043  getCellGeometry(aScrPos, aScrSize, mrViewData, nCol, nRow, eWhich);
1044  DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol, nRow, nTab), pDPObj);
1045 }
1046 
1047 void ScGridWindow::ShowFilterMenu(weld::Window* pParent, const tools::Rectangle& rCellRect, bool bLayoutRTL)
1048 {
1049  auto nSizeX = rCellRect.GetWidth();
1050 
1051  // minimum width in pixel
1053  {
1054  const tools::Long nMinLOKWinWidth = o3tl::convert(STD_COL_WIDTH * 13 / 10, o3tl::Length::twip, o3tl::Length::px);
1055  if (nSizeX < nMinLOKWinWidth)
1056  nSizeX = nMinLOKWinWidth;
1057  }
1058 
1059  weld::TreeView& rFilterBox = mpFilterBox->get_widget();
1060  int nEntryCount = rFilterBox.n_children();
1061  if (nEntryCount > SC_FILTERLISTBOX_LINES)
1062  nEntryCount = SC_FILTERLISTBOX_LINES;
1063  auto nHeight = rFilterBox.get_height_rows(nEntryCount);
1064  rFilterBox.set_size_request(-1, nHeight);
1065  Size aSize(rFilterBox.get_preferred_size());
1066  auto nMaxToExpandTo = std::min(nSizeX, static_cast<decltype(nSizeX)>(300)); // do not over do it (Pixel)
1067  if (aSize.Width() < nMaxToExpandTo)
1068  aSize.setWidth(nMaxToExpandTo);
1069 
1070  aSize.AdjustWidth(4); // add a little margin
1071  nSizeX += 4;
1072  aSize.AdjustHeight(4);
1073 
1074  tools::Rectangle aCellRect(rCellRect);
1075  aCellRect.AdjustLeft(-2); // offset the little margin above
1076 
1077  if (!bLayoutRTL && aSize.Width() > nSizeX)
1078  {
1079  // move popup position
1080  tools::Long nDiff = aSize.Width() - nSizeX;
1081  tools::Long nNewX = aCellRect.Left() - nDiff;
1082  if ( nNewX < 0 )
1083  nNewX = 0;
1084  aCellRect.SetLeft( nNewX );
1085  }
1086 
1087  rFilterBox.set_size_request(aSize.Width(), aSize.Height());
1088 
1089  if (IsMouseCaptured())
1090  ReleaseMouse();
1091  mpFilterBox->popup_at_rect(pParent, aCellRect);
1092 }
1093 
1094 void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange )
1095 {
1096  bool bMenuAtTop = true;
1097 
1098  ScDocument& rDoc = mrViewData.GetDocument();
1099  mpFilterBox.reset();
1100 
1101  SCCOL nCol = rScenRange.aEnd.Col(); // Cell is below the Buttons
1102  SCROW nRow = rScenRange.aStart.Row();
1103  if (nRow == 0)
1104  {
1105  nRow = rScenRange.aEnd.Row() + 1; // Range at very the top -> Button below
1106  if (nRow>rDoc.MaxRow()) nRow = rDoc.MaxRow();
1107  bMenuAtTop = false;
1108  }
1109 
1110  SCTAB nTab = mrViewData.GetTabNo();
1111  bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1112 
1113  tools::Long nSizeX = 0;
1114  tools::Long nSizeY = 0;
1115  mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
1116  // The button height should not use the merged cell height, should still use single row height
1117  nSizeY = ScViewData::ToPixel(rDoc.GetRowHeight(nRow, nTab), mrViewData.GetPPTY());
1118  Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
1119  if ( bLayoutRTL )
1120  aPos.AdjustX( -nSizeX );
1121  tools::Rectangle aCellRect(aPos, Size(nSizeX, nSizeY));
1122  aCellRect.AdjustTop( -nSizeY );
1123  aCellRect.AdjustBottom( -(nSizeY - 1) );
1124  if (!bMenuAtTop)
1125  {
1126  Size aButSize = mrViewData.GetScenButSize();
1127  aCellRect.AdjustBottom(aButSize.Height());
1128  }
1129 
1130  // Place the ListBox directly below the black line of the cell grid
1131  // (It looks odd if the line gets hidden...)
1132 
1133  weld::Window* pParent = weld::GetPopupParent(*this, aCellRect);
1134  mpFilterBox = std::make_shared<ScFilterListBox>(pParent, this, nCol, nRow, ScFilterBoxMode::Scenario);
1135  mpFilterBox->connect_closed(LINK(this, ScGridWindow, PopupModeEndHdl));
1136  weld::TreeView& rFilterBox = mpFilterBox->get_widget();
1137  rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR
1138 
1139  // Listbox fill
1140  rFilterBox.freeze();
1141  OUString aCurrent;
1142  OUString aTabName;
1143  SCTAB nTabCount = rDoc.GetTableCount();
1144  SCTAB nEntryCount = 0;
1145  for (SCTAB i=nTab+1; i<nTabCount && rDoc.IsScenario(i); i++)
1146  {
1147  if (rDoc.HasScenarioRange( i, rScenRange ))
1148  if (rDoc.GetName( i, aTabName ))
1149  {
1150  rFilterBox.append_text(aTabName);
1151  if (rDoc.IsActiveScenario(i))
1152  aCurrent = aTabName;
1153  ++nEntryCount;
1154  }
1155  }
1156  rFilterBox.thaw();
1157 
1158  ShowFilterMenu(pParent, aCellRect, bLayoutRTL);
1159 
1160  rFilterBox.grab_focus();
1161 
1162  sal_Int32 nPos = -1;
1163  if (!aCurrent.isEmpty())
1164  {
1165  nPos = rFilterBox.find_text(aCurrent);
1166  }
1167  if (nPos == -1 && rFilterBox.n_children() > 0 )
1168  {
1169  nPos = 0;
1170  }
1171  if (nPos != -1)
1172  {
1173  rFilterBox.set_cursor(nPos);
1174  rFilterBox.select(nPos);
1175  }
1176  mpFilterBox->EndInit();
1177 }
1178 
1180 {
1181  mpFilterBox.reset();
1182 
1183  ScDocument& rDoc = mrViewData.GetDocument();
1184  SCTAB nTab = mrViewData.GetTabNo();
1185  bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1186 
1187  tools::Long nSizeX = 0;
1188  tools::Long nSizeY = 0;
1189  mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
1190  Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
1191  bool bLOKActive = comphelper::LibreOfficeKit::isActive();
1192 
1193  if (bLOKActive)
1194  {
1195  // aPos is now view-zoom adjusted and in pixels an more importantly this is pixel aligned to the view-zoom,
1196  // but once we use this to set the position of the floating window, it has no information of view-zoom level
1197  // so if we don't reverse the zoom now, a simple PixelToLogic(aPos, MapMode(MapUnit::MapTwip)) employed in
1198  // FloatingWindow::ImplCalcPos will produce a 'scaled' twips position which will again get zoom scaled in the
1199  // client (effective double scaling) causing wrong positioning/size.
1200  double fZoomX(mrViewData.GetZoomX());
1201  double fZoomY(mrViewData.GetZoomY());
1202  aPos.setX(aPos.getX() / fZoomX);
1203  aPos.setY(aPos.getY() / fZoomY);
1204  nSizeX = nSizeX / fZoomX;
1205  nSizeY = nSizeY / fZoomY;
1206  }
1207 
1208  if ( bLayoutRTL )
1209  aPos.AdjustX( -nSizeX );
1210  tools::Rectangle aCellRect(aPos, Size(nSizeX, nSizeY));
1211 
1212  weld::Window* pParent = weld::GetPopupParent(*this, aCellRect);
1213  mpFilterBox = std::make_shared<ScFilterListBox>(pParent, this, nCol, nRow, ScFilterBoxMode::DataSelect);
1214  mpFilterBox->connect_closed(LINK(this, ScGridWindow, PopupModeEndHdl));
1215  weld::TreeView& rFilterBox = mpFilterBox->get_widget();
1216  rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR
1217 
1218  // SetSize later
1219 
1220  bool bEmpty = false;
1221  std::vector<ScTypedStrData> aStrings; // case sensitive
1222  // Fill List
1223  rDoc.GetDataEntries(nCol, nRow, nTab, aStrings, true /* bValidation */);
1224  if (aStrings.empty())
1225  bEmpty = true;
1226 
1227  if (!bEmpty)
1228  {
1229  rFilterBox.freeze();
1230 
1231  // Fill Listbox
1232  bool bWait = aStrings.size() > 100;
1233 
1234  if (bWait)
1235  EnterWait();
1236 
1237  for (const auto& rString : aStrings)
1238  rFilterBox.append_text(rString.GetString());
1239 
1240  if (bWait)
1241  LeaveWait();
1242 
1243  rFilterBox.thaw();
1244 
1245  ShowFilterMenu(pParent, aCellRect, bLayoutRTL);
1246  }
1247 
1248  sal_Int32 nSelPos = -1;
1249 
1250  sal_uLong nIndex = rDoc.GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
1251  if ( nIndex )
1252  {
1253  const ScValidationData* pData = rDoc.GetValidationEntry( nIndex );
1254  if (pData)
1255  {
1256  std::unique_ptr<ScTypedStrData> pNew;
1257  OUString aDocStr = rDoc.GetString(nCol, nRow, nTab);
1258  if ( rDoc.HasValueData( nCol, nRow, nTab ) )
1259  {
1260  double fVal = rDoc.GetValue(ScAddress(nCol, nRow, nTab));
1261  pNew.reset(new ScTypedStrData(aDocStr, fVal, ScTypedStrData::Value));
1262  }
1263  else
1264  pNew.reset(new ScTypedStrData(aDocStr, 0.0, ScTypedStrData::Standard));
1265 
1266  if (pData->GetListType() == css::sheet::TableValidationVisibility::SORTEDASCENDING)
1267  {
1268  auto it = std::lower_bound(aStrings.begin(), aStrings.end(), *pNew, ScTypedStrData::LessCaseSensitive());
1269  if (it != aStrings.end() && ScTypedStrData::EqualCaseSensitive()(*it, *pNew))
1270  nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
1271  }
1272  else
1273  {
1274  auto it = std::find_if(aStrings.begin(), aStrings.end(), FindTypedStrData(*pNew, true));
1275  if (it != aStrings.end())
1276  nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
1277  }
1278  }
1279  }
1280 
1281  // Do not show an empty selection List:
1282 
1283  if ( bEmpty )
1284  {
1285  mpFilterBox.reset();
1286  }
1287  else
1288  {
1289  rFilterBox.grab_focus();
1290 
1291  // Select only after GrabFocus, so that the focus rectangle gets correct
1292  if (nSelPos != -1)
1293  {
1294  rFilterBox.set_cursor(nSelPos);
1295  rFilterBox.select(nSelPos);
1296  }
1297  else
1298  rFilterBox.unselect_all();
1299 
1300  mpFilterBox->EndInit();
1301  }
1302  collectUIInformation(OUString::number(nRow), OUString::number(nCol),"SELECTMENU");
1303 }
1304 
1306 {
1307  weld::TreeView& rFilterBox = mpFilterBox->get_widget();
1308  OUString aString = rFilterBox.get_text(static_cast<sal_Int32>(nSel));
1309 
1310  SCCOL nCol = mpFilterBox->GetCol();
1311  SCROW nRow = mpFilterBox->GetRow();
1312  switch (mpFilterBox->GetMode())
1313  {
1315  ExecDataSelect(nCol, nRow, aString);
1316  break;
1318  mrViewData.GetView()->UseScenario(aString);
1319  break;
1320  }
1321 
1322  if (mpFilterBox)
1323  mpFilterBox->popdown();
1324 
1325  GrabFocus(); // Otherwise the focus would be wrong on OS/2
1326 }
1327 
1328 void ScGridWindow::ExecDataSelect( SCCOL nCol, SCROW nRow, const OUString& rStr )
1329 {
1330  ScModule* pScMod = SC_MOD();
1331  ScInputHandler* pViewHdl = pScMod->GetInputHdl(mrViewData.GetViewShell());
1332  if (pViewHdl && mrViewData.HasEditView(mrViewData.GetActivePart()))
1333  pViewHdl->CancelHandler();
1334 
1335  SCTAB nTab = mrViewData.GetTabNo();
1336  ScViewFunc* pView = mrViewData.GetView();
1337  pView->EnterData( nCol, nRow, nTab, rStr );
1338 
1339  // #i52307# CellContentChanged is not in EnterData so it isn't called twice
1340  // if the cursor is moved afterwards.
1341  pView->CellContentChanged();
1342 }
1343 
1345 {
1346  if (nButtonDown)
1347  {
1348  rDestWin.nButtonDown = nButtonDown;
1349  rDestWin.nMouseStatus = nMouseStatus;
1350  }
1351 
1352  if (bRFMouse)
1353  {
1354  rDestWin.bRFMouse = bRFMouse;
1355  rDestWin.bRFSize = bRFSize;
1356  rDestWin.nRFIndex = nRFIndex;
1357  rDestWin.nRFAddX = nRFAddX;
1358  rDestWin.nRFAddY = nRFAddY;
1359  bRFMouse = false;
1360  }
1361 
1362  if (nPagebreakMouse)
1363  {
1364  rDestWin.nPagebreakMouse = nPagebreakMouse;
1365  rDestWin.nPagebreakBreak = nPagebreakBreak;
1366  rDestWin.nPagebreakPrev = nPagebreakPrev;
1368  rDestWin.aPagebreakDrag = aPagebreakDrag;
1370  }
1371 }
1372 
1373 bool ScGridWindow::TestMouse( const MouseEvent& rMEvt, bool bAction )
1374 {
1375  // MouseEvent buttons must only be checked if bAction==TRUE
1376  // to allow changing the mouse pointer in MouseMove,
1377  // but not start AutoFill with right button (#74229#).
1378  // with bAction==sal_True, SetFillMode / SetDragMode is called
1379 
1380  if ( bAction && !rMEvt.IsLeft() )
1381  return false;
1382 
1383  bool bNewPointer = false;
1384 
1386  bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() );
1387 
1388  if ( mrViewData.IsActive() && !bOleActive )
1389  {
1390  ScDocument& rDoc = mrViewData.GetDocument();
1391  SCTAB nTab = mrViewData.GetTabNo();
1392  bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
1393 
1394  // Auto-Fill
1395 
1396  ScRange aMarkRange;
1397  if (mrViewData.GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE)
1398  {
1399  if (aMarkRange.aStart.Tab() == mrViewData.GetTabNo() && mpAutoFillRect)
1400  {
1401  Point aMousePos = rMEvt.GetPosPixel();
1402  if (mpAutoFillRect->IsInside(aMousePos))
1403  {
1404  SetPointer( PointerStyle::Cross );
1405  if (bAction)
1406  {
1407  SCCOL nX = aMarkRange.aEnd.Col();
1408  SCROW nY = aMarkRange.aEnd.Row();
1409 
1410  if ( lcl_IsEditableMatrix( mrViewData.GetDocument(), aMarkRange ) )
1412  aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY, ScFillMode::MATRIX );
1413  else
1415  aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY );
1416 
1417  // The simple selection must also be recognized when dragging,
1418  // where the Marking flag is set and MarkToSimple won't work anymore.
1420  }
1421  bNewPointer = true;
1422  }
1423  }
1424  }
1425 
1426  // Embedded rectangle
1427 
1428  if (rDoc.IsEmbedded())
1429  {
1430  ScRange aRange;
1431  rDoc.GetEmbedded( aRange );
1432  if ( mrViewData.GetTabNo() == aRange.aStart.Tab() )
1433  {
1434  Point aStartPos = mrViewData.GetScrPos( aRange.aStart.Col(), aRange.aStart.Row(), eWhich );
1435  Point aEndPos = mrViewData.GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich );
1436  Point aMousePos = rMEvt.GetPosPixel();
1437  if ( bLayoutRTL )
1438  {
1439  aStartPos.AdjustX(2 );
1440  aEndPos.AdjustX(2 );
1441  }
1442  bool bTop = ( aMousePos.X() >= aStartPos.X()-3 && aMousePos.X() <= aStartPos.X()+1 &&
1443  aMousePos.Y() >= aStartPos.Y()-3 && aMousePos.Y() <= aStartPos.Y()+1 );
1444  bool bBottom = ( aMousePos.X() >= aEndPos.X()-3 && aMousePos.X() <= aEndPos.X()+1 &&
1445  aMousePos.Y() >= aEndPos.Y()-3 && aMousePos.Y() <= aEndPos.Y()+1 );
1446  if ( bTop || bBottom )
1447  {
1448  SetPointer( PointerStyle::Cross );
1449  if (bAction)
1450  {
1453  aRange.aStart.Col(), aRange.aStart.Row(),
1454  aRange.aEnd.Col(), aRange.aEnd.Row(), nMode );
1455  }
1456  bNewPointer = true;
1457  }
1458  }
1459  }
1460  }
1461 
1462  if (!bNewPointer && bAction)
1463  {
1465  }
1466 
1467  return bNewPointer;
1468 }
1469 
1471 {
1472  MouseButtonDown(rMouseEvent);
1473 }
1474 
1476 {
1477  MouseButtonUp(rMouseEvent);
1478 }
1479 
1481 {
1482  MouseMove(rMouseEvent);
1483 }
1484 
1486 {
1487  if (SfxLokHelper::getDeviceFormFactor() == LOKDeviceFormFactor::MOBILE)
1488  {
1489  ScViewFunc* pView = mrViewData.GetView();
1490  ScTabViewShell* pViewShell = mrViewData.GetViewShell();
1491  bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
1492 
1493  Point aPos(rMEvt.GetPosPixel());
1494  SCCOL nPosX;
1495  SCROW nPosY;
1496  mrViewData.GetPosFromPixel(aPos.X(), aPos.Y(), eWhich, nPosX, nPosY);
1497 
1498  if (bRefMode && pView->GetFunctionSet().CheckRefBounds(nPosX, nPosY))
1499  return;
1500  }
1501 
1503 
1504  MouseEventState aState;
1505  HandleMouseButtonDown(rMEvt, aState);
1506  if (aState.mbActivatePart)
1507  mrViewData.GetView()->ActivatePart(eWhich);
1508 
1510  {
1511  // #i41690# If an object is deactivated from MouseButtonDown, it might reschedule,
1512  // so MouseButtonUp comes before the MouseButtonDown call is finished. In this case,
1513  // simulate another MouseButtonUp call, so the selection state is consistent.
1514 
1515  nButtonDown = rMEvt.GetButtons();
1516  FakeButtonUp();
1517 
1518  if ( IsTracking() )
1519  EndTracking(); // normally done in VCL as part of MouseButtonUp handling
1520  }
1522 }
1523 
1524 bool ScGridWindow::IsCellCoveredByText(SCCOL nPosX, SCROW nPosY, SCTAB nTab, SCCOL &rTextStartPosX)
1525 {
1526  ScDocument& rDoc = mrViewData.GetDocument();
1527 
1528  // find the first non-empty cell (this, or to the left)
1529  SCCOL nNonEmptyX = nPosX;
1530  for (; nNonEmptyX >= 0; --nNonEmptyX)
1531  {
1532  ScRefCellValue aCell(rDoc, ScAddress(nNonEmptyX, nPosY, nTab));
1533  if (!aCell.isEmpty())
1534  break;
1535  }
1536 
1537  // the initial cell already contains text
1538  if (nNonEmptyX == nPosX)
1539  {
1540  rTextStartPosX = nNonEmptyX;
1541  return true;
1542  }
1543 
1544  // to the left, there is no cell that would contain (potentially
1545  // overrunning) text
1546  if (nNonEmptyX < 0 || rDoc.HasAttrib(nNonEmptyX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped))
1547  return false;
1548 
1549  double nPPTX = mrViewData.GetPPTX();
1550  double nPPTY = mrViewData.GetPPTY();
1551 
1552  ScTableInfo aTabInfo;
1553  rDoc.FillInfo(aTabInfo, 0, nPosY, nPosX, nPosY, nTab, nPPTX, nPPTY, false, false);
1554 
1555  Fraction aZoomX = mrViewData.GetZoomX();
1556  Fraction aZoomY = mrViewData.GetZoomY();
1557  ScOutputData aOutputData(GetOutDev(), OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
1558  0, 0, 0, nPosY, nPosX, nPosY, nPPTX, nPPTY,
1559  &aZoomX, &aZoomY);
1560 
1561  MapMode aCurrentMapMode(GetMapMode());
1562  SetMapMode(MapMode(MapUnit::MapPixel));
1563 
1564  // obtain the bounding box of the text in first non-empty cell
1565  // to the left
1566  tools::Rectangle aRect(aOutputData.LayoutStrings(false, false, ScAddress(nNonEmptyX, nPosY, nTab)));
1567 
1568  SetMapMode(aCurrentMapMode);
1569 
1570  // the text does not overrun from the cell
1571  if (aRect.IsEmpty())
1572  return false;
1573 
1574  SCCOL nTextEndX;
1575  SCROW nTextEndY;
1576 
1577  // test the rightmost position of the text bounding box
1578  tools::Long nMiddle = (aRect.Top() + aRect.Bottom()) / 2;
1579  mrViewData.GetPosFromPixel(aRect.Right(), nMiddle, eWhich, nTextEndX, nTextEndY);
1580  if (nTextEndX >= nPosX)
1581  {
1582  rTextStartPosX = nNonEmptyX;
1583  return true;
1584  }
1585 
1586  return false;
1587 }
1588 
1590 {
1591  // We have to check if a context menu is shown and we have an UI
1592  // active inplace client. In that case we have to ignore the event.
1593  // Otherwise we would crash (context menu has been
1594  // opened by inplace client and we would deactivate the inplace client,
1595  // the context menu is closed by VCL asynchronously which in the end
1596  // would work on deleted objects or the context menu has no parent anymore)
1597  SfxViewShell* pViewSh = mrViewData.GetViewShell();
1598  SfxInPlaceClient* pClient = pViewSh->GetIPClient();
1599  if ( pClient &&
1600  pClient->IsObjectInPlaceActive() &&
1602  return;
1603 
1604  aCurMousePos = rMEvt.GetPosPixel();
1605 
1606  // Filter popup is ended with its own mouse click, not when clicking into the Grid Window,
1607  // so the following query is no longer necessary:
1608  ClickExtern(); // deletes FilterBox when available
1609 
1610  HideNoteMarker();
1611 
1612  bEEMouse = false;
1613 
1614  ScModule* pScMod = SC_MOD();
1615  if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
1616  return;
1617 
1618  pScActiveViewShell = mrViewData.GetViewShell(); // if left is clicked
1619  nScClickMouseModifier = rMEvt.GetModifier(); // to always catch a control click
1620 
1621  bool bDetective = mrViewData.GetViewShell()->IsAuditShell();
1622  bool bRefMode = mrViewData.IsRefMode(); // Start reference
1623  bool bFormulaMode = pScMod->IsFormulaMode(); // next click -> reference
1624  bool bEditMode = mrViewData.HasEditView(eWhich); // also in Mode==SC_INPUT_TYPE
1625  bool bDouble = (rMEvt.GetClicks() == 2);
1626  ScDocument& rDoc = mrViewData.GetDocument();
1627  bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
1628 
1629  // DeactivateIP does only happen when MarkListHasChanged
1630 
1631  // An error message can show up during GrabFocus call
1632  // (for instance when renaming tables per sheet title)
1633 
1634  if ( !nButtonDown || !bDouble ) // single (first) click is always valid
1635  nButtonDown = rMEvt.GetButtons(); // set nButtonDown first, so StopMarking works
1636 
1637  // special handling of empty cells with tiled rendering
1638  if (bIsTiledRendering)
1639  {
1640  Point aPos(rMEvt.GetPosPixel());
1641  SCCOL nPosX, nNonEmptyX(0);
1642  SCROW nPosY;
1643  SCTAB nTab = mrViewData.GetTabNo();
1644  mrViewData.GetPosFromPixel(aPos.X(), aPos.Y(), eWhich, nPosX, nPosY);
1645 
1646  ScRefCellValue aCell(rDoc, ScAddress(nPosX, nPosY, nTab));
1647  bool bIsEmpty = aCell.isEmpty();
1648  bool bIsCoveredByText = bIsEmpty && IsCellCoveredByText(nPosX, nPosY, nTab, nNonEmptyX);
1649 
1650  if (bIsCoveredByText)
1651  {
1652  // if there's any text flowing to this cell, activate the
1653  // editengine, so that the text actually gets the events
1654  if (bDouble)
1655  {
1656  ScViewFunc* pView = mrViewData.GetView();
1657 
1658  pView->SetCursor(nNonEmptyX, nPosY);
1659  SC_MOD()->SetInputMode(SC_INPUT_TABLE);
1660 
1661  bEditMode = mrViewData.HasEditView(eWhich);
1662  assert(bEditMode);
1663 
1664  // synthesize the 1st click
1665  EditView* pEditView = mrViewData.GetEditView(eWhich);
1666  MouseEvent aEditEvt(rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0);
1667  pEditView->MouseButtonDown(aEditEvt);
1668  pEditView->MouseButtonUp(aEditEvt);
1669  }
1670  }
1671  else if (bIsEmpty && bEditMode && bDouble)
1672  {
1673  // double-click in an empty cell: the entire cell is selected
1674  SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aPos.X(), aPos.Y());
1675  SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aPos.X(), aPos.Y());
1676  return;
1677  }
1678  }
1679 
1680  if ( ( bEditMode && mrViewData.GetActivePart() == eWhich ) || !bFormulaMode )
1681  GrabFocus();
1682 
1683  // #i31846# need to cancel a double click if the first click has set the "ignore" state,
1684  // but a single (first) click is always valid
1685  if ( nMouseStatus == SC_GM_IGNORE && bDouble )
1686  {
1687  nButtonDown = 0;
1689  return;
1690  }
1691 
1692  if ( bDetective ) // Detectiv fill mode
1693  {
1694  if ( rMEvt.IsLeft() && !rMEvt.GetModifier() )
1695  {
1696  Point aPos = rMEvt.GetPosPixel();
1697  SCCOL nPosX;
1698  SCROW nPosY;
1699  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1700 
1701  SfxInt16Item aPosXItem( SID_RANGE_COL, nPosX );
1702  SfxInt32Item aPosYItem( SID_RANGE_ROW, nPosY );
1703  mrViewData.GetDispatcher().ExecuteList(SID_FILL_SELECT,
1704  SfxCallMode::SLOT | SfxCallMode::RECORD,
1705  { &aPosXItem, &aPosYItem });
1706 
1707  }
1708  nButtonDown = 0;
1710  return;
1711  }
1712 
1713  if (!bDouble)
1715 
1716  rState.mbActivatePart = !bFormulaMode; // Don't activate when in formula mode.
1717 
1718  if (bFormulaMode)
1719  {
1721  pSelEng->SetWindow(this);
1722  pSelEng->SetWhich(eWhich);
1724  }
1725 
1726  if (bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo()))
1727  {
1728  Point aPos = rMEvt.GetPosPixel();
1729  SCCOL nPosX;
1730  SCROW nPosY;
1731  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1732 
1733  EditView* pEditView;
1734  SCCOL nEditCol;
1735  SCROW nEditRow;
1736  mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
1737  SCCOL nEndCol = mrViewData.GetEditEndCol();
1738  SCROW nEndRow = mrViewData.GetEditEndRow();
1739 
1740  if ( nPosX >= nEditCol && nPosX <= nEndCol &&
1741  nPosY >= nEditRow && nPosY <= nEndRow )
1742  {
1743  // when clicking in the table EditView, always reset the focus
1744  if (bFormulaMode) // otherwise this has already happen above
1745  GrabFocus();
1746 
1747  pScMod->SetInputMode( SC_INPUT_TABLE );
1748  bEEMouse = true;
1749  pEditView->MouseButtonDown( rMEvt );
1750  return;
1751  }
1752  }
1753 
1754  if (pScMod->GetIsWaterCan())
1755  {
1757  if ( rMEvt.GetModifier() + rMEvt.GetButtons() == MOUSE_RIGHT )
1758  {
1760  return;
1761  }
1762  }
1763 
1764  // Order that matches the displayed Cursor:
1765  // RangeFinder, AutoFill, PageBreak, Drawing
1766 
1767  RfCorner rCorner = NONE;
1768  bool bFound = HitRangeFinder(rMEvt.GetPosPixel(), rCorner, &nRFIndex, &nRFAddX, &nRFAddY);
1769  bRFSize = (rCorner != NONE);
1770  aRFSelectedCorned = rCorner;
1771 
1772  if (bFound)
1773  {
1774  bRFMouse = true; // the other variables are initialized above
1775 
1776  rState.mbActivatePart = true; // always activate ?
1777  StartTracking();
1778  return;
1779  }
1780 
1781  bool bCrossPointer = TestMouse( rMEvt, true );
1782  if ( bCrossPointer )
1783  {
1784  if ( bDouble )
1786  else
1787  pScMod->InputEnterHandler(); // Autofill etc.
1788  }
1789 
1790  if ( !bCrossPointer )
1791  {
1794  if (nPagebreakMouse)
1795  {
1796  bPagebreakDrawn = false;
1797  StartTracking();
1798  PagebreakMove( rMEvt, false );
1799  return;
1800  }
1801  }
1802 
1803  // in the tiled rendering case, single clicks into drawing objects take
1804  // precedence over bEditMode
1805  if (((!bFormulaMode && !bEditMode) || bIsTiledRendering) && rMEvt.IsLeft())
1806  {
1807  if ( !bCrossPointer && DrawMouseButtonDown(rMEvt) )
1808  {
1809  return;
1810  }
1811 
1812  mrViewData.GetViewShell()->SetDrawShell( false ); // no Draw-object selected
1813 
1814  // TestMouse has already happened above
1815  }
1816 
1817  Point aPos = rMEvt.GetPosPixel();
1818  SCCOL nPosX;
1819  SCROW nPosY;
1820  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1821  SCTAB nTab = mrViewData.GetTabNo();
1822 
1823  // FIXME: this is to limit the number of rows handled in the Online
1824  // to 1000; this will be removed again when the performance
1825  // bottlenecks are sorted out
1826  if ( comphelper::LibreOfficeKit::isActive() && nPosY > MAXTILEDROW - 1 )
1827  {
1828  nButtonDown = 0;
1830  return;
1831  }
1832 
1833  // Auto filter / pivot table / data select popup. This shouldn't activate the part.
1834 
1835  if ( !bDouble && !bFormulaMode && rMEvt.IsLeft() )
1836  {
1837  SCCOL nRealPosX;
1838  SCROW nRealPosY;
1839  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nRealPosX, nRealPosY, false );//the real row/col
1840 
1841  // show in the merged cells the filter of the first cell (nPosX instead of nRealPosX)
1842  const ScMergeFlagAttr* pRealPosAttr = rDoc.GetAttr(nPosX, nRealPosY, nTab, ATTR_MERGE_FLAG);
1843  if( pRealPosAttr->HasAutoFilter() )
1844  {
1845  SC_MOD()->InputEnterHandler();
1846  if (DoAutoFilterButton(nPosX, nRealPosY, rMEvt))
1847  return;
1848  }
1849 
1850  const ScMergeFlagAttr* pAttr = rDoc.GetAttr(nPosX, nPosY, nTab, ATTR_MERGE_FLAG);
1851  if (pAttr->HasAutoFilter())
1852  {
1853  if (DoAutoFilterButton(nPosX, nPosY, rMEvt))
1854  {
1855  rState.mbActivatePart = false;
1856  return;
1857  }
1858  }
1859 
1860  if (pAttr->HasPivotButton() || pAttr->HasPivotPopupButton())
1861  {
1862  DoPushPivotButton(nPosX, nPosY, rMEvt, pAttr->HasPivotButton(), pAttr->HasPivotPopupButton());
1863  rState.mbActivatePart = false;
1864  return;
1865  }
1866 
1867  // List Validity drop-down button
1868 
1869  if ( bListValButton )
1870  {
1872  if ( aButtonRect.IsInside( aPos ) )
1873  {
1874  // tdf#125917 typically we have the mouse captured already, except if are editing the cell.
1875  // Ensure its captured before the menu is launched even in the cell editing case
1876  CaptureMouse();
1877 
1879 
1880  nMouseStatus = SC_GM_FILTER; // not set in DoAutoFilterMenue for bDataSelect
1881  rState.mbActivatePart = false;
1882  return;
1883  }
1884  }
1885  }
1886 
1887  // scenario selection
1888 
1889  ScRange aScenRange;
1890  if ( rMEvt.IsLeft() && HasScenarioButton( aPos, aScenRange ) )
1891  {
1892  CaptureMouse();
1893 
1894  DoScenarioMenu( aScenRange );
1895 
1896  // Scenario selection comes from MouseButtonDown:
1897  // The next MouseMove on the FilterBox is like a ButtonDown
1899  return;
1900  }
1901 
1902  // double click started ?
1903 
1904  // StopMarking can be called from DrawMouseButtonDown
1905 
1906  if ( nMouseStatus != SC_GM_IGNORE && !bRefMode )
1907  {
1908  if ( bDouble && !bCrossPointer )
1909  {
1910  if (nMouseStatus == SC_GM_TABDOWN)
1912  }
1913  else
1915  }
1916 
1917  // links in the edit cell
1918 
1919  bool bAlt = rMEvt.IsMod2();
1920  if ( !bAlt && rMEvt.IsLeft() && ScGlobal::ShouldOpenURL() &&
1921  GetEditUrl(rMEvt.GetPosPixel()) ) // click on link: do not move cursor
1922  {
1923  SetPointer( PointerStyle::RefHand );
1924  nMouseStatus = SC_GM_URLDOWN; // also only execute when ButtonUp
1925  return;
1926  }
1927 
1928  // Gridwin - Selection Engine
1929 
1930  if ( !rMEvt.IsLeft() )
1931  return;
1932 
1934  pSelEng->SetWindow(this);
1935  pSelEng->SetWhich(eWhich);
1937 
1938  // SelMouseButtonDown on the View is still setting the bMoveIsShift flag
1939  if ( mrViewData.GetView()->SelMouseButtonDown( rMEvt ) )
1940  {
1941  if (IsMouseCaptured())
1942  {
1943  // Tracking instead of CaptureMouse, so it can be canceled cleanly
1945  ReleaseMouse();
1946  StartTracking();
1947  }
1949  return;
1950  }
1951 }
1952 
1954 {
1955  aCurMousePos = rMEvt.GetPosPixel();
1956  ScDocument& rDoc = mrViewData.GetDocument();
1957  ScMarkData& rMark = mrViewData.GetMarkData();
1958  // #i41690# detect a MouseButtonUp call from within MouseButtonDown
1959  // (possible through Reschedule from storing an OLE object that is deselected)
1960 
1963 
1964  if (nButtonDown != rMEvt.GetButtons())
1965  nMouseStatus = SC_GM_IGNORE; // reset and return
1966 
1967  nButtonDown = 0;
1968 
1969  if (nMouseStatus == SC_GM_IGNORE)
1970  {
1972  // Selection engine: cancel selection
1974  rMark.SetMarking(false);
1975  if (mrViewData.IsAnyFillMode())
1976  {
1979  }
1980  StopMarking();
1981  DrawEndAction(); // cancel selection/moving in drawing layer
1982  ReleaseMouse();
1983  return;
1984  }
1985 
1986  if (nMouseStatus == SC_GM_FILTER)
1987  {
1989  ReleaseMouse();
1990  return; // nothing more should happen here
1991  }
1992 
1993  ScModule* pScMod = SC_MOD();
1994  if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
1995  return;
1996 
1997  SfxBindings& rBindings = mrViewData.GetBindings();
1998  if (bEEMouse && mrViewData.HasEditView( eWhich ))
1999  {
2000  EditView* pEditView;
2001  SCCOL nEditCol;
2002  SCROW nEditRow;
2003  mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2004  pEditView->MouseButtonUp( rMEvt );
2005 
2006  if ( rMEvt.IsMiddle() &&
2007  GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
2008  {
2009  // EditView may have pasted from selection
2010  pScMod->InputChanged( pEditView );
2011  }
2012  else
2013  pScMod->InputSelection( pEditView ); // parentheses etc.
2014 
2016  rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2017  bEEMouse = false;
2018  return;
2019  }
2020 
2021  if (bDPMouse)
2022  {
2023  DPMouseButtonUp( rMEvt ); // resets bDPMouse
2024  return;
2025  }
2026 
2027  if (bRFMouse)
2028  {
2029  RFMouseMove( rMEvt, true ); // Again the proper range
2030  bRFMouse = false;
2031  SetPointer( PointerStyle::Arrow );
2032  ReleaseMouse();
2033  return;
2034  }
2035 
2036  if (nPagebreakMouse)
2037  {
2038  PagebreakMove( rMEvt, true );
2040  SetPointer( PointerStyle::Arrow );
2041  ReleaseMouse();
2042  return;
2043  }
2044 
2045  if (nMouseStatus == SC_GM_WATERUNDO) // Undo in format paintbrush mode
2046  {
2048  if ( pMgr->GetUndoActionCount() && dynamic_cast<ScUndoSelectionStyle*>(pMgr->GetUndoAction()) )
2049  pMgr->Undo();
2050  return;
2051  }
2052 
2053  if (DrawMouseButtonUp(rMEvt)) // includes format paint brush handling for drawing objects
2054  {
2055  ScTabViewShell* pViewShell = mrViewData.GetViewShell();
2056  SfxBindings& rFrmBindings=pViewShell->GetViewFrame()->GetBindings();
2057  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_WIDTH);
2058  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_HEIGHT);
2059  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_X);
2060  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_Y);
2061  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ANGLE);
2062  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_X);
2063  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_Y);
2064  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOWIDTH);
2065  rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOHEIGHT);
2066  return;
2067  }
2068 
2069  rMark.SetMarking(false);
2070 
2071  SetPointer( mrViewData.IsThemedCursor() ? PointerStyle::FatCross : PointerStyle::Arrow );
2072 
2073  if (mrViewData.IsFillMode() ||
2074  ( mrViewData.GetFillMode() == ScFillMode::MATRIX && rMEvt.IsMod1() ))
2075  {
2077  SCCOL nStartCol;
2078  SCROW nStartRow;
2079  SCCOL nEndCol;
2080  SCROW nEndRow;
2081  mrViewData.GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
2082  ScRange aDelRange;
2083  bool bIsDel = mrViewData.GetDelMark( aDelRange );
2084 
2085  ScViewFunc* pView = mrViewData.GetView();
2086  pView->StopRefMode();
2088  pView->GetFunctionSet().SetAnchorFlag( false ); // #i5819# don't use AutoFill anchor flag for selection
2089 
2090  if ( bIsDel )
2091  {
2092  pView->MarkRange( aDelRange, false );
2094  SCTAB nTab = mrViewData.GetTabNo();
2095  ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
2096  if ( aBlockRange != aDelRange )
2097  {
2098  if ( aDelRange.aStart.Row() == nStartRow )
2099  aBlockRange.aEnd.SetCol( aDelRange.aStart.Col() - 1 );
2100  else
2101  aBlockRange.aEnd.SetRow( aDelRange.aStart.Row() - 1 );
2102  pView->MarkRange( aBlockRange, false );
2103  }
2104  }
2105  else
2106  mrViewData.GetDispatcher().Execute( FID_FILL_AUTO, SfxCallMode::SLOT | SfxCallMode::RECORD );
2107  }
2109  {
2110  SCTAB nTab = mrViewData.GetTabNo();
2111  SCCOL nStartCol;
2112  SCROW nStartRow;
2113  SCCOL nEndCol;
2114  SCROW nEndRow;
2115  mrViewData.GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
2116  ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
2117  SCCOL nFillCol = mrViewData.GetRefEndX();
2118  SCROW nFillRow = mrViewData.GetRefEndY();
2119  ScAddress aEndPos( nFillCol, nFillRow, nTab );
2120 
2121  ScTabView* pView = mrViewData.GetView();
2122  pView->StopRefMode();
2124  pView->GetFunctionSet().SetAnchorFlag( false );
2125 
2126  if ( aEndPos != aBlockRange.aEnd )
2127  {
2128  mrViewData.GetDocShell()->GetDocFunc().ResizeMatrix( aBlockRange, aEndPos );
2129  mrViewData.GetView()->MarkRange( ScRange( aBlockRange.aStart, aEndPos ) );
2130  }
2131  }
2132  else if (mrViewData.IsAnyFillMode())
2133  {
2134  // Embedded area has been changed
2135  ScTabView* pView = mrViewData.GetView();
2136  pView->StopRefMode();
2138  pView->GetFunctionSet().SetAnchorFlag( false );
2140  }
2141 
2142  bool bRefMode = mrViewData.IsRefMode();
2143  if (bRefMode)
2144  pScMod->EndReference();
2145 
2146  // Format paintbrush mode (Switch)
2147 
2148  if (pScMod->GetIsWaterCan())
2149  {
2150  // Check on undo already done above
2151 
2152  ScStyleSheetPool* pStylePool = mrViewData.GetDocument().
2153  GetStyleSheetPool();
2154  if ( pStylePool )
2155  {
2156  SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(
2157  pStylePool->GetActualStyleSheet());
2158 
2159  if ( pStyleSheet )
2160  {
2161  SfxStyleFamily eFamily = pStyleSheet->GetFamily();
2162 
2163  switch ( eFamily )
2164  {
2165  case SfxStyleFamily::Para:
2166  mrViewData.GetView()->SetStyleSheetToMarked( pStyleSheet );
2168  break;
2169 
2170  case SfxStyleFamily::Page:
2172  pStyleSheet->GetName() );
2173 
2176  mrViewData.GetTabNo() ).UpdatePages();
2177 
2178  rBindings.Invalidate( SID_STATUS_PAGESTYLE );
2179  break;
2180 
2181  default:
2182  break;
2183  }
2184  }
2185  }
2186  }
2187 
2188  ScDBFunc* pView = mrViewData.GetView();
2189  ScDocument* pBrushDoc = pView->GetBrushDocument();
2190  if ( pBrushDoc )
2191  {
2192  pView->PasteFromClip( InsertDeleteFlags::ATTRIB, pBrushDoc );
2193  if ( !pView->IsPaintBrushLocked() )
2194  pView->ResetBrushDocument(); // invalidates pBrushDoc pointer
2195  }
2196 
2197  Point aPos = rMEvt.GetPosPixel();
2198  SCCOL nPosX;
2199  SCROW nPosY;
2200  SCTAB nTab = mrViewData.GetTabNo();
2201  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2202  ScDPObject* pDPObj = rDoc.GetDPAtCursor( nPosX, nPosY, nTab );
2203 
2204  bool bInDataPilotTable = (pDPObj != nullptr);
2205 
2206  // double click (only left button)
2207  // in the tiled rendering case, single click works this way too
2208 
2209  bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
2210  bool bDouble = ( rMEvt.GetClicks() == 2 && rMEvt.IsLeft() );
2211  if ((bDouble || (bIsTiledRendering && !bInDataPilotTable))
2212  && !bRefMode
2213  && (nMouseStatus == SC_GM_DBLDOWN || (bIsTiledRendering && nMouseStatus != SC_GM_URLDOWN))
2214  && !pScMod->IsRefDialogOpen())
2215  {
2216  // data pilot table
2217  if ( pDPObj && pDPObj->GetSaveData()->GetDrillDown() )
2218  {
2219  ScAddress aCellPos( nPosX, nPosY, mrViewData.GetTabNo() );
2220 
2221  // Check for header drill-down first.
2222  sheet::DataPilotTableHeaderData aData;
2223  pDPObj->GetHeaderPositionData(aCellPos, aData);
2224 
2225  if ( ( aData.Flags & sheet::MemberResultFlags::HASMEMBER ) &&
2226  ! ( aData.Flags & sheet::MemberResultFlags::SUBTOTAL ) )
2227  {
2228  css::sheet::DataPilotFieldOrientation nDummy;
2229  if ( pView->HasSelectionForDrillDown( nDummy ) )
2230  {
2231  // execute slot to show dialog
2232  mrViewData.GetDispatcher().Execute( SID_OUTLINE_SHOW, SfxCallMode::SLOT | SfxCallMode::RECORD );
2233  }
2234  else
2235  {
2236  // toggle single entry
2237  ScDPObject aNewObj( *pDPObj );
2238  pDPObj->ToggleDetails( aData, &aNewObj );
2239  ScDBDocFunc aFunc( *mrViewData.GetDocShell() );
2240  aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
2241  mrViewData.GetView()->CursorPosChanged(); // shells may be switched
2242  }
2243  }
2244  else
2245  {
2246  // Check if the data area is double-clicked.
2247 
2248  Sequence<sheet::DataPilotFieldFilter> aFilters;
2249  if ( pDPObj->GetDataFieldPositionData(aCellPos, aFilters) )
2250  mrViewData.GetView()->ShowDataPilotSourceData( *pDPObj, aFilters );
2251  }
2252 
2253  return;
2254  }
2255 
2256  // Check for cell protection attribute.
2257  const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
2258  bool bEditAllowed = true;
2259  if ( pProtect && pProtect->isProtected() )
2260  {
2261  bool bCellProtected = rDoc.HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Protected);
2262  bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
2263  bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
2264 
2265  if ( bSkipProtected && bSkipUnprotected )
2266  bEditAllowed = false;
2267  else if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
2268  bEditAllowed = false;
2269  }
2270 
2271  // We don't want to activate the edit view for a single click in tiled rendering
2272  // (but we should probably keep the same behaviour for double clicks).
2273  if ( bEditAllowed && (!bIsTiledRendering || bDouble) )
2274  {
2275  // don't forward the event to an empty cell, causes deselection in
2276  // case we used the double-click to select the empty cell
2277  if (bIsTiledRendering && bDouble)
2278  {
2279  ScRefCellValue aCell(mrViewData.GetDocument(), ScAddress(nPosX, nPosY, nTab));
2280  if (aCell.isEmpty())
2281  return;
2282  }
2283 
2284  // edit cell contents
2286  pScMod->SetInputMode( SC_INPUT_TABLE );
2287  if (mrViewData.HasEditView(eWhich))
2288  {
2289  // Set text cursor where clicked
2290  EditView* pEditView = mrViewData.GetEditView( eWhich );
2291  MouseEvent aEditEvt( rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0 );
2292  pEditView->MouseButtonDown( aEditEvt );
2293  pEditView->MouseButtonUp( aEditEvt );
2294  }
2295  }
2296 
2297  if ( bIsTiledRendering && rMEvt.IsLeft() && mrViewData.GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt ) )
2298  {
2300  }
2301 
2302  if ( bDouble )
2303  return;
2304  }
2305 
2306  // Links in edit cells
2307 
2308  bool bAlt = rMEvt.IsMod2();
2309  if ( !bAlt && !bRefMode && !bDouble && nMouseStatus == SC_GM_URLDOWN )
2310  {
2311  // Only execute on ButtonUp, if ButtonDown also was done on a URL
2312 
2313  OUString aName, aUrl, aTarget;
2314  if ( GetEditUrl( rMEvt.GetPosPixel(), &aName, &aUrl, &aTarget ) )
2315  {
2316  nMouseStatus = SC_GM_NONE; // Ignore double-click
2317  bool isTiledRendering = comphelper::LibreOfficeKit::isActive();
2318  // ScGlobal::OpenURL() only understands Calc A1 style syntax.
2319  // Convert it to Calc A1 before calling OpenURL().
2321  {
2322  if (aUrl.startsWith("#")) {
2323  ScGlobal::OpenURL(aUrl, aTarget, isTiledRendering);
2324  return;
2325  }
2326  // On a mobile device view there is no ctrl+click and for hyperlink popup
2327  // the cell coordinates must be sent along with click position for elegance
2328  ScTabViewShell* pViewShell = mrViewData.GetViewShell();
2329  if (isTiledRendering && pViewShell &&
2330  (pViewShell->isLOKMobilePhone() || pViewShell->isLOKTablet()))
2331  {
2332  aPos = rMEvt.GetPosPixel();
2333  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2334  OString aCursor = pViewShell->GetViewData().describeCellCursorAt(nPosX, nPosY);
2335  double fPPTX = pViewShell->GetViewData().GetPPTX();
2336  int mouseX = aPos.X() / fPPTX;
2337  OString aMsg(aUrl.toUtf8() + " coordinates: " + aCursor + ", " + OString::number(mouseX));
2338  pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, aMsg.getStr());
2339  } else
2340  ScGlobal::OpenURL(aUrl, aTarget);
2341  }
2342  else
2343  {
2344  ScAddress aTempAddr;
2345  ScAddress::ExternalInfo aExtInfo;
2346  ScRefFlags nRes = aTempAddr.Parse(aUrl, rDoc, rDoc.GetAddressConvention(), &aExtInfo);
2347  if (!(nRes & ScRefFlags::VALID))
2348  {
2349  // Not a reference string. Pass it through unmodified.
2350  ScGlobal::OpenURL(aUrl, aTarget);
2351  return;
2352  }
2353 
2354  OUStringBuffer aBuf;
2355  if (aExtInfo.mbExternal)
2356  {
2357  // External reference.
2358  ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
2359  const OUString* pStr = pRefMgr->getExternalFileName(aExtInfo.mnFileId);
2360  if (pStr)
2361  aBuf.append(*pStr);
2362 
2363  aBuf.append('#');
2364  aBuf.append(aExtInfo.maTabName);
2365  aBuf.append('.');
2366  OUString aRefCalcA1(aTempAddr.Format(ScRefFlags::ADDR_ABS, nullptr, formula::FormulaGrammar::CONV_OOO));
2367  aBuf.append(aRefCalcA1);
2368  ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget);
2369  }
2370  else
2371  {
2372  // Internal reference.
2373  aBuf.append('#');
2374  OUString aUrlCalcA1(aTempAddr.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, formula::FormulaGrammar::CONV_OOO));
2375  aBuf.append(aUrlCalcA1);
2376  ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget, isTiledRendering);
2377  }
2378  }
2379 
2380  // fire worksheet_followhyperlink event
2381  uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = rDoc.GetVbaEventProcessor();
2382  if( xVbaEvents.is() ) try
2383  {
2384  aPos = rMEvt.GetPosPixel();
2385  nTab = mrViewData.GetTabNo();
2386  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2387  OUString sURL;
2388  ScRefCellValue aCell;
2389  if (lcl_GetHyperlinkCell(rDoc, nPosX, nPosY, nTab, aCell, sURL))
2390  {
2391  ScAddress aCellPos( nPosX, nPosY, nTab );
2392  uno::Reference< table::XCell > xCell( new ScCellObj( mrViewData.GetDocShell(), aCellPos ) );
2393  uno::Sequence< uno::Any > aArgs(1);
2394  aArgs[0] <<= xCell;
2395  xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_FOLLOWHYPERLINK, aArgs );
2396  }
2397  }
2398  catch( uno::Exception& )
2399  {
2400  }
2401 
2402  return;
2403  }
2404  }
2405 
2406  // Gridwin - SelectionEngine
2407 
2408  // SelMouseButtonDown is called only for left button, but SelMouseButtonUp would return
2409  // sal_True for any call, so IsLeft must be checked here, too.
2410 
2411  if ( !(rMEvt.IsLeft() && mrViewData.GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt )) )
2412  return;
2413 
2415 
2417  bool bFormulaMode = pScMod->IsFormulaMode();
2418  OSL_ENSURE( pDisp || bFormulaMode, "Cursor moved on inactive View ?" );
2419 
2420  // #i14927# execute SID_CURRENTCELL (for macro recording) only if there is no
2421  // multiple selection, so the argument string completely describes the selection,
2422  // and executing the slot won't change the existing selection (executing the slot
2423  // here and from a recorded macro is treated equally)
2424  if ( pDisp && !bFormulaMode && !rMark.IsMultiMarked() )
2425  {
2426  OUString aAddr; // CurrentCell
2427  if( rMark.IsMarked() )
2428  {
2429  ScRange aScRange;
2430  rMark.GetMarkArea( aScRange );
2431  aAddr = aScRange.Format(rDoc, ScRefFlags::RANGE_ABS);
2432  if ( aScRange.aStart == aScRange.aEnd )
2433  {
2434  // make sure there is a range selection string even for a single cell
2435  aAddr += ":" + aAddr;
2436  }
2437 
2440  }
2441  else // only move cursor
2442  {
2443  ScAddress aScAddress( mrViewData.GetCurX(), mrViewData.GetCurY(), 0 );
2444  aAddr = aScAddress.Format(ScRefFlags::ADDR_ABS);
2445  }
2446 
2447  SfxStringItem aPosItem( SID_CURRENTCELL, aAddr );
2448  // We don't want to align to the cursor position because if the
2449  // cell cursor isn't visible after making selection, it would jump
2450  // back to the origin of the selection where the cell cursor is.
2451  SfxBoolItem aAlignCursorItem( FN_PARAM_2, false );
2452  pDisp->ExecuteList(SID_CURRENTCELL,
2453  SfxCallMode::SLOT | SfxCallMode::RECORD,
2454  { &aPosItem, &aAlignCursorItem });
2455 
2457 
2458  }
2460 
2461  return;
2462 }
2463 
2465 {
2466  if ( nButtonDown )
2467  {
2468  MouseEvent aEvent( aCurMousePos ); // nButtons = 0 -> ignore
2469  MouseButtonUp( aEvent );
2470  }
2471 }
2472 
2474 {
2475  aCurMousePos = rMEvt.GetPosPixel();
2476 
2477  if (rMEvt.IsLeaveWindow() && mpNoteMarker && !mpNoteMarker->IsByKeyboard())
2478  HideNoteMarker();
2479 
2480  ScModule* pScMod = SC_MOD();
2481  if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
2482  return;
2483 
2484  // If the Drag&Drop is started in the edit mode then sadly nothing else is kept
2485  if (bEEMouse && nButtonDown && !rMEvt.GetButtons())
2486  {
2487  bEEMouse = false;
2488  nButtonDown = 0;
2490  return;
2491  }
2492 
2493  if (nMouseStatus == SC_GM_IGNORE)
2494  return;
2495 
2496  if (nMouseStatus == SC_GM_WATERUNDO) // Undo in format paintbrush mode -> only what for Up
2497  return;
2498 
2499  if ( mrViewData.GetViewShell()->IsAuditShell() ) // Detective Fill Mode
2500  {
2501  SetPointer( PointerStyle::Fill );
2502  return;
2503  }
2504 
2505  bool bFormulaMode = pScMod->IsFormulaMode(); // next click -> reference
2506 
2507  if (bEEMouse && mrViewData.HasEditView( eWhich ))
2508  {
2509  EditView* pEditView;
2510  SCCOL nEditCol;
2511  SCROW nEditRow;
2512  mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2513  pEditView->MouseMove( rMEvt );
2514  return;
2515  }
2516 
2517  if (bDPMouse)
2518  {
2519  DPMouseMove( rMEvt );
2520  return;
2521  }
2522 
2523  if (bRFMouse)
2524  {
2525  RFMouseMove( rMEvt, false );
2526  return;
2527  }
2528 
2529  if (nPagebreakMouse)
2530  {
2531  PagebreakMove( rMEvt, false );
2532  return;
2533  }
2534 
2535  // Show other mouse pointer?
2536 
2537  bool bEditMode = mrViewData.HasEditView(eWhich);
2538 
2540  if ( bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo()) )
2541  {
2542  Point aPos = rMEvt.GetPosPixel();
2543  SCCOL nPosX;
2544  SCROW nPosY;
2545  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2546 
2547  EditView* pEditView;
2548  SCCOL nEditCol;
2549  SCROW nEditRow;
2550  mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2551  SCCOL nEndCol = mrViewData.GetEditEndCol();
2552  SCROW nEndRow = mrViewData.GetEditEndRow();
2553 
2554  if ( nPosX >= nEditCol && nPosX <= nEndCol &&
2555  nPosY >= nEditRow && nPosY <= nEndRow )
2556  {
2557  if ( !pEditView )
2558  {
2559  SetPointer( PointerStyle::Text );
2560  return;
2561  }
2562 
2563  const SvxFieldItem* pFld;
2565  {
2566  Point aLogicClick = pEditView->GetOutputDevice().PixelToLogic(aPos);
2567  pFld = pEditView->GetField( aLogicClick );
2568  }
2569  else
2570  {
2571  pFld = pEditView->GetFieldUnderMousePointer();
2572  }
2573  // Field can only be URL field
2574  bool bAlt = rMEvt.IsMod2();
2575  if ( !bAlt && !nButtonDown && ScGlobal::ShouldOpenURL() && pFld )
2576  SetPointer( PointerStyle::RefHand );
2577  else if ( pEditView->GetEditEngine()->IsEffectivelyVertical() )
2578  SetPointer( PointerStyle::TextVertical );
2579  else
2580  SetPointer( PointerStyle::Text );
2581  return;
2582  }
2583  }
2584 
2585  bool bWater = SC_MOD()->GetIsWaterCan() || mrViewData.GetView()->HasPaintBrush();
2586  if (bWater)
2587  SetPointer( PointerStyle::Fill );
2588 
2589  if (!bWater)
2590  {
2591  bool bCross = false;
2592 
2593  // range finder
2594 
2595  RfCorner rCorner = NONE;
2596  if ( HitRangeFinder( rMEvt.GetPosPixel(), rCorner, nullptr, nullptr, nullptr ) )
2597  {
2598  if (rCorner != NONE)
2599  SetPointer( PointerStyle::Cross );
2600  else
2601  SetPointer( PointerStyle::Hand );
2602  bCross = true;
2603  }
2604 
2605  // Page-Break-Mode
2606 
2608  {
2609  sal_uInt16 nBreakType = HitPageBreak( rMEvt.GetPosPixel(), nullptr, nullptr, nullptr );
2610  if (nBreakType != 0 )
2611  {
2612  PointerStyle eNew = PointerStyle::Arrow;
2613  switch ( nBreakType )
2614  {
2615  case SC_PD_RANGE_L:
2616  case SC_PD_RANGE_R:
2617  case SC_PD_BREAK_H:
2618  eNew = PointerStyle::ESize;
2619  break;
2620  case SC_PD_RANGE_T:
2621  case SC_PD_RANGE_B:
2622  case SC_PD_BREAK_V:
2623  eNew = PointerStyle::SSize;
2624  break;
2625  case SC_PD_RANGE_TL:
2626  case SC_PD_RANGE_BR:
2627  eNew = PointerStyle::SESize;
2628  break;
2629  case SC_PD_RANGE_TR:
2630  case SC_PD_RANGE_BL:
2631  eNew = PointerStyle::NESize;
2632  break;
2633  }
2634  SetPointer( eNew );
2635  bCross = true;
2636  }
2637  }
2638 
2639  // Show fill cursor?
2640 
2641  if ( !bFormulaMode && !nButtonDown )
2642  if (TestMouse( rMEvt, false ))
2643  bCross = true;
2644 
2646  {
2647  SetPointer( PointerStyle::Cross );
2648  bCross = true;
2649  nScFillModeMouseModifier = rMEvt.GetModifier(); // evaluated for AutoFill and Matrix
2650  }
2651 
2652  if (!bCross)
2653  {
2654  bool bAlt = rMEvt.IsMod2();
2655 
2656  if (bEditMode) // First has to be in edit mode!
2657  SetPointer( mrViewData.IsThemedCursor() ? PointerStyle::FatCross : PointerStyle::Arrow );
2658  else if ( !bAlt && !nButtonDown && ScGlobal::ShouldOpenURL() &&
2659  GetEditUrl(rMEvt.GetPosPixel()) )
2660  SetPointer( PointerStyle::RefHand );
2661  else if ( DrawMouseMove(rMEvt) ) // Reset pointer
2662  return;
2663  }
2664  }
2665 
2666  if ( mrViewData.GetView()->GetSelEngine()->SelMouseMove( rMEvt ) )
2667  return;
2668 }
2669 
2670 static void lcl_InitMouseEvent(css::awt::MouseEvent& rEvent, const MouseEvent& rEvt)
2671 {
2672  rEvent.Modifiers = 0;
2673  if ( rEvt.IsShift() )
2674  rEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
2675  if ( rEvt.IsMod1() )
2676  rEvent.Modifiers |= css::awt::KeyModifier::MOD1;
2677  if ( rEvt.IsMod2() )
2678  rEvent.Modifiers |= css::awt::KeyModifier::MOD2;
2679  if ( rEvt.IsMod3() )
2680  rEvent.Modifiers |= css::awt::KeyModifier::MOD3;
2681 
2682  rEvent.Buttons = 0;
2683  if ( rEvt.IsLeft() )
2684  rEvent.Buttons |= css::awt::MouseButton::LEFT;
2685  if ( rEvt.IsRight() )
2686  rEvent.Buttons |= css::awt::MouseButton::RIGHT;
2687  if ( rEvt.IsMiddle() )
2688  rEvent.Buttons |= css::awt::MouseButton::MIDDLE;
2689 
2690  rEvent.X = rEvt.GetPosPixel().X();
2691  rEvent.Y = rEvt.GetPosPixel().Y();
2692  rEvent.ClickCount = rEvt.GetClicks();
2693  rEvent.PopupTrigger = false;
2694 }
2695 
2697 {
2698  bool bDone = false;
2699  MouseNotifyEvent nType = rNEvt.GetType();
2700  if ( nType == MouseNotifyEvent::MOUSEBUTTONUP || nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
2701  {
2702  vcl::Window* pWindow = rNEvt.GetWindow();
2703  if (pWindow == this)
2704  {
2705  SfxViewFrame* pViewFrame = mrViewData.GetViewShell()->GetViewFrame();
2706  if (pViewFrame)
2707  {
2708  css::uno::Reference<css::frame::XController> xController = pViewFrame->GetFrame().GetController();
2709  if (xController.is())
2710  {
2711  ScTabViewObj* pImp = comphelper::getUnoTunnelImplementation<ScTabViewObj>( xController );
2712  if (pImp && pImp->IsMouseListening())
2713  {
2714  css::awt::MouseEvent aEvent;
2715  lcl_InitMouseEvent( aEvent, *rNEvt.GetMouseEvent() );
2716  if ( rNEvt.GetWindow() )
2717  aEvent.Source = rNEvt.GetWindow()->GetComponentInterface();
2718  if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN)
2719  bDone = pImp->MousePressed( aEvent );
2720  else
2721  bDone = pImp->MouseReleased( aEvent );
2722  }
2723  }
2724  }
2725  }
2726  }
2727  if (bDone) // event consumed by a listener
2728  {
2729  if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
2730  {
2731  const MouseEvent* pMouseEvent = rNEvt.GetMouseEvent();
2732  if ( pMouseEvent->IsRight() && pMouseEvent->GetClicks() == 1 )
2733  {
2734  // If a listener returned true for a right-click call, also prevent opening the context menu
2735  // (this works only if the context menu is opened on mouse-down)
2737  }
2738  }
2739 
2740  return true;
2741  }
2742  else
2743  return Window::PreNotify( rNEvt );
2744 }
2745 
2747 {
2748  // Since the SelectionEngine does not track, the events have to be
2749  // handed to the different MouseHandler...
2750 
2751  const MouseEvent& rMEvt = rTEvt.GetMouseEvent();
2752 
2753  if ( rTEvt.IsTrackingCanceled() ) // Cancel everything...
2754  {
2755  if (!mrViewData.GetView()->IsInActivatePart() && !SC_MOD()->IsRefDialogOpen())
2756  {
2757  if (bDPMouse)
2758  bDPMouse = false; // Paint for each bDragRect
2759  if (bDragRect)
2760  {
2761  bDragRect = false;
2763  }
2764  if (bRFMouse)
2765  {
2766  RFMouseMove( rMEvt, true ); // Not possible to cancel properly...
2767  bRFMouse = false;
2768  }
2769  if (nPagebreakMouse)
2770  {
2771  bPagebreakDrawn = false;
2774  }
2775 
2776  SetPointer( PointerStyle::Arrow );
2777  StopMarking();
2778  MouseButtonUp( rMEvt ); // With status SC_GM_IGNORE from StopMarking
2779 
2780  bool bRefMode = mrViewData.IsRefMode();
2781  if (bRefMode)
2782  SC_MOD()->EndReference(); // Do not let the Dialog remain minimized
2783  }
2784  }
2785  else if ( rTEvt.IsTrackingEnded() )
2786  {
2788  {
2789  // MouseButtonUp always with matching buttons (eg for test tool, # 63148 #)
2790  // The tracking event will indicate if it was completed and not canceled.
2791  MouseEvent aUpEvt( rMEvt.GetPosPixel(), rMEvt.GetClicks(),
2792  rMEvt.GetMode(), nButtonDown, rMEvt.GetModifier() );
2793  MouseButtonUp( aUpEvt );
2794  }
2795  }
2797  MouseMove( rMEvt );
2798 }
2799 
2800 void ScGridWindow::StartDrag( sal_Int8 /* nAction */, const Point& rPosPixel )
2801 {
2803  return;
2804 
2805  HideNoteMarker();
2806 
2807  CommandEvent aDragEvent( rPosPixel, CommandEventId::StartDrag, true );
2808 
2809  if (bEEMouse && mrViewData.HasEditView( eWhich ))
2810  {
2811  EditView* pEditView;
2812  SCCOL nEditCol;
2813  SCROW nEditRow;
2814  mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2815 
2816  // don't remove the edit view while switching views
2817  ScModule* pScMod = SC_MOD();
2818  pScMod->SetInEditCommand( true );
2819 
2820  pEditView->Command( aDragEvent );
2821 
2822  ScInputHandler* pHdl = pScMod->GetInputHdl();
2823  if (pHdl)
2824  pHdl->DataChanged();
2825 
2826  pScMod->SetInEditCommand( false );
2827  if (!mrViewData.IsActive()) // dropped to different view?
2828  {
2829  ScInputHandler* pViewHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
2830  if ( pViewHdl && mrViewData.HasEditView( eWhich ) )
2831  {
2832  pViewHdl->CancelHandler();
2833  ShowCursor(); // missing from KillEditView
2834  }
2835  }
2836  }
2837  else
2838  if ( !DrawCommand(aDragEvent) )
2839  mrViewData.GetView()->GetSelEngine()->Command( aDragEvent );
2840 }
2841 
2842 static void lcl_SetTextCursorPos( ScViewData& rViewData, ScSplitPos eWhich, vcl::Window* pWin )
2843 {
2844  SCCOL nCol = rViewData.GetCurX();
2845  SCROW nRow = rViewData.GetCurY();
2846  tools::Rectangle aEditArea = rViewData.GetEditArea( eWhich, nCol, nRow, pWin, nullptr, true );
2847  aEditArea.SetRight( aEditArea.Left() );
2848  aEditArea = pWin->PixelToLogic( aEditArea );
2849  pWin->SetCursorRect( &aEditArea );
2850 }
2851 
2853 {
2854  // The command event is send to the window after a possible context
2855  // menu from an inplace client is closed. Now we have the chance to
2856  // deactivate the inplace client without any problem regarding parent
2857  // windows and code on the stack.
2858  CommandEventId nCmd = rCEvt.GetCommand();
2859  ScTabViewShell* pTabViewSh = mrViewData.GetViewShell();
2860  SfxInPlaceClient* pClient = pTabViewSh->GetIPClient();
2861  if ( pClient &&
2862  pClient->IsObjectInPlaceActive() &&
2863  nCmd == CommandEventId::ContextMenu )
2864  {
2865  pTabViewSh->DeactivateOle();
2866  return;
2867  }
2868 
2869  ScModule* pScMod = SC_MOD();
2870  OSL_ENSURE( nCmd != CommandEventId::StartDrag, "ScGridWindow::Command called with CommandEventId::StartDrag" );
2871 
2872  if (nCmd == CommandEventId::ModKeyChange)
2873  {
2874  Window::Command(rCEvt);
2875  return;
2876  }
2877 
2878  if ( nCmd == CommandEventId::StartExtTextInput ||
2879  nCmd == CommandEventId::EndExtTextInput ||
2880  nCmd == CommandEventId::ExtTextInput ||
2881  nCmd == CommandEventId::CursorPos ||
2882  nCmd == CommandEventId::QueryCharPosition )
2883  {
2884  bool bEditView = mrViewData.HasEditView( eWhich );
2885  if (!bEditView)
2886  {
2887  // only if no cell editview is active, look at drawview
2888  SdrView* pSdrView = mrViewData.GetView()->GetScDrawView();
2889  if ( pSdrView )
2890  {
2891  OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
2892  if ( pOlView && pOlView->GetWindow() == this )
2893  {
2894  pOlView->Command( rCEvt );
2895  return; // done
2896  }
2897  }
2898  }
2899 
2900  if ( nCmd == CommandEventId::CursorPos && !bEditView )
2901  {
2902  // CURSORPOS may be called without following text input,
2903  // to set the input method window position
2904  // -> input mode must not be started,
2905  // manually calculate text insert position if not in input mode
2906 
2907  lcl_SetTextCursorPos( mrViewData, eWhich, this );
2908  return;
2909  }
2910 
2911  ScInputHandler* pHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
2912  if ( pHdl )
2913  {
2914  pHdl->InputCommand( rCEvt );
2915  return; // done
2916  }
2917 
2918  Window::Command( rCEvt );
2919  return;
2920  }
2921 
2922  if ( nCmd == CommandEventId::PasteSelection )
2923  {
2924  if ( bEEMouse )
2925  {
2926  // EditEngine handles selection in MouseButtonUp - no action
2927  // needed in command handler
2928  }
2929  else
2930  {
2931  PasteSelection( rCEvt.GetMousePosPixel() );
2932  }
2933  return;
2934  }
2935 
2936  if ( nCmd == CommandEventId::InputLanguageChange )
2937  {
2938  // #i55929# Font and font size state depends on input language if nothing is selected,
2939  // so the slots have to be invalidated when the input language is changed.
2940 
2941  SfxBindings& rBindings = mrViewData.GetBindings();
2942  rBindings.Invalidate( SID_ATTR_CHAR_FONT );
2943  rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
2944  return;
2945  }
2946 
2947  if ( nCmd == CommandEventId::Wheel || nCmd == CommandEventId::StartAutoScroll || nCmd == CommandEventId::AutoScroll )
2948  {
2949  bool bDone = mrViewData.GetView()->ScrollCommand( rCEvt, eWhich );
2950  if (!bDone)
2951  Window::Command(rCEvt);
2952  return;
2953  }
2954  // #i7560# FormulaMode check is below scrolling - scrolling is allowed during formula input
2955  bool bDisable = pScMod->IsFormulaMode() ||
2957  if (bDisable)
2958  return;
2959 
2960  if (nCmd != CommandEventId::ContextMenu || SC_MOD()->GetIsWaterCan())
2961  return;
2962 
2963  bool bMouse = rCEvt.IsMouseEvent();
2964  if ( bMouse && nMouseStatus == SC_GM_IGNORE )
2965  return;
2966 
2967  if (mrViewData.IsAnyFillMode())
2968  {
2971  }
2972  ReleaseMouse();
2973  StopMarking();
2974 
2975  Point aPosPixel = rCEvt.GetMousePosPixel();
2976  Point aMenuPos = aPosPixel;
2977 
2978  SCCOL nCellX = -1;
2979  SCROW nCellY = -1;
2980  mrViewData.GetPosFromPixel(aPosPixel.X(), aPosPixel.Y(), eWhich, nCellX, nCellY);
2981 
2982  bool bSpellError = false;
2983  SCCOL nColSpellError = nCellX;
2984 
2985  if ( bMouse )
2986  {
2987  ScDocument& rDoc = mrViewData.GetDocument();
2988  SCTAB nTab = mrViewData.GetTabNo();
2989  const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
2990  bool bSelectAllowed = true;
2991  if ( pProtect && pProtect->isProtected() )
2992  {
2993  // This sheet is protected. Check if a context menu is allowed on this cell.
2994  bool bCellProtected = rDoc.HasAttrib(nCellX, nCellY, nTab, nCellX, nCellY, nTab, HasAttrFlags::Protected);
2995  bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
2996  bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
2997 
2998  if (bCellProtected)
2999  bSelectAllowed = bSelProtected;
3000  else
3001  bSelectAllowed = bSelUnprotected;
3002  }
3003  if (!bSelectAllowed)
3004  // Selecting this cell is not allowed, neither is context menu.
3005  return;
3006 
3007  if (mpSpellCheckCxt)
3008  {
3009  // Find the first string to the left for spell checking in case the current cell is empty.
3010  ScAddress aPos(nCellX, nCellY, nTab);
3011  ScRefCellValue aSpellCheckCell(rDoc, aPos);
3012  while (aSpellCheckCell.meType == CELLTYPE_NONE)
3013  {
3014  // Loop until we get the first non-empty cell in the row.
3015  aPos.IncCol(-1);
3016  if (aPos.Col() < 0)
3017  break;
3018 
3019  aSpellCheckCell.assign(rDoc, aPos);
3020  }
3021 
3022  if (aPos.Col() >= 0 && (aSpellCheckCell.meType == CELLTYPE_STRING || aSpellCheckCell.meType == CELLTYPE_EDIT))
3023  nColSpellError = aPos.Col();
3024 
3025  bSpellError = (mpSpellCheckCxt->isMisspelled(nColSpellError, nCellY));
3026  if (bSpellError)
3027  {
3028  // Check and see if a misspelled word is under the mouse pointer.
3029  bSpellError = IsSpellErrorAtPos(aPosPixel, nColSpellError, nCellY);
3030  }
3031  }
3032 
3033  // #i18735# First select the item under the mouse pointer.
3034  // This can change the selection, and the view state (edit mode, etc).
3035  SelectForContextMenu(aPosPixel, bSpellError ? nColSpellError : nCellX, nCellY);
3036  }
3037 
3038  bool bDone = false;
3039  bool bEdit = mrViewData.HasEditView(eWhich);
3040 
3041  if ( !bEdit )
3042  {
3043  // Edit cell with spelling errors ?
3044  if (bMouse && (GetEditUrl(aPosPixel) || bSpellError))
3045  {
3046  // GetEditUrlOrError has already moved the Cursor
3047 
3048  pScMod->SetInputMode( SC_INPUT_TABLE );
3049  bEdit = mrViewData.HasEditView(eWhich); // Did it work?
3050 
3051  OSL_ENSURE( bEdit, "Can not be switched in edit mode" );
3052  }
3053  }
3054  if ( bEdit )
3055  {
3056  EditView* pEditView = mrViewData.GetEditView( eWhich ); // is then not 0
3057 
3058  if ( !bMouse )
3059  {
3060  vcl::Cursor* pCur = pEditView->GetCursor();
3061  if ( pCur )
3062  {
3063  Point aLogicPos = pCur->GetPos();
3064  // use the position right of the cursor (spell popup is opened if
3065  // the cursor is before the word, but not if behind it)
3066  aLogicPos.AdjustX(pCur->GetWidth() );
3067  aLogicPos.AdjustY(pCur->GetHeight() / 2 ); // center vertically
3068  aMenuPos = LogicToPixel( aLogicPos );
3069  }
3070  }
3071 
3072  // if edit mode was just started above, online spelling may be incomplete
3073  pEditView->GetEditEngine()->CompleteOnlineSpelling();
3074 
3075  // IsCursorAtWrongSpelledWord could be used for !bMouse
3076  // if there was a corresponding ExecuteSpellPopup call
3077 
3078  if (bSpellError)
3079  {
3080  // On OS/2 when clicking next to the Popup menu, the MouseButtonDown
3081  // comes before the end of menu execute, thus the SetModified has to
3082  // be done prior to this (Bug #40968#)
3083  ScInputHandler* pHdl = pScMod->GetInputHdl();
3084  if (pHdl)
3085  pHdl->SetModified();
3086 
3087  Link<SpellCallbackInfo&,void> aLink = LINK( this, ScGridWindow, PopupSpellingHdl );
3088  pEditView->ExecuteSpellPopup(aMenuPos, aLink);
3089 
3090  bDone = true;
3091  }
3092  }
3093  else if ( !bMouse )
3094  {
3095  // non-edit menu by keyboard -> use lower right of cell cursor position
3096  ScDocument& rDoc = mrViewData.GetDocument();
3097  SCTAB nTabNo = mrViewData.GetTabNo();
3098  bool bLayoutIsRTL = rDoc.IsLayoutRTL(nTabNo);
3099 
3100  SCCOL nCurX = mrViewData.GetCurX();
3101  SCROW nCurY = mrViewData.GetCurY();
3102  aMenuPos = mrViewData.GetScrPos( nCurX, nCurY, eWhich, true );
3103  tools::Long nSizeXPix;
3104  tools::Long nSizeYPix;
3105  mrViewData.GetMergeSizePixel( nCurX, nCurY, nSizeXPix, nSizeYPix );
3106  // fdo#55432 take the correct position for RTL sheet
3107  aMenuPos.AdjustX(bLayoutIsRTL ? -nSizeXPix : nSizeXPix );
3108  aMenuPos.AdjustY(nSizeYPix );
3109 
3110  ScTabViewShell* pViewSh = mrViewData.GetViewShell();
3111  if (pViewSh)
3112  {
3113  // Is a draw object selected?
3114 
3115  SdrView* pDrawView = pViewSh->GetScDrawView();
3116  if (pDrawView && pDrawView->AreObjectsMarked())
3117  {
3118  // #100442#; the context menu should open in the middle of the selected objects
3119  tools::Rectangle aSelectRect(LogicToPixel(pDrawView->GetAllMarkedBoundRect()));
3120  aMenuPos = aSelectRect.Center();
3121  }
3122  }
3123  }
3124 
3125  if (!bDone)
3126  {
3127  // tdf#140361 at this context menu popup time get what the
3128  // DisableEditHyperlink would be for this position
3129  bool bShouldDisableEditHyperlink = mrViewData.GetViewShell()->ShouldDisableEditHyperlink();
3130 
3131  SfxDispatcher::ExecutePopup( this, &aMenuPos );
3132 
3133  if (!bShouldDisableEditHyperlink)
3134  {
3135  SfxBindings& rBindings = mrViewData.GetBindings();
3136  // tdf#140361 set what the menu popup state for this was
3138  // ensure moAtContextMenu_DisableEditHyperlink will be cleared
3139  // in the case that EditHyperlink is not dispatched by the menu
3140  rBindings.Invalidate(SID_EDIT_HYPERLINK);
3141  }
3142  }
3143 }
3144 
3145 void ScGridWindow::SelectForContextMenu( const Point& rPosPixel, SCCOL nCellX, SCROW nCellY )
3146 {
3147  // #i18735# if the click was outside of the current selection,
3148  // the cursor is moved or an object at the click position selected.
3149  // (see SwEditWin::SelectMenuPosition in Writer)
3150 
3151  ScTabView* pView = mrViewData.GetView();
3152  ScDrawView* pDrawView = pView->GetScDrawView();
3153 
3154  // check cell edit mode
3155 
3156  if ( mrViewData.HasEditView(eWhich) )
3157  {
3158  ScModule* pScMod = SC_MOD();
3159  SCCOL nEditStartCol = mrViewData.GetEditViewCol();
3160  SCROW nEditStartRow = mrViewData.GetEditViewRow();
3161  SCCOL nEditEndCol = mrViewData.GetEditEndCol();
3162  SCROW nEditEndRow = mrViewData.GetEditEndRow();
3163 
3164  if ( nCellX >= nEditStartCol && nCellX <= nEditEndCol &&
3165  nCellY >= nEditStartRow && nCellY <= nEditEndRow )
3166  {
3167  // handle selection within the EditView
3168 
3169  EditView* pEditView = mrViewData.GetEditView( eWhich ); // not NULL (HasEditView)
3170  EditEngine* pEditEngine = pEditView->GetEditEngine();
3171  tools::Rectangle aOutputArea = pEditView->GetOutputArea();
3172  tools::Rectangle aVisArea = pEditView->GetVisArea();
3173 
3174  Point aTextPos = PixelToLogic( rPosPixel );
3175  if ( pEditEngine->IsEffectivelyVertical() ) // have to manually transform position
3176  {
3177  aTextPos -= aOutputArea.TopRight();
3178  tools::Long nTemp = -aTextPos.X();
3179  aTextPos.setX( aTextPos.Y() );
3180  aTextPos.setY( nTemp );
3181  }
3182  else
3183  aTextPos -= aOutputArea.TopLeft();
3184  aTextPos += aVisArea.TopLeft(); // position in the edit document
3185 
3186  EPosition aDocPosition = pEditEngine->FindDocPosition(aTextPos);
3187  ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
3188  ESelection aSelection = pEditView->GetSelection();
3189  aSelection.Adjust(); // needed for IsLess/IsGreater
3190  if ( aCompare < aSelection || aCompare > aSelection )
3191  {
3192  // clicked outside the selected text - deselect and move text cursor
3193  MouseEvent aEvent( rPosPixel );
3194  pEditView->MouseButtonDown( aEvent );
3195  pEditView->MouseButtonUp( aEvent );
3196  pScMod->InputSelection( pEditView );
3197  }
3198 
3199  return; // clicked within the edit view - keep edit mode
3200  }
3201  else
3202  {
3203  // outside of the edit view - end edit mode, regardless of cell selection, then continue
3204  pScMod->InputEnterHandler();
3205  }
3206  }
3207 
3208  // check draw text edit mode
3209 
3210  Point aLogicPos = PixelToLogic( rPosPixel ); // after cell edit mode is ended
3211  if ( pDrawView && pDrawView->GetTextEditObject() && pDrawView->GetTextEditOutlinerView() )
3212  {
3213  OutlinerView* pOlView = pDrawView->GetTextEditOutlinerView();
3214  tools::Rectangle aOutputArea = pOlView->GetOutputArea();
3215  if ( aOutputArea.IsInside( aLogicPos ) )
3216  {
3217  // handle selection within the OutlinerView
3218 
3219  Outliner* pOutliner = pOlView->GetOutliner();
3220  const EditEngine& rEditEngine = pOutliner->GetEditEngine();
3221  tools::Rectangle aVisArea = pOlView->GetVisArea();
3222 
3223  Point aTextPos = aLogicPos;
3224  if ( pOutliner->IsVertical() ) // have to manually transform position
3225  {
3226  aTextPos -= aOutputArea.TopRight();
3227  tools::Long nTemp = -aTextPos.X();
3228  aTextPos.setX( aTextPos.Y() );
3229  aTextPos.setY( nTemp );
3230  }
3231  else
3232  aTextPos -= aOutputArea.TopLeft();
3233  aTextPos += aVisArea.TopLeft(); // position in the edit document
3234 
3235  EPosition aDocPosition = rEditEngine.FindDocPosition(aTextPos);
3236  ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
3237  ESelection aSelection = pOlView->GetSelection();
3238  aSelection.Adjust(); // needed for IsLess/IsGreater
3239  if ( aCompare < aSelection || aCompare > aSelection )
3240  {
3241  // clicked outside the selected text - deselect and move text cursor
3242  // use DrawView to allow extra handling there (none currently)
3243  MouseEvent aEvent( rPosPixel );
3244  pDrawView->MouseButtonDown( aEvent, GetOutDev() );
3245  pDrawView->MouseButtonUp( aEvent, GetOutDev() );
3246  }
3247 
3248  return; // clicked within the edit area - keep edit mode
3249  }
3250  else
3251  {
3252  // Outside of the edit area - end text edit mode, then continue.
3253  // DrawDeselectAll also ends text edit mode and updates the shells.
3254  // If the click was on the edited object, it will be selected again below.
3255  pView->DrawDeselectAll();
3256  }
3257  }
3258 
3259  // look for existing selection
3260 
3261  bool bHitSelected = false;
3262  if ( pDrawView && pDrawView->IsMarkedObjHit( aLogicPos ) )
3263  {
3264  // clicked on selected object -> don't change anything
3265  bHitSelected = true;
3266  }
3267  else if ( mrViewData.GetMarkData().IsCellMarked(nCellX, nCellY) )
3268  {
3269  // clicked on selected cell -> don't change anything
3270  bHitSelected = true;
3271  }
3272 
3273  // select drawing object or move cell cursor
3274 
3275  if ( bHitSelected )
3276  return;
3277 
3278  bool bWasDraw = ( pDrawView && pDrawView->AreObjectsMarked() );
3279  bool bHitDraw = false;
3280  if ( pDrawView )
3281  {
3282  pDrawView->UnmarkAllObj();
3283  // Unlock the Internal Layer in order to activate the context menu.
3284  // re-lock in ScDrawView::MarkListHasChanged()
3285  lcl_UnLockComment(pDrawView, aLogicPos, mrViewData);
3286  bHitDraw = pDrawView->MarkObj( aLogicPos );
3287  // draw shell is activated in MarkListHasChanged
3288  }
3289  if ( !bHitDraw )
3290  {
3291  pView->Unmark();
3292  pView->SetCursor(nCellX, nCellY);
3293  if ( bWasDraw )
3294  mrViewData.GetViewShell()->SetDrawShell( false ); // switch shells
3295  }
3296 }
3297 
3299 {
3300  // Cursor control for ref input dialog
3301  const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
3302 
3303 #ifdef DBG_UTIL
3304 
3305  if (rKeyCode.IsMod1() && rKeyCode.IsShift())
3306  {
3307  if (rKeyCode.GetCode() == KEY_F12)
3308  {
3310  }
3311  else if (rKeyCode.GetCode() == KEY_F11)
3312  {
3314  }
3315  else if (rKeyCode.GetCode() == KEY_F10)
3316  {
3318  }
3319  else if (rKeyCode.GetCode() == KEY_F6)
3320  {
3322  }
3323  else if (rKeyCode.GetCode() == KEY_F8)
3324  {
3326  }
3327  else if (rKeyCode.GetCode() == KEY_F7)
3328  {
3329  ScDocument& rDoc = mrViewData.GetDocument();
3330  auto& rMapper = rDoc.GetExternalDataMapper();
3331  for (auto& itr : rMapper.getDataSources())
3332  {
3333  itr.refresh(&rDoc);
3334  }
3335  return;
3336  }
3337  }
3338 
3339 #endif
3340 
3341  if( SC_MOD()->IsRefDialogOpen() )
3342  {
3343  if( !rKeyCode.GetModifier() && (rKeyCode.GetCode() == KEY_F2) )
3344  {
3345  SC_MOD()->EndReference();
3346  }
3347  else if( mrViewData.GetViewShell()->MoveCursorKeyInput( rKEvt ) )
3348  {
3349  ScRange aRef(
3352  SC_MOD()->SetReference( aRef, mrViewData.GetDocument() );
3353  }
3355  return ;
3356  }
3357  else if( rKeyCode.GetCode() == KEY_RETURN && mrViewData.IsPasteMode()
3358  && SC_MOD()->GetInputOptions().GetEnterPasteMode() )
3359  {
3360  ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
3361  ScClipUtil::PasteFromClipboard( mrViewData, pTabViewShell, true );
3362 
3363  // Clear clipboard content.
3364  uno::Reference<datatransfer::clipboard::XClipboard> xSystemClipboard =
3365  GetClipboard();
3366  if (xSystemClipboard.is())
3367  {
3368  xSystemClipboard->setContents(
3369  uno::Reference<datatransfer::XTransferable>(),
3370  uno::Reference<datatransfer::clipboard::XClipboardOwner>());
3371  }
3372 
3373  // hide the border around the copy source
3375  // Clear CopySourceOverlay in each window of a split/frozen tabview
3377  return;
3378  }
3379  // if semi-modeless SfxChildWindow dialog above, then no KeyInputs:
3380  else if( !mrViewData.IsAnyFillMode() )
3381  {
3382  if (rKeyCode.GetCode() == KEY_ESCAPE)
3383  {
3385  // Clear CopySourceOverlay in each window of a split/frozen tabview
3387  }
3388  // query for existing note marker before calling ViewShell's keyboard handling
3389  // which may remove the marker
3390  bool bHadKeyMarker = mpNoteMarker && mpNoteMarker->IsByKeyboard();
3391  ScTabViewShell* pViewSh = mrViewData.GetViewShell();
3392 
3394  return;
3395 
3396  if (DrawKeyInput(rKEvt, this))
3397  {
3398  const vcl::KeyCode& rLclKeyCode = rKEvt.GetKeyCode();
3399  if (rLclKeyCode.GetCode() == KEY_DOWN
3400  || rLclKeyCode.GetCode() == KEY_UP
3401  || rLclKeyCode.GetCode() == KEY_LEFT
3402  || rLclKeyCode.GetCode() == KEY_RIGHT)
3403  {
3404  ScTabViewShell* pViewShell = mrViewData.GetViewShell();
3405  SfxBindings& rBindings = pViewShell->GetViewFrame()->GetBindings();
3406  rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_X);
3407  rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_Y);
3408  }
3409  return;
3410  }
3411 
3412  if (!mrViewData.GetView()->IsDrawSelMode() && !DrawHasMarkedObj()) // No entries in draw mode
3413  {
3414  if (pViewSh->TabKeyInput(rKEvt))
3415  return;
3416  }
3417  else
3418  if (pViewSh->SfxViewShell::KeyInput(rKEvt)) // from SfxViewShell
3419  return;
3420 
3421  vcl::KeyCode aCode = rKEvt.GetKeyCode();
3422  if ( aCode.GetCode() == KEY_ESCAPE && aCode.GetModifier() == 0 )
3423  {
3424  if ( bHadKeyMarker )
3425  HideNoteMarker();
3426  else
3427  pViewSh->Escape();
3428  return;
3429  }
3430  if ( aCode.GetCode() == KEY_F1 && aCode.GetModifier() == KEY_MOD1 )
3431  {
3432  // ctrl-F1 shows or hides the note or redlining info for the cursor position
3433  // (hard-coded because F1 can't be configured)
3434 
3435  if ( bHadKeyMarker )
3436  HideNoteMarker(); // hide when previously visible
3437  else
3439  return;
3440  }
3441  if (aCode.GetCode() == KEY_BRACKETLEFT && aCode.GetModifier() == KEY_MOD1)
3442  {
3443  pViewSh->DetectiveMarkPred();
3444  return;
3445  }
3446  if (aCode.GetCode() == KEY_BRACKETRIGHT && aCode.GetModifier() == KEY_MOD1)
3447  {
3448  pViewSh->DetectiveMarkSucc();
3449  return;
3450  }
3451 
3452  }
3453 
3454  Window::KeyInput(rKEvt);
3455 }
3456 
3458 {
3459  bool bEditView = mrViewData.HasEditView(eWhich);
3460  if (bEditView)
3461  {
3462  ScModule* pScMod = SC_MOD();
3464  if (pHdl)
3465  return pHdl->GetSurroundingText();
3466  }
3467  else if (SdrView* pSdrView = mrViewData.GetView()->GetScDrawView())
3468  {
3469  // if no cell editview is active, look at drawview
3470  OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
3471  if (pOlView && pOlView->GetWindow() == this)
3472  return pOlView->GetSurroundingText();
3473  }
3474 
3475  return Window::GetSurroundingText();
3476 }
3477 
3479 {
3480  bool bEditView = mrViewData.HasEditView(eWhich);
3481  if (bEditView)
3482  {
3483  ScModule* pScMod = SC_MOD();
3485  if (pHdl)
3486  return pHdl->GetSurroundingTextSelection();
3487  }
3488  else if (SdrView* pSdrView = mrViewData.GetView()->GetScDrawView())
3489  {
3490  // if no cell editview is active, look at drawview
3491  OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
3492  if (pOlView && pOlView->GetWindow() == this)
3493  return pOlView->GetSurroundingTextSelection();
3494  }
3495 
3496  return Window::GetSurroundingTextSelection();
3497 }
3498 
3500 {
3501  bool bEditView = mrViewData.HasEditView(eWhich);
3502  if (bEditView)
3503  {
3504  ScModule* pScMod = SC_MOD();
3506  if (pHdl)
3507  return pHdl->DeleteSurroundingText(rSelection);
3508  }
3509  else if (SdrView* pSdrView = mrViewData.GetView()->GetScDrawView())
3510  {
3511  // if no cell editview is active, look at drawview
3512  OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
3513  if (pOlView && pOlView->GetWindow() == this)
3514  return pOlView->DeleteSurroundingText(rSelection);
3515  }
3516 
3517  return Window::DeleteSurroundingText(rSelection);
3518 }
3519 
3521 {
3522  DrawEndAction(); // Cancel Select/move on Drawing-Layer
3523 
3524  if (nButtonDown)
3525  {
3528  }
3529 }
3530 
3532 {
3534  InputContextFlags nOptions = bReadOnly ? InputContextFlags::NONE : ( InputContextFlags::Text | InputContextFlags::ExtText );
3535 
3536  // when font from InputContext is used,
3537  // it must be taken from the cursor position's cell attributes
3538 
3539  InputContext aContext;
3540  aContext.SetOptions( nOptions );
3541  SetInputContext( aContext );
3542 }
3543 
3544  // sensitive range (Pixel)
3545 #define SCROLL_SENSITIVE 20
3546 
3547 void ScGridWindow::DropScroll( const Point& rMousePos )
3548 {
3549  ScDocument& rDoc = mrViewData.GetDocument();
3550  SCCOL nDx = 0;
3551  SCROW nDy = 0;
3552  Size aSize = GetOutputSizePixel();
3553 
3554  if (aSize.Width() > SCROLL_SENSITIVE * 3)
3555  {
3556  if ( rMousePos.X() < SCROLL_SENSITIVE && mrViewData.GetPosX(WhichH(eWhich)) > 0 )
3557  nDx = -1;
3558  if ( rMousePos.X() >= aSize.Width() - SCROLL_SENSITIVE
3559  && mrViewData.GetPosX(WhichH(eWhich)) < rDoc.MaxCol() )
3560  nDx = 1;
3561  }
3562  if (aSize.Height() > SCROLL_SENSITIVE * 3)
3563  {
3564  if ( rMousePos.Y() < SCROLL_SENSITIVE && mrViewData.GetPosY(WhichV(eWhich)) > 0 )
3565  nDy = -1;
3566  if ( rMousePos.Y() >= aSize.Height() - SCROLL_SENSITIVE
3567  && mrViewData.GetPosY(WhichV(eWhich)) < rDoc.MaxRow() )
3568  nDy = 1;
3569  }
3570 
3571  if ( nDx != 0 || nDy != 0 )
3572  {
3573  if ( nDx != 0 )
3574  mrViewData.GetView()->ScrollX( nDx, WhichH(eWhich) );
3575  if ( nDy != 0 )
3576  mrViewData.GetView()->ScrollY( nDy, WhichV(eWhich) );
3577  }
3578 }
3579 
3580 static bool lcl_TestScenarioRedliningDrop( const ScDocument* pDoc, const ScRange& aDragRange)
3581 {
3582  // Test, if a scenario is affected by a drop when turing on RedLining,
3583  bool bReturn = false;
3584  SCTAB nTab = aDragRange.aStart.Tab();
3585  SCTAB nTabCount = pDoc->GetTableCount();
3586 
3587  if(pDoc->GetChangeTrack()!=nullptr)
3588  {
3589  if( pDoc->IsScenario(nTab) && pDoc->HasScenarioRange(nTab, aDragRange))
3590  {
3591  bReturn = true;
3592  }
3593  else
3594  {
3595  for(SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++)
3596  {
3597  if(pDoc->HasScenarioRange(i, aDragRange))
3598  {
3599  bReturn = true;
3600  break;
3601  }
3602  }
3603  }
3604  }
3605  return bReturn;
3606 }
3607 
3608 static ScRange lcl_MakeDropRange( const ScDocument& rDoc, SCCOL nPosX, SCROW nPosY, SCTAB nTab, const ScRange& rSource )
3609 {
3610  SCCOL nCol1 = nPosX;
3611  SCCOL nCol2 = nCol1 + ( rSource.aEnd.Col() - rSource.aStart.Col() );
3612  if ( nCol2 > rDoc.MaxCol() )
3613  {
3614  nCol1 -= nCol2 - rDoc.MaxCol();
3615  nCol2 = rDoc.MaxCol();
3616  }
3617  SCROW nRow1 = nPosY;
3618  SCROW nRow2 = nRow1 + ( rSource.aEnd.Row() - rSource.aStart.Row() );
3619  if ( nRow2 > rDoc.MaxRow() )
3620  {
3621  nRow1 -= nRow2 - rDoc.MaxRow();
3622  nRow2 = rDoc.MaxRow();
3623  }
3624 
3625  return ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
3626 }
3627 
3629 {
3630  if ( rEvt.mbLeaving )
3631  {
3632  bDragRect = false;
3634  return rEvt.mnAction;
3635  }
3636 
3637  const ScDragData& rData = SC_MOD()->GetDragData();
3638  if ( rData.pCellTransfer )
3639  {
3640  // Don't move source that would include filtered rows.
3641  if ((rEvt.mnAction & DND_ACTION_MOVE) && rData.pCellTransfer->HasFilteredRows())
3642  {
3643  if (bDragRect)
3644  {
3645  bDragRect = false;
3647  }
3648  return DND_ACTION_NONE;
3649  }
3650 
3651  Point aPos = rEvt.maPosPixel;
3652 
3653  ScDocument* pSourceDoc = rData.pCellTransfer->GetSourceDocument();
3654  ScDocument& rThisDoc = mrViewData.GetDocument();
3655  if (pSourceDoc == &rThisDoc)
3656  {
3657  OUString aName;
3658  if ( rThisDoc.HasChartAtPoint(mrViewData.GetTabNo(), PixelToLogic(aPos), aName ))
3659  {
3660  if (bDragRect) // Remove rectangle
3661  {
3662  bDragRect = false;
3664  }
3665 
3667 
3668  sal_Int8 nRet = rEvt.mnAction;
3669  return nRet;
3670  }
3671  }
3672 
3673  if (rData.pCellTransfer->GetDragSourceFlags() & ScDragSrc::Table) // whole sheet?
3674  {
3675  bool bOk = rThisDoc.IsDocEditable();
3676  return bOk ? rEvt.mnAction : 0; // don't draw selection frame
3677  }
3678 
3679  SCCOL nPosX;
3680  SCROW nPosY;
3681  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
3682 
3683  ScRange aSourceRange = rData.pCellTransfer->GetRange();
3684  SCCOL nSourceStartX = aSourceRange.aStart.Col();
3685  SCROW nSourceStartY = aSourceRange.aStart.Row();
3686  SCCOL nSourceEndX = aSourceRange.aEnd.Col();
3687  SCROW nSourceEndY = aSourceRange.aEnd.Row();
3688  SCCOL nSizeX = nSourceEndX - nSourceStartX + 1;
3689  SCROW nSizeY = nSourceEndY - nSourceStartY + 1;
3690 
3691  if ( rEvt.mnAction != DND_ACTION_MOVE )
3692  nSizeY = rData.pCellTransfer->GetNonFilteredRows(); // copy/link: no filtered rows
3693 
3694  SCCOL nNewDragX = nPosX - rData.pCellTransfer->GetDragHandleX();
3695  if (nNewDragX<0) nNewDragX=0;
3696  if (nNewDragX+(nSizeX-1) > rThisDoc.MaxCol())
3697  nNewDragX = rThisDoc.MaxCol()-(nSizeX-1);
3698  SCROW nNewDragY = nPosY - rData.pCellTransfer->GetDragHandleY();
3699  if (nNewDragY<0) nNewDragY=0;
3700  if (nNewDragY+(nSizeY-1) > rThisDoc.MaxRow())
3701  nNewDragY = rThisDoc.MaxRow()-(nSizeY-1);
3702 
3703  // don't break scenario ranges, don't drop on filtered
3704  SCTAB nTab = mrViewData.GetTabNo();
3705  ScRange aDropRange = lcl_MakeDropRange( rThisDoc, nNewDragX, nNewDragY, nTab, aSourceRange );
3706  if ( lcl_TestScenarioRedliningDrop( &rThisDoc, aDropRange ) ||
3707  lcl_TestScenarioRedliningDrop( pSourceDoc, aSourceRange ) ||
3708  ScViewUtil::HasFiltered( aDropRange, rThisDoc) )
3709  {
3710  if (bDragRect)
3711  {
3712  bDragRect = false;
3714  }
3715  return DND_ACTION_NONE;
3716  }
3717 
3718  InsCellCmd eDragInsertMode = INS_NONE;
3719  Window::PointerState aState = GetPointerState();
3720 
3721  // check for datapilot item sorting
3722  ScDPObject* pDPObj = nullptr;
3723  if ( &rThisDoc == pSourceDoc && ( pDPObj = rThisDoc.GetDPAtCursor( nNewDragX, nNewDragY, nTab ) ) != nullptr )
3724  {
3725  // drop on DataPilot table: sort or nothing
3726 
3727  bool bDPSort = false;
3728  if ( rThisDoc.GetDPAtCursor( nSourceStartX, nSourceStartY, aSourceRange.aStart.Tab() ) == pDPObj )
3729  {
3730  sheet::DataPilotTableHeaderData aDestData;
3731  pDPObj->GetHeaderPositionData( ScAddress(nNewDragX, nNewDragY, nTab), aDestData );
3732  bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
3733 
3734  // look through the source range
3735  for (SCROW nRow = aSourceRange.aStart.Row(); bValid && nRow <= aSourceRange.aEnd.Row(); ++nRow )
3736  for (SCCOL nCol = aSourceRange.aStart.Col(); bValid && nCol <= aSourceRange.aEnd.Col(); ++nCol )
3737  {
3738  sheet::DataPilotTableHeaderData aSourceData;
3739  pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, aSourceRange.aStart.Tab() ), aSourceData );
3740  if ( aSourceData.Dimension != aDestData.Dimension || aSourceData.MemberName.isEmpty() )
3741  bValid = false; // empty (subtotal) or different field
3742  }
3743 
3744  if ( bValid )
3745  {
3746  bool bIsDataLayout;
3747  OUString aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
3748  const ScDPSaveDimension* pDim = pDPObj->GetSaveData()->GetExistingDimensionByName( aDimName );
3749  if ( pDim )
3750  {
3751  ScRange aOutRange = pDPObj->GetOutRange();
3752 
3753  sheet::DataPilotFieldOrientation nOrient = pDim->GetOrientation();
3754  if ( nOrient == sheet::DataPilotFieldOrientation_COLUMN )
3755  {
3756  eDragInsertMode = INS_CELLSRIGHT;
3757  nSizeY = aOutRange.aEnd.Row() - nNewDragY + 1;
3758  bDPSort = true;
3759  }
3760  else if ( nOrient == sheet::DataPilotFieldOrientation_ROW )
3761  {
3762  eDragInsertMode = INS_CELLSDOWN;
3763  nSizeX = aOutRange.aEnd.Col() - nNewDragX + 1;
3764  bDPSort = true;
3765  }
3766  }
3767  }
3768  }
3769 
3770  if ( !bDPSort )
3771  {
3772  // no valid sorting in a DataPilot table -> disallow
3773  if ( bDragRect )
3774  {
3775  bDragRect = false;
3777  }
3778  return DND_ACTION_NONE;
3779  }
3780  }
3781  else if ( aState.mnState & KEY_MOD2 )
3782  {
3783  if ( &rThisDoc == pSourceDoc && nTab == aSourceRange.aStart.Tab() )
3784  {
3785  tools::Long nDeltaX = std::abs( static_cast< tools::Long >( nNewDragX - nSourceStartX ) );
3786  tools::Long nDeltaY = std::abs( static_cast< tools::Long >( nNewDragY - nSourceStartY ) );
3787  if ( nDeltaX <= nDeltaY )
3788  {
3789  eDragInsertMode = INS_CELLSDOWN;
3790  }
3791  else
3792  {
3793  eDragInsertMode = INS_CELLSRIGHT;
3794  }
3795 
3796  if ( ( eDragInsertMode == INS_CELLSDOWN && nNewDragY <= nSourceEndY &&
3797  ( nNewDragX + nSizeX - 1 ) >= nSourceStartX && nNewDragX <= nSourceEndX &&
3798  ( nNewDragX != nSourceStartX || nNewDragY >= nSourceStartY ) ) ||
3799  ( eDragInsertMode == INS_CELLSRIGHT && nNewDragX <= nSourceEndX &&
3800  ( nNewDragY + nSizeY - 1 ) >= nSourceStartY && nNewDragY <= nSourceEndY &&
3801  ( nNewDragY != nSourceStartY || nNewDragX >= nSourceStartX ) ) )
3802  {
3803  if ( bDragRect )
3804  {
3805  bDragRect = false;
3807  }
3808  return DND_ACTION_NONE;
3809  }
3810  }
3811  else
3812  {
3813  if ( static_cast< tools::Long >( nSizeX ) >= static_cast< tools::Long >( nSizeY ) )
3814  {
3815  eDragInsertMode = INS_CELLSDOWN;
3816 
3817  }
3818  else
3819  {
3820  eDragInsertMode = INS_CELLSRIGHT;
3821  }
3822  }
3823  }
3824 
3825  if ( nNewDragX != nDragStartX || nNewDragY != nDragStartY ||
3826  nDragStartX+nSizeX-1 != nDragEndX || nDragStartY+nSizeY-1 != nDragEndY ||
3827  !bDragRect || eDragInsertMode != meDragInsertMode )
3828  {
3829  nDragStartX = nNewDragX;
3830  nDragStartY = nNewDragY;
3831  nDragEndX = nDragStartX+nSizeX-1;
3832  nDragEndY = nDragStartY+nSizeY-1;
3833  bDragRect = true;
3834  meDragInsertMode = eDragInsertMode;
3835 
3837  }
3838  }
3839 
3840  return rEvt.mnAction;
3841 }
3842 
3844 {
3845  const ScDragData& rData = SC_MOD()->GetDragData();
3846  if ( rEvt.mbLeaving )
3847  {
3848  DrawMarkDropObj( nullptr );
3849  if ( rData.pCellTransfer )
3850  return AcceptPrivateDrop( rEvt ); // hide drop marker for internal D&D
3851  else
3852  return rEvt.mnAction;
3853  }
3854 
3855  if ( mrViewData.GetDocShell()->IsReadOnly() )
3856  return DND_ACTION_NONE;
3857 
3858  ScDocument& rThisDoc = mrViewData.GetDocument();
3859  sal_Int8 nRet = DND_ACTION_NONE;
3860 
3861  if (rData.pCellTransfer)
3862  {
3863  ScRange aSource = rData.pCellTransfer->GetRange();
3864  if ( aSource.aStart.Col() != 0 || aSource.aEnd.Col() != rThisDoc.MaxCol() ||
3865  aSource.aStart.Row() != 0 || aSource.aEnd.Row() != rThisDoc.MaxRow() )
3866  DropScroll( rEvt.maPosPixel );
3867 
3868  nRet = AcceptPrivateDrop( rEvt );
3869  }
3870  else
3871  {
3872  if ( !rData.aLinkDoc.isEmpty() )
3873  {
3874  OUString aThisName;
3875  ScDocShell* pDocSh = mrViewData.GetDocShell();
3876  if (pDocSh && pDocSh->HasName())
3877  aThisName = pDocSh->GetMedium()->GetName();
3878 
3879  if ( rData.aLinkDoc != aThisName )
3880  nRet = rEvt.mnAction;
3881  }
3882  else if (!rData.aJumpTarget.isEmpty())
3883  {
3884  // internal bookmarks (from Navigator)
3885  // local jumps from an unnamed document are possible only within a document
3886 
3887  if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == &mrViewData.GetDocument() )
3888  nRet = rEvt.mnAction;
3889  }
3890  else
3891  {
3892  sal_Int8 nMyAction = rEvt.mnAction;
3893 
3894  // clear DND_ACTION_LINK when other actions are set. The usage below cannot handle
3895  // multiple set values
3896  if((nMyAction & DND_ACTION_LINK) && (nMyAction & DND_ACTION_COPYMOVE))
3897  {
3898  nMyAction &= ~DND_ACTION_LINK;
3899  }
3900 
3901  if ( !rData.pDrawTransfer ||
3902  !IsMyModel(rData.pDrawTransfer->GetDragSourceView()) ) // drawing within the document
3903  if ( rEvt.mbDefault && nMyAction == DND_ACTION_MOVE )
3904  nMyAction = DND_ACTION_COPY;
3905 
3906  SdrObject* pHitObj = rThisDoc.GetObjectAtPoint(
3908  if ( pHitObj && nMyAction == DND_ACTION_LINK )
3909  {
3910  if ( IsDropFormatSupported(SotClipboardFormatId::SVXB)
3911  || IsDropFormatSupported(SotClipboardFormatId::GDIMETAFILE)
3912  || IsDropFormatSupported(SotClipboardFormatId::PNG)
3913  || IsDropFormatSupported(SotClipboardFormatId::BITMAP) )
3914  {
3915  // graphic dragged onto drawing object
3916  DrawMarkDropObj( pHitObj );
3917  nRet = nMyAction;
3918  }
3919  }
3920  if (!nRet)
3921  {
3922  DrawMarkDropObj(nullptr);
3923 
3924  switch ( nMyAction )
3925  {
3926  case DND_ACTION_COPY:
3927  case DND_ACTION_MOVE:
3928  case DND_ACTION_COPYMOVE:
3929  {
3930  bool bMove = ( nMyAction == DND_ACTION_MOVE );
3931  if ( IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE ) ||
3932  IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
3933  IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE_OLE ) ||
3934  IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
3935  IsDropFormatSupported( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) ||
3936  IsDropFormatSupported( SotClipboardFormatId::STRING ) ||
3937  IsDropFormatSupported( SotClipboardFormatId::STRING_TSVC ) ||
3938  IsDropFormatSupported( SotClipboardFormatId::SYLK ) ||
3939  IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
3940  IsDropFormatSupported( SotClipboardFormatId::HTML ) ||
3941  IsDropFormatSupported( SotClipboardFormatId::HTML_SIMPLE ) ||
3942  IsDropFormatSupported( SotClipboardFormatId::DIF ) ||
3943  IsDropFormatSupported( SotClipboardFormatId::DRAWING ) ||
3944  IsDropFormatSupported( SotClipboardFormatId::SVXB ) ||
3945  IsDropFormatSupported( SotClipboardFormatId::RTF ) ||
3946  IsDropFormatSupported( SotClipboardFormatId::RICHTEXT ) ||
3947  IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ) ||
3948  IsDropFormatSupported( SotClipboardFormatId::PNG ) ||
3949  IsDropFormatSupported( SotClipboardFormatId::BITMAP ) ||
3950  IsDropFormatSupported( SotClipboardFormatId::SBA_DATAEXCHANGE ) ||
3951  IsDropFormatSupported( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) ||
3952  ( !bMove && (
3953  IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
3954  IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
3955  IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
3956  IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
3957  IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
3958  IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) ) ) )
3959  {
3960  nRet = nMyAction;
3961  }
3962  }
3963  break;
3964  case DND_ACTION_LINK:
3965  if ( IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
3966  IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
3967  IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
3968  IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
3969  IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
3970  IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
3971  IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
3972  IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
3973  IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
3974  {
3975  nRet = nMyAction;
3976  }
3977  break;
3978  }
3979 
3980  if ( nRet )
3981  {
3982  // Simple check for protection: It's not known here if the drop will result
3983  // in cells or drawing objects (some formats can be both) and how many cells
3984  // the result will be. But if IsFormatEditable for the drop cell position
3985  // is sal_False (ignores matrix formulas), nothing can be pasted, so the drop
3986  // can already be rejected here.
3987 
3988  Point aPos = rEvt.maPosPixel;
3989  SCCOL nPosX;
3990  SCROW nPosY;
3991  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
3992  SCTAB nTab = mrViewData.GetTabNo();
3993  ScDocument& rDoc = mrViewData.GetDocument();
3994 
3995  ScEditableTester aTester( rDoc, nTab, nPosX,nPosY, nPosX,nPosY );
3996  if ( !aTester.IsFormatEditable() )
3997  nRet = DND_ACTION_NONE; // forbidden
3998  }
3999  }
4000  }
4001 
4002  // scroll only for accepted formats
4003  if (nRet)
4004  DropScroll( rEvt.maPosPixel );
4005  }
4006 
4007  return nRet;
4008 }
4009 
4010 static SotClipboardFormatId lcl_GetDropFormatId( const uno::Reference<datatransfer::XTransferable>& xTransfer, bool bPreferText )
4011 {
4012  TransferableDataHelper aDataHelper( xTransfer );
4013 
4014  if ( !aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
4015  {
4016  // use bookmark formats if no sba is present
4017 
4018  if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
4019  return SotClipboardFormatId::SOLK;
4020  else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
4021  return SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
4022  else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
4023  return SotClipboardFormatId::NETSCAPE_BOOKMARK;
4024  else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
4025  return SotClipboardFormatId::FILEGRPDESCRIPTOR;
4026  }
4027 
4028  SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
4029  if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
4030  nFormatId = SotClipboardFormatId::DRAWING;
4031  else if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
4032  nFormatId = SotClipboardFormatId::SVXB;
4033  else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) )
4034  {
4035  // If it's a Writer object, insert RTF instead of OLE
4036 
4037  bool bDoRtf = false;
4040  if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) &&
4041  aDataHelper.GetSotStorageStream( SotClipboardFormatId::EMBED_SOURCE, xStm ) )
4042  {
4043  bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
4044  aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
4045  && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
4046  }
4047  if ( bDoRtf )
4048  nFormatId = aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
4049  else
4050  nFormatId = SotClipboardFormatId::EMBED_SOURCE;
4051  }
4052  else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
4053  nFormatId = SotClipboardFormatId::LINK_SOURCE;
4054  else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
4055  nFormatId = SotClipboardFormatId::SBA_DATAEXCHANGE;
4056  else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) )
4057  nFormatId = SotClipboardFormatId::SBA_FIELDDATAEXCHANGE;
4058  else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_8 ) )
4059  nFormatId = SotClipboardFormatId::BIFF_8;
4060  else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_5 ) )
4061  nFormatId = SotClipboardFormatId::BIFF_5;
4062  else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ) )
4063  nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
4064  else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) )
4065  nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
4066  else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
4067  nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
4068  else if ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
4069  nFormatId = SotClipboardFormatId::RTF;
4070  else if ( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
4071  nFormatId = SotClipboardFormatId::RICHTEXT;
4072  else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML ) )
4073  nFormatId = SotClipboardFormatId::HTML;
4074  else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML_SIMPLE ) )
4075  nFormatId = SotClipboardFormatId::HTML_SIMPLE;
4076  else if ( aDataHelper.HasFormat( SotClipboardFormatId::SYLK ) )
4077  nFormatId = SotClipboardFormatId::SYLK;
4078  else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
4079  nFormatId = SotClipboardFormatId::LINK;
4080  else if ( bPreferText && aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ) // #i86734# the behaviour introduced in #i62773# is wrong when pasting
4081  nFormatId = SotClipboardFormatId::STRING;
4082  else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
4083  nFormatId = SotClipboardFormatId::FILE_LIST;
4084  else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) ) // #i62773# FILE_LIST/FILE before STRING (Unix file managers)
4085  nFormatId = SotClipboardFormatId::SIMPLE_FILE;
4086  else if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING_TSVC ) )
4087  nFormatId = SotClipboardFormatId::STRING_TSVC;
4088  else if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
4089  nFormatId = SotClipboardFormatId::STRING;
4090  else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
4091  nFormatId = SotClipboardFormatId::GDIMETAFILE;
4092  else if ( aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
4093  nFormatId = SotClipboardFormatId::PNG;
4094  else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) )
4095  nFormatId = SotClipboardFormatId::BITMAP;
4096 
4097  return nFormatId;
4098 }
4099 
4100 static SotClipboardFormatId lcl_GetDropLinkId( const uno::Reference<datatransfer::XTransferable>& xTransfer )
4101 {
4102  TransferableDataHelper aDataHelper( xTransfer );
4103 
4104  SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
4105  if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
4106  nFormatId = SotClipboardFormatId::LINK_SOURCE;
4107  else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
4108  nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
4109  else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
4110  nFormatId = SotClipboardFormatId::LINK;
4111  else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
4112  nFormatId = SotClipboardFormatId::FILE_LIST;
4113  else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) )
4114  nFormatId = SotClipboardFormatId::SIMPLE_FILE;
4115  else if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
4116  nFormatId = SotClipboardFormatId::SOLK;
4117  else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
4118  nFormatId = SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
4119  else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
4120  nFormatId = SotClipboardFormatId::NETSCAPE_BOOKMARK;
4121  else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
4122  nFormatId = SotClipboardFormatId::FILEGRPDESCRIPTOR;
4123 
4124  return nFormatId;
4125 }
4126 
4128 {
4129  // hide drop marker
4130  bDragRect = false;
4132 
4133  ScModule* pScMod = SC_MOD();
4134  const ScDragData& rData = pScMod->GetDragData();
4135 
4137  PixelToLogic(rEvt.maPosPixel), rEvt.mnAction );
4138 }
4139 
4141  const Point& rLogicPos, sal_Int8 nDndAction )
4142 {
4143  if ( !pTransObj )
4144  return 0;
4145 
4146  ScDocument* pSourceDoc = pTransObj->GetSourceDocument();
4147  ScDocShell* pDocSh = mrViewData.GetDocShell();
4148  ScDocument& rThisDoc = mrViewData.GetDocument();
4149  ScViewFunc* pView = mrViewData.GetView();
4150  SCTAB nThisTab = mrViewData.GetTabNo();
4151  ScDragSrc nFlags = pTransObj->GetDragSourceFlags();
4152 
4153  bool bIsNavi = (nFlags & ScDragSrc::Navigator) == ScDragSrc::Navigator;
4154  bool bIsMove = ( nDndAction == DND_ACTION_MOVE && !bIsNavi );
4155 
4156  // workaround for wrong nDndAction on Windows when pressing solely
4157  // the Alt key during drag and drop;
4158  // can be removed after #i79215# has been fixed
4159  if ( meDragInsertMode != INS_NONE )
4160  {
4161  bIsMove = ( nDndAction & DND_ACTION_MOVE && !bIsNavi );
4162  }
4163 
4164  bool bIsLink = ( nDndAction == DND_ACTION_LINK );
4165 
4166  ScRange aSource = pTransObj->GetRange();
4167 
4168  // only use visible tab from source range - when dragging within one table,
4169  // all selected tables at the time of dropping are used (handled in MoveBlockTo)
4170  SCTAB nSourceTab = pTransObj->GetVisibleTab();
4171  aSource.aStart.SetTab( nSourceTab );
4172  aSource.aEnd.SetTab( nSourceTab );
4173 
4174  SCCOL nSizeX = aSource.aEnd.Col() - aSource.aStart.Col() + 1;
4175  SCROW nSizeY = (bIsMove ? (aSource.aEnd.Row() - aSource.aStart.Row() + 1) :
4176  pTransObj->GetNonFilteredRows()); // copy/link: no filtered rows
4177  ScRange aDest( nDestPosX, nDestPosY, nThisTab,
4178  nDestPosX + nSizeX - 1, nDestPosY + nSizeY - 1, nThisTab );
4179 
4180  /* NOTE: AcceptPrivateDrop() already checked for filtered conditions during
4181  * dragging and adapted drawing of the selection frame. We check here
4182  * (again) because this may actually also be called from PasteSelection(),
4183  * we would have to duplicate determination of flags and destination range
4184  * and would lose the context of the "filtered destination is OK" cases
4185  * below, which is already awkward enough as is. */
4186 
4187  // Don't move filtered source.
4188  bool bFiltered = (bIsMove && pTransObj->HasFilteredRows());
4189  if (!bFiltered)
4190  {
4191  if (pSourceDoc != &rThisDoc && ((nFlags & ScDragSrc::Table) ||
4192  (!bIsLink && meDragInsertMode == INS_NONE)))
4193  {
4194  // Nothing. Either entire sheet to be dropped, or the one case
4195  // where PasteFromClip() is to be called that handles a filtered
4196  // destination itself. Drag-copy from another document without
4197  // inserting cells.
4198  }
4199  else
4200  // Don't copy or move to filtered destination.
4201  bFiltered = ScViewUtil::HasFiltered(aDest, rThisDoc);
4202  }
4203 
4204  bool bDone = false;
4205 
4206  if (!bFiltered && pSourceDoc == &rThisDoc)
4207  {
4208  if (nFlags & ScDragSrc::Table) // whole sheet?
4209  {
4210  if ( rThisDoc.IsDocEditable() )
4211  {
4212  SCTAB nSrcTab = aSource.aStart.Tab();
4213  mrViewData.GetDocShell()->MoveTable( nSrcTab, nThisTab, !bIsMove, true ); // with Undo
4214  pView->SetTabNo( nThisTab, true );
4215  bDone = true;
4216  }
4217  }
4218  else // move/copy block
4219  {
4220  OUString aChartName;
4221  if (rThisDoc.HasChartAtPoint( nThisTab, rLogicPos, aChartName ))
4222  {
4223  OUString aRangeName(aSource.Format(rThisDoc, ScRefFlags::RANGE_ABS_3D));
4224  SfxStringItem aNameItem( SID_CHART_NAME, aChartName );
4225  SfxStringItem aRangeItem( SID_CHART_SOURCE, aRangeName );
4226  sal_uInt16 nId = bIsMove ? SID_CHART_SOURCE : SID_CHART_ADDSOURCE;
4228  SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
4229  { &aRangeItem, &aNameItem });
4230  bDone = true;
4231  }
4232  else if ( rThisDoc.GetDPAtCursor( nDestPosX, nDestPosY, nThisTab ) )
4233  {
4234  // drop on DataPilot table: try to sort, fail if that isn't possible
4235 
4236  ScAddress aDestPos( nDestPosX, nDestPosY, nThisTab );
4237  if ( aDestPos != aSource.aStart )
4238  bDone = mrViewData.GetView()->DataPilotMove( aSource, aDestPos );
4239  else
4240  bDone = true; // same position: nothing
4241  }
4242  else if ( nDestPosX != aSource.aStart.Col() || nDestPosY != aSource.aStart.Row() ||
4243  nSourceTab != nThisTab )
4244  {
4245  OUString aUndo = ScResId( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
4246  pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
4247 
4248  SCCOL nCorrectCursorPosCol = 0;
4249  SCROW nCorrectCursorPosRow = 0;
4250 
4251  bDone = true;
4252  if ( meDragInsertMode != INS_NONE )
4253  {
4254  // call with bApi = sal_True to avoid error messages in drop handler
4255  bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4256  if ( bDone )
4257  {
4258  if ( nThisTab == nSourceTab )
4259  {
4260  if ( meDragInsertMode == INS_CELLSDOWN &&
4261  nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
4262  {
4263  ScRange aErrorRange( ScAddress::UNINITIALIZED );
4264  bDone = aSource.Move( 0, nSizeY, 0, aErrorRange, pSourceDoc );
4265  nCorrectCursorPosRow = nSizeY;
4266  }
4267  else if ( meDragInsertMode == INS_CELLSRIGHT &&
4268  nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
4269  {
4270  ScRange aErrorRange( ScAddress::UNINITIALIZED );
4271  bDone = aSource.Move( nSizeX, 0, 0, aErrorRange, pSourceDoc );
4272  nCorrectCursorPosCol = nSizeX;
4273  }
4274  }
4275  pDocSh->UpdateOle(mrViewData);
4276  pView->CellContentChanged();
4277  }
4278  }
4279 
4280  if ( bDone )
4281  {
4282  if ( bIsLink )
4283  {
4284  bDone = pView->LinkBlock( aSource, aDest.aStart );
4285  }
4286  else
4287  {
4288  bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove );
4289  }
4290  }
4291 
4292  if ( bDone && meDragInsertMode != INS_NONE && bIsMove && nThisTab == nSourceTab )
4293  {
4296  {
4297  eCmd = DelCellCmd::CellsUp;
4298  }
4299  else if ( meDragInsertMode == INS_CELLSRIGHT )
4300  {
4301  eCmd = DelCellCmd::CellsLeft;
4302  }
4303 
4304  if ( ( eCmd == DelCellCmd::CellsUp && nDestPosX == aSource.aStart.Col() ) ||
4305  ( eCmd == DelCellCmd::CellsLeft && nDestPosY == aSource.aStart.Row() ) )
4306  {
4307  // call with bApi = sal_True to avoid error messages in drop handler
4308  bDone = pDocSh->GetDocFunc().DeleteCells( aSource, nullptr, eCmd, true /*bApi*/ );
4309  if ( bDone )
4310  {
4311  if ( eCmd == DelCellCmd::CellsUp && nDestPosY > aSource.aEnd.Row() )
4312  {
4313  ScRange aErrorRange( ScAddress::UNINITIALIZED );
4314  bDone = aDest.Move( 0, -nSizeY, 0, aErrorRange, &rThisDoc );
4315  }
4316  else if ( eCmd == DelCellCmd::CellsLeft && nDestPosX > aSource.aEnd.Col() )
4317  {
4318  ScRange aErrorRange( ScAddress::UNINITIALIZED );
4319  bDone = aDest.Move( -nSizeX, 0, 0, aErrorRange, &rThisDoc );
4320  }
4321  pDocSh->UpdateOle(mrViewData);
4322  pView->CellContentChanged();
4323  }
4324  }
4325  }
4326 
4327  if ( bDone )
4328  {
4329  pView->MarkRange( aDest, false );
4330 
4331  SCCOL nDCol;
4332  SCROW nDRow;
4333  if (pTransObj->WasSourceCursorInSelection())
4334  {
4335  nDCol = pTransObj->GetSourceCursorX() - aSource.aStart.Col() + nCorrectCursorPosCol;
4336  nDRow = pTransObj->GetSourceCursorY() - aSource.aStart.Row() + nCorrectCursorPosRow;
4337  }
4338  else
4339  {
4340  nDCol = 0;
4341  nDRow = 0;
4342  }
4343  pView->SetCursor( aDest.aStart.Col() + nDCol, aDest.aStart.Row() + nDRow );
4344  }
4345 
4346  pDocSh->GetUndoManager()->LeaveListAction();
4347 
4348  }
4349  else
4350  bDone = true; // nothing to do
4351  }
4352 
4353  if (bDone)
4354  pTransObj->SetDragWasInternal(); // don't delete source in DragFinished
4355  }
4356  else if ( !bFiltered && pSourceDoc ) // between documents
4357  {
4358  if (nFlags & ScDragSrc::Table) // copy/link sheets between documents
4359  {
4360  if ( rThisDoc.IsDocEditable() )
4361  {
4362  ScDocShell* pSrcShell = pTransObj->GetSourceDocShell();
4363 
4364  std::vector<SCTAB> nTabs;
4365 
4366  ScMarkData aMark = pTransObj->GetSourceMarkData();
4367  SCTAB nTabCount = pSourceDoc->GetTableCount();
4368 
4369  for(SCTAB i=0; i<nTabCount; i++)
4370  {
4371  if(aMark.GetTableSelect(i))
4372  {
4373  nTabs.push_back(i);
4374  for(SCTAB j=i+1;j<nTabCount;j++)
4375  {
4376  if((!pSourceDoc->IsVisible(j))&&(pSourceDoc->IsScenario(j)))
4377  {
4378  nTabs.push_back( j );
4379  i=j;
4380  }
4381  else break;
4382  }
4383  }
4384  }
4385 
4386  pView->ImportTables( pSrcShell,static_cast<SCTAB>(nTabs.size()), nTabs.data(), bIsLink, nThisTab );
4387  bDone = true;
4388  }
4389  }
4390  else if ( bIsLink )
4391  {
4392  // as in PasteDDE
4393  // (external references might be used instead?)
4394 
4395  SfxObjectShell* pSourceSh = pSourceDoc->GetDocumentShell();
4396  OSL_ENSURE(pSourceSh, "drag document has no shell");
4397  if (pSourceSh)
4398  {
4399  OUString aUndo = ScResId( STR_UNDO_COPY );
4400  pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
4401 
4402  bDone = true;
4403  if ( meDragInsertMode != INS_NONE )
4404  {
4405  // call with bApi = sal_True to avoid error messages in drop handler
4406  bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4407  if ( bDone )
4408  {
4409  pDocSh->UpdateOle(mrViewData);
4410  pView->CellContentChanged();
4411  }
4412  }
4413 
4414  if ( bDone )
4415  {
4416  OUString aApp = Application::GetAppName();
4417  OUString aTopic = pSourceSh->GetTitle( SFX_TITLE_FULLNAME );
4418  OUString aItem(aSource.Format(*pSourceDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D));
4419 
4420  // TODO: we could define ocQuote for "
4421  const OUString aQuote('"');
4422  const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
4423  OUString aFormula =
4424  "=" +
4427  aQuote +
4428  aApp +
4429  aQuote +
4430  sSep +
4431  aQuote +
4432  aTopic +
4433  aQuote +
4434  sSep +
4435  aQuote +
4436  aItem +
4437  aQuote +
4439 
4440  pView->DoneBlockMode();
4441  pView->InitBlockMode( nDestPosX, nDestPosY, nThisTab );
4442  pView->MarkCursor( nDestPosX + nSizeX - 1,
4443  nDestPosY + nSizeY - 1, nThisTab );
4444 
4445  pView->EnterMatrix( aFormula, ::formula::FormulaGrammar::GRAM_NATIVE );
4446 
4447  pView->MarkRange( aDest, false );
4448  pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
4449  }
4450 
4451  pDocSh->GetUndoManager()->LeaveListAction();
4452  }
4453  }
4454  else
4455  {
4458 
4459  OUString aUndo = ScResId( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
4460  pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
4461 
4462  bDone = true;
4463  if ( meDragInsertMode != INS_NONE )
4464  {
4465  // call with bApi = sal_True to avoid error messages in drop handler
4466  bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4467  if ( bDone )
4468  {
4469  pDocSh->UpdateOle(mrViewData);
4470  pView->CellContentChanged();
4471  }
4472  }
4473 
4474  if ( bDone )
4475  {
4476  pView->Unmark(); // before SetCursor, so CheckSelectionTransfer isn't called with a selection
4477  pView->SetCursor( nDestPosX, nDestPosY );
4478  bDone = pView->PasteFromClip( InsertDeleteFlags::ALL, pTransObj->GetDocument() ); // clip-doc
4479  if ( bDone )
4480  {
4481  pView->MarkRange( aDest, false );
4482  pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
4483  }
4484  }
4485 
4486  pDocSh->GetUndoManager()->LeaveListAction();
4487 
4488  // no longer call ResetMark here - the inserted block has been selected
4489  // and may have been copied to primary selection
4490  }
4491  }
4492 
4493  sal_Int8 nRet = bDone ? nDndAction : DND_ACTION_NONE;
4494  return nRet;
4495 }
4496 
4498 {
4499  DrawMarkDropObj( nullptr ); // drawing layer
4500 
4501  ScModule* pScMod = SC_MOD();
4502  const ScDragData& rData = pScMod->GetDragData();
4503  if (rData.pCellTransfer)
4504  return ExecutePrivateDrop( rEvt );
4505 
4506  Point aPos = rEvt.maPosPixel;
4507 
4508  if ( !rData.aLinkDoc.isEmpty() )
4509  {
4510  // try to insert a link
4511 
4512  bool bOk = true;
4513  OUString aThisName;
4514  ScDocShell* pDocSh = mrViewData.GetDocShell();
4515  if (pDocSh && pDocSh->HasName())
4516  aThisName = pDocSh->GetMedium()->GetName();
4517 
4518  if ( rData.aLinkDoc == aThisName ) // error - no link within a document
4519  bOk = false;
4520  else
4521  {
4522  ScViewFunc* pView = mrViewData.GetView();
4523  if ( !rData.aLinkTable.isEmpty() )
4525  rData.aLinkTable );
4526  else if ( !rData.aLinkArea.isEmpty() )
4527  {
4528  SCCOL nPosX;
4529  SCROW nPosY;
4530  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
4531  pView->MoveCursorAbs( nPosX, nPosY, SC_FOLLOW_NONE, false, false );
4532 
4534  rData.aLinkArea );
4535  }
4536  else
4537  {
4538  OSL_FAIL("drop with link: no sheet nor area");
4539  bOk = false;
4540  }
4541  }
4542 
4543  return bOk ? rEvt.mnAction : DND_ACTION_NONE; // don't try anything else
4544  }
4545 
4546  Point aLogicPos = PixelToLogic(aPos);
4547  bool bIsLink = ( rEvt.mnAction == DND_ACTION_LINK );
4548 
4549  if (!bIsLink && rData.pDrawTransfer)
4550  {
4551  ScDragSrc nFlags = rData.pDrawTransfer->GetDragSourceFlags();
4552 
4553  bool bIsNavi = (nFlags & ScDragSrc::Navigator) == ScDragSrc::Navigator;
4554  bool bIsMove = ( rEvt.mnAction == DND_ACTION_MOVE && !bIsNavi );
4555 
4556  bPasteIsMove = bIsMove;
4557 
4559  aLogicPos, rData.pDrawTransfer->GetModel(), false, u"A", u"B");
4560 
4561  if (bPasteIsMove)
4563  bPasteIsMove = false;
4564 
4565  return rEvt.mnAction;
4566  }
4567 
4568  SCCOL nPosX;
4569  SCROW nPosY;
4570  mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
4571 
4572  if (!rData.aJumpTarget.isEmpty())
4573  {
4574  // internal bookmark (from Navigator)
4575  // bookmark clipboard formats are in PasteScDataObject
4576 
4577  if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == &mrViewData.GetDocument() )
4578  {
4580  nPosX, nPosY );
4581  return rEvt.mnAction;
4582  }
4583  }
4584 
4585  ScDocument& rThisDoc = mrViewData.GetDocument();
4586  SdrObject* pHitObj = rThisDoc.GetObjectAtPoint( mrViewData.GetTabNo(), PixelToLogic(aPos) );
4587  if ( pHitObj && bIsLink )
4588  {
4589  // dropped on drawing object
4590  // PasteOnDrawObjectLinked checks for valid formats
4591  if ( mrViewData.GetView()->PasteOnDrawObjectLinked( rEvt.maDropEvent.Transferable, *pHitObj ) )
4592  return rEvt.mnAction;
4593  }
4594 
4595  bool bDone = false;
4596 
4597  SotClipboardFormatId nFormatId = bIsLink ?
4598  lcl_GetDropLinkId( rEvt.maDropEvent.Transferable ) :
4599  lcl_GetDropFormatId( rEvt.maDropEvent.Transferable, false );
4600  if ( nFormatId != SotClipboardFormatId::NONE )
4601  {
4602  pScMod->SetInExecuteDrop( true ); // #i28468# prevent error messages from PasteDataFormat
4603  bDone = mrViewData.GetView()->PasteDataFormat(
4604  nFormatId, rEvt.maDropEvent.Transferable, nPosX, nPosY, &aLogicPos, bIsLink );
4605  pScMod->SetInExecuteDrop( false );
4606  }
4607 
4608  sal_Int8 nRet = bDone ? rEvt.mnAction : DND_ACTION_NONE;
4609  return nRet;
4610 }
4611 
4612 void ScGridWindow::PasteSelection( const Point& rPosPixel )
4613 {
4614  Point aLogicPos = PixelToLogic( rPosPixel );
4615 
4616  SCCOL nPosX;
4617  SCROW nPosY;
4618  mrViewData.GetPosFromPixel( rPosPixel.X(), rPosPixel.Y(), eWhich, nPosX, nPosY );
4619 
4620  // If the mouse down was inside a visible note window, ignore it and
4621  // leave it up to the ScPostIt to handle it
4622  SdrView* pDrawView = mrViewData.GetViewShell()->GetScDrawView();
4623  if (pDrawView)
4624  {
4625  const size_t nCount = pDrawView->GetMarkedObjectCount();
4626  for (size_t i = 0; i < nCount; ++i)
4627  {
4628  SdrObject* pObj = pDrawView->GetMarkedObjectByIndex(i);
4629  if (pObj && pObj->GetLogicRect().IsInside(aLogicPos))
4630  {
4631  // Inside an active drawing object. Bail out.
4632  return;
4633  }
4634  }
4635  }
4636 
4637  ScSelectionTransferObj* pOwnSelection = SC_MOD()->GetSelectionTransfer();
4638  if ( pOwnSelection )
4639  {
4640  // within Calc
4641 
4642  // keep a reference to the data in case the selection is changed during paste
4643  rtl::Reference<ScTransferObj> pCellTransfer = pOwnSelection->GetCellData();
4644  if ( pCellTransfer )
4645  {
4646  DropTransferObj( pCellTransfer.get(), nPosX, nPosY, aLogicPos, DND_ACTION_COPY );
4647  }
4648  else
4649  {
4650  // keep a reference to the data in case the selection is changed during paste
4651  rtl::Reference<ScDrawTransferObj> pDrawTransfer = pOwnSelection->GetDrawData();
4652  if ( pDrawTransfer )
4653  {
4654  // bSameDocClipboard argument for PasteDraw is needed
4655  // because only DragData is checked directly inside PasteDraw
4657  aLogicPos, pDrawTransfer->GetModel(), false,
4658  pDrawTransfer->GetShellID(), SfxObjectShell::CreateShellID(mrViewData.GetDocShell()));
4659  }
4660  }
4661  }
4662  else
4663  {
4664  // get selection from system
4666  const uno::Reference<datatransfer::XTransferable>& xTransferable = aDataHelper.GetTransferable();
4667  if ( xTransferable.is() )
4668  {
4669  SotClipboardFormatId nFormatId = lcl_GetDropFormatId( xTransferable, true );
4670  if ( nFormatId != SotClipboardFormatId::NONE )
4671  mrViewData.GetView()->PasteDataFormat( nFormatId, xTransferable, nPosX, nPosY, &aLogicPos );
4672  }
4673  }
4674 }
4675 
4677 {
4678  if (!mrViewData.HasEditView(eWhich))
4679  return;
4680 
4681  EditView* pView;
4682  SCCOL nCol;
4683  SCROW nRow;
4684  mrViewData.GetEditView( eWhich, pView, nCol, nRow );
4685  SCCOL nEndCol = mrViewData.GetEditEndCol();
4686  SCROW nEndRow = mrViewData.GetEditEndRow();
4687 
4688  // hide EditView?
4689 
4690  bool bHide = ( nEndCol<mrViewData.GetPosX(eHWhich) || nEndRow<mrViewData.GetPosY(eVWhich) );
4691  if ( SC_MOD()->IsFormulaMode() )
4693  bHide = true;
4694 
4695  if (bHide)
4696  {
4697  tools::Rectangle aRect = pView->GetOutputArea();
4698  tools::Long nHeight = aRect.Bottom() - aRect.Top();
4700  Height() * 2 );
4701  aRect.SetBottom( aRect.Top() + nHeight );
4702  pView->SetOutputArea( aRect );
4703  pView->HideCursor();
4704  }
4705  else
4706  {
4707  // bForceToTop = sal_True for editing
4708  tools::Rectangle aPixRect = mrViewData.GetEditArea( eWhich, nCol, nRow, this, nullptr, true );
4709 
4712  comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
4713  {
4714  tools::Rectangle aPTwipsRect = mrViewData.GetEditArea(eWhich, nCol, nRow, this, nullptr,
4715  true, true /* bInPrintTwips */);
4716  tools::Rectangle aOutputAreaPTwips = pView->GetLOKSpecialOutputArea();
4717  aOutputAreaPTwips.SetPos(aPTwipsRect.TopLeft());
4718  pView->SetLOKSpecialOutputArea(aOutputAreaPTwips);
4719  }
4720 
4721  Point aScrPos = PixelToLogic( aPixRect.TopLeft(), mrViewData.GetLogicMode() );
4722 
4723  tools::Rectangle aRect = pView->GetOutputArea();