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