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