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