fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / view / gridwin.cxx
blobcfc0b5e27dd1a4784a61b335b9e94561655cd6a6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "scitems.hxx"
22 #include <memory>
23 #include <editeng/adjustitem.hxx>
24 #include <sot/storage.hxx>
25 #include <svx/algitem.hxx>
26 #include <editeng/editview.hxx>
27 #include <editeng/editstat.hxx>
28 #include <editeng/flditem.hxx>
29 #include <editeng/justifyitem.hxx>
30 #include <editeng/unolingu.hxx>
31 #include <editeng/langitem.hxx>
32 #include <editeng/misspellrange.hxx>
33 #include <svx/svdetc.hxx>
34 #include <editeng/editobj.hxx>
35 #include <sfx2/dispatch.hxx>
36 #include <sfx2/viewfrm.hxx>
37 #include <sfx2/docfile.hxx>
38 #include <svl/stritem.hxx>
39 #include <svtools/svtabbx.hxx>
40 #include <svl/urlbmk.hxx>
41 #include <svl/sharedstringpool.hxx>
42 #include <vcl/cursor.hxx>
43 #include <vcl/graph.hxx>
44 #include <vcl/hatch.hxx>
45 #include <vcl/settings.hxx>
46 #include <sot/formats.hxx>
47 #include <comphelper/classids.hxx>
48 #include <sal/macros.h>
50 #include <svx/svdview.hxx>
51 #include <editeng/outliner.hxx>
52 #include <svx/svditer.hxx>
53 #include <svx/svdocapt.hxx>
54 #include <svx/svdpagv.hxx>
56 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
57 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
58 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
59 #include <com/sun/star/sheet/DataPilotTableResultData.hpp>
60 #include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
61 #include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
62 #include <com/sun/star/sheet/MemberResultFlags.hpp>
63 #include <com/sun/star/awt/KeyModifier.hpp>
64 #include <com/sun/star/awt/MouseButton.hpp>
65 #include <com/sun/star/script/vba/VBAEventId.hpp>
66 #include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
67 #include <com/sun/star/text/textfield/Type.hpp>
69 #include "gridwin.hxx"
70 #include "tabvwsh.hxx"
71 #include "docsh.hxx"
72 #include "viewdata.hxx"
73 #include "tabview.hxx"
74 #include "select.hxx"
75 #include "scmod.hxx"
76 #include "document.hxx"
77 #include "attrib.hxx"
78 #include "dbdata.hxx"
79 #include "stlpool.hxx"
80 #include "printfun.hxx"
81 #include "cbutton.hxx"
82 #include "sc.hrc"
83 #include "globstr.hrc"
84 #include "editutil.hxx"
85 #include "scresid.hxx"
86 #include "inputhdl.hxx"
87 #include "uiitems.hxx"
88 #include "filtdlg.hxx"
89 #include "impex.hxx"
90 #include "formulacell.hxx"
91 #include "patattr.hxx"
92 #include "notemark.hxx"
93 #include "rfindlst.hxx"
94 #include "docpool.hxx"
95 #include "output.hxx"
96 #include "docfunc.hxx"
97 #include "dbdocfun.hxx"
98 #include "dpobject.hxx"
99 #include "dpoutput.hxx"
100 #include "transobj.hxx"
101 #include "drwtrans.hxx"
102 #include "seltrans.hxx"
103 #include "sizedev.hxx"
104 #include "AccessibilityHints.hxx"
105 #include "dpsave.hxx"
106 #include "viewuno.hxx"
107 #include "compiler.hxx"
108 #include "editable.hxx"
109 #include "fillinfo.hxx"
110 #include "userdat.hxx"
111 #include "drwlayer.hxx"
112 #include "validat.hxx"
113 #include "tabprotection.hxx"
114 #include "postit.hxx"
115 #include "dpcontrol.hxx"
116 #include "checklistmenu.hxx"
117 #include "clipparam.hxx"
118 #include "cellsh.hxx"
119 #include "overlayobject.hxx"
120 #include "cellsuno.hxx"
121 #include "drawview.hxx"
122 #include "dragdata.hxx"
123 #include "cliputil.hxx"
124 #include "queryentry.hxx"
125 #include "markdata.hxx"
126 #include "checklistmenu.hrc"
127 #include "strload.hxx"
128 #include "externalrefmgr.hxx"
129 #include "dociter.hxx"
130 #include "hints.hxx"
131 #include "spellcheckcontext.hxx"
133 #include <svx/sdrpagewindow.hxx>
134 #include <svx/sdr/overlay/overlaymanager.hxx>
135 #include <vcl/svapp.hxx>
136 #include <svx/sdr/overlay/overlayselection.hxx>
138 #define LOK_USE_UNSTABLE_API
139 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
141 #include <vector>
142 #include <boost/shared_ptr.hpp>
144 using namespace css;
145 using namespace css::uno;
147 const sal_uInt8 SC_NESTEDBUTTON_NONE = 0;
148 const sal_uInt8 SC_NESTEDBUTTON_DOWN = 1;
149 const sal_uInt8 SC_NESTEDBUTTON_UP = 2;
151 #define SC_AUTOFILTER_ALL 0
152 #define SC_AUTOFILTER_TOP10 1
153 #define SC_AUTOFILTER_CUSTOM 2
154 #define SC_AUTOFILTER_EMPTY 3
155 #define SC_AUTOFILTER_NOTEMPTY 4
157 // Modi fuer die FilterListBox
158 enum ScFilterBoxMode
160 SC_FILTERBOX_FILTER,
161 SC_FILTERBOX_DATASELECT,
162 SC_FILTERBOX_SCENARIO,
163 SC_FILTERBOX_PAGEFIELD
166 extern SfxViewShell* pScActiveViewShell; // global.cxx
167 extern sal_uInt16 nScClickMouseModifier; // global.cxx
168 extern sal_uInt16 nScFillModeMouseModifier; // global.cxx
170 struct ScGridWindow::MouseEventState
172 bool mbActivatePart;
174 MouseEventState() :
175 mbActivatePart(false)
179 #define SC_FILTERLISTBOX_LINES 12
181 ScGridWindow::VisibleRange::VisibleRange()
182 : mnCol1(0)
183 , mnCol2(MAXCOL)
184 , mnRow1(0)
185 , mnRow2(MAXROW)
189 bool ScGridWindow::VisibleRange::isInside(SCCOL nCol, SCROW nRow) const
191 return mnCol1 <= nCol && nCol <= mnCol2 && mnRow1 <= nRow && nRow <= mnRow2;
194 bool ScGridWindow::VisibleRange::set(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
196 bool bChanged = mnCol1 != nCol1 || mnRow1 != nRow1 || mnCol2 != nCol2 || mnRow2 != nRow2;
198 mnCol1 = nCol1;
199 mnRow1 = nRow1;
200 mnCol2 = nCol2;
201 mnRow2 = nRow2;
203 return bChanged;
206 class ScFilterListBox : public ListBox
208 private:
209 VclPtr<ScGridWindow> pGridWin;
210 SCCOL nCol;
211 SCROW nRow;
212 bool bButtonDown;
213 bool bInit;
214 bool bCancelled;
215 bool bInSelect;
216 bool mbListHasDates;
217 sal_uLong nSel;
218 ScFilterBoxMode eMode;
220 protected:
221 virtual void LoseFocus() SAL_OVERRIDE;
222 void SelectHdl();
224 public:
225 ScFilterListBox( vcl::Window* pParent, ScGridWindow* pGrid,
226 SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode );
227 virtual ~ScFilterListBox();
228 virtual void dispose() SAL_OVERRIDE;
230 virtual bool PreNotify( NotifyEvent& rNEvt ) SAL_OVERRIDE;
231 virtual void Select() SAL_OVERRIDE;
233 SCCOL GetCol() const { return nCol; }
234 SCROW GetRow() const { return nRow; }
235 ScFilterBoxMode GetMode() const { return eMode; }
236 void EndInit();
237 bool IsInInit() const { return bInit; }
238 void SetCancelled() { bCancelled = true; }
239 bool IsInSelect() const { return bInSelect; }
240 void SetListHasDates(bool b) { mbListHasDates = b; }
241 bool HasDates() const { return mbListHasDates; }
244 // ListBox in einem FloatingWindow (pParent)
245 ScFilterListBox::ScFilterListBox( vcl::Window* pParent, ScGridWindow* pGrid,
246 SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode ) :
247 ListBox( pParent, WB_AUTOHSCROLL ),
248 pGridWin( pGrid ),
249 nCol( nNewCol ),
250 nRow( nNewRow ),
251 bButtonDown( false ),
252 bInit( true ),
253 bCancelled( false ),
254 bInSelect( false ),
255 mbListHasDates(false),
256 nSel( 0 ),
257 eMode( eNewMode )
261 ScFilterListBox::~ScFilterListBox()
263 disposeOnce();
266 void ScFilterListBox::dispose()
268 if (IsMouseCaptured())
269 ReleaseMouse();
270 pGridWin.clear();
271 ListBox::dispose();
274 void ScFilterListBox::EndInit()
276 sal_Int32 nPos = GetSelectEntryPos();
277 if ( LISTBOX_ENTRY_NOTFOUND == nPos )
278 nSel = 0;
279 else
280 nSel = nPos;
282 bInit = false;
285 void ScFilterListBox::LoseFocus()
287 #ifndef UNX
288 Hide();
289 #endif
290 vcl::Window::LoseFocus();
293 bool ScFilterListBox::PreNotify( NotifyEvent& rNEvt )
295 bool nDone = false;
296 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
298 KeyEvent aKeyEvt = *rNEvt.GetKeyEvent();
299 vcl::KeyCode aCode = aKeyEvt.GetKeyCode();
300 if ( !aCode.GetModifier() ) // no modifiers
302 sal_uInt16 nKey = aCode.GetCode();
303 if ( nKey == KEY_RETURN )
305 SelectHdl(); // select
306 nDone = true;
308 else if ( nKey == KEY_ESCAPE )
310 pGridWin->ClickExtern(); // clears the listbox
311 nDone = true;
316 return nDone || ListBox::PreNotify( rNEvt );
319 void ScFilterListBox::Select()
321 ListBox::Select();
322 SelectHdl();
325 void ScFilterListBox::SelectHdl()
327 if ( !IsTravelSelect() && !bInit && !bCancelled )
329 sal_Int32 nPos = GetSelectEntryPos();
330 if ( LISTBOX_ENTRY_NOTFOUND != nPos )
332 nSel = nPos;
333 if (!bButtonDown)
335 // #i81298# set bInSelect flag, so the box isn't deleted from modifications within FilterSelect
336 bInSelect = true;
337 pGridWin->FilterSelect( nSel );
338 bInSelect = false;
344 // use a System floating window for the above filter listbox
345 class ScFilterFloatingWindow : public FloatingWindow
347 public:
348 ScFilterFloatingWindow( vcl::Window* pParent, WinBits nStyle = WB_STDFLOATWIN );
349 virtual ~ScFilterFloatingWindow();
350 virtual void dispose() SAL_OVERRIDE;
351 // required for System FloatingWindows that will not process KeyInput by themselves
352 virtual vcl::Window* GetPreferredKeyInputWindow() SAL_OVERRIDE;
355 ScFilterFloatingWindow::ScFilterFloatingWindow( vcl::Window* pParent, WinBits nStyle ) :
356 FloatingWindow( pParent, nStyle|WB_SYSTEMWINDOW ) // make it a system floater
359 ScFilterFloatingWindow::~ScFilterFloatingWindow()
361 disposeOnce();
364 void ScFilterFloatingWindow::dispose()
366 EndPopupMode();
367 FloatingWindow::dispose();
370 vcl::Window* ScFilterFloatingWindow::GetPreferredKeyInputWindow()
372 // redirect keyinput in the child window
373 return GetWindow(GetWindowType::FirstChild) ? GetWindow(GetWindowType::FirstChild)->GetPreferredKeyInputWindow() : NULL; // will be the FilterBox
376 static bool lcl_IsEditableMatrix( ScDocument* pDoc, const ScRange& rRange )
378 // wenn es ein editierbarer Bereich ist, und rechts unten eine Matrix-Zelle
379 // mit Origin links oben liegt, enthaelt der Bereich genau die Matrix.
380 //! Direkt die MatrixEdges Funktionen von der Column herausreichen ???
382 if ( !pDoc->IsBlockEditable( rRange.aStart.Tab(), rRange.aStart.Col(),rRange.aStart.Row(),
383 rRange.aEnd.Col(),rRange.aEnd.Row() ) )
384 return false;
386 ScRefCellValue aCell;
387 aCell.assign(*pDoc, rRange.aEnd);
388 ScAddress aPos;
389 return (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->GetMatrixOrigin(aPos) && aPos == rRange.aStart);
392 static void lcl_UnLockComment( ScDrawView* pView, const Point& rPos, ScViewData* pViewData )
394 if (!pView || !pViewData)
395 return;
397 ScDocument& rDoc = *pViewData->GetDocument();
398 ScAddress aCellPos( pViewData->GetCurX(), pViewData->GetCurY(), pViewData->GetTabNo() );
399 ScPostIt* pNote = rDoc.GetNote( aCellPos );
400 SdrObject* pObj = pNote ? pNote->GetCaption() : 0;
401 if( pObj && pObj->GetLogicRect().IsInside( rPos ) && ScDrawLayer::IsNoteCaption( pObj ) )
403 const ScProtectionAttr* pProtAttr = static_cast< const ScProtectionAttr* > (rDoc.GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_PROTECTION ) );
404 bool bProtectAttr = pProtAttr->GetProtection() || pProtAttr->GetHideCell() ;
405 bool bProtectDoc = rDoc.IsTabProtected( aCellPos.Tab() ) || pViewData->GetSfxDocShell()->IsReadOnly() ;
406 // unlock internal layer (if not protected), will be relocked in ScDrawView::MarkListHasChanged()
407 pView->LockInternalLayer( bProtectDoc && bProtectAttr );
411 static bool lcl_GetHyperlinkCell(
412 ScDocument* pDoc, SCCOL& rPosX, SCROW& rPosY, SCTAB nTab, ScRefCellValue& rCell, OUString& rURL )
414 bool bFound = false;
417 ScAddress aPos(rPosX, rPosY, nTab);
418 rCell.assign(*pDoc, aPos);
419 if (rCell.isEmpty())
421 if ( rPosX <= 0 )
422 return false; // alles leer bis links
423 else
424 --rPosX; // weitersuchen
426 else
428 const ScPatternAttr* pPattern = pDoc->GetPattern(aPos);
429 if ( !static_cast<const SfxStringItem&>(pPattern->GetItem(ATTR_HYPERLINK)).GetValue().isEmpty() )
431 rURL = static_cast<const SfxStringItem&>(pPattern->GetItem(ATTR_HYPERLINK)).GetValue();
432 bFound = true;
434 else if (rCell.meType == CELLTYPE_EDIT)
435 bFound = true;
436 else if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->IsHyperLinkCell())
437 bFound = true;
438 else
439 return false; // andere Zelle
442 while ( !bFound );
444 return bFound;
447 // WB_DIALOGCONTROL noetig fuer UNO-Controls
448 ScGridWindow::ScGridWindow( vcl::Window* pParent, ScViewData* pData, ScSplitPos eWhichPos )
449 : Window( pParent, WB_CLIPCHILDREN | WB_DIALOGCONTROL ),
450 DropTargetHelper( this ),
451 DragSourceHelper( this ),
452 mpOOCursors(),
453 mpOOSelection(),
454 mpOOSelectionBorder(),
455 mpOOAutoFill(),
456 mpOODragRect(),
457 mpOOHeader(),
458 mpOOShrink(),
459 mpAutoFillRect(static_cast<Rectangle*>(NULL)),
460 pViewData( pData ),
461 eWhich( eWhichPos ),
462 mpNoteMarker(),
463 mpFilterBox(),
464 mpFilterFloat(),
465 mpAutoFilterPopup(),
466 mpDPFieldPopup(),
467 mpFilterButton(),
468 nCursorHideCount( 0 ),
469 nButtonDown( 0 ),
470 nMouseStatus( SC_GM_NONE ),
471 nNestedButtonState( SC_NESTEDBUTTON_NONE ),
472 nDPField( 0 ),
473 pDragDPObj( NULL ),
474 nRFIndex( 0 ),
475 nRFAddX( 0 ),
476 nRFAddY( 0 ),
477 nPagebreakMouse( SC_PD_NONE ),
478 nPagebreakBreak( 0 ),
479 nPagebreakPrev( 0 ),
480 nPageScript( SvtScriptType::NONE ),
481 nLastClickX( 0 ),
482 nLastClickY( 0 ),
483 nDragStartX( -1 ),
484 nDragStartY( -1 ),
485 nDragEndX( -1 ),
486 nDragEndY( -1 ),
487 meDragInsertMode( INS_NONE ),
488 nCurrentPointer( 0 ),
489 aComboButton( this ),
490 aCurMousePos( 0,0 ),
491 nPaintCount( 0 ),
492 aRFSelectedCorned( NONE ),
493 bEEMouse( false ),
494 bDPMouse( false ),
495 bRFMouse( false ),
496 bRFSize( false ),
497 bPagebreakDrawn( false ),
498 bDragRect( false ),
499 bIsInScroll( false ),
500 bIsInPaint( false ),
501 bNeedsRepaint( false ),
502 bAutoMarkVisible( false ),
503 bListValButton( false )
505 switch(eWhich)
507 case SC_SPLIT_TOPLEFT:
508 eHWhich = SC_SPLIT_LEFT;
509 eVWhich = SC_SPLIT_TOP;
510 break;
511 case SC_SPLIT_TOPRIGHT:
512 eHWhich = SC_SPLIT_RIGHT;
513 eVWhich = SC_SPLIT_TOP;
514 break;
515 case SC_SPLIT_BOTTOMLEFT:
516 eHWhich = SC_SPLIT_LEFT;
517 eVWhich = SC_SPLIT_BOTTOM;
518 break;
519 case SC_SPLIT_BOTTOMRIGHT:
520 eHWhich = SC_SPLIT_RIGHT;
521 eVWhich = SC_SPLIT_BOTTOM;
522 break;
523 default:
524 OSL_FAIL("GridWindow: falsche Position");
527 SetBackground();
529 SetMapMode(pViewData->GetLogicMode(eWhich));
530 EnableChildTransparentMode();
531 SetDialogControlFlags( WINDOW_DLGCTRL_RETURN | WINDOW_DLGCTRL_WANTFOCUS );
533 SetHelpId( HID_SC_WIN_GRIDWIN );
534 SetUniqueId( HID_SC_WIN_GRIDWIN );
536 SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
537 EnableRTL( false );
540 ScGridWindow::~ScGridWindow()
542 disposeOnce();
545 void ScGridWindow::dispose()
547 // #114409#
548 ImpDestroyOverlayObjects();
550 mpFilterBox.disposeAndClear();
551 mpFilterFloat.disposeAndClear();
552 mpNoteMarker.reset();
553 mpAutoFilterPopup.disposeAndClear();
554 mpDPFieldPopup.disposeAndClear();
556 vcl::Window::dispose();
559 void ScGridWindow::ClickExtern()
563 // #i81298# don't delete the filter box when called from its select handler
564 // (possible through row header size update)
565 // #i84277# when initializing the filter box, a Basic error can deactivate the view
566 if (mpFilterBox && (mpFilterBox->IsInSelect() || mpFilterBox->IsInInit()))
568 break;
570 mpFilterBox.disposeAndClear();
571 mpFilterFloat.disposeAndClear();
573 while (false);
575 if (mpDPFieldPopup)
577 mpDPFieldPopup->close(false);
578 mpDPFieldPopup.disposeAndClear();
582 IMPL_LINK_NOARG(ScGridWindow, PopupModeEndHdl)
584 if (mpFilterBox)
585 mpFilterBox->SetCancelled(); // nicht mehr auswaehlen
586 GrabFocus();
587 return 0;
590 IMPL_LINK( ScGridWindow, PopupSpellingHdl, SpellCallbackInfo*, pInfo )
592 if( pInfo->nCommand == SpellCallbackCommand::STARTSPELLDLG )
593 pViewData->GetDispatcher().Execute( SID_SPELL_DIALOG, SfxCallMode::ASYNCHRON );
594 return 0;
597 void ScGridWindow::ExecPageFieldSelect( SCCOL nCol, SCROW nRow, bool bHasSelection, const OUString& rStr )
599 //! gridwin2 ?
601 ScDocument* pDoc = pViewData->GetDocument();
602 SCTAB nTab = pViewData->GetTabNo();
603 ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab);
604 if ( pDPObj && nCol > 0 )
606 // look for the dimension header left of the drop-down arrow
607 sal_uInt16 nOrient = sheet::DataPilotFieldOrientation_HIDDEN;
608 long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient );
609 if ( nField >= 0 && nOrient == sheet::DataPilotFieldOrientation_PAGE )
611 ScDPSaveData aSaveData( *pDPObj->GetSaveData() );
613 bool bIsDataLayout;
614 OUString aDimName = pDPObj->GetDimName( nField, bIsDataLayout );
615 if ( !bIsDataLayout )
617 ScDPSaveDimension* pDim = aSaveData.GetDimensionByName(aDimName);
619 if ( bHasSelection )
621 const OUString aName = rStr;
622 pDim->SetCurrentPage( &aName );
624 else
625 pDim->SetCurrentPage( NULL );
627 ScDPObject aNewObj( *pDPObj );
628 aNewObj.SetSaveData( aSaveData );
629 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
630 aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
631 pViewData->GetView()->CursorPosChanged(); // shells may be switched
637 namespace {
639 struct AutoFilterData : public ScCheckListMenuWindow::ExtendedData
641 ScAddress maPos;
642 ScDBData* mpData;
645 class AutoFilterAction : public ScMenuFloatingWindow::Action
647 VclPtr<ScGridWindow> mpWindow;
648 ScGridWindow::AutoFilterMode meMode;
649 public:
650 AutoFilterAction(ScGridWindow* p, ScGridWindow::AutoFilterMode eMode) :
651 mpWindow(p), meMode(eMode) {}
652 virtual void execute() SAL_OVERRIDE
654 mpWindow->UpdateAutoFilterFromMenu(meMode);
658 class AutoFilterPopupEndAction : public ScMenuFloatingWindow::Action
660 VclPtr<ScGridWindow> mpWindow;
661 ScAddress maPos;
662 public:
663 AutoFilterPopupEndAction(ScGridWindow* p, const ScAddress& rPos) :
664 mpWindow(p), maPos(rPos) {}
665 virtual void execute() SAL_OVERRIDE
667 mpWindow->RefreshAutoFilterButton(maPos);
671 class AddItemToEntry : public std::unary_function<OUString, void>
673 ScQueryEntry::QueryItemsType& mrItems;
674 svl::SharedStringPool& mrPool;
675 public:
676 AddItemToEntry(ScQueryEntry::QueryItemsType& rItems, svl::SharedStringPool& rPool) :
677 mrItems(rItems), mrPool(rPool) {}
678 void operator() (const OUString& rSelected)
680 ScQueryEntry::Item aNew;
681 aNew.maString = mrPool.intern(rSelected);
682 aNew.meType = ScQueryEntry::ByString;
683 aNew.mfVal = 0.0;
684 mrItems.push_back(aNew);
688 class AddSelectedItemString : public std::unary_function<ScQueryEntry::Item, void>
690 std::unordered_set<OUString, OUStringHash>& mrSet;
691 public:
692 AddSelectedItemString(std::unordered_set<OUString, OUStringHash>& r) :
693 mrSet(r) {}
695 void operator() (const ScQueryEntry::Item& rItem)
697 mrSet.insert(rItem.maString.getString());
703 void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
705 SCTAB nTab = pViewData->GetTabNo();
706 ScDocument* pDoc = pViewData->GetDocument();
708 mpAutoFilterPopup.disposeAndClear();
709 mpAutoFilterPopup.reset(VclPtr<ScCheckListMenuWindow>::Create(this, pDoc));
710 mpAutoFilterPopup->setOKAction(new AutoFilterAction(this, Normal));
711 mpAutoFilterPopup->setPopupEndAction(
712 new AutoFilterPopupEndAction(this, ScAddress(nCol, nRow, nTab)));
713 std::unique_ptr<AutoFilterData> pData(new AutoFilterData);
714 pData->maPos = ScAddress(nCol, nRow, nTab);
716 Point aPos = pViewData->GetScrPos(nCol, nRow, eWhich);
717 long nSizeX = 0;
718 long nSizeY = 0;
719 pViewData->GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
720 Rectangle aCellRect(OutputToScreenPixel(aPos), Size(nSizeX, nSizeY));
722 ScDBData* pDBData = pDoc->GetDBAtCursor(nCol, nRow, nTab);
723 if (!pDBData)
724 return;
726 pData->mpData = pDBData;
727 mpAutoFilterPopup->setExtendedData(pData.release());
729 ScQueryParam aParam;
730 pDBData->GetQueryParam(aParam);
731 ScQueryEntry* pEntry = aParam.FindEntryByField(nCol, false);
732 std::unordered_set<OUString, OUStringHash> aSelected;
733 if (pEntry && pEntry->bDoQuery)
735 if (pEntry->eOp == SC_EQUAL)
737 ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
738 std::for_each(rItems.begin(), rItems.end(), AddSelectedItemString(aSelected));
742 // Populate the check box list.
743 bool bHasDates = false;
744 std::vector<ScTypedStrData> aStrings;
745 pDoc->GetFilterEntries(nCol, nRow, nTab, true, aStrings, bHasDates);
747 mpAutoFilterPopup->setMemberSize(aStrings.size());
748 std::vector<ScTypedStrData>::const_iterator it = aStrings.begin(), itEnd = aStrings.end();
749 for (; it != itEnd; ++it)
751 const OUString& aVal = it->GetString();
752 bool bSelected = true;
753 if (!aSelected.empty())
754 bSelected = aSelected.count(aVal) > 0;
755 if ( it->IsDate() )
756 mpAutoFilterPopup->addDateMember( aVal, it->GetValue(), bSelected );
757 else
758 mpAutoFilterPopup->addMember(aVal, bSelected);
760 mpAutoFilterPopup->initMembers();
762 // Populate the menu.
763 mpAutoFilterPopup->addMenuItem(
764 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_ASC),
765 true, new AutoFilterAction(this, SortAscending));
766 mpAutoFilterPopup->addMenuItem(
767 SC_STRLOAD(RID_POPUP_FILTER, STR_MENU_SORT_DESC),
768 true, new AutoFilterAction(this, SortDescending));
769 mpAutoFilterPopup->addSeparator();
770 mpAutoFilterPopup->addMenuItem(
771 SC_RESSTR(SCSTR_TOP10FILTER), true, new AutoFilterAction(this, Top10));
772 mpAutoFilterPopup->addMenuItem(
773 SC_RESSTR(SCSTR_FILTER_EMPTY), true, new AutoFilterAction(this, Empty));
774 mpAutoFilterPopup->addMenuItem(
775 SC_RESSTR(SCSTR_FILTER_NOTEMPTY), true, new AutoFilterAction(this, NonEmpty));
776 mpAutoFilterPopup->addSeparator();
777 mpAutoFilterPopup->addMenuItem(
778 SC_RESSTR(SCSTR_STDFILTER), true, new AutoFilterAction(this, Custom));
780 ScCheckListMenuWindow::Config aConfig;
781 aConfig.mbAllowEmptySet = false;
782 aConfig.mbRTL = pViewData->GetDocument()->IsLayoutRTL(pViewData->GetTabNo());
783 mpAutoFilterPopup->setConfig(aConfig);
784 mpAutoFilterPopup->launch(aCellRect);
787 void ScGridWindow::RefreshAutoFilterButton(const ScAddress& rPos)
789 if (mpFilterButton)
791 bool bFilterActive = IsAutoFilterActive(rPos.Col(), rPos.Row(), rPos.Tab());
792 mpFilterButton->setHasHiddenMember(bFilterActive);
793 mpFilterButton->setPopupPressed(false);
794 mpFilterButton->draw();
798 void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode)
800 const AutoFilterData* pData =
801 static_cast<const AutoFilterData*>(mpAutoFilterPopup->getExtendedData());
803 if (!pData)
804 return;
806 const ScAddress& rPos = pData->maPos;
807 ScDBData* pDBData = pData->mpData;
808 if (!pDBData)
809 return;
811 ScDocument* pDoc = pViewData->GetDocument();
812 svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
813 switch (eMode)
815 case SortAscending:
816 case SortDescending:
818 SCCOL nCol = rPos.Col();
819 ScSortParam aSortParam;
820 pDBData->GetSortParam(aSortParam);
821 if (nCol < aSortParam.nCol1 || nCol > aSortParam.nCol2)
822 // out of bound
823 return;
825 bool bHasHeader = pDBData->HasHeader();
827 aSortParam.bHasHeader = bHasHeader;
828 aSortParam.bByRow = true;
829 aSortParam.bCaseSens = false;
830 aSortParam.bNaturalSort = false;
831 aSortParam.bIncludePattern = true;
832 aSortParam.bInplace = true;
833 aSortParam.maKeyState[0].bDoSort = true;
834 aSortParam.maKeyState[0].nField = nCol;
835 aSortParam.maKeyState[0].bAscending = (eMode == SortAscending);
837 for (size_t i = 1; i < aSortParam.GetSortKeyCount(); ++i)
838 aSortParam.maKeyState[i].bDoSort = false;
840 pViewData->GetViewShell()->UISort(aSortParam);
841 return;
843 default:
847 if (eMode == Custom)
849 ScRange aRange;
850 pDBData->GetArea(aRange);
851 pViewData->GetView()->MarkRange(aRange);
852 pViewData->GetView()->SetCursor(rPos.Col(), rPos.Row());
853 pViewData->GetDispatcher().Execute(SID_FILTER, SfxCallMode::SLOT|SfxCallMode::RECORD);
854 return;
857 ScQueryParam aParam;
858 pDBData->GetQueryParam(aParam);
860 if (eMode == Normal && mpAutoFilterPopup->isAllSelected())
862 // Remove this entry.
863 aParam.RemoveEntryByField(rPos.Col());
865 else
867 // Try to use the existing entry for the column (if one exists).
868 ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
870 if (!pEntry)
871 // Something went terribly wrong!
872 return;
874 pEntry->bDoQuery = true;
875 pEntry->nField = rPos.Col();
876 pEntry->eConnect = SC_AND;
878 switch (eMode)
880 case Normal:
882 pEntry->eOp = SC_EQUAL;
884 ScCheckListMenuWindow::ResultType aResult;
885 mpAutoFilterPopup->getResult(aResult);
886 std::vector<OUString> aSelected;
887 ScCheckListMenuWindow::ResultType::const_iterator itr = aResult.begin(), itrEnd = aResult.end();
888 for (; itr != itrEnd; ++itr)
890 if (itr->second)
891 aSelected.push_back(itr->first);
894 ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
895 rItems.clear();
896 std::for_each(aSelected.begin(), aSelected.end(), AddItemToEntry(rItems, rPool));
898 break;
899 case Top10:
900 pEntry->eOp = SC_TOPVAL;
901 pEntry->GetQueryItem().meType = ScQueryEntry::ByString;
902 pEntry->GetQueryItem().maString = rPool.intern("10");
903 break;
904 case Empty:
905 pEntry->SetQueryByEmpty();
906 break;
907 case NonEmpty:
908 pEntry->SetQueryByNonEmpty();
909 break;
910 default:
911 // We don't know how to handle this!
912 return;
916 pViewData->GetView()->Query(aParam, NULL, true);
917 pDBData->SetQueryParam(aParam);
920 namespace {
922 void getCellGeometry(Point& rScrPos, Size& rScrSize, const ScViewData* pViewData, SCCOL nCol, SCROW nRow, ScSplitPos eWhich)
924 // Get the screen position of the cell.
925 rScrPos = pViewData->GetScrPos(nCol, nRow, eWhich);
927 // Get the screen size of the cell.
928 long nSizeX, nSizeY;
929 pViewData->GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
930 rScrSize = Size(nSizeX-1, nSizeY-1);
935 void ScGridWindow::LaunchPageFieldMenu( SCCOL nCol, SCROW nRow )
937 if (nCol == 0)
938 // We assume that the page field button is located in cell to the immediate left.
939 return;
941 SCTAB nTab = pViewData->GetTabNo();
942 ScDPObject* pDPObj = pViewData->GetDocument()->GetDPAtCursor(nCol, nRow, nTab);
943 if (!pDPObj)
944 return;
946 Point aScrPos;
947 Size aScrSize;
948 getCellGeometry(aScrPos, aScrSize, pViewData, nCol, nRow, eWhich);
949 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol-1, nRow, nTab), pDPObj);
952 void ScGridWindow::LaunchDPFieldMenu( SCCOL nCol, SCROW nRow )
954 SCTAB nTab = pViewData->GetTabNo();
955 ScDPObject* pDPObj = pViewData->GetDocument()->GetDPAtCursor(nCol, nRow, nTab);
956 if (!pDPObj)
957 return;
959 Point aScrPos;
960 Size aScrSize;
961 getCellGeometry(aScrPos, aScrSize, pViewData, nCol, nRow, eWhich);
962 DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol, nRow, nTab), pDPObj);
965 void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange )
967 mpFilterBox.disposeAndClear();
968 mpFilterFloat.disposeAndClear();
970 SCCOL nCol = rScenRange.aEnd.Col(); // Zelle unterhalb des Buttons
971 SCROW nRow = rScenRange.aStart.Row();
972 if (nRow == 0)
974 nRow = rScenRange.aEnd.Row() + 1; // Bereich ganz oben -> Button unterhalb
975 if (nRow>MAXROW) nRow = MAXROW;
976 //! Texthoehe addieren (wenn sie an der View gespeichert ist...)
979 ScDocument* pDoc = pViewData->GetDocument();
980 SCTAB nTab = pViewData->GetTabNo();
981 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
983 long nSizeX = 0;
984 long nSizeY = 0;
985 long nHeight = 0;
986 pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
987 // The button height should not use the merged cell height, should still use single row height
988 nSizeY = ScViewData::ToPixel(pDoc->GetRowHeight(nRow, nTab), pViewData->GetPPTY());
989 Point aPos = pViewData->GetScrPos( nCol, nRow, eWhich );
990 if ( bLayoutRTL )
991 aPos.X() -= nSizeX;
992 Rectangle aCellRect( OutputToScreenPixel(aPos), Size(nSizeX,nSizeY) );
993 aCellRect.Top() -= nSizeY;
994 aCellRect.Bottom() -= nSizeY - 1;
995 // Die ListBox direkt unter der schwarzen Linie auf dem Zellgitter
996 // (wenn die Linie verdeckt wird, sieht es komisch aus...)
998 mpFilterFloat.reset(VclPtr<ScFilterFloatingWindow>::Create(this, WinBits(WB_BORDER)));
999 mpFilterFloat->SetPopupModeEndHdl( LINK( this, ScGridWindow, PopupModeEndHdl ) );
1000 mpFilterBox.reset(VclPtr<ScFilterListBox>::Create(mpFilterFloat.get(), this, nCol, nRow, SC_FILTERBOX_SCENARIO));
1001 if (bLayoutRTL)
1002 mpFilterBox->EnableMirroring();
1004 nSizeX += 1;
1007 vcl::Font aOldFont = GetFont();
1008 SetFont(mpFilterBox->GetFont());
1009 MapMode aOldMode = GetMapMode();
1010 SetMapMode( MAP_PIXEL );
1012 nHeight = GetTextHeight();
1013 nHeight *= SC_FILTERLISTBOX_LINES;
1015 SetMapMode( aOldMode );
1016 SetFont( aOldFont );
1019 // SetSize spaeter
1021 // ParentSize Abfrage fehlt
1022 Size aSize( nSizeX, nHeight );
1023 mpFilterBox->SetSizePixel( aSize );
1024 mpFilterBox->Show(); // Show muss vor SetUpdateMode kommen !!!
1025 mpFilterBox->SetUpdateMode(false);
1027 // SetOutputSizePixel/StartPopupMode erst unten, wenn die Groesse feststeht
1029 // Listbox fuellen
1031 long nMaxText = 0;
1032 OUString aCurrent;
1033 OUString aTabName;
1034 SCTAB nTabCount = pDoc->GetTableCount();
1035 SCTAB nEntryCount = 0;
1036 for (SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++)
1038 if (pDoc->HasScenarioRange( i, rScenRange ))
1039 if (pDoc->GetName( i, aTabName ))
1041 mpFilterBox->InsertEntry(aTabName);
1042 if (pDoc->IsActiveScenario(i))
1043 aCurrent = aTabName;
1044 long nTextWidth = mpFilterBox->GetTextWidth(aTabName);
1045 if ( nTextWidth > nMaxText )
1046 nMaxText = nTextWidth;
1047 ++nEntryCount;
1050 if (nEntryCount > SC_FILTERLISTBOX_LINES)
1051 nMaxText += GetSettings().GetStyleSettings().GetScrollBarSize();
1052 nMaxText += 4; // fuer Rand
1053 if ( nMaxText > 300 )
1054 nMaxText = 300; // auch nicht uebertreiben (Pixel)
1056 if (nMaxText > nSizeX) // Groesse auf benoetigte Groesse anpassen
1058 long nDiff = nMaxText - nSizeX;
1059 aSize = Size( nMaxText, nHeight );
1060 mpFilterBox->SetSizePixel(aSize);
1061 mpFilterFloat->SetOutputSizePixel(aSize);
1063 if ( !bLayoutRTL )
1065 // also move popup position
1066 long nNewX = aCellRect.Left() - nDiff;
1067 if ( nNewX < 0 )
1068 nNewX = 0;
1069 aCellRect.Left() = nNewX;
1073 mpFilterFloat->SetOutputSizePixel( aSize );
1074 mpFilterFloat->StartPopupMode( aCellRect, FloatWinPopupFlags::Down|FloatWinPopupFlags::GrabFocus );
1076 mpFilterBox->SetUpdateMode(true);
1077 mpFilterBox->GrabFocus();
1079 sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
1080 if (!aCurrent.isEmpty())
1082 nPos = mpFilterBox->GetEntryPos(aCurrent);
1084 if (LISTBOX_ENTRY_NOTFOUND == nPos && mpFilterBox->GetEntryCount() > 0 )
1086 nPos = 0;
1088 if (LISTBOX_ENTRY_NOTFOUND != nPos )
1090 mpFilterBox->SelectEntryPos(nPos);
1092 mpFilterBox->EndInit();
1094 // Szenario-Auswahl kommt aus MouseButtonDown:
1095 // der naechste MouseMove auf die Filterbox ist wie ein ButtonDown
1097 nMouseStatus = SC_GM_FILTER;
1098 CaptureMouse();
1101 void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow, bool bDataSelect )
1103 mpFilterBox.disposeAndClear();
1104 mpFilterFloat.disposeAndClear();
1106 sal_uInt16 i;
1107 ScDocument* pDoc = pViewData->GetDocument();
1108 SCTAB nTab = pViewData->GetTabNo();
1109 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
1111 long nSizeX = 0;
1112 long nSizeY = 0;
1113 long nHeight = 0;
1114 pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
1115 Point aPos = pViewData->GetScrPos( nCol, nRow, eWhich );
1116 if ( bLayoutRTL )
1117 aPos.X() -= nSizeX;
1119 Rectangle aCellRect( OutputToScreenPixel(aPos), Size(nSizeX,nSizeY) );
1121 aPos.X() -= 1;
1122 aPos.Y() += nSizeY - 1;
1124 mpFilterFloat.reset(VclPtr<ScFilterFloatingWindow>::Create(this, WinBits(WB_BORDER)));
1125 mpFilterFloat->SetPopupModeEndHdl(LINK( this, ScGridWindow, PopupModeEndHdl));
1126 ScFilterBoxMode eFilterMode = bDataSelect ? SC_FILTERBOX_DATASELECT : SC_FILTERBOX_FILTER;
1127 mpFilterBox.reset(VclPtr<ScFilterListBox>::Create(mpFilterFloat.get(), this, nCol, nRow, eFilterMode));
1128 // Fix for bug fdo#44925
1129 if (AllSettings::GetLayoutRTL() != bLayoutRTL)
1130 mpFilterBox->EnableMirroring();
1132 nSizeX += 1;
1135 vcl::Font aOldFont = GetFont();
1136 SetFont(mpFilterBox->GetFont());
1137 MapMode aOldMode = GetMapMode();
1138 SetMapMode(MAP_PIXEL);
1140 nHeight = GetTextHeight();
1141 nHeight *= SC_FILTERLISTBOX_LINES;
1143 SetMapMode( aOldMode );
1144 SetFont( aOldFont );
1147 // SetSize spaeter
1149 bool bEmpty = false;
1150 std::vector<ScTypedStrData> aStrings; // case sensitive
1151 if ( bDataSelect ) // Auswahl-Liste
1153 // Liste fuellen
1154 pDoc->GetDataEntries(nCol, nRow, nTab, true, aStrings);
1155 if (aStrings.empty())
1156 bEmpty = true;
1158 else // AutoFilter
1160 //! wird der Titel ueberhaupt ausgewertet ???
1161 OUString aString = pDoc->GetString(nCol, nRow, nTab);
1162 mpFilterBox->SetText(aString);
1164 long nMaxText = 0;
1166 // default entries
1167 static const sal_uInt16 nDefIDs[] = { SCSTR_TOP10FILTER, SCSTR_STDFILTER, SCSTR_FILTER_EMPTY, SCSTR_FILTER_NOTEMPTY };
1168 const size_t nDefCount = SAL_N_ELEMENTS(nDefIDs);
1169 for (i=0; i<nDefCount; i++)
1171 OUString aEntry( static_cast<ScResId>(nDefIDs[i]) );
1172 mpFilterBox->InsertEntry(aEntry);
1173 long nTextWidth = mpFilterBox->GetTextWidth(aEntry);
1174 if ( nTextWidth > nMaxText )
1175 nMaxText = nTextWidth;
1177 mpFilterBox->SetSeparatorPos(nDefCount - 1);
1179 // get list entries
1180 bool bHasDates = false;
1181 pDoc->GetFilterEntries( nCol, nRow, nTab, true, aStrings, bHasDates);
1182 mpFilterBox->SetListHasDates(bHasDates);
1184 // check widths of numerical entries (string entries are not included)
1185 // so all numbers are completely visible
1186 std::vector<ScTypedStrData>::const_iterator it = aStrings.begin(), itEnd = aStrings.end();
1187 for (; it != itEnd; ++it)
1189 if (!it->IsStrData()) // only numerical entries
1191 long nTextWidth = mpFilterBox->GetTextWidth(it->GetString());
1192 if ( nTextWidth > nMaxText )
1193 nMaxText = nTextWidth;
1197 // add scrollbar width if needed (string entries are counted here)
1198 // (scrollbar is shown if the box is exactly full?)
1199 if (aStrings.size() + nDefCount >= SC_FILTERLISTBOX_LINES)
1200 nMaxText += GetSettings().GetStyleSettings().GetScrollBarSize();
1202 nMaxText += 4; // for borders
1204 if ( nMaxText > nSizeX )
1205 nSizeX = nMaxText; // just modify width - starting position is unchanged
1208 if (!bEmpty)
1210 // Position und Groesse an Fenster anpassen
1211 //! vorher Abfrage, ob die Eintraege hineinpassen (Breite)
1213 Size aParentSize = GetParent()->GetOutputSizePixel();
1214 Size aSize( nSizeX, nHeight );
1216 if ( aSize.Height() > aParentSize.Height() )
1217 aSize.Height() = aParentSize.Height();
1218 if ( aPos.Y() + aSize.Height() > aParentSize.Height() )
1219 aPos.Y() = aParentSize.Height() - aSize.Height();
1221 mpFilterBox->SetSizePixel(aSize);
1222 mpFilterBox->Show(); // Show muss vor SetUpdateMode kommen !!!
1223 mpFilterBox->SetUpdateMode(false);
1225 mpFilterFloat->SetOutputSizePixel(aSize);
1226 mpFilterFloat->StartPopupMode(aCellRect, FloatWinPopupFlags::Down | FloatWinPopupFlags::GrabFocus);
1228 // Listbox fuellen
1229 bool bWait = aStrings.size() > 100;
1231 if (bWait)
1232 EnterWait();
1234 std::vector<ScTypedStrData>::const_iterator it = aStrings.begin(), itEnd = aStrings.end();
1235 for (; it != itEnd; ++it)
1236 mpFilterBox->InsertEntry(it->GetString());
1238 if (bWait)
1239 LeaveWait();
1241 mpFilterBox->SetUpdateMode(true);
1244 sal_Int32 nSelPos = LISTBOX_ENTRY_NOTFOUND;
1246 if (!bDataSelect) // AutoFilter: aktiven Eintrag selektieren
1248 ScDBData* pDBData = pDoc->GetDBAtCursor( nCol, nRow, nTab );
1249 if (pDBData)
1251 ScQueryParam aParam;
1252 pDBData->GetQueryParam( aParam ); // kann nur MAXQUERY Eintraege ergeben
1254 bool bValid = true;
1255 SCSIZE nCount = aParam.GetEntryCount();
1256 for (SCSIZE j = 0; j < nCount && bValid; ++j) // bisherige Filter-Einstellungen
1257 if (aParam.GetEntry(j).bDoQuery)
1259 //! Abfrage mit DrawButtons zusammenfassen!
1261 ScQueryEntry& rEntry = aParam.GetEntry(j);
1262 if (j>0)
1263 if (rEntry.eConnect != SC_AND)
1264 bValid = false;
1265 if (rEntry.nField == nCol)
1267 OUString aQueryStr = rEntry.GetQueryItem().maString.getString();
1268 if (rEntry.eOp == SC_EQUAL)
1270 if (!aQueryStr.isEmpty())
1272 nSelPos = mpFilterBox->GetEntryPos(aQueryStr);
1275 else if ( rEntry.eOp == SC_TOPVAL && aQueryStr == "10" )
1276 nSelPos = SC_AUTOFILTER_TOP10;
1277 else
1278 nSelPos = SC_AUTOFILTER_CUSTOM;
1282 if (!bValid)
1283 nSelPos = SC_AUTOFILTER_CUSTOM;
1286 else
1289 sal_uLong nIndex = static_cast<const SfxUInt32Item*>(pDoc->GetAttr(
1290 nCol, nRow, nTab, ATTR_VALIDDATA ))->GetValue();
1291 if ( nIndex )
1293 const ScValidationData* pData = pDoc->GetValidationEntry( nIndex );
1294 if (pData)
1296 std::unique_ptr<ScTypedStrData> pNew;
1297 OUString aDocStr = pDoc->GetString(nCol, nRow, nTab);
1298 if ( pDoc->HasValueData( nCol, nRow, nTab ) )
1300 double fVal = pDoc->GetValue(ScAddress(nCol, nRow, nTab));
1301 pNew.reset(new ScTypedStrData(aDocStr, fVal, ScTypedStrData::Value));
1303 else
1304 pNew.reset(new ScTypedStrData(aDocStr, 0.0, ScTypedStrData::Standard));
1306 bool bSortList = ( pData->GetListType() == css::sheet::TableValidationVisibility::SORTEDASCENDING);
1307 if ( bSortList )
1309 std::vector<ScTypedStrData>::const_iterator itBeg = aStrings.begin(), itEnd = aStrings.end();
1310 std::vector<ScTypedStrData>::const_iterator it =
1311 std::find_if(itBeg, itEnd, FindTypedStrData(*pNew, true));
1312 if (it != itEnd)
1313 // Found!
1314 nSelPos = std::distance(itBeg, it);
1316 else
1318 ScTypedStrData::EqualCaseSensitive aHdl;
1319 std::vector<ScTypedStrData>::const_iterator itBeg = aStrings.begin(), itEnd = aStrings.end();
1320 std::vector<ScTypedStrData>::const_iterator it = itBeg;
1321 for (; it != itEnd && LISTBOX_ENTRY_NOTFOUND == nSelPos; ++it)
1323 if (aHdl(*it, *pNew))
1324 nSelPos = std::distance(itBeg, it);
1331 // neu (309): irgendwas muss immer selektiert sein:
1332 if (LISTBOX_ENTRY_NOTFOUND == nSelPos && mpFilterBox->GetEntryCount() > 0 && !bDataSelect)
1333 nSelPos = 0;
1335 // keine leere Auswahl-Liste anzeigen:
1337 if ( bEmpty )
1339 mpFilterBox.disposeAndClear();
1340 mpFilterFloat.disposeAndClear();
1342 else
1344 mpFilterBox->GrabFocus();
1346 // Select erst nach GrabFocus, damit das Focus-Rechteck richtig landet
1347 if ( LISTBOX_ENTRY_NOTFOUND != nSelPos )
1348 mpFilterBox->SelectEntryPos(nSelPos);
1349 else
1351 if (bDataSelect)
1352 mpFilterBox->SetNoSelection();
1355 mpFilterBox->EndInit();
1357 if (!bDataSelect)
1359 // AutoFilter (aus MouseButtonDown):
1360 // der naechste MouseMove auf die Filterbox ist wie ein ButtonDown
1362 nMouseStatus = SC_GM_FILTER;
1363 CaptureMouse();
1368 void ScGridWindow::FilterSelect( sal_uLong nSel )
1370 OUString aString = mpFilterBox->GetEntry(static_cast<sal_Int32>(nSel));
1372 SCCOL nCol = mpFilterBox->GetCol();
1373 SCROW nRow = mpFilterBox->GetRow();
1374 switch (mpFilterBox->GetMode())
1376 case SC_FILTERBOX_DATASELECT:
1377 ExecDataSelect(nCol, nRow, aString);
1378 break;
1379 case SC_FILTERBOX_FILTER:
1380 ExecFilter(nSel, nCol, nRow, aString, mpFilterBox->HasDates());
1381 break;
1382 case SC_FILTERBOX_SCENARIO:
1383 pViewData->GetView()->UseScenario(aString);
1384 break;
1385 case SC_FILTERBOX_PAGEFIELD:
1386 // first entry is "all"
1387 ExecPageFieldSelect( nCol, nRow, (nSel != 0), aString );
1388 break;
1391 if (mpFilterFloat)
1392 mpFilterFloat->EndPopupMode();
1394 GrabFocus(); // unter OS/2 stimmt der Focus sonst nicht
1397 void ScGridWindow::ExecDataSelect( SCCOL nCol, SCROW nRow, const OUString& rStr )
1399 if ( !rStr.isEmpty() )
1401 SCTAB nTab = pViewData->GetTabNo();
1402 ScViewFunc* pView = pViewData->GetView();
1403 pView->EnterData( nCol, nRow, nTab, rStr );
1405 // #i52307# CellContentChanged is not in EnterData so it isn't called twice
1406 // if the cursor is moved afterwards.
1407 pView->CellContentChanged();
1411 void ScGridWindow::ExecFilter( sal_uLong nSel,
1412 SCCOL nCol, SCROW nRow,
1413 const OUString& aValue, bool bCheckForDates )
1415 SCTAB nTab = pViewData->GetTabNo();
1416 ScDocument* pDoc = pViewData->GetDocument();
1417 svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
1419 ScDBData* pDBData = pDoc->GetDBAtCursor( nCol, nRow, nTab );
1420 if (pDBData)
1422 ScQueryParam aParam;
1423 pDBData->GetQueryParam( aParam ); // kann nur MAXQUERY Eintraege ergeben
1425 if (SC_AUTOFILTER_CUSTOM == nSel)
1427 SCTAB nAreaTab;
1428 SCCOL nStartCol;
1429 SCROW nStartRow;
1430 SCCOL nEndCol;
1431 SCROW nEndRow;
1432 pDBData->GetArea( nAreaTab, nStartCol,nStartRow,nEndCol,nEndRow );
1433 pViewData->GetView()->MarkRange( ScRange( nStartCol,nStartRow,nAreaTab,nEndCol,nEndRow,nAreaTab));
1434 pViewData->GetView()->SetCursor(nCol,nRow); //! auch ueber Slot ??
1435 pViewData->GetDispatcher().Execute( SID_FILTER, SfxCallMode::SLOT | SfxCallMode::RECORD );
1437 else
1439 bool bDeleteOld = false;
1440 SCSIZE nQueryPos = 0;
1441 bool bFound = false;
1442 if (!aParam.bInplace)
1443 bDeleteOld = true;
1444 if (aParam.bRegExp)
1445 bDeleteOld = true;
1446 SCSIZE nCount = aParam.GetEntryCount();
1447 for (SCSIZE i = 0; i < nCount && !bDeleteOld; ++i) // bisherige Filter-Einstellungen
1448 if (aParam.GetEntry(i).bDoQuery)
1450 //! Abfrage mit DrawButtons zusammenfassen!
1452 ScQueryEntry& rEntry = aParam.GetEntry(i);
1453 if (i>0)
1454 if (rEntry.eConnect != SC_AND)
1455 bDeleteOld = true;
1457 if (rEntry.nField == nCol)
1459 if (bFound) // diese Spalte zweimal?
1460 bDeleteOld = true;
1461 nQueryPos = i;
1462 bFound = true;
1464 if (!bFound)
1465 nQueryPos = i + 1;
1468 if (bDeleteOld)
1470 SCSIZE nEC = aParam.GetEntryCount();
1471 for (SCSIZE i=0; i<nEC; i++)
1472 aParam.GetEntry(i).Clear();
1473 nQueryPos = 0;
1474 aParam.bInplace = true;
1475 aParam.bRegExp = false;
1478 if ( nQueryPos < nCount || SC_AUTOFILTER_ALL == nSel ) // loeschen geht immer
1480 if (nSel)
1482 ScQueryEntry& rNewEntry = aParam.GetEntry(nQueryPos);
1483 ScQueryEntry::Item& rItem = rNewEntry.GetQueryItem();
1484 rNewEntry.bDoQuery = true;
1485 rNewEntry.nField = nCol;
1486 rItem.meType = bCheckForDates ? ScQueryEntry::ByDate : ScQueryEntry::ByString;
1488 if ( nSel == SC_AUTOFILTER_TOP10 )
1490 rNewEntry.eOp = SC_TOPVAL;
1491 rItem.maString = rPool.intern("10");
1493 else if (nSel == SC_AUTOFILTER_EMPTY)
1495 rNewEntry.SetQueryByEmpty();
1497 else if (nSel == SC_AUTOFILTER_NOTEMPTY)
1499 rNewEntry.SetQueryByNonEmpty();
1501 else
1503 rNewEntry.eOp = SC_EQUAL;
1504 rItem.maString = rPool.intern(aValue);
1506 if (nQueryPos > 0)
1507 rNewEntry.eConnect = SC_AND;
1509 else
1511 if (bFound)
1512 aParam.RemoveEntryByField(nCol);
1515 // end edit mode - like in ScCellShell::ExecuteDB
1516 if ( pViewData->HasEditView( pViewData->GetActivePart() ) )
1518 SC_MOD()->InputEnterHandler();
1519 pViewData->GetViewShell()->UpdateInputHandler();
1522 pViewData->GetView()->Query( aParam, NULL, true );
1523 pDBData->SetQueryParam( aParam ); // speichern
1525 else // "Zuviele Bedingungen"
1526 pViewData->GetView()->ErrorMessage( STR_FILTER_TOOMANY );
1529 else
1531 OSL_FAIL("Wo ist der Datenbankbereich?");
1535 void ScGridWindow::SetPointer( const Pointer& rPointer )
1537 nCurrentPointer = 0;
1538 Window::SetPointer( rPointer );
1541 void ScGridWindow::MoveMouseStatus( ScGridWindow& rDestWin )
1543 if (nButtonDown)
1545 rDestWin.nButtonDown = nButtonDown;
1546 rDestWin.nMouseStatus = nMouseStatus;
1549 if (bRFMouse)
1551 rDestWin.bRFMouse = bRFMouse;
1552 rDestWin.bRFSize = bRFSize;
1553 rDestWin.nRFIndex = nRFIndex;
1554 rDestWin.nRFAddX = nRFAddX;
1555 rDestWin.nRFAddY = nRFAddY;
1556 bRFMouse = false;
1559 if (nPagebreakMouse)
1561 rDestWin.nPagebreakMouse = nPagebreakMouse;
1562 rDestWin.nPagebreakBreak = nPagebreakBreak;
1563 rDestWin.nPagebreakPrev = nPagebreakPrev;
1564 rDestWin.aPagebreakSource = aPagebreakSource;
1565 rDestWin.aPagebreakDrag = aPagebreakDrag;
1566 nPagebreakMouse = SC_PD_NONE;
1570 bool ScGridWindow::TestMouse( const MouseEvent& rMEvt, bool bAction )
1572 // MouseEvent buttons must only be checked if bAction==TRUE
1573 // to allow changing the mouse pointer in MouseMove,
1574 // but not start AutoFill with right button (#74229#).
1575 // with bAction==sal_True, SetFillMode / SetDragMode is called
1577 if ( bAction && !rMEvt.IsLeft() )
1578 return false;
1580 bool bNewPointer = false;
1582 SfxInPlaceClient* pClient = pViewData->GetViewShell()->GetIPClient();
1583 bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() );
1585 if ( pViewData->IsActive() && !bOleActive )
1587 ScDocument* pDoc = pViewData->GetDocument();
1588 SCTAB nTab = pViewData->GetTabNo();
1589 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
1591 // Auto-Fill
1593 ScRange aMarkRange;
1594 if (pViewData->GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE)
1596 if (aMarkRange.aStart.Tab() == pViewData->GetTabNo() && mpAutoFillRect)
1598 Point aMousePos = rMEvt.GetPosPixel();
1599 if (mpAutoFillRect->IsInside(aMousePos))
1601 SetPointer( Pointer( PointerStyle::Cross ) ); //! dickeres Kreuz ?
1602 if (bAction)
1604 SCCOL nX = aMarkRange.aEnd.Col();
1605 SCROW nY = aMarkRange.aEnd.Row();
1607 if ( lcl_IsEditableMatrix( pViewData->GetDocument(), aMarkRange ) )
1608 pViewData->SetDragMode(
1609 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY, SC_FILL_MATRIX );
1610 else
1611 pViewData->SetFillMode(
1612 aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY );
1614 // The simple selection must also be recognized when dragging,
1615 // where the Marking flag is set and MarkToSimple won't work anymore.
1616 pViewData->GetMarkData().MarkToSimple();
1618 bNewPointer = true;
1623 // Embedded-Rechteck
1625 if (pDoc->IsEmbedded())
1627 ScRange aRange;
1628 pDoc->GetEmbedded( aRange );
1629 if ( pViewData->GetTabNo() == aRange.aStart.Tab() )
1631 Point aStartPos = pViewData->GetScrPos( aRange.aStart.Col(), aRange.aStart.Row(), eWhich );
1632 Point aEndPos = pViewData->GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich );
1633 Point aMousePos = rMEvt.GetPosPixel();
1634 if ( bLayoutRTL )
1636 aStartPos.X() += 2;
1637 aEndPos.X() += 2;
1639 bool bTop = ( aMousePos.X() >= aStartPos.X()-3 && aMousePos.X() <= aStartPos.X()+1 &&
1640 aMousePos.Y() >= aStartPos.Y()-3 && aMousePos.Y() <= aStartPos.Y()+1 );
1641 bool bBottom = ( aMousePos.X() >= aEndPos.X()-3 && aMousePos.X() <= aEndPos.X()+1 &&
1642 aMousePos.Y() >= aEndPos.Y()-3 && aMousePos.Y() <= aEndPos.Y()+1 );
1643 if ( bTop || bBottom )
1645 SetPointer( Pointer( PointerStyle::Cross ) );
1646 if (bAction)
1648 sal_uInt8 nMode = bTop ? SC_FILL_EMBED_LT : SC_FILL_EMBED_RB;
1649 pViewData->SetDragMode(
1650 aRange.aStart.Col(), aRange.aStart.Row(),
1651 aRange.aEnd.Col(), aRange.aEnd.Row(), nMode );
1653 bNewPointer = true;
1659 if (!bNewPointer && bAction)
1661 pViewData->ResetFillMode();
1664 return bNewPointer;
1667 void ScGridWindow::MouseButtonDown( const MouseEvent& rMEvt )
1669 nNestedButtonState = SC_NESTEDBUTTON_DOWN;
1671 MouseEventState aState;
1672 HandleMouseButtonDown(rMEvt, aState);
1673 if (aState.mbActivatePart)
1674 pViewData->GetView()->ActivatePart(eWhich);
1676 if ( nNestedButtonState == SC_NESTEDBUTTON_UP )
1678 // #i41690# If an object is deactivated from MouseButtonDown, it might reschedule,
1679 // so MouseButtonUp comes before the MouseButtonDown call is finished. In this case,
1680 // simulate another MouseButtonUp call, so the selection state is consistent.
1682 nButtonDown = rMEvt.GetButtons();
1683 FakeButtonUp();
1685 if ( IsTracking() )
1686 EndTracking(); // normally done in VCL as part of MouseButtonUp handling
1688 nNestedButtonState = SC_NESTEDBUTTON_NONE;
1691 bool ScGridWindow::IsCellCoveredByText(SCsCOL nPosX, SCsROW nPosY, SCTAB nTab, SCsCOL &rTextStartPosX)
1693 ScDocument* pDoc = pViewData->GetDocument();
1695 // find the first non-empty cell (this, or to the left)
1696 ScRefCellValue aCell;
1697 SCsCOL nNonEmptyX = nPosX;
1698 for (; nNonEmptyX >= 0; --nNonEmptyX)
1700 aCell.assign(*pDoc, ScAddress(nNonEmptyX, nPosY, nTab));
1701 if (!aCell.isEmpty())
1702 break;
1705 // the inital cell already contains text
1706 if (nNonEmptyX == nPosX)
1708 rTextStartPosX = nNonEmptyX;
1709 return true;
1712 // to the left, there is no cell that would contain (potentially
1713 // overrunning) text
1714 if (nNonEmptyX < 0 || pDoc->HasAttrib(nNonEmptyX, nPosY, nTab, nPosX, nPosY, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED))
1715 return false;
1717 double nPPTX = pViewData->GetPPTX();
1718 double nPPTY = pViewData->GetPPTY();
1720 ScTableInfo aTabInfo;
1721 pDoc->FillInfo(aTabInfo, 0, nPosY, nPosX, nPosY, nTab, nPPTX, nPPTY, false, false);
1723 Fraction aZoomX = pViewData->GetZoomX();
1724 Fraction aZoomY = pViewData->GetZoomY();
1725 ScOutputData aOutputData(this, OUTTYPE_WINDOW, aTabInfo, pDoc, nTab,
1726 0, 0, 0, nPosY, nPosX, nPosY, nPPTX, nPPTY,
1727 &aZoomX, &aZoomY);
1729 MapMode aCurrentMapMode(GetMapMode());
1730 SetMapMode(MAP_PIXEL);
1732 // obtain the bounding box of the text in first non-empty cell
1733 // to the left
1734 Rectangle aRect(aOutputData.LayoutStrings(false, false, ScAddress(nNonEmptyX, nPosY, nTab)));
1736 SetMapMode(aCurrentMapMode);
1738 // the text does not overrun from the cell
1739 if (aRect.IsEmpty())
1740 return false;
1742 SCsCOL nTextEndX;
1743 SCsROW nTextEndY;
1745 // test the rightmost position of the text bounding box
1746 long nMiddle = (aRect.Top() + aRect.Bottom()) / 2;
1747 pViewData->GetPosFromPixel(aRect.Right(), nMiddle, eWhich, nTextEndX, nTextEndY);
1748 if (nTextEndX >= nPosX)
1750 rTextStartPosX = nNonEmptyX;
1751 return true;
1754 return false;
1757 void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventState& rState )
1759 // We have to check if a context menu is shown and we have an UI
1760 // active inplace client. In that case we have to ignore the event.
1761 // Otherwise we would crash (context menu has been
1762 // opened by inplace client and we would deactivate the inplace client,
1763 // the contex menu is closed by VCL asynchronously which in the end
1764 // would work on deleted objects or the context menu has no parent anymore)
1765 SfxViewShell* pViewSh = pViewData->GetViewShell();
1766 SfxInPlaceClient* pClient = pViewSh->GetIPClient();
1767 if ( pClient &&
1768 pClient->IsObjectInPlaceActive() &&
1769 PopupMenu::IsInExecute() )
1770 return;
1772 aCurMousePos = rMEvt.GetPosPixel();
1774 // Filter-Popup beendet sich mit eigenem Mausklick, nicht erst beim Klick
1775 // in das GridWindow, darum ist die folgende Abfrage nicht mehr noetig:
1776 ClickExtern(); // loescht FilterBox, wenn vorhanden
1778 HideNoteMarker(); // Notiz-Anzeige
1780 bEEMouse = false;
1782 ScModule* pScMod = SC_MOD();
1783 if (pScMod->IsModalMode(pViewData->GetSfxDocShell()))
1784 return;
1786 pScActiveViewShell = pViewData->GetViewShell(); // falls auf Link geklickt wird
1787 nScClickMouseModifier = rMEvt.GetModifier(); // um Control-Klick immer zu erkennen
1789 bool bDetective = pViewData->GetViewShell()->IsAuditShell();
1790 bool bRefMode = pViewData->IsRefMode(); // Referenz angefangen
1791 bool bFormulaMode = pScMod->IsFormulaMode(); // naechster Klick -> Referenz
1792 bool bEditMode = pViewData->HasEditView(eWhich); // auch bei Mode==SC_INPUT_TYPE
1793 bool bDouble = (rMEvt.GetClicks() == 2);
1794 ScDocument* pDoc = pViewData->GetDocument();
1795 bool bIsTiledRendering = pDoc->GetDrawLayer()->isTiledRendering();
1797 // DeactivateIP passiert nur noch bei MarkListHasChanged
1799 // im GrabFocus Aufruf kann eine Fehlermeldung hochkommen
1800 // (z.B. beim Umbenennen von Tabellen per Tab-Reiter)
1802 if ( !nButtonDown || !bDouble ) // single (first) click is always valid
1803 nButtonDown = rMEvt.GetButtons(); // set nButtonDown first, so StopMarking works
1805 // special handling of empty cells with tiled rendering
1806 if (bIsTiledRendering)
1808 Point aPos(rMEvt.GetPosPixel());
1809 SCsCOL nPosX, nNonEmptyX(0);
1810 SCsROW nPosY;
1811 SCTAB nTab = pViewData->GetTabNo();
1812 pViewData->GetPosFromPixel(aPos.X(), aPos.Y(), eWhich, nPosX, nPosY);
1814 ScRefCellValue aCell;
1815 aCell.assign(*pDoc, ScAddress(nPosX, nPosY, nTab));
1816 bool bIsEmpty = aCell.isEmpty();
1817 bool bIsCoveredByText = bIsEmpty && IsCellCoveredByText(nPosX, nPosY, nTab, nNonEmptyX);
1819 if (bIsCoveredByText)
1821 // if there's any text flowing to this cell, activate the
1822 // editengine, so that the text actually gets the events
1823 if (bDouble)
1825 ScViewFunc* pView = pViewData->GetView();
1827 pView->SetCursor(nNonEmptyX, nPosY);
1828 SC_MOD()->SetInputMode(SC_INPUT_TABLE);
1830 bEditMode = pViewData->HasEditView(eWhich);
1831 assert(bEditMode);
1833 // synthesize the 1st click
1834 EditView* pEditView = pViewData->GetEditView(eWhich);
1835 MouseEvent aEditEvt(rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0);
1836 pEditView->MouseButtonDown(aEditEvt);
1837 pEditView->MouseButtonUp(aEditEvt);
1840 else if (bIsEmpty && bEditMode && bDouble)
1842 // double-click in an empty cell: the entire cell is selected
1843 SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aPos.X(), aPos.Y());
1844 SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aPos.X(), aPos.Y());
1845 return;
1849 if ( ( bEditMode && pViewData->GetActivePart() == eWhich ) || !bFormulaMode )
1850 GrabFocus();
1852 // #i31846# need to cancel a double click if the first click has set the "ignore" state,
1853 // but a single (first) click is always valid
1854 if ( nMouseStatus == SC_GM_IGNORE && bDouble )
1856 nButtonDown = 0;
1857 nMouseStatus = SC_GM_NONE;
1858 return;
1861 if ( bDetective ) // Detektiv-Fuell-Modus
1863 if ( rMEvt.IsLeft() && !rMEvt.GetModifier() )
1865 Point aPos = rMEvt.GetPosPixel();
1866 SCsCOL nPosX;
1867 SCsROW nPosY;
1868 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1870 SfxInt16Item aPosXItem( SID_RANGE_COL, nPosX );
1871 SfxInt32Item aPosYItem( SID_RANGE_ROW, nPosY );
1872 pViewData->GetDispatcher().Execute( SID_FILL_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD,
1873 &aPosXItem, &aPosYItem, (void*)0L );
1876 nButtonDown = 0;
1877 nMouseStatus = SC_GM_NONE;
1878 return;
1881 if (!bDouble)
1882 nMouseStatus = SC_GM_NONE;
1884 rState.mbActivatePart = !bFormulaMode; // Don't activate when in formula mode.
1886 if (bFormulaMode)
1888 ScViewSelectionEngine* pSelEng = pViewData->GetView()->GetSelEngine();
1889 pSelEng->SetWindow(this);
1890 pSelEng->SetWhich(eWhich);
1891 pSelEng->SetVisibleArea( Rectangle(Point(), GetOutputSizePixel()) );
1894 if (bEditMode && (pViewData->GetRefTabNo() == pViewData->GetTabNo()))
1896 Point aPos = rMEvt.GetPosPixel();
1897 SCsCOL nPosX;
1898 SCsROW nPosY;
1899 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1901 EditView* pEditView;
1902 SCCOL nEditCol;
1903 SCROW nEditRow;
1904 pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow );
1905 SCCOL nEndCol = pViewData->GetEditEndCol();
1906 SCROW nEndRow = pViewData->GetEditEndRow();
1908 if ( nPosX >= (SCsCOL) nEditCol && nPosX <= (SCsCOL) nEndCol &&
1909 nPosY >= (SCsROW) nEditRow && nPosY <= (SCsROW) nEndRow )
1911 // beim Klick in die Tabellen-EditView immer den Focus umsetzen
1912 if (bFormulaMode) // sonst ist es oben schon passiert
1913 GrabFocus();
1915 pScMod->SetInputMode( SC_INPUT_TABLE );
1916 bEEMouse = true;
1917 bEditMode = pEditView->MouseButtonDown( rMEvt );
1918 return;
1922 if (pScMod->GetIsWaterCan())
1924 //! was is mit'm Mac ???
1925 if ( rMEvt.GetModifier() + rMEvt.GetButtons() == MOUSE_RIGHT )
1927 nMouseStatus = SC_GM_WATERUNDO;
1928 return;
1932 // Reihenfolge passend zum angezeigten Cursor:
1933 // RangeFinder, AutoFill, PageBreak, Drawing
1935 RfCorner rCorner = NONE;
1936 bool bFound = HitRangeFinder(rMEvt.GetPosPixel(), rCorner, &nRFIndex, &nRFAddX, &nRFAddY);
1937 bRFSize = (rCorner != NONE);
1938 aRFSelectedCorned = rCorner;
1940 if (bFound)
1942 bRFMouse = true; // die anderen Variablen sind oben initialisiert
1944 rState.mbActivatePart = true; // always activate ?
1945 StartTracking();
1946 return;
1949 bool bCrossPointer = TestMouse( rMEvt, true );
1950 if ( bCrossPointer )
1952 if ( bDouble )
1953 pViewData->GetView()->FillCrossDblClick();
1954 else
1955 pScMod->InputEnterHandler(); // Autofill etc.
1958 if ( !bCrossPointer )
1960 nPagebreakMouse = HitPageBreak( rMEvt.GetPosPixel(), &aPagebreakSource,
1961 &nPagebreakBreak, &nPagebreakPrev );
1962 if (nPagebreakMouse)
1964 bPagebreakDrawn = false;
1965 StartTracking();
1966 PagebreakMove( rMEvt, false );
1967 return;
1971 // in the tiled rendering case, single clicks into drawing objects take
1972 // precedence over bEditMode
1973 if (((!bFormulaMode && !bEditMode) || bIsTiledRendering) && rMEvt.IsLeft())
1975 if ( !bCrossPointer && DrawMouseButtonDown(rMEvt) )
1977 return;
1980 pViewData->GetViewShell()->SetDrawShell( false ); // kein Draw-Objekt selektiert
1982 // TestMouse schon oben passiert
1985 Point aPos = rMEvt.GetPosPixel();
1986 SCsCOL nPosX;
1987 SCsROW nPosY;
1988 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
1989 SCTAB nTab = pViewData->GetTabNo();
1991 // Auto filter / pivot table / data select popup. This shouldn't activate the part.
1993 if ( !bDouble && !bFormulaMode && rMEvt.IsLeft() )
1995 SCsCOL nRealPosX;
1996 SCsROW nRealPosY;
1997 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nRealPosX, nRealPosY, false );//the real row/col
1998 const ScMergeFlagAttr* pRealPosAttr = static_cast<const ScMergeFlagAttr*>(
1999 pDoc->GetAttr( nRealPosX, nRealPosY, nTab, ATTR_MERGE_FLAG ));
2000 const ScMergeFlagAttr* pAttr = static_cast<const ScMergeFlagAttr*>(
2001 pDoc->GetAttr( nPosX, nPosY, nTab, ATTR_MERGE_FLAG ));
2002 if( pRealPosAttr->HasAutoFilter() )
2004 SC_MOD()->InputEnterHandler();
2005 if (DoAutoFilterButton( nRealPosX, nRealPosY, rMEvt))
2006 return;
2008 if (pAttr->HasAutoFilter())
2010 if (DoAutoFilterButton(nPosX, nPosY, rMEvt))
2012 rState.mbActivatePart = false;
2013 return;
2017 if (pAttr->HasPivotButton() || pAttr->HasPivotPopupButton())
2019 DoPushPivotButton(nPosX, nPosY, rMEvt, pAttr->HasPivotButton(), pAttr->HasPivotPopupButton());
2020 rState.mbActivatePart = false;
2021 return;
2024 // List Validity drop-down button
2026 if ( bListValButton )
2028 Rectangle aButtonRect = GetListValButtonRect( aListValPos );
2029 if ( aButtonRect.IsInside( aPos ) )
2031 LaunchDataSelectMenu( aListValPos.Col(), aListValPos.Row(), true );
2033 nMouseStatus = SC_GM_FILTER; // not set in DoAutoFilterMenue for bDataSelect
2034 CaptureMouse();
2035 rState.mbActivatePart = false;
2036 return;
2041 // scenario selection
2043 ScRange aScenRange;
2044 if ( rMEvt.IsLeft() && HasScenarioButton( aPos, aScenRange ) )
2046 DoScenarioMenu( aScenRange );
2047 return;
2050 // Doppelklick angefangen ?
2052 // StopMarking kann aus DrawMouseButtonDown gerufen werden
2054 if ( nMouseStatus != SC_GM_IGNORE && !bRefMode )
2056 if ( bDouble && !bCrossPointer )
2058 if (nMouseStatus == SC_GM_TABDOWN)
2059 nMouseStatus = SC_GM_DBLDOWN;
2061 else
2062 nMouseStatus = SC_GM_TABDOWN;
2065 // Links in Edit-Zellen
2067 bool bAlt = rMEvt.IsMod2();
2068 if ( !bAlt && rMEvt.IsLeft() &&
2069 GetEditUrl(rMEvt.GetPosPixel()) ) // Klick auf Link: Cursor nicht bewegen
2071 SetPointer( Pointer( PointerStyle::RefHand ) );
2072 nMouseStatus = SC_GM_URLDOWN; // auch nur dann beim ButtonUp ausfuehren
2073 return;
2076 // Gridwin - SelectionEngine
2078 if ( rMEvt.IsLeft() )
2080 ScViewSelectionEngine* pSelEng = pViewData->GetView()->GetSelEngine();
2081 pSelEng->SetWindow(this);
2082 pSelEng->SetWhich(eWhich);
2083 pSelEng->SetVisibleArea( Rectangle(Point(), GetOutputSizePixel()) );
2085 // SelMouseButtonDown an der View setzt noch das bMoveIsShift Flag
2086 if ( pViewData->GetView()->SelMouseButtonDown( rMEvt ) )
2088 if (IsMouseCaptured())
2090 // Tracking statt CaptureMouse, damit sauber abgebrochen werden kann
2091 //! Irgendwann sollte die SelectionEngine selber StartTracking rufen!?!
2092 ReleaseMouse();
2093 StartTracking();
2095 pViewData->GetMarkData().SetMarking(true);
2096 return;
2101 void ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt )
2103 aCurMousePos = rMEvt.GetPosPixel();
2104 ScDocument* pDoc = pViewData->GetDocument();
2105 ScMarkData& rMark = pViewData->GetMarkData();
2107 // #i41690# detect a MouseButtonUp call from within MouseButtonDown
2108 // (possible through Reschedule from storing an OLE object that is deselected)
2110 if ( nNestedButtonState == SC_NESTEDBUTTON_DOWN )
2111 nNestedButtonState = SC_NESTEDBUTTON_UP;
2113 if (nButtonDown != rMEvt.GetButtons())
2114 nMouseStatus = SC_GM_IGNORE; // reset und return
2116 nButtonDown = 0;
2118 if (nMouseStatus == SC_GM_IGNORE)
2120 nMouseStatus = SC_GM_NONE;
2121 // Selection-Engine: Markieren abbrechen
2122 pViewData->GetView()->GetSelEngine()->Reset();
2123 rMark.SetMarking(false);
2124 if (pViewData->IsAnyFillMode())
2126 pViewData->GetView()->StopRefMode();
2127 pViewData->ResetFillMode();
2129 StopMarking();
2130 DrawEndAction(); // Markieren/Verschieben auf Drawing-Layer abbrechen
2131 ReleaseMouse();
2132 return;
2135 if (nMouseStatus == SC_GM_FILTER)
2137 nMouseStatus = SC_GM_NONE;
2138 ReleaseMouse();
2139 return; // da muss nix mehr passieren
2142 ScModule* pScMod = SC_MOD();
2143 if (pScMod->IsModalMode(pViewData->GetSfxDocShell()))
2144 return;
2146 SfxBindings& rBindings = pViewData->GetBindings();
2147 if (bEEMouse && pViewData->HasEditView( eWhich ))
2149 EditView* pEditView;
2150 SCCOL nEditCol;
2151 SCROW nEditRow;
2152 pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2153 pEditView->MouseButtonUp( rMEvt );
2155 if ( rMEvt.IsMiddle() &&
2156 GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
2158 // EditView may have pasted from selection
2159 pScMod->InputChanged( pEditView );
2161 else
2162 pScMod->InputSelection( pEditView ); // parentheses etc.
2164 pViewData->GetView()->InvalidateAttribs();
2165 rBindings.Invalidate( SID_HYPERLINK_GETLINK );
2166 bEEMouse = false;
2167 return;
2170 if (bDPMouse)
2172 DPMouseButtonUp( rMEvt ); // resets bDPMouse
2173 return;
2176 if (bRFMouse)
2178 RFMouseMove( rMEvt, true ); // Range wieder richtigherum
2179 bRFMouse = false;
2180 SetPointer( Pointer( PointerStyle::Arrow ) );
2181 ReleaseMouse();
2182 return;
2185 if (nPagebreakMouse)
2187 PagebreakMove( rMEvt, true );
2188 nPagebreakMouse = SC_PD_NONE;
2189 SetPointer( Pointer( PointerStyle::Arrow ) );
2190 ReleaseMouse();
2191 return;
2194 if (nMouseStatus == SC_GM_WATERUNDO) // Undo im Giesskannenmodus
2196 ::svl::IUndoManager* pMgr = pViewData->GetDocShell()->GetUndoManager();
2197 if ( pMgr->GetUndoActionCount() && pMgr->GetUndoActionId() == STR_UNDO_APPLYCELLSTYLE )
2198 pMgr->Undo();
2199 return;
2202 if (DrawMouseButtonUp(rMEvt)) // includes format paint brush handling for drawing objects
2204 ScTabViewShell* pViewShell = pViewData->GetViewShell();
2205 SfxBindings& rFrmBindings=pViewShell->GetViewFrame()->GetBindings();
2206 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_WIDTH);
2207 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_HEIGHT);
2208 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_X);
2209 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_Y);
2210 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ANGLE);
2211 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_X);
2212 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_Y);
2213 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOWIDTH);
2214 rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOHEIGHT);
2215 return;
2218 rMark.SetMarking(false);
2220 SetPointer( Pointer( PointerStyle::Arrow ) );
2222 if (pViewData->IsFillMode() ||
2223 ( pViewData->GetFillMode() == SC_FILL_MATRIX && rMEvt.IsMod1() ))
2225 nScFillModeMouseModifier = rMEvt.GetModifier();
2226 SCCOL nStartCol;
2227 SCROW nStartRow;
2228 SCCOL nEndCol;
2229 SCROW nEndRow;
2230 pViewData->GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
2231 ScRange aDelRange;
2232 bool bIsDel = pViewData->GetDelMark( aDelRange );
2234 ScViewFunc* pView = pViewData->GetView();
2235 pView->StopRefMode();
2236 pViewData->ResetFillMode();
2237 pView->GetFunctionSet().SetAnchorFlag( false ); // #i5819# don't use AutoFill anchor flag for selection
2239 if ( bIsDel )
2241 pView->MarkRange( aDelRange, false );
2242 pView->DeleteContents( IDF_CONTENTS );
2243 SCTAB nTab = pViewData->GetTabNo();
2244 ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
2245 if ( aBlockRange != aDelRange )
2247 if ( aDelRange.aStart.Row() == nStartRow )
2248 aBlockRange.aEnd.SetCol( aDelRange.aStart.Col() - 1 );
2249 else
2250 aBlockRange.aEnd.SetRow( aDelRange.aStart.Row() - 1 );
2251 pView->MarkRange( aBlockRange, false );
2254 else
2255 pViewData->GetDispatcher().Execute( FID_FILL_AUTO, SfxCallMode::SLOT | SfxCallMode::RECORD );
2257 else if (pViewData->GetFillMode() == SC_FILL_MATRIX)
2259 SCTAB nTab = pViewData->GetTabNo();
2260 SCCOL nStartCol;
2261 SCROW nStartRow;
2262 SCCOL nEndCol;
2263 SCROW nEndRow;
2264 pViewData->GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
2265 ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
2266 SCCOL nFillCol = pViewData->GetRefEndX();
2267 SCROW nFillRow = pViewData->GetRefEndY();
2268 ScAddress aEndPos( nFillCol, nFillRow, nTab );
2270 ScTabView* pView = pViewData->GetView();
2271 pView->StopRefMode();
2272 pViewData->ResetFillMode();
2273 pView->GetFunctionSet().SetAnchorFlag( false );
2275 if ( aEndPos != aBlockRange.aEnd )
2277 pViewData->GetDocShell()->GetDocFunc().ResizeMatrix( aBlockRange, aEndPos, false );
2278 pViewData->GetView()->MarkRange( ScRange( aBlockRange.aStart, aEndPos ) );
2281 else if (pViewData->IsAnyFillMode())
2283 // Embedded-Area has been changed
2284 ScTabView* pView = pViewData->GetView();
2285 pView->StopRefMode();
2286 pViewData->ResetFillMode();
2287 pView->GetFunctionSet().SetAnchorFlag( false );
2288 pViewData->GetDocShell()->UpdateOle(pViewData);
2291 bool bRefMode = pViewData->IsRefMode();
2292 if (bRefMode)
2293 pScMod->EndReference();
2295 // Giesskannen-Modus (Gestalter)
2297 if (pScMod->GetIsWaterCan())
2299 // Abfrage auf Undo schon oben
2301 ScStyleSheetPool* pStylePool = (pViewData->GetDocument()->
2302 GetStyleSheetPool());
2303 if ( pStylePool )
2305 SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(
2306 pStylePool->GetActualStyleSheet());
2308 if ( pStyleSheet )
2310 SfxStyleFamily eFamily = pStyleSheet->GetFamily();
2312 switch ( eFamily )
2314 case SFX_STYLE_FAMILY_PARA:
2315 pViewData->GetView()->SetStyleSheetToMarked( pStyleSheet );
2316 pViewData->GetView()->DoneBlockMode();
2317 break;
2319 case SFX_STYLE_FAMILY_PAGE:
2320 pViewData->GetDocument()->SetPageStyle( pViewData->GetTabNo(),
2321 pStyleSheet->GetName() );
2323 ScPrintFunc( pViewData->GetDocShell(),
2324 pViewData->GetViewShell()->GetPrinter(true),
2325 pViewData->GetTabNo() ).UpdatePages();
2327 rBindings.Invalidate( SID_STATUS_PAGESTYLE );
2328 break;
2330 default:
2331 break;
2337 ScDBFunc* pView = pViewData->GetView();
2338 ScDocument* pBrushDoc = pView->GetBrushDocument();
2339 if ( pBrushDoc )
2341 pView->PasteFromClip( IDF_ATTRIB, pBrushDoc );
2342 if ( !pView->IsPaintBrushLocked() )
2343 pView->ResetBrushDocument(); // invalidates pBrushDoc pointer
2346 // double click (only left button)
2347 // in the tiled rendering case, single click works this way too
2349 bool bIsTiledRendering = pViewData->GetDocument()->GetDrawLayer()->isTiledRendering();
2350 bool bDouble = ( rMEvt.GetClicks() == 2 && rMEvt.IsLeft() );
2351 if ((bDouble || bIsTiledRendering) && !bRefMode && (nMouseStatus == SC_GM_DBLDOWN || bIsTiledRendering) && !pScMod->IsRefDialogOpen())
2353 // data pilot table
2354 Point aPos = rMEvt.GetPosPixel();
2355 SCsCOL nPosX;
2356 SCsROW nPosY;
2357 SCTAB nTab = pViewData->GetTabNo();
2358 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2359 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nPosX, nPosY, nTab );
2360 if ( pDPObj && pDPObj->GetSaveData()->GetDrillDown() )
2362 ScAddress aCellPos( nPosX, nPosY, pViewData->GetTabNo() );
2364 // Check for header drill-down first.
2365 sheet::DataPilotTableHeaderData aData;
2366 pDPObj->GetHeaderPositionData(aCellPos, aData);
2368 if ( ( aData.Flags & sheet::MemberResultFlags::HASMEMBER ) &&
2369 ! ( aData.Flags & sheet::MemberResultFlags::SUBTOTAL ) )
2371 sal_uInt16 nDummy;
2372 if ( pView->HasSelectionForDrillDown( nDummy ) )
2374 // execute slot to show dialog
2375 pViewData->GetDispatcher().Execute( SID_OUTLINE_SHOW, SfxCallMode::SLOT | SfxCallMode::RECORD );
2377 else
2379 // toggle single entry
2380 ScDPObject aNewObj( *pDPObj );
2381 pDPObj->ToggleDetails( aData, &aNewObj );
2382 ScDBDocFunc aFunc( *pViewData->GetDocShell() );
2383 aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
2384 pViewData->GetView()->CursorPosChanged(); // shells may be switched
2387 else
2389 // Check if the data area is double-clicked.
2391 Sequence<sheet::DataPilotFieldFilter> aFilters;
2392 if ( pDPObj->GetDataFieldPositionData(aCellPos, aFilters) )
2393 pViewData->GetView()->ShowDataPilotSourceData( *pDPObj, aFilters );
2396 return;
2399 // Check for cell protection attribute.
2400 ScTableProtection* pProtect = pDoc->GetTabProtection( nTab );
2401 bool bEditAllowed = true;
2402 if ( pProtect && pProtect->isProtected() )
2404 bool bCellProtected = pDoc->HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HASATTR_PROTECTED);
2405 bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
2406 bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
2408 if ( bSkipProtected && bSkipUnprotected )
2409 bEditAllowed = false;
2410 else if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
2411 bEditAllowed = false;
2414 if ( bEditAllowed )
2416 // don't forward the event to an empty cell, causes deselection in
2417 // case we used the double-click to select the empty cell
2418 if (bIsTiledRendering && bDouble)
2420 ScRefCellValue aCell;
2421 aCell.assign(*pViewData->GetDocument(), ScAddress(nPosX, nPosY, nTab));
2422 if (aCell.isEmpty())
2423 return;
2426 // edit cell contents
2427 pViewData->GetViewShell()->UpdateInputHandler();
2428 pScMod->SetInputMode( SC_INPUT_TABLE );
2429 if (pViewData->HasEditView(eWhich))
2431 // Text-Cursor gleich an die geklickte Stelle setzen
2432 EditView* pEditView = pViewData->GetEditView( eWhich );
2433 MouseEvent aEditEvt( rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0 );
2434 pEditView->MouseButtonDown( aEditEvt );
2435 pEditView->MouseButtonUp( aEditEvt );
2438 return;
2441 // Links in edit cells
2443 bool bAlt = rMEvt.IsMod2();
2444 if ( !bAlt && !bRefMode && !bDouble && nMouseStatus == SC_GM_URLDOWN )
2446 // beim ButtonUp nur ausfuehren, wenn ButtonDown auch ueber einer URL war
2448 OUString aName, aUrl, aTarget;
2449 if ( GetEditUrl( rMEvt.GetPosPixel(), &aName, &aUrl, &aTarget ) )
2451 nMouseStatus = SC_GM_NONE; // keinen Doppelklick anfangen
2453 // ScGlobal::OpenURL() only understands Calc A1 style syntax.
2454 // Convert it to Calc A1 before calling OpenURL().
2455 if (pDoc->GetAddressConvention() == formula::FormulaGrammar::CONV_OOO)
2456 ScGlobal::OpenURL(aUrl, aTarget, pViewData->GetDocument()->GetDrawLayer());
2457 else
2459 ScAddress aTempAddr;
2460 ScAddress::ExternalInfo aExtInfo;
2461 sal_uInt16 nRes = aTempAddr.Parse(aUrl, pDoc, pDoc->GetAddressConvention(), &aExtInfo);
2462 if (!(nRes & SCA_VALID))
2464 // Not a reference string. Pass it through unmodified.
2465 ScGlobal::OpenURL(aUrl, aTarget);
2466 return;
2469 OUStringBuffer aBuf;
2470 if (aExtInfo.mbExternal)
2472 // External reference.
2473 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
2474 const OUString* pStr = pRefMgr->getExternalFileName(aExtInfo.mnFileId);
2475 if (pStr)
2476 aBuf.append(*pStr);
2478 aBuf.append('#');
2479 aBuf.append(aExtInfo.maTabName);
2480 aBuf.append('.');
2481 OUString aRefCalcA1(aTempAddr.Format(SCA_ABS, NULL, formula::FormulaGrammar::CONV_OOO));
2482 aBuf.append(aRefCalcA1);
2483 ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget);
2485 else
2487 // Internal reference.
2488 aBuf.append('#');
2489 OUString aUrlCalcA1(aTempAddr.Format(SCA_ABS_3D, pDoc, formula::FormulaGrammar::CONV_OOO));
2490 aBuf.append(aUrlCalcA1);
2491 ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget);
2495 // fire worksheet_followhyperlink event
2496 uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = pDoc->GetVbaEventProcessor();
2497 if( xVbaEvents.is() ) try
2499 Point aPos = rMEvt.GetPosPixel();
2500 SCsCOL nPosX;
2501 SCsROW nPosY;
2502 SCTAB nTab = pViewData->GetTabNo();
2503 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2504 OUString sURL;
2505 ScRefCellValue aCell;
2506 if (lcl_GetHyperlinkCell(pDoc, nPosX, nPosY, nTab, aCell, sURL))
2508 ScAddress aCellPos( nPosX, nPosY, nTab );
2509 uno::Reference< table::XCell > xCell( new ScCellObj( pViewData->GetDocShell(), aCellPos ) );
2510 uno::Sequence< uno::Any > aArgs(1);
2511 aArgs[0] <<= xCell;
2512 xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_FOLLOWHYPERLINK, aArgs );
2515 catch( uno::Exception& )
2519 return;
2523 // Gridwin - SelectionEngine
2525 // SelMouseButtonDown is called only for left button, but SelMouseButtonUp would return
2526 // sal_True for any call, so IsLeft must be checked here, too.
2528 if ( rMEvt.IsLeft() && pViewData->GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt ) )
2530 pViewData->GetView()->SelectionChanged();
2532 SfxDispatcher* pDisp = pViewData->GetViewShell()->GetDispatcher();
2533 bool bFormulaMode = pScMod->IsFormulaMode();
2534 OSL_ENSURE( pDisp || bFormulaMode, "Cursor auf nicht aktiver View bewegen ?" );
2536 // #i14927# execute SID_CURRENTCELL (for macro recording) only if there is no
2537 // multiple selection, so the argument string completely describes the selection,
2538 // and executing the slot won't change the existing selection (executing the slot
2539 // here and from a recorded macro is treated equally)
2541 if ( pDisp && !bFormulaMode && !rMark.IsMultiMarked() )
2543 OUString aAddr; // CurrentCell
2544 if( rMark.IsMarked() )
2546 ScRange aScRange;
2547 rMark.GetMarkArea( aScRange );
2548 aAddr = aScRange.Format(SCR_ABS);
2549 if ( aScRange.aStart == aScRange.aEnd )
2551 // make sure there is a range selection string even for a single cell
2552 aAddr = aAddr + ":" + aAddr;
2555 //! SID_MARKAREA gibts nicht mehr ???
2556 //! was passiert beim Markieren mit dem Cursor ???
2558 else // nur Cursor bewegen
2560 ScAddress aScAddress( pViewData->GetCurX(), pViewData->GetCurY(), 0 );
2561 aAddr = aScAddress.Format(SCA_ABS);
2564 SfxStringItem aPosItem( SID_CURRENTCELL, aAddr );
2565 // We don't want to align to the cursor position because if the
2566 // cell cursor isn't visible after making selection, it would jump
2567 // back to the origin of the selection where the cell cursor is.
2568 SfxBoolItem aAlignCursorItem( FN_PARAM_2, false );
2569 pDisp->Execute( SID_CURRENTCELL, SfxCallMode::SLOT | SfxCallMode::RECORD,
2570 &aPosItem, &aAlignCursorItem, (void*)0L );
2572 pViewData->GetView()->InvalidateAttribs();
2574 pViewData->GetViewShell()->SelectionChanged();
2575 return;
2579 void ScGridWindow::FakeButtonUp()
2581 if ( nButtonDown )
2583 MouseEvent aEvent( aCurMousePos ); // nButtons = 0 -> ignore
2584 MouseButtonUp( aEvent );
2588 void ScGridWindow::MouseMove( const MouseEvent& rMEvt )
2590 aCurMousePos = rMEvt.GetPosPixel();
2592 if (rMEvt.IsLeaveWindow() && mpNoteMarker && !mpNoteMarker->IsByKeyboard())
2593 HideNoteMarker();
2595 ScModule* pScMod = SC_MOD();
2596 if (pScMod->IsModalMode(pViewData->GetSfxDocShell()))
2597 return;
2599 // Ob aus dem Edit-Modus Drag&Drop gestartet wurde, bekommt man leider
2600 // nicht anders mit:
2602 if (bEEMouse && nButtonDown && !rMEvt.GetButtons())
2604 bEEMouse = false;
2605 nButtonDown = 0;
2606 nMouseStatus = SC_GM_NONE;
2607 return;
2610 if (nMouseStatus == SC_GM_IGNORE)
2611 return;
2613 if (nMouseStatus == SC_GM_WATERUNDO) // Undo im Giesskannenmodus -> nur auf Up warten
2614 return;
2616 if ( pViewData->GetViewShell()->IsAuditShell() ) // Detektiv-Fuell-Modus
2618 SetPointer( Pointer( PointerStyle::Fill ) );
2619 return;
2622 if (nMouseStatus == SC_GM_FILTER && mpFilterBox)
2624 Point aRelPos = mpFilterBox->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) );
2625 if ( Rectangle(Point(), mpFilterBox->GetOutputSizePixel()).IsInside(aRelPos) )
2627 nButtonDown = 0;
2628 nMouseStatus = SC_GM_NONE;
2629 ReleaseMouse();
2630 mpFilterBox->MouseButtonDown( MouseEvent( aRelPos, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT ) );
2631 return;
2635 bool bFormulaMode = pScMod->IsFormulaMode(); // naechster Klick -> Referenz
2637 if (bEEMouse && pViewData->HasEditView( eWhich ))
2639 EditView* pEditView;
2640 SCCOL nEditCol;
2641 SCROW nEditRow;
2642 pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2643 pEditView->MouseMove( rMEvt );
2644 return;
2647 if (bDPMouse)
2649 DPMouseMove( rMEvt );
2650 return;
2653 if (bRFMouse)
2655 RFMouseMove( rMEvt, false );
2656 return;
2659 if (nPagebreakMouse)
2661 PagebreakMove( rMEvt, false );
2662 return;
2665 // anderen Mauszeiger anzeigen?
2667 bool bEditMode = pViewData->HasEditView(eWhich);
2669 //! Testen ob RefMode-Dragging !!!
2670 if ( bEditMode && (pViewData->GetRefTabNo() == pViewData->GetTabNo()) )
2672 Point aPos = rMEvt.GetPosPixel();
2673 SCsCOL nPosX;
2674 SCsROW nPosY;
2675 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
2677 EditView* pEditView;
2678 SCCOL nEditCol;
2679 SCROW nEditRow;
2680 pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2681 SCCOL nEndCol = pViewData->GetEditEndCol();
2682 SCROW nEndRow = pViewData->GetEditEndRow();
2684 if ( nPosX >= (SCsCOL) nEditCol && nPosX <= (SCsCOL) nEndCol &&
2685 nPosY >= (SCsROW) nEditRow && nPosY <= (SCsROW) nEndRow )
2687 // Field can only be URL field
2688 bool bAlt = rMEvt.IsMod2();
2689 if ( !bAlt && !nButtonDown && pEditView && pEditView->GetFieldUnderMousePointer() )
2690 SetPointer( Pointer( PointerStyle::RefHand ) );
2691 else if ( pEditView && pEditView->GetEditEngine()->IsVertical() )
2692 SetPointer( Pointer( PointerStyle::TextVertical ) );
2693 else
2694 SetPointer( Pointer( PointerStyle::Text ) );
2695 return;
2699 bool bWater = SC_MOD()->GetIsWaterCan() || pViewData->GetView()->HasPaintBrush();
2700 if (bWater)
2701 SetPointer( Pointer(PointerStyle::Fill) );
2703 if (!bWater)
2705 bool bCross = false;
2707 // Range-Finder
2709 RfCorner rCorner = NONE;
2710 if ( HitRangeFinder( rMEvt.GetPosPixel(), rCorner ) )
2712 if (rCorner != NONE)
2713 SetPointer( Pointer( PointerStyle::Cross ) );
2714 else
2715 SetPointer( Pointer( PointerStyle::Hand ) );
2716 bCross = true;
2719 // Page-Break-Modus
2721 sal_uInt16 nBreakType;
2722 if ( !nButtonDown && pViewData->IsPagebreakMode() &&
2723 ( nBreakType = HitPageBreak( rMEvt.GetPosPixel() ) ) != 0 )
2725 PointerStyle eNew = PointerStyle::Arrow;
2726 switch ( nBreakType )
2728 case SC_PD_RANGE_L:
2729 case SC_PD_RANGE_R:
2730 case SC_PD_BREAK_H:
2731 eNew = PointerStyle::ESize;
2732 break;
2733 case SC_PD_RANGE_T:
2734 case SC_PD_RANGE_B:
2735 case SC_PD_BREAK_V:
2736 eNew = PointerStyle::SSize;
2737 break;
2738 case SC_PD_RANGE_TL:
2739 case SC_PD_RANGE_BR:
2740 eNew = PointerStyle::SESize;
2741 break;
2742 case SC_PD_RANGE_TR:
2743 case SC_PD_RANGE_BL:
2744 eNew = PointerStyle::NESize;
2745 break;
2747 SetPointer( Pointer( eNew ) );
2748 bCross = true;
2751 // Fill-Cursor anzeigen ?
2753 if ( !bFormulaMode && !nButtonDown )
2754 if (TestMouse( rMEvt, false ))
2755 bCross = true;
2757 if ( nButtonDown && pViewData->IsAnyFillMode() )
2759 SetPointer( Pointer( PointerStyle::Cross ) );
2760 bCross = true;
2761 nScFillModeMouseModifier = rMEvt.GetModifier(); // ausgewertet bei AutoFill und Matrix
2764 if (!bCross)
2766 bool bAlt = rMEvt.IsMod2();
2768 if (bEditMode) // Edit-Mode muss zuerst kommen!
2769 SetPointer( Pointer( PointerStyle::Arrow ) );
2770 else if ( !bAlt && !nButtonDown &&
2771 GetEditUrl(rMEvt.GetPosPixel()) )
2772 SetPointer( Pointer( PointerStyle::RefHand ) );
2773 else if ( DrawMouseMove(rMEvt) ) // setzt Pointer um
2774 return;
2778 if ( pViewData->GetView()->GetSelEngine()->SelMouseMove( rMEvt ) )
2779 return;
2782 static void lcl_InitMouseEvent(css::awt::MouseEvent& rEvent, const MouseEvent& rEvt)
2784 rEvent.Modifiers = 0;
2785 if ( rEvt.IsShift() )
2786 rEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
2787 if ( rEvt.IsMod1() )
2788 rEvent.Modifiers |= css::awt::KeyModifier::MOD1;
2789 if ( rEvt.IsMod2() )
2790 rEvent.Modifiers |= css::awt::KeyModifier::MOD2;
2791 if ( rEvt.IsMod3() )
2792 rEvent.Modifiers |= css::awt::KeyModifier::MOD3;
2794 rEvent.Buttons = 0;
2795 if ( rEvt.IsLeft() )
2796 rEvent.Buttons |= css::awt::MouseButton::LEFT;
2797 if ( rEvt.IsRight() )
2798 rEvent.Buttons |= css::awt::MouseButton::RIGHT;
2799 if ( rEvt.IsMiddle() )
2800 rEvent.Buttons |= css::awt::MouseButton::MIDDLE;
2802 rEvent.X = rEvt.GetPosPixel().X();
2803 rEvent.Y = rEvt.GetPosPixel().Y();
2804 rEvent.ClickCount = rEvt.GetClicks();
2805 rEvent.PopupTrigger = false;
2808 bool ScGridWindow::PreNotify( NotifyEvent& rNEvt )
2810 bool bDone = false;
2811 MouseNotifyEvent nType = rNEvt.GetType();
2812 if ( nType == MouseNotifyEvent::MOUSEBUTTONUP || nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
2814 vcl::Window* pWindow = rNEvt.GetWindow();
2815 if (pWindow == this && pViewData)
2817 SfxViewFrame* pViewFrame = pViewData->GetViewShell()->GetViewFrame();
2818 if (pViewFrame)
2820 com::sun::star::uno::Reference<com::sun::star::frame::XController> xController = pViewFrame->GetFrame().GetController();
2821 if (xController.is())
2823 ScTabViewObj* pImp = ScTabViewObj::getImplementation( xController );
2824 if (pImp && pImp->IsMouseListening())
2826 ::com::sun::star::awt::MouseEvent aEvent;
2827 lcl_InitMouseEvent( aEvent, *rNEvt.GetMouseEvent() );
2828 if ( rNEvt.GetWindow() )
2829 aEvent.Source = rNEvt.GetWindow()->GetComponentInterface();
2830 if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN)
2831 bDone = pImp->MousePressed( aEvent );
2832 else
2833 bDone = pImp->MouseReleased( aEvent );
2839 if (bDone) // event consumed by a listener
2841 if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
2843 const MouseEvent* pMouseEvent = rNEvt.GetMouseEvent();
2844 if ( pMouseEvent->IsRight() && pMouseEvent->GetClicks() == 1 )
2846 // If a listener returned true for a right-click call, also prevent opening the context menu
2847 // (this works only if the context menu is opened on mouse-down)
2848 nMouseStatus = SC_GM_IGNORE;
2852 return true;
2854 else
2855 return Window::PreNotify( rNEvt );
2858 void ScGridWindow::Tracking( const TrackingEvent& rTEvt )
2860 // Weil die SelectionEngine kein Tracking kennt, die Events nur auf
2861 // die verschiedenen MouseHandler verteilen...
2863 const MouseEvent& rMEvt = rTEvt.GetMouseEvent();
2865 if ( rTEvt.IsTrackingCanceled() ) // alles abbrechen...
2867 if (!pViewData->GetView()->IsInActivatePart() && !SC_MOD()->IsRefDialogOpen())
2869 if (bDPMouse)
2870 bDPMouse = false; // gezeichnet wird per bDragRect
2871 if (bDragRect)
2873 // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich );
2874 bDragRect = false;
2875 UpdateDragRectOverlay();
2877 if (bRFMouse)
2879 RFMouseMove( rMEvt, true ); // richtig abbrechen geht dabei nicht...
2880 bRFMouse = false;
2882 if (nPagebreakMouse)
2884 // if (bPagebreakDrawn)
2885 // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(),
2886 // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False );
2887 bPagebreakDrawn = false;
2888 UpdateDragRectOverlay();
2889 nPagebreakMouse = SC_PD_NONE;
2892 SetPointer( Pointer( PointerStyle::Arrow ) );
2893 StopMarking();
2894 MouseButtonUp( rMEvt ); // mit Status SC_GM_IGNORE aus StopMarking
2896 bool bRefMode = pViewData->IsRefMode();
2897 if (bRefMode)
2898 SC_MOD()->EndReference(); // Dialog nicht verkleinert lassen
2901 else if ( rTEvt.IsTrackingEnded() )
2903 // MouseButtonUp immer mit passenden Buttons (z.B. wegen Testtool, #63148#)
2904 // Schliesslich behauptet der Tracking-Event ja, dass normal beendet und nicht
2905 // abgebrochen wurde.
2907 MouseEvent aUpEvt( rMEvt.GetPosPixel(), rMEvt.GetClicks(),
2908 rMEvt.GetMode(), nButtonDown, rMEvt.GetModifier() );
2909 MouseButtonUp( aUpEvt );
2911 else
2912 MouseMove( rMEvt );
2915 void ScGridWindow::StartDrag( sal_Int8 /* nAction */, const Point& rPosPixel )
2917 if (mpFilterBox || nPagebreakMouse)
2918 return;
2920 HideNoteMarker();
2922 CommandEvent aDragEvent( rPosPixel, CommandEventId::StartDrag, true );
2924 if (bEEMouse && pViewData->HasEditView( eWhich ))
2926 EditView* pEditView;
2927 SCCOL nEditCol;
2928 SCROW nEditRow;
2929 pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow );
2931 // don't remove the edit view while switching views
2932 ScModule* pScMod = SC_MOD();
2933 pScMod->SetInEditCommand( true );
2935 pEditView->Command( aDragEvent );
2937 ScInputHandler* pHdl = pScMod->GetInputHdl();
2938 if (pHdl)
2939 pHdl->DataChanged();
2941 pScMod->SetInEditCommand( false );
2942 if (!pViewData->IsActive()) // dropped to different view?
2944 ScInputHandler* pViewHdl = pScMod->GetInputHdl( pViewData->GetViewShell() );
2945 if ( pViewHdl && pViewData->HasEditView( eWhich ) )
2947 pViewHdl->CancelHandler();
2948 ShowCursor(); // missing from KillEditView
2952 else
2953 if ( !DrawCommand(aDragEvent) )
2954 pViewData->GetView()->GetSelEngine()->Command( aDragEvent );
2957 static void lcl_SetTextCursorPos( ScViewData* pViewData, ScSplitPos eWhich, vcl::Window* pWin )
2959 SCCOL nCol = pViewData->GetCurX();
2960 SCROW nRow = pViewData->GetCurY();
2961 Rectangle aEditArea = pViewData->GetEditArea( eWhich, nCol, nRow, pWin, NULL, true );
2962 aEditArea.Right() = aEditArea.Left();
2963 aEditArea = pWin->PixelToLogic( aEditArea );
2964 pWin->SetCursorRect( &aEditArea );
2967 void ScGridWindow::Command( const CommandEvent& rCEvt )
2969 // The command event is send to the window after a possible context
2970 // menu from an inplace client is closed. Now we have the chance to
2971 // deactivate the inplace client without any problem regarding parent
2972 // windows and code on the stack.
2973 CommandEventId nCmd = rCEvt.GetCommand();
2974 ScTabViewShell* pTabViewSh = pViewData->GetViewShell();
2975 SfxInPlaceClient* pClient = pTabViewSh->GetIPClient();
2976 if ( pClient &&
2977 pClient->IsObjectInPlaceActive() &&
2978 nCmd == CommandEventId::ContextMenu )
2980 pTabViewSh->DeactivateOle();
2981 return;
2984 ScModule* pScMod = SC_MOD();
2985 OSL_ENSURE( nCmd != CommandEventId::StartDrag, "ScGridWindow::Command called with CommandEventId::StartDrag" );
2987 if ( nCmd == CommandEventId::StartExtTextInput ||
2988 nCmd == CommandEventId::EndExtTextInput ||
2989 nCmd == CommandEventId::ExtTextInput ||
2990 nCmd == CommandEventId::CursorPos ||
2991 nCmd == CommandEventId::QueryCharPosition )
2993 bool bEditView = pViewData->HasEditView( eWhich );
2994 if (!bEditView)
2996 // only if no cell editview is active, look at drawview
2997 SdrView* pSdrView = pViewData->GetView()->GetSdrView();
2998 if ( pSdrView )
3000 OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
3001 if ( pOlView && pOlView->GetWindow() == this )
3003 pOlView->Command( rCEvt );
3004 return; // done
3009 if ( nCmd == CommandEventId::CursorPos && !bEditView )
3011 // CURSORPOS may be called without following text input,
3012 // to set the input method window position
3013 // -> input mode must not be started,
3014 // manually calculate text insert position if not in input mode
3016 lcl_SetTextCursorPos( pViewData, eWhich, this );
3017 return;
3020 ScInputHandler* pHdl = pScMod->GetInputHdl( pViewData->GetViewShell() );
3021 if ( pHdl )
3023 pHdl->InputCommand( rCEvt, true );
3024 return; // done
3027 Window::Command( rCEvt );
3028 return;
3031 if ( nCmd == CommandEventId::PasteSelection )
3033 if ( bEEMouse )
3035 // EditEngine handles selection in MouseButtonUp - no action
3036 // needed in command handler
3038 else
3040 PasteSelection( rCEvt.GetMousePosPixel() );
3042 return;
3045 if ( nCmd == CommandEventId::InputLanguageChange )
3047 // #i55929# Font and font size state depends on input language if nothing is selected,
3048 // so the slots have to be invalidated when the input language is changed.
3050 SfxBindings& rBindings = pViewData->GetBindings();
3051 rBindings.Invalidate( SID_ATTR_CHAR_FONT );
3052 rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
3053 return;
3056 if ( nCmd == CommandEventId::Wheel || nCmd == CommandEventId::StartAutoScroll || nCmd == CommandEventId::AutoScroll )
3058 bool bDone = pViewData->GetView()->ScrollCommand( rCEvt, eWhich );
3059 if (!bDone)
3060 Window::Command(rCEvt);
3061 return;
3063 // #i7560# FormulaMode check is below scrolling - scrolling is allowed during formula input
3064 bool bDisable = pScMod->IsFormulaMode() ||
3065 pScMod->IsModalMode(pViewData->GetSfxDocShell());
3066 if (bDisable)
3067 return;
3069 if ( nCmd == CommandEventId::ContextMenu && !SC_MOD()->GetIsWaterCan() )
3071 bool bMouse = rCEvt.IsMouseEvent();
3072 if ( bMouse && nMouseStatus == SC_GM_IGNORE )
3073 return;
3075 if (pViewData->IsAnyFillMode())
3077 pViewData->GetView()->StopRefMode();
3078 pViewData->ResetFillMode();
3080 ReleaseMouse();
3081 StopMarking();
3083 Point aPosPixel = rCEvt.GetMousePosPixel();
3084 Point aMenuPos = aPosPixel;
3086 SCsCOL nCellX = -1;
3087 SCsROW nCellY = -1;
3088 pViewData->GetPosFromPixel(aPosPixel.X(), aPosPixel.Y(), eWhich, nCellX, nCellY);
3090 bool bSpellError = false;
3091 SCCOL nColSpellError = nCellX;
3092 ScRefCellValue aSpellCheckCell;
3094 if ( bMouse )
3096 ScDocument* pDoc = pViewData->GetDocument();
3097 SCTAB nTab = pViewData->GetTabNo();
3098 const ScTableProtection* pProtect = pDoc->GetTabProtection(nTab);
3099 bool bSelectAllowed = true;
3100 if ( pProtect && pProtect->isProtected() )
3102 // This sheet is protected. Check if a context menu is allowed on this cell.
3103 bool bCellProtected = pDoc->HasAttrib(nCellX, nCellY, nTab, nCellX, nCellY, nTab, HASATTR_PROTECTED);
3104 bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
3105 bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
3107 if (bCellProtected)
3108 bSelectAllowed = bSelProtected;
3109 else
3110 bSelectAllowed = bSelUnprotected;
3112 if (!bSelectAllowed)
3113 // Selecting this cell is not allowed, neither is context menu.
3114 return;
3116 if (mpSpellCheckCxt)
3118 // Find the first string to the left for spell checking in case the current cell is empty.
3119 ScAddress aPos(nCellX, nCellY, nTab);
3120 aSpellCheckCell.assign(*pDoc, aPos);
3121 while (aSpellCheckCell.meType == CELLTYPE_NONE)
3123 // Loop until we get the first non-empty cell in the row.
3124 aPos.IncCol(-1);
3125 if (aPos.Col() < 0)
3126 break;
3128 aSpellCheckCell.assign(*pDoc, aPos);
3131 if (aPos.Col() >= 0 && (aSpellCheckCell.meType == CELLTYPE_STRING || aSpellCheckCell.meType == CELLTYPE_EDIT))
3132 nColSpellError = aPos.Col();
3134 bSpellError = (mpSpellCheckCxt->isMisspelled(nColSpellError, nCellY));
3135 if (bSpellError)
3137 // Check and see if a misspelled word is under the mouse pointer.
3138 bSpellError = IsSpellErrorAtPos(aPosPixel, nColSpellError, nCellY);
3142 // #i18735# First select the item under the mouse pointer.
3143 // This can change the selection, and the view state (edit mode, etc).
3144 SelectForContextMenu(aPosPixel, bSpellError ? nColSpellError : nCellX, nCellY);
3147 bool bDone = false;
3148 bool bEdit = pViewData->HasEditView(eWhich);
3150 if ( !bEdit )
3152 // Edit-Zelle mit Spelling-Errors ?
3153 if (bMouse && (GetEditUrl(aPosPixel) || bSpellError))
3155 // GetEditUrlOrError hat den Cursor schon bewegt
3157 pScMod->SetInputMode( SC_INPUT_TABLE );
3158 bEdit = pViewData->HasEditView(eWhich); // hat's geklappt ?
3160 OSL_ENSURE( bEdit, "kann nicht in Edit-Modus schalten" );
3163 if ( bEdit )
3165 EditView* pEditView = pViewData->GetEditView( eWhich ); // ist dann nicht 0
3167 if ( !bMouse )
3169 vcl::Cursor* pCur = pEditView->GetCursor();
3170 if ( pCur )
3172 Point aLogicPos = pCur->GetPos();
3173 // use the position right of the cursor (spell popup is opened if
3174 // the cursor is before the word, but not if behind it)
3175 aLogicPos.X() += pCur->GetWidth();
3176 aLogicPos.Y() += pCur->GetHeight() / 2; // center vertically
3177 aMenuPos = LogicToPixel( aLogicPos );
3181 // if edit mode was just started above, online spelling may be incomplete
3182 pEditView->GetEditEngine()->CompleteOnlineSpelling();
3184 // IsCursorAtWrongSpelledWord could be used for !bMouse
3185 // if there was a corresponding ExecuteSpellPopup call
3187 if (bSpellError)
3189 // Wenn man unter OS/2 neben das Popupmenue klickt, kommt MouseButtonDown
3190 // vor dem Ende des Menue-Execute, darum muss SetModified vorher kommen
3191 // (Bug #40968#)
3192 ScInputHandler* pHdl = pScMod->GetInputHdl();
3193 if (pHdl)
3194 pHdl->SetModified();
3196 Link<> aLink = LINK( this, ScGridWindow, PopupSpellingHdl );
3197 pEditView->ExecuteSpellPopup( aMenuPos, &aLink );
3199 bDone = true;
3202 else if ( !bMouse )
3204 // non-edit menu by keyboard -> use lower right of cell cursor position
3205 ScDocument* aDoc = pViewData->GetDocument();
3206 SCTAB nTabNo = pViewData->GetTabNo();
3207 bool bLayoutIsRTL = aDoc->IsLayoutRTL(nTabNo);
3209 SCCOL nCurX = pViewData->GetCurX();
3210 SCROW nCurY = pViewData->GetCurY();
3211 aMenuPos = pViewData->GetScrPos( nCurX, nCurY, eWhich, true );
3212 long nSizeXPix;
3213 long nSizeYPix;
3214 pViewData->GetMergeSizePixel( nCurX, nCurY, nSizeXPix, nSizeYPix );
3215 // fdo#55432 take the correct position for RTL sheet
3216 aMenuPos.X() += bLayoutIsRTL ? -nSizeXPix : nSizeXPix;
3217 aMenuPos.Y() += nSizeYPix;
3219 ScTabViewShell* pViewSh = pViewData->GetViewShell();
3220 if (pViewSh)
3222 // Is a draw object selected?
3224 SdrView* pDrawView = pViewSh->GetSdrView();
3225 if (pDrawView && pDrawView->AreObjectsMarked())
3227 // #100442#; the conext menu should open in the middle of the selected objects
3228 Rectangle aSelectRect(LogicToPixel(pDrawView->GetAllMarkedBoundRect()));
3229 aMenuPos = aSelectRect.Center();
3234 if (!bDone)
3236 SfxDispatcher::ExecutePopup( 0, this, &aMenuPos );
3241 void ScGridWindow::SelectForContextMenu( const Point& rPosPixel, SCsCOL nCellX, SCsROW nCellY )
3243 // #i18735# if the click was outside of the current selection,
3244 // the cursor is moved or an object at the click position selected.
3245 // (see SwEditWin::SelectMenuPosition in Writer)
3247 ScTabView* pView = pViewData->GetView();
3248 ScDrawView* pDrawView = pView->GetScDrawView();
3250 // check cell edit mode
3252 if ( pViewData->HasEditView(eWhich) )
3254 ScModule* pScMod = SC_MOD();
3255 SCCOL nEditStartCol = pViewData->GetEditViewCol(); //! change to GetEditStartCol after calcrtl is integrated
3256 SCROW nEditStartRow = pViewData->GetEditViewRow();
3257 SCCOL nEditEndCol = pViewData->GetEditEndCol();
3258 SCROW nEditEndRow = pViewData->GetEditEndRow();
3260 if ( nCellX >= (SCsCOL) nEditStartCol && nCellX <= (SCsCOL) nEditEndCol &&
3261 nCellY >= (SCsROW) nEditStartRow && nCellY <= (SCsROW) nEditEndRow )
3263 // handle selection within the EditView
3265 EditView* pEditView = pViewData->GetEditView( eWhich ); // not NULL (HasEditView)
3266 EditEngine* pEditEngine = pEditView->GetEditEngine();
3267 Rectangle aOutputArea = pEditView->GetOutputArea();
3268 Rectangle aVisArea = pEditView->GetVisArea();
3270 Point aTextPos = PixelToLogic( rPosPixel );
3271 if ( pEditEngine->IsVertical() ) // have to manually transform position
3273 aTextPos -= aOutputArea.TopRight();
3274 long nTemp = -aTextPos.X();
3275 aTextPos.X() = aTextPos.Y();
3276 aTextPos.Y() = nTemp;
3278 else
3279 aTextPos -= aOutputArea.TopLeft();
3280 aTextPos += aVisArea.TopLeft(); // position in the edit document
3282 EPosition aDocPosition = pEditEngine->FindDocPosition(aTextPos);
3283 ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
3284 ESelection aSelection = pEditView->GetSelection();
3285 aSelection.Adjust(); // needed for IsLess/IsGreater
3286 if ( aCompare.IsLess(aSelection) || aCompare.IsGreater(aSelection) )
3288 // clicked outside the selected text - deselect and move text cursor
3289 MouseEvent aEvent( rPosPixel );
3290 pEditView->MouseButtonDown( aEvent );
3291 pEditView->MouseButtonUp( aEvent );
3292 pScMod->InputSelection( pEditView );
3295 return; // clicked within the edit view - keep edit mode
3297 else
3299 // outside of the edit view - end edit mode, regardless of cell selection, then continue
3300 pScMod->InputEnterHandler();
3304 // check draw text edit mode
3306 Point aLogicPos = PixelToLogic( rPosPixel ); // after cell edit mode is ended
3307 if ( pDrawView && pDrawView->GetTextEditObject() && pDrawView->GetTextEditOutlinerView() )
3309 OutlinerView* pOlView = pDrawView->GetTextEditOutlinerView();
3310 Rectangle aOutputArea = pOlView->GetOutputArea();
3311 if ( aOutputArea.IsInside( aLogicPos ) )
3313 // handle selection within the OutlinerView
3315 Outliner* pOutliner = pOlView->GetOutliner();
3316 const EditEngine& rEditEngine = pOutliner->GetEditEngine();
3317 Rectangle aVisArea = pOlView->GetVisArea();
3319 Point aTextPos = aLogicPos;
3320 if ( pOutliner->IsVertical() ) // have to manually transform position
3322 aTextPos -= aOutputArea.TopRight();
3323 long nTemp = -aTextPos.X();
3324 aTextPos.X() = aTextPos.Y();
3325 aTextPos.Y() = nTemp;
3327 else
3328 aTextPos -= aOutputArea.TopLeft();
3329 aTextPos += aVisArea.TopLeft(); // position in the edit document
3331 EPosition aDocPosition = rEditEngine.FindDocPosition(aTextPos);
3332 ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
3333 ESelection aSelection = pOlView->GetSelection();
3334 aSelection.Adjust(); // needed for IsLess/IsGreater
3335 if ( aCompare.IsLess(aSelection) || aCompare.IsGreater(aSelection) )
3337 // clicked outside the selected text - deselect and move text cursor
3338 // use DrawView to allow extra handling there (none currently)
3339 MouseEvent aEvent( rPosPixel );
3340 pDrawView->MouseButtonDown( aEvent, this );
3341 pDrawView->MouseButtonUp( aEvent, this );
3344 return; // clicked within the edit area - keep edit mode
3346 else
3348 // Outside of the edit area - end text edit mode, then continue.
3349 // DrawDeselectAll also ends text edit mode and updates the shells.
3350 // If the click was on the edited object, it will be selected again below.
3351 pView->DrawDeselectAll();
3355 // look for existing selection
3357 bool bHitSelected = false;
3358 if ( pDrawView && pDrawView->IsMarkedObjHit( aLogicPos ) )
3360 // clicked on selected object -> don't change anything
3361 bHitSelected = true;
3363 else if ( pViewData->GetMarkData().IsCellMarked(nCellX, nCellY) )
3365 // clicked on selected cell -> don't change anything
3366 bHitSelected = true;
3369 // select drawing object or move cell cursor
3371 if ( !bHitSelected )
3373 bool bWasDraw = ( pDrawView && pDrawView->AreObjectsMarked() );
3374 bool bHitDraw = false;
3375 if ( pDrawView )
3377 pDrawView->UnmarkAllObj();
3378 // Unlock the Internal Layer in order to activate the context menu.
3379 // re-lock in ScDrawView::MarkListHasChanged()
3380 lcl_UnLockComment( pDrawView, aLogicPos ,pViewData);
3381 bHitDraw = pDrawView->MarkObj( aLogicPos );
3382 // draw shell is activated in MarkListHasChanged
3384 if ( !bHitDraw )
3386 pView->Unmark();
3387 pView->SetCursor(nCellX, nCellY);
3388 if ( bWasDraw )
3389 pViewData->GetViewShell()->SetDrawShell( false ); // switch shells
3394 void ScGridWindow::KeyInput(const KeyEvent& rKEvt)
3396 // Cursor control for ref input dialog
3397 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
3398 if( SC_MOD()->IsRefDialogOpen() )
3400 if( !rKeyCode.GetModifier() && (rKeyCode.GetCode() == KEY_F2) )
3402 SC_MOD()->EndReference();
3404 else if( pViewData->GetViewShell()->MoveCursorKeyInput( rKEvt ) )
3406 ScRange aRef(
3407 pViewData->GetRefStartX(), pViewData->GetRefStartY(), pViewData->GetRefStartZ(),
3408 pViewData->GetRefEndX(), pViewData->GetRefEndY(), pViewData->GetRefEndZ() );
3409 SC_MOD()->SetReference( aRef, pViewData->GetDocument() );
3411 pViewData->GetViewShell()->SelectionChanged();
3412 return ;
3414 else if( rKeyCode.GetCode() == KEY_RETURN && pViewData->IsPasteMode() )
3416 ScTabViewShell* pTabViewShell = pViewData->GetViewShell();
3417 ScClipUtil::PasteFromClipboard( pViewData, pTabViewShell, false );
3419 // Clear clipboard content.
3420 uno::Reference<datatransfer::clipboard::XClipboard> xSystemClipboard =
3421 TransferableHelper::GetSystemClipboard();
3422 if (xSystemClipboard.is())
3424 xSystemClipboard->setContents(
3425 uno::Reference<datatransfer::XTransferable>(),
3426 uno::Reference<datatransfer::clipboard::XClipboardOwner>());
3429 // hide the border around the copy source
3430 pViewData->SetPasteMode( SC_PASTE_NONE );
3431 // Clear CopySourceOverlay in each window of a split/frozen tabview
3432 pViewData->GetView()->UpdateCopySourceOverlay();
3433 return;
3435 // wenn semi-Modeless-SfxChildWindow-Dialog oben, keine KeyInputs:
3436 else if( !pViewData->IsAnyFillMode() )
3438 if (rKeyCode.GetCode() == KEY_ESCAPE)
3440 pViewData->SetPasteMode( SC_PASTE_NONE );
3441 // Clear CopySourceOverlay in each window of a split/frozen tabview
3442 pViewData->GetView()->UpdateCopySourceOverlay();
3444 // query for existing note marker before calling ViewShell's keyboard handling
3445 // which may remove the marker
3446 bool bHadKeyMarker = mpNoteMarker && mpNoteMarker->IsByKeyboard();
3447 ScTabViewShell* pViewSh = pViewData->GetViewShell();
3449 if (pViewData->GetDocShell()->GetProgress())
3450 return;
3452 if (DrawKeyInput(rKEvt))
3454 const vcl::KeyCode& rLclKeyCode = rKEvt.GetKeyCode();
3455 if (rLclKeyCode.GetCode() == KEY_DOWN
3456 || rLclKeyCode.GetCode() == KEY_UP
3457 || rLclKeyCode.GetCode() == KEY_LEFT
3458 || rLclKeyCode.GetCode() == KEY_RIGHT)
3460 ScTabViewShell* pViewShell = pViewData->GetViewShell();
3461 SfxBindings& rBindings = pViewShell->GetViewFrame()->GetBindings();
3462 rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_X);
3463 rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_Y);
3465 return;
3468 if (!pViewData->GetView()->IsDrawSelMode() && !DrawHasMarkedObj()) // keine Eingaben im Zeichenmodus
3469 { //! DrawShell abfragen !!!
3470 if (pViewSh->TabKeyInput(rKEvt))
3471 return;
3473 else
3474 if (pViewSh->SfxViewShell::KeyInput(rKEvt)) // von SfxViewShell
3475 return;
3477 vcl::KeyCode aCode = rKEvt.GetKeyCode();
3478 if ( aCode.GetCode() == KEY_ESCAPE && aCode.GetModifier() == 0 )
3480 if ( bHadKeyMarker )
3481 HideNoteMarker();
3482 else
3483 pViewSh->Escape();
3484 return;
3486 if ( aCode.GetCode() == KEY_F1 && aCode.GetModifier() == KEY_MOD1 )
3488 // ctrl-F1 shows or hides the note or redlining info for the cursor position
3489 // (hard-coded because F1 can't be configured)
3491 if ( bHadKeyMarker )
3492 HideNoteMarker(); // hide when previously visible
3493 else
3494 ShowNoteMarker( pViewData->GetCurX(), pViewData->GetCurY(), true );
3495 return;
3497 if (aCode.GetCode() == KEY_BRACKETLEFT && aCode.GetModifier() == KEY_MOD1)
3499 pViewSh->DetectiveMarkPred();
3500 return;
3502 if (aCode.GetCode() == KEY_BRACKETRIGHT && aCode.GetModifier() == KEY_MOD1)
3504 pViewSh->DetectiveMarkSucc();
3505 return;
3510 Window::KeyInput(rKEvt);
3513 void ScGridWindow::StopMarking()
3515 DrawEndAction(); // Markieren/Verschieben auf Drawing-Layer abbrechen
3517 if (nButtonDown)
3519 pViewData->GetMarkData().SetMarking(false);
3520 nMouseStatus = SC_GM_IGNORE;
3524 void ScGridWindow::UpdateInputContext()
3526 bool bReadOnly = pViewData->GetDocShell()->IsReadOnly();
3527 InputContextFlags nOptions = bReadOnly ? InputContextFlags::NONE : ( InputContextFlags::Text | InputContextFlags::ExtText );
3529 // when font from InputContext is used,
3530 // it must be taken from the cursor position's cell attributes
3532 InputContext aContext;
3533 aContext.SetOptions( nOptions );
3534 SetInputContext( aContext );
3537 // sensitiver Bereich (Pixel)
3538 #define SCROLL_SENSITIVE 20
3540 bool ScGridWindow::DropScroll( const Point& rMousePos )
3542 SCsCOL nDx = 0;
3543 SCsROW nDy = 0;
3544 Size aSize = GetOutputSizePixel();
3546 if (aSize.Width() > SCROLL_SENSITIVE * 3)
3548 if ( rMousePos.X() < SCROLL_SENSITIVE && pViewData->GetPosX(WhichH(eWhich)) > 0 )
3549 nDx = -1;
3550 if ( rMousePos.X() >= aSize.Width() - SCROLL_SENSITIVE
3551 && pViewData->GetPosX(WhichH(eWhich)) < MAXCOL )
3552 nDx = 1;
3554 if (aSize.Height() > SCROLL_SENSITIVE * 3)
3556 if ( rMousePos.Y() < SCROLL_SENSITIVE && pViewData->GetPosY(WhichV(eWhich)) > 0 )
3557 nDy = -1;
3558 if ( rMousePos.Y() >= aSize.Height() - SCROLL_SENSITIVE
3559 && pViewData->GetPosY(WhichV(eWhich)) < MAXROW )
3560 nDy = 1;
3563 if ( nDx != 0 || nDy != 0 )
3565 if ( nDx != 0 )
3566 pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
3567 if ( nDy != 0 )
3568 pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
3571 return false;
3574 static bool lcl_TestScenarioRedliningDrop( ScDocument* pDoc, const ScRange& aDragRange)
3576 // Testet, ob bei eingeschalteten RedLining,
3577 // bei einem Drop ein Scenario betroffen ist.
3579 bool bReturn = false;
3580 SCTAB nTab = aDragRange.aStart.Tab();
3581 SCTAB nTabCount = pDoc->GetTableCount();
3583 if(pDoc->GetChangeTrack()!=NULL)
3585 if( pDoc->IsScenario(nTab) && pDoc->HasScenarioRange(nTab, aDragRange))
3587 bReturn = true;
3589 else
3591 for(SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++)
3593 if(pDoc->HasScenarioRange(i, aDragRange))
3595 bReturn = true;
3596 break;
3601 return bReturn;
3604 static ScRange lcl_MakeDropRange( SCCOL nPosX, SCROW nPosY, SCTAB nTab, const ScRange& rSource )
3606 SCCOL nCol1 = nPosX;
3607 SCCOL nCol2 = nCol1 + ( rSource.aEnd.Col() - rSource.aStart.Col() );
3608 if ( nCol2 > MAXCOL )
3610 nCol1 -= nCol2 - MAXCOL;
3611 nCol2 = MAXCOL;
3613 SCROW nRow1 = nPosY;
3614 SCROW nRow2 = nRow1 + ( rSource.aEnd.Row() - rSource.aStart.Row() );
3615 if ( nRow2 > MAXROW )
3617 nRow1 -= nRow2 - MAXROW;
3618 nRow2 = MAXROW;
3621 return ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
3624 extern bool bPasteIsDrop; // viewfun4 -> move to header
3625 extern bool bPasteIsMove; // viewfun7 -> move to header
3627 sal_Int8 ScGridWindow::AcceptPrivateDrop( const AcceptDropEvent& rEvt )
3629 if ( rEvt.mbLeaving )
3631 bDragRect = false;
3632 UpdateDragRectOverlay();
3633 return rEvt.mnAction;
3636 const ScDragData& rData = SC_MOD()->GetDragData();
3637 if ( rData.pCellTransfer )
3639 // Don't move source that would include filtered rows.
3640 if ((rEvt.mnAction & DND_ACTION_MOVE) && rData.pCellTransfer->HasFilteredRows())
3642 if (bDragRect)
3644 bDragRect = false;
3645 UpdateDragRectOverlay();
3647 return DND_ACTION_NONE;
3650 Point aPos = rEvt.maPosPixel;
3652 ScDocument* pSourceDoc = rData.pCellTransfer->GetSourceDocument();
3653 ScDocument* pThisDoc = pViewData->GetDocument();
3654 if (pSourceDoc == pThisDoc)
3656 OUString aName;
3657 if ( pThisDoc->HasChartAtPoint(pViewData->GetTabNo(), PixelToLogic(aPos), aName ))
3659 if (bDragRect) // Rechteck loeschen
3661 bDragRect = false;
3662 UpdateDragRectOverlay();
3665 //! highlight chart? (selection border?)
3667 sal_Int8 nRet = rEvt.mnAction;
3668 return nRet;
3672 if ( rData.pCellTransfer->GetDragSourceFlags() & SC_DROP_TABLE ) // whole sheet?
3674 bool bOk = pThisDoc->IsDocEditable();
3675 return bOk ? rEvt.mnAction : 0; // don't draw selection frame
3678 SCsCOL nPosX;
3679 SCsROW nPosY;
3680 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
3682 ScRange aSourceRange = rData.pCellTransfer->GetRange();
3683 SCCOL nSourceStartX = aSourceRange.aStart.Col();
3684 SCROW nSourceStartY = aSourceRange.aStart.Row();
3685 SCCOL nSourceEndX = aSourceRange.aEnd.Col();
3686 SCROW nSourceEndY = aSourceRange.aEnd.Row();
3687 SCCOL nSizeX = nSourceEndX - nSourceStartX + 1;
3688 SCROW nSizeY = nSourceEndY - nSourceStartY + 1;
3690 if ( rEvt.mnAction != DND_ACTION_MOVE )
3691 nSizeY = rData.pCellTransfer->GetNonFilteredRows(); // copy/link: no filtered rows
3693 SCsCOL nNewDragX = nPosX - rData.pCellTransfer->GetDragHandleX();
3694 if (nNewDragX<0) nNewDragX=0;
3695 if (nNewDragX+(nSizeX-1) > MAXCOL)
3696 nNewDragX = MAXCOL-(nSizeX-1);
3697 SCsROW nNewDragY = nPosY - rData.pCellTransfer->GetDragHandleY();
3698 if (nNewDragY<0) nNewDragY=0;
3699 if (nNewDragY+(nSizeY-1) > MAXROW)
3700 nNewDragY = MAXROW-(nSizeY-1);
3702 // don't break scenario ranges, don't drop on filtered
3703 SCTAB nTab = pViewData->GetTabNo();
3704 ScRange aDropRange = lcl_MakeDropRange( nNewDragX, nNewDragY, nTab, aSourceRange );
3705 if ( lcl_TestScenarioRedliningDrop( pThisDoc, aDropRange ) ||
3706 lcl_TestScenarioRedliningDrop( pSourceDoc, aSourceRange ) ||
3707 ScViewUtil::HasFiltered( aDropRange, pThisDoc) )
3709 if (bDragRect)
3711 bDragRect = false;
3712 UpdateDragRectOverlay();
3714 return DND_ACTION_NONE;
3717 InsCellCmd eDragInsertMode = INS_NONE;
3718 Window::PointerState aState = GetPointerState();
3720 // check for datapilot item sorting
3721 ScDPObject* pDPObj = NULL;
3722 if ( pThisDoc == pSourceDoc && ( pDPObj = pThisDoc->GetDPAtCursor( nNewDragX, nNewDragY, nTab ) ) != NULL )
3724 // drop on DataPilot table: sort or nothing
3726 bool bDPSort = false;
3727 if ( pThisDoc->GetDPAtCursor( nSourceStartX, nSourceStartY, aSourceRange.aStart.Tab() ) == pDPObj )
3729 sheet::DataPilotTableHeaderData aDestData;
3730 pDPObj->GetHeaderPositionData( ScAddress(nNewDragX, nNewDragY, nTab), aDestData );
3731 bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
3733 // look through the source range
3734 for (SCROW nRow = aSourceRange.aStart.Row(); bValid && nRow <= aSourceRange.aEnd.Row(); ++nRow )
3735 for (SCCOL nCol = aSourceRange.aStart.Col(); bValid && nCol <= aSourceRange.aEnd.Col(); ++nCol )
3737 sheet::DataPilotTableHeaderData aSourceData;
3738 pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, aSourceRange.aStart.Tab() ), aSourceData );
3739 if ( aSourceData.Dimension != aDestData.Dimension || aSourceData.MemberName.isEmpty() )
3740 bValid = false; // empty (subtotal) or different field
3743 if ( bValid )
3745 bool bIsDataLayout;
3746 OUString aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
3747 const ScDPSaveDimension* pDim = pDPObj->GetSaveData()->GetExistingDimensionByName( aDimName );
3748 if ( pDim )
3750 ScRange aOutRange = pDPObj->GetOutRange();
3752 sal_uInt16 nOrient = pDim->GetOrientation();
3753 if ( nOrient == sheet::DataPilotFieldOrientation_COLUMN )
3755 eDragInsertMode = INS_CELLSRIGHT;
3756 nSizeY = aOutRange.aEnd.Row() - nNewDragY + 1;
3757 bDPSort = true;
3759 else if ( nOrient == sheet::DataPilotFieldOrientation_ROW )
3761 eDragInsertMode = INS_CELLSDOWN;
3762 nSizeX = aOutRange.aEnd.Col() - nNewDragX + 1;
3763 bDPSort = true;
3769 if ( !bDPSort )
3771 // no valid sorting in a DataPilot table -> disallow
3772 if ( bDragRect )
3774 bDragRect = false;
3775 UpdateDragRectOverlay();
3777 return DND_ACTION_NONE;
3780 else if ( aState.mnState & KEY_MOD2 )
3782 if ( pThisDoc == pSourceDoc && nTab == aSourceRange.aStart.Tab() )
3784 long nDeltaX = labs( static_cast< long >( nNewDragX - nSourceStartX ) );
3785 long nDeltaY = labs( static_cast< long >( nNewDragY - nSourceStartY ) );
3786 if ( nDeltaX <= nDeltaY )
3788 eDragInsertMode = INS_CELLSDOWN;
3790 else
3792 eDragInsertMode = INS_CELLSRIGHT;
3795 if ( ( eDragInsertMode == INS_CELLSDOWN && nNewDragY <= nSourceEndY &&
3796 ( nNewDragX + nSizeX - 1 ) >= nSourceStartX && nNewDragX <= nSourceEndX &&
3797 ( nNewDragX != nSourceStartX || nNewDragY >= nSourceStartY ) ) ||
3798 ( eDragInsertMode == INS_CELLSRIGHT && nNewDragX <= nSourceEndX &&
3799 ( nNewDragY + nSizeY - 1 ) >= nSourceStartY && nNewDragY <= nSourceEndY &&
3800 ( nNewDragY != nSourceStartY || nNewDragX >= nSourceStartX ) ) )
3802 if ( bDragRect )
3804 bDragRect = false;
3805 UpdateDragRectOverlay();
3807 return DND_ACTION_NONE;
3810 else
3812 if ( static_cast< long >( nSizeX ) >= static_cast< long >( nSizeY ) )
3814 eDragInsertMode = INS_CELLSDOWN;
3817 else
3819 eDragInsertMode = INS_CELLSRIGHT;
3824 if ( nNewDragX != (SCsCOL) nDragStartX || nNewDragY != (SCsROW) nDragStartY ||
3825 nDragStartX+nSizeX-1 != nDragEndX || nDragStartY+nSizeY-1 != nDragEndY ||
3826 !bDragRect || eDragInsertMode != meDragInsertMode )
3828 nDragStartX = nNewDragX;
3829 nDragStartY = nNewDragY;
3830 nDragEndX = nDragStartX+nSizeX-1;
3831 nDragEndY = nDragStartY+nSizeY-1;
3832 bDragRect = true;
3833 meDragInsertMode = eDragInsertMode;
3835 UpdateDragRectOverlay();
3839 return rEvt.mnAction;
3842 sal_Int8 ScGridWindow::AcceptDrop( const AcceptDropEvent& rEvt )
3844 const ScDragData& rData = SC_MOD()->GetDragData();
3845 if ( rEvt.mbLeaving )
3847 DrawMarkDropObj( NULL );
3848 if ( rData.pCellTransfer )
3849 return AcceptPrivateDrop( rEvt ); // hide drop marker for internal D&D
3850 else
3851 return rEvt.mnAction;
3854 if ( pViewData->GetDocShell()->IsReadOnly() )
3855 return DND_ACTION_NONE;
3857 sal_Int8 nRet = DND_ACTION_NONE;
3859 if (rData.pCellTransfer)
3861 ScRange aSource = rData.pCellTransfer->GetRange();
3862 if ( aSource.aStart.Col() != 0 || aSource.aEnd.Col() != MAXCOL ||
3863 aSource.aStart.Row() != 0 || aSource.aEnd.Row() != MAXROW )
3864 DropScroll( rEvt.maPosPixel );
3866 nRet = AcceptPrivateDrop( rEvt );
3868 else
3870 if ( !rData.aLinkDoc.isEmpty() )
3872 OUString aThisName;
3873 ScDocShell* pDocSh = pViewData->GetDocShell();
3874 if (pDocSh && pDocSh->HasName())
3875 aThisName = pDocSh->GetMedium()->GetName();
3877 if ( !rData.aLinkDoc.equals(aThisName) )
3878 nRet = rEvt.mnAction;
3880 else if (!rData.aJumpTarget.isEmpty())
3882 // internal bookmarks (from Navigator)
3883 // local jumps from an unnamed document are possible only within a document
3885 if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == pViewData->GetDocument() )
3886 nRet = rEvt.mnAction;
3888 else
3890 sal_Int8 nMyAction = rEvt.mnAction;
3892 // clear DND_ACTION_LINK when other actions are set. The usage below cannot handle
3893 // multiple set values
3894 if((nMyAction & DND_ACTION_LINK) && (nMyAction & (DND_ACTION_COPYMOVE)))
3896 nMyAction &= ~DND_ACTION_LINK;
3899 if ( !rData.pDrawTransfer ||
3900 !IsMyModel(rData.pDrawTransfer->GetDragSourceView()) ) // drawing within the document
3901 if ( rEvt.mbDefault && nMyAction == DND_ACTION_MOVE )
3902 nMyAction = DND_ACTION_COPY;
3904 ScDocument* pThisDoc = pViewData->GetDocument();
3905 SdrObject* pHitObj = pThisDoc->GetObjectAtPoint(
3906 pViewData->GetTabNo(), PixelToLogic(rEvt.maPosPixel) );
3907 if ( pHitObj && nMyAction == DND_ACTION_LINK ) // && !rData.pDrawTransfer )
3909 if ( IsDropFormatSupported(SotClipboardFormatId::SVXB)
3910 || IsDropFormatSupported(SotClipboardFormatId::GDIMETAFILE)
3911 || IsDropFormatSupported(SotClipboardFormatId::PNG)
3912 || IsDropFormatSupported(SotClipboardFormatId::BITMAP) )
3914 // graphic dragged onto drawing object
3915 DrawMarkDropObj( pHitObj );
3916 nRet = nMyAction;
3919 if (!nRet)
3920 DrawMarkDropObj( NULL );
3922 if (!nRet)
3924 switch ( nMyAction )
3926 case DND_ACTION_COPY:
3927 case DND_ACTION_MOVE:
3928 case DND_ACTION_COPYMOVE:
3930 bool bMove = ( nMyAction == DND_ACTION_MOVE );
3931 if ( IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE ) ||
3932 IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
3933 IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE_OLE ) ||
3934 IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
3935 IsDropFormatSupported( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) ||
3936 IsDropFormatSupported( SotClipboardFormatId::STRING ) ||
3937 IsDropFormatSupported( SotClipboardFormatId::SYLK ) ||
3938 IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
3939 IsDropFormatSupported( SotClipboardFormatId::HTML ) ||
3940 IsDropFormatSupported( SotClipboardFormatId::HTML_SIMPLE ) ||
3941 IsDropFormatSupported( SotClipboardFormatId::DIF ) ||
3942 IsDropFormatSupported( SotClipboardFormatId::DRAWING ) ||
3943 IsDropFormatSupported( SotClipboardFormatId::SVXB ) ||
3944 IsDropFormatSupported( SotClipboardFormatId::RTF ) ||
3945 IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ) ||
3946 IsDropFormatSupported( SotClipboardFormatId::PNG ) ||
3947 IsDropFormatSupported( SotClipboardFormatId::BITMAP ) ||
3948 IsDropFormatSupported( SotClipboardFormatId::SBA_DATAEXCHANGE ) ||
3949 IsDropFormatSupported( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) ||
3950 ( !bMove && (
3951 IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
3952 IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
3953 IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
3954 IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
3955 IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
3956 IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) ) ) )
3958 nRet = nMyAction;
3961 break;
3962 case DND_ACTION_LINK:
3963 if ( IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
3964 IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
3965 IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
3966 IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
3967 IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
3968 IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
3969 IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
3970 IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
3971 IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
3973 nRet = nMyAction;
3975 break;
3978 if ( nRet )
3980 // Simple check for protection: It's not known here if the drop will result
3981 // in cells or drawing objects (some formats can be both) and how many cells
3982 // the result will be. But if IsFormatEditable for the drop cell position
3983 // is sal_False (ignores matrix formulas), nothing can be pasted, so the drop
3984 // can already be rejected here.
3986 Point aPos = rEvt.maPosPixel;
3987 SCsCOL nPosX;
3988 SCsROW nPosY;
3989 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
3990 SCTAB nTab = pViewData->GetTabNo();
3991 ScDocument* pDoc = pViewData->GetDocument();
3993 ScEditableTester aTester( pDoc, nTab, nPosX,nPosY, nPosX,nPosY );
3994 if ( !aTester.IsFormatEditable() )
3995 nRet = DND_ACTION_NONE; // forbidden
4000 // scroll only for accepted formats
4001 if (nRet)
4002 DropScroll( rEvt.maPosPixel );
4005 return nRet;
4008 static SotClipboardFormatId lcl_GetDropFormatId( const uno::Reference<datatransfer::XTransferable>& xTransfer, bool bPreferText = false )
4010 TransferableDataHelper aDataHelper( xTransfer );
4012 if ( !aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
4014 // use bookmark formats if no sba is present
4016 if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
4017 return SotClipboardFormatId::SOLK;
4018 else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
4019 return SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
4020 else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
4021 return SotClipboardFormatId::NETSCAPE_BOOKMARK;
4022 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
4023 return SotClipboardFormatId::FILEGRPDESCRIPTOR;
4026 SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
4027 if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
4028 nFormatId = SotClipboardFormatId::DRAWING;
4029 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
4030 nFormatId = SotClipboardFormatId::SVXB;
4031 else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) )
4033 // If it's a Writer object, insert RTF instead of OLE
4035 bool bDoRtf = false;
4036 tools::SvRef<SotStorageStream> xStm;
4037 TransferableObjectDescriptor aObjDesc;
4038 if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) &&
4039 aDataHelper.GetSotStorageStream( SotClipboardFormatId::EMBED_SOURCE, xStm ) )
4041 tools::SvRef<SotStorage> xStore( new SotStorage( *xStm ) );
4042 bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
4043 aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
4044 && aDataHelper.HasFormat( SotClipboardFormatId::RTF ) );
4046 if ( bDoRtf )
4047 nFormatId = SotClipboardFormatId::RTF;
4048 else
4049 nFormatId = SotClipboardFormatId::EMBED_SOURCE;
4051 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
4052 nFormatId = SotClipboardFormatId::LINK_SOURCE;
4053 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
4054 nFormatId = SotClipboardFormatId::SBA_DATAEXCHANGE;
4055 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) )
4056 nFormatId = SotClipboardFormatId::SBA_FIELDDATAEXCHANGE;
4057 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_8 ) )
4058 nFormatId = SotClipboardFormatId::BIFF_8;
4059 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_5 ) )
4060 nFormatId = SotClipboardFormatId::BIFF_5;
4061 else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ) )
4062 nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
4063 else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) )
4064 nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
4065 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
4066 nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
4067 else if ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
4068 nFormatId = SotClipboardFormatId::RTF;
4069 else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML ) )
4070 nFormatId = SotClipboardFormatId::HTML;
4071 else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML_SIMPLE ) )
4072 nFormatId = SotClipboardFormatId::HTML_SIMPLE;
4073 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SYLK ) )
4074 nFormatId = SotClipboardFormatId::SYLK;
4075 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
4076 nFormatId = SotClipboardFormatId::LINK;
4077 else if ( bPreferText && aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ) // #i86734# the behaviour introduced in #i62773# is wrong when pasting
4078 nFormatId = SotClipboardFormatId::STRING;
4079 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
4080 nFormatId = SotClipboardFormatId::FILE_LIST;
4081 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) ) // #i62773# FILE_LIST/FILE before STRING (Unix file managers)
4082 nFormatId = SotClipboardFormatId::SIMPLE_FILE;
4083 else if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
4084 nFormatId = SotClipboardFormatId::STRING;
4085 else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
4086 nFormatId = SotClipboardFormatId::GDIMETAFILE;
4087 else if ( aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
4088 nFormatId = SotClipboardFormatId::PNG;
4089 else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) )
4090 nFormatId = SotClipboardFormatId::BITMAP;
4092 return nFormatId;
4095 static SotClipboardFormatId lcl_GetDropLinkId( const uno::Reference<datatransfer::XTransferable>& xTransfer )
4097 TransferableDataHelper aDataHelper( xTransfer );
4099 SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
4100 if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
4101 nFormatId = SotClipboardFormatId::LINK_SOURCE;
4102 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
4103 nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
4104 else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
4105 nFormatId = SotClipboardFormatId::LINK;
4106 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
4107 nFormatId = SotClipboardFormatId::FILE_LIST;
4108 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) )
4109 nFormatId = SotClipboardFormatId::SIMPLE_FILE;
4110 else if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
4111 nFormatId = SotClipboardFormatId::SOLK;
4112 else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
4113 nFormatId = SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
4114 else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
4115 nFormatId = SotClipboardFormatId::NETSCAPE_BOOKMARK;
4116 else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
4117 nFormatId = SotClipboardFormatId::FILEGRPDESCRIPTOR;
4119 return nFormatId;
4122 sal_Int8 ScGridWindow::ExecutePrivateDrop( const ExecuteDropEvent& rEvt )
4124 // hide drop marker
4125 bDragRect = false;
4126 UpdateDragRectOverlay();
4128 ScModule* pScMod = SC_MOD();
4129 const ScDragData& rData = pScMod->GetDragData();
4131 return DropTransferObj( rData.pCellTransfer, nDragStartX, nDragStartY,
4132 PixelToLogic(rEvt.maPosPixel), rEvt.mnAction );
4135 sal_Int8 ScGridWindow::DropTransferObj( ScTransferObj* pTransObj, SCCOL nDestPosX, SCROW nDestPosY,
4136 const Point& rLogicPos, sal_Int8 nDndAction )
4138 if ( !pTransObj )
4139 return 0;
4141 ScDocument* pSourceDoc = pTransObj->GetSourceDocument();
4142 ScDocShell* pDocSh = pViewData->GetDocShell();
4143 ScDocument* pThisDoc = pViewData->GetDocument();
4144 ScViewFunc* pView = pViewData->GetView();
4145 SCTAB nThisTab = pViewData->GetTabNo();
4146 sal_uInt16 nFlags = pTransObj->GetDragSourceFlags();
4148 bool bIsNavi = ( nFlags & SC_DROP_NAVIGATOR ) != 0;
4149 bool bIsMove = ( nDndAction == DND_ACTION_MOVE && !bIsNavi );
4151 // workaround for wrong nDndAction on Windows when pressing solely
4152 // the Alt key during drag and drop;
4153 // can be removed after #i79215# has been fixed
4154 if ( meDragInsertMode != INS_NONE )
4156 bIsMove = ( nDndAction & DND_ACTION_MOVE && !bIsNavi );
4159 bool bIsLink = ( nDndAction == DND_ACTION_LINK );
4161 ScRange aSource = pTransObj->GetRange();
4163 // only use visible tab from source range - when dragging within one table,
4164 // all selected tables at the time of dropping are used (handled in MoveBlockTo)
4165 SCTAB nSourceTab = pTransObj->GetVisibleTab();
4166 aSource.aStart.SetTab( nSourceTab );
4167 aSource.aEnd.SetTab( nSourceTab );
4169 SCCOL nSizeX = aSource.aEnd.Col() - aSource.aStart.Col() + 1;
4170 SCROW nSizeY = (bIsMove ? (aSource.aEnd.Row() - aSource.aStart.Row() + 1) :
4171 pTransObj->GetNonFilteredRows()); // copy/link: no filtered rows
4172 ScRange aDest( nDestPosX, nDestPosY, nThisTab,
4173 nDestPosX + nSizeX - 1, nDestPosY + nSizeY - 1, nThisTab );
4175 /* NOTE: AcceptPrivateDrop() already checked for filtered conditions during
4176 * dragging and adapted drawing of the selection frame. We check here
4177 * (again) because this may actually also be called from PasteSelection(),
4178 * we would have to duplicate determination of flags and destination range
4179 * and would lose the context of the "filtered destination is OK" cases
4180 * below, which is already awkward enough as is. */
4182 // Don't move filtered source.
4183 bool bFiltered = (bIsMove && pTransObj->HasFilteredRows());
4184 if (!bFiltered)
4186 if (pSourceDoc != pThisDoc && ((nFlags & SC_DROP_TABLE) ||
4187 (!bIsLink && meDragInsertMode == INS_NONE)))
4189 // Nothing. Either entire sheet to be dropped, or the one case
4190 // where PasteFromClip() is to be called that handles a filtered
4191 // destination itself. Drag-copy from another document without
4192 // inserting cells.
4194 else
4195 // Don't copy or move to filtered destination.
4196 bFiltered = ScViewUtil::HasFiltered( aDest, pThisDoc);
4199 bool bDone = false;
4201 if (!bFiltered && pSourceDoc == pThisDoc)
4203 if ( nFlags & SC_DROP_TABLE ) // whole sheet?
4205 if ( pThisDoc->IsDocEditable() )
4207 SCTAB nSrcTab = aSource.aStart.Tab();
4208 pViewData->GetDocShell()->MoveTable( nSrcTab, nThisTab, !bIsMove, true ); // with Undo
4209 pView->SetTabNo( nThisTab, true );
4210 bDone = true;
4213 else // move/copy block
4215 OUString aChartName;
4216 if (pThisDoc->HasChartAtPoint( nThisTab, rLogicPos, aChartName ))
4218 OUString aRangeName(aSource.Format(SCR_ABS_3D, pThisDoc));
4219 SfxStringItem aNameItem( SID_CHART_NAME, aChartName );
4220 SfxStringItem aRangeItem( SID_CHART_SOURCE, aRangeName );
4221 sal_uInt16 nId = bIsMove ? SID_CHART_SOURCE : SID_CHART_ADDSOURCE;
4222 pViewData->GetDispatcher().Execute( nId, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
4223 &aRangeItem, &aNameItem, (void*) NULL );
4224 bDone = true;
4226 else if ( pThisDoc->GetDPAtCursor( nDestPosX, nDestPosY, nThisTab ) )
4228 // drop on DataPilot table: try to sort, fail if that isn't possible
4230 ScAddress aDestPos( nDestPosX, nDestPosY, nThisTab );
4231 if ( aDestPos != aSource.aStart )
4232 bDone = pViewData->GetView()->DataPilotMove( aSource, aDestPos );
4233 else
4234 bDone = true; // same position: nothing
4236 else if ( nDestPosX != aSource.aStart.Col() || nDestPosY != aSource.aStart.Row() ||
4237 nSourceTab != nThisTab )
4239 OUString aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
4240 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
4242 SCsCOL nCorrectCursorPosCol = 0;
4243 SCsROW nCorrectCursorPosRow = 0;
4245 bDone = true;
4246 if ( meDragInsertMode != INS_NONE )
4248 // call with bApi = sal_True to avoid error messages in drop handler
4249 bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4250 if ( bDone )
4252 if ( nThisTab == nSourceTab )
4254 if ( meDragInsertMode == INS_CELLSDOWN &&
4255 nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
4257 bDone = aSource.Move( 0, nSizeY, 0, pSourceDoc );
4258 nCorrectCursorPosRow = nSizeY;
4260 else if ( meDragInsertMode == INS_CELLSRIGHT &&
4261 nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
4263 bDone = aSource.Move( nSizeX, 0, 0, pSourceDoc );
4264 nCorrectCursorPosCol = nSizeX;
4267 pDocSh->UpdateOle( pViewData );
4268 pView->CellContentChanged();
4272 if ( bDone )
4274 if ( bIsLink )
4276 // call with bApi = sal_True to avoid error messages in drop handler
4277 bDone = pView->LinkBlock( aSource, aDest.aStart, true /*bApi*/ );
4279 else
4281 // call with bApi = sal_True to avoid error messages in drop handler
4282 bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, true /*bRecord*/, true /*bPaint*/, true /*bApi*/ );
4286 if ( bDone && meDragInsertMode != INS_NONE && bIsMove && nThisTab == nSourceTab )
4288 DelCellCmd eCmd = DEL_NONE;
4289 if ( meDragInsertMode == INS_CELLSDOWN )
4291 eCmd = DEL_CELLSUP;
4293 else if ( meDragInsertMode == INS_CELLSRIGHT )
4295 eCmd = DEL_CELLSLEFT;
4298 if ( ( eCmd == DEL_CELLSUP && nDestPosX == aSource.aStart.Col() ) ||
4299 ( eCmd == DEL_CELLSLEFT && nDestPosY == aSource.aStart.Row() ) )
4301 // call with bApi = sal_True to avoid error messages in drop handler
4302 bDone = pDocSh->GetDocFunc().DeleteCells( aSource, NULL, eCmd, true /*bRecord*/, true /*bApi*/ );
4303 if ( bDone )
4305 if ( eCmd == DEL_CELLSUP && nDestPosY > aSource.aEnd.Row() )
4307 bDone = aDest.Move( 0, -nSizeY, 0, pThisDoc );
4309 else if ( eCmd == DEL_CELLSLEFT && nDestPosX > aSource.aEnd.Col() )
4311 bDone = aDest.Move( -nSizeX, 0, 0, pThisDoc );
4313 pDocSh->UpdateOle( pViewData );
4314 pView->CellContentChanged();
4319 if ( bDone )
4321 pView->MarkRange( aDest, false, false );
4323 SCCOL nDCol = pViewData->GetCurX() - aSource.aStart.Col() + nCorrectCursorPosCol;
4324 SCROW nDRow = pViewData->GetCurY() - aSource.aStart.Row() + nCorrectCursorPosRow;
4325 pView->SetCursor( aDest.aStart.Col() + nDCol, aDest.aStart.Row() + nDRow );
4328 pDocSh->GetUndoManager()->LeaveListAction();
4331 else
4332 bDone = true; // nothing to do
4335 if (bDone)
4336 pTransObj->SetDragWasInternal(); // don't delete source in DragFinished
4338 else if ( !bFiltered && pSourceDoc ) // between documents
4340 if ( nFlags & SC_DROP_TABLE ) // copy/link sheets between documents
4342 if ( pThisDoc->IsDocEditable() )
4344 ScDocShell* pSrcShell = pTransObj->GetSourceDocShell();
4346 std::vector<SCTAB> nTabs;
4348 ScMarkData aMark = pTransObj->GetSourceMarkData();
4349 SCTAB nTabCount = pSourceDoc->GetTableCount();
4351 for(SCTAB i=0; i<nTabCount; i++)
4353 if(aMark.GetTableSelect(i))
4355 nTabs.push_back(i);
4356 for(SCTAB j=i+1;j<nTabCount;j++)
4358 if((!pSourceDoc->IsVisible(j))&&(pSourceDoc->IsScenario(j)))
4360 nTabs.push_back( j );
4361 i=j;
4363 else break;
4368 pView->ImportTables( pSrcShell,static_cast<SCTAB>(nTabs.size()), &nTabs[0], bIsLink, nThisTab );
4369 bDone = true;
4372 else if ( bIsLink )
4374 // as in PasteDDE
4375 // (external references might be used instead?)
4377 SfxObjectShell* pSourceSh = pSourceDoc->GetDocumentShell();
4378 OSL_ENSURE(pSourceSh, "drag document has no shell");
4379 if (pSourceSh)
4381 OUString aUndo = ScGlobal::GetRscString( STR_UNDO_COPY );
4382 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
4384 bDone = true;
4385 if ( meDragInsertMode != INS_NONE )
4387 // call with bApi = sal_True to avoid error messages in drop handler
4388 bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4389 if ( bDone )
4391 pDocSh->UpdateOle( pViewData );
4392 pView->CellContentChanged();
4396 if ( bDone )
4398 OUString aApp = Application::GetAppName();
4399 OUString aTopic = pSourceSh->GetTitle( SFX_TITLE_FULLNAME );
4400 OUString aItem(aSource.Format(SCA_VALID | SCA_TAB_3D, pSourceDoc));
4402 // TODO: we could define ocQuote for "
4403 const OUString aQuote('"');
4404 const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
4405 OUStringBuffer aFormula;
4406 aFormula.append('=');
4407 aFormula.append(ScCompiler::GetNativeSymbol(ocDde));
4408 aFormula.append(ScCompiler::GetNativeSymbol(ocOpen));
4409 aFormula.append(aQuote);
4410 aFormula.append(aApp);
4411 aFormula.append(aQuote);
4412 aFormula.append(sSep);
4413 aFormula.append(aQuote);
4414 aFormula.append(aTopic);
4415 aFormula.append(aQuote);
4416 aFormula.append(sSep);
4417 aFormula.append(aQuote);
4418 aFormula.append(aItem);
4419 aFormula.append(aQuote);
4420 aFormula.append(ScCompiler::GetNativeSymbol(ocClose));
4422 pView->DoneBlockMode();
4423 pView->InitBlockMode( nDestPosX, nDestPosY, nThisTab );
4424 pView->MarkCursor( nDestPosX + nSizeX - 1,
4425 nDestPosY + nSizeY - 1, nThisTab );
4427 pView->EnterMatrix( aFormula.makeStringAndClear(), ::formula::FormulaGrammar::GRAM_NATIVE );
4429 pView->MarkRange( aDest, false, false );
4430 pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
4433 pDocSh->GetUndoManager()->LeaveListAction();
4436 else
4438 //! HasSelectedBlockMatrixFragment without selected sheet?
4439 //! or don't start dragging on a part of a matrix
4441 OUString aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
4442 pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo );
4444 bDone = true;
4445 if ( meDragInsertMode != INS_NONE )
4447 // call with bApi = sal_True to avoid error messages in drop handler
4448 bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
4449 if ( bDone )
4451 pDocSh->UpdateOle( pViewData );
4452 pView->CellContentChanged();
4456 if ( bDone )
4458 pView->Unmark(); // before SetCursor, so CheckSelectionTransfer isn't called with a selection
4459 pView->SetCursor( nDestPosX, nDestPosY );
4460 bDone = pView->PasteFromClip( IDF_ALL, pTransObj->GetDocument() ); // clip-doc
4461 if ( bDone )
4463 pView->MarkRange( aDest, false, false );
4464 pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
4468 pDocSh->GetUndoManager()->LeaveListAction();
4470 // no longer call ResetMark here - the inserted block has been selected
4471 // and may have been copied to primary selection
4475 sal_Int8 nRet = bDone ? nDndAction : DND_ACTION_NONE;
4476 return nRet;
4479 sal_Int8 ScGridWindow::ExecuteDrop( const ExecuteDropEvent& rEvt )
4481 DrawMarkDropObj( NULL ); // drawing layer
4483 ScModule* pScMod = SC_MOD();
4484 const ScDragData& rData = pScMod->GetDragData();
4485 if (rData.pCellTransfer)
4486 return ExecutePrivateDrop( rEvt );
4488 Point aPos = rEvt.maPosPixel;
4490 if ( !rData.aLinkDoc.isEmpty() )
4492 // try to insert a link
4494 bool bOk = true;
4495 OUString aThisName;
4496 ScDocShell* pDocSh = pViewData->GetDocShell();
4497 if (pDocSh && pDocSh->HasName())
4498 aThisName = pDocSh->GetMedium()->GetName();
4500 if ( rData.aLinkDoc.equals(aThisName) ) // error - no link within a document
4501 bOk = false;
4502 else
4504 ScViewFunc* pView = pViewData->GetView();
4505 if ( !rData.aLinkTable.isEmpty() )
4506 pView->InsertTableLink( rData.aLinkDoc, EMPTY_OUSTRING, EMPTY_OUSTRING,
4507 rData.aLinkTable );
4508 else if ( !rData.aLinkArea.isEmpty() )
4510 SCsCOL nPosX;
4511 SCsROW nPosY;
4512 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
4513 pView->MoveCursorAbs( nPosX, nPosY, SC_FOLLOW_NONE, false, false );
4515 pView->InsertAreaLink( rData.aLinkDoc, EMPTY_OUSTRING, EMPTY_OUSTRING,
4516 rData.aLinkArea, 0 );
4518 else
4520 OSL_FAIL("drop with link: no sheet nor area");
4521 bOk = false;
4525 return bOk ? rEvt.mnAction : DND_ACTION_NONE; // don't try anything else
4528 Point aLogicPos = PixelToLogic(aPos);
4529 bool bIsLink = ( rEvt.mnAction == DND_ACTION_LINK );
4531 if (!bIsLink && rData.pDrawTransfer)
4533 sal_uInt16 nFlags = rData.pDrawTransfer->GetDragSourceFlags();
4535 bool bIsNavi = ( nFlags & SC_DROP_NAVIGATOR ) != 0;
4536 bool bIsMove = ( rEvt.mnAction == DND_ACTION_MOVE && !bIsNavi );
4538 bPasteIsMove = bIsMove;
4540 pViewData->GetView()->PasteDraw(
4541 aLogicPos, rData.pDrawTransfer->GetModel(), false, "A", "B");
4543 if (bPasteIsMove)
4544 rData.pDrawTransfer->SetDragWasInternal();
4545 bPasteIsMove = false;
4547 return rEvt.mnAction;
4550 SCsCOL nPosX;
4551 SCsROW nPosY;
4552 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
4554 if (!rData.aJumpTarget.isEmpty())
4556 // internal bookmark (from Navigator)
4557 // bookmark clipboard formats are in PasteScDataObject
4559 if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == pViewData->GetDocument() )
4561 pViewData->GetViewShell()->InsertBookmark( rData.aJumpText, rData.aJumpTarget,
4562 nPosX, nPosY );
4563 return rEvt.mnAction;
4567 ScDocument* pThisDoc = pViewData->GetDocument();
4568 SdrObject* pHitObj = pThisDoc->GetObjectAtPoint( pViewData->GetTabNo(), PixelToLogic(aPos) );
4569 if ( pHitObj && bIsLink )
4571 // dropped on drawing object
4572 // PasteOnDrawObjectLinked checks for valid formats
4573 if ( pViewData->GetView()->PasteOnDrawObjectLinked( rEvt.maDropEvent.Transferable, *pHitObj ) )
4574 return rEvt.mnAction;
4577 bool bDone = false;
4579 SotClipboardFormatId nFormatId = bIsLink ?
4580 lcl_GetDropLinkId( rEvt.maDropEvent.Transferable ) :
4581 lcl_GetDropFormatId( rEvt.maDropEvent.Transferable );
4582 if ( nFormatId != SotClipboardFormatId::NONE )
4584 pScMod->SetInExecuteDrop( true ); // #i28468# prevent error messages from PasteDataFormat
4585 bPasteIsDrop = true;
4586 bDone = pViewData->GetView()->PasteDataFormat(
4587 nFormatId, rEvt.maDropEvent.Transferable, nPosX, nPosY, &aLogicPos, bIsLink );
4588 bPasteIsDrop = false;
4589 pScMod->SetInExecuteDrop( false );
4592 sal_Int8 nRet = bDone ? rEvt.mnAction : DND_ACTION_NONE;
4593 return nRet;
4596 void ScGridWindow::PasteSelection( const Point& rPosPixel )
4598 Point aLogicPos = PixelToLogic( rPosPixel );
4600 SCsCOL nPosX;
4601 SCsROW nPosY;
4602 pViewData->GetPosFromPixel( rPosPixel.X(), rPosPixel.Y(), eWhich, nPosX, nPosY );
4604 // If the mouse down was inside a visible note window, ignore it and
4605 // leave it up to the ScPostIt to handle it
4606 SdrView* pDrawView = pViewData->GetViewShell()->GetSdrView();
4607 if (pDrawView)
4609 const size_t nCount = pDrawView->GetMarkedObjectCount();
4610 for (size_t i = 0; i < nCount; ++i)
4612 SdrObject* pObj = pDrawView->GetMarkedObjectByIndex(i);
4613 if (pObj && pObj->GetLogicRect().IsInside(aLogicPos))
4615 // Inside an active drawing object. Bail out.
4616 return;
4621 ScSelectionTransferObj* pOwnSelection = SC_MOD()->GetSelectionTransfer();
4622 if ( pOwnSelection )
4624 // within Calc
4626 ScTransferObj* pCellTransfer = pOwnSelection->GetCellData();
4627 if ( pCellTransfer )
4629 // keep a reference to the data in case the selection is changed during paste
4630 uno::Reference<datatransfer::XTransferable> xRef( pCellTransfer );
4631 DropTransferObj( pCellTransfer, nPosX, nPosY, aLogicPos, DND_ACTION_COPY );
4633 else
4635 ScDrawTransferObj* pDrawTransfer = pOwnSelection->GetDrawData();
4636 if ( pDrawTransfer )
4638 // keep a reference to the data in case the selection is changed during paste
4639 uno::Reference<datatransfer::XTransferable> xRef( pDrawTransfer );
4641 // bSameDocClipboard argument for PasteDraw is needed
4642 // because only DragData is checked directly inside PasteDraw
4643 pViewData->GetView()->PasteDraw(
4644 aLogicPos, pDrawTransfer->GetModel(), false,
4645 pDrawTransfer->GetShellID(), SfxObjectShell::CreateShellID(pViewData->GetDocShell()));
4649 else
4651 // get selection from system
4653 TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSelection( this ) );
4654 uno::Reference<datatransfer::XTransferable> xTransferable = aDataHelper.GetTransferable();
4655 if ( xTransferable.is() )
4657 SotClipboardFormatId nFormatId = lcl_GetDropFormatId( xTransferable, true );
4658 if ( nFormatId != SotClipboardFormatId::NONE )
4660 bPasteIsDrop = true;
4661 pViewData->GetView()->PasteDataFormat( nFormatId, xTransferable, nPosX, nPosY, &aLogicPos );
4662 bPasteIsDrop = false;
4668 void ScGridWindow::UpdateEditViewPos()
4670 if (pViewData->HasEditView(eWhich))
4672 EditView* pView;
4673 SCCOL nCol;
4674 SCROW nRow;
4675 pViewData->GetEditView( eWhich, pView, nCol, nRow );
4676 SCCOL nEndCol = pViewData->GetEditEndCol();
4677 SCROW nEndRow = pViewData->GetEditEndRow();
4679 // hide EditView?
4681 bool bHide = ( nEndCol<pViewData->GetPosX(eHWhich) || nEndRow<pViewData->GetPosY(eVWhich) );
4682 if ( SC_MOD()->IsFormulaMode() )
4683 if ( pViewData->GetTabNo() != pViewData->GetRefTabNo() )
4684 bHide = true;
4686 if (bHide)
4688 Rectangle aRect = pView->GetOutputArea();
4689 long nHeight = aRect.Bottom() - aRect.Top();
4690 aRect.Top() = PixelToLogic(GetOutputSizePixel(), pViewData->GetLogicMode()).
4691 Height() * 2;
4692 aRect.Bottom() = aRect.Top() + nHeight;
4693 pView->SetOutputArea( aRect );
4694 pView->HideCursor();
4696 else
4698 // bForceToTop = sal_True for editing
4699 Rectangle aPixRect = pViewData->GetEditArea( eWhich, nCol, nRow, this, NULL, true );
4700 Point aScrPos = PixelToLogic( aPixRect.TopLeft(), pViewData->GetLogicMode() );
4702 Rectangle aRect = pView->GetOutputArea();
4703 aRect.SetPos( aScrPos );
4704 pView->SetOutputArea( aRect );
4705 pView->ShowCursor();
4710 void ScGridWindow::ScrollPixel( long nDifX, long nDifY )
4712 ClickExtern();
4713 HideNoteMarker();
4715 bIsInScroll = true;
4717 SetMapMode(MAP_PIXEL);
4718 Scroll( nDifX, nDifY, SCROLL_CHILDREN );
4719 SetMapMode( GetDrawMapMode() ); // verschobenen MapMode erzeugen
4721 UpdateEditViewPos();
4723 DrawAfterScroll();
4724 bIsInScroll = false;
4727 // Formeln neu zeichnen -------------------------------------------------
4729 void ScGridWindow::UpdateFormulas()
4731 if (pViewData->GetView()->IsMinimized())
4732 return;
4734 if ( nPaintCount )
4736 // nicht anfangen, verschachtelt zu painten
4737 // (dann wuerde zumindest der MapMode nicht mehr stimmen)
4739 bNeedsRepaint = true; // -> am Ende vom Paint nochmal Invalidate auf alles
4740 aRepaintPixel = Rectangle(); // alles
4741 return;
4744 SCCOL nX1 = pViewData->GetPosX( eHWhich );
4745 SCROW nY1 = pViewData->GetPosY( eVWhich );
4746 SCCOL nX2 = nX1 + pViewData->VisibleCellsX( eHWhich );
4747 SCROW nY2 = nY1 + pViewData->VisibleCellsY( eVWhich );
4749 if (nX2 > MAXCOL) nX2 = MAXCOL;
4750 if (nY2 > MAXROW) nY2 = MAXROW;
4752 // Draw( nX1, nY1, nX2, nY2, SC_UPDATE_CHANGED );
4754 // don't draw directly - instead use OutputData to find changed area and invalidate
4756 SCROW nPosY = nY1;
4758 ScDocShell* pDocSh = pViewData->GetDocShell();
4759 ScDocument& rDoc = pDocSh->GetDocument();
4760 SCTAB nTab = pViewData->GetTabNo();
4762 rDoc.ExtendHidden( nX1, nY1, nX2, nY2, nTab );
4764 Point aScrPos = pViewData->GetScrPos( nX1, nY1, eWhich );
4765 long nMirrorWidth = GetSizePixel().Width();
4766 bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
4767 if ( bLayoutRTL )
4769 long nEndPixel = pViewData->GetScrPos( nX2+1, nPosY, eWhich ).X();
4770 nMirrorWidth = aScrPos.X() - nEndPixel;
4771 aScrPos.X() = nEndPixel + 1;
4774 long nScrX = aScrPos.X();
4775 long nScrY = aScrPos.Y();
4777 double nPPTX = pViewData->GetPPTX();
4778 double nPPTY = pViewData->GetPPTY();
4780 ScTableInfo aTabInfo;
4781 rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab, nPPTX, nPPTY, false, false );
4783 Fraction aZoomX = pViewData->GetZoomX();
4784 Fraction aZoomY = pViewData->GetZoomY();
4785 ScOutputData aOutputData( this, OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
4786 nScrX, nScrY, nX1, nY1, nX2, nY2, nPPTX, nPPTY,
4787 &aZoomX, &aZoomY );
4788 aOutputData.SetMirrorWidth( nMirrorWidth );
4790 aOutputData.FindChanged();
4792 // #i122149# do not use old GetChangedArea() which used polygon-based Regions, but use
4793 // the region-band based new version; anyways, only rectangles are added
4794 vcl::Region aChangedRegion( aOutputData.GetChangedAreaRegion() ); // logic (PixelToLogic)
4795 if(!aChangedRegion.IsEmpty())
4797 Invalidate(aChangedRegion);
4800 CheckNeedsRepaint(); // #i90362# used to be called via Draw() - still needed here
4803 void ScGridWindow::UpdateAutoFillMark(bool bMarked, const ScRange& rMarkRange)
4805 if ( bMarked != bAutoMarkVisible || ( bMarked && rMarkRange.aEnd != aAutoMarkPos ) )
4807 bAutoMarkVisible = bMarked;
4808 if ( bMarked )
4809 aAutoMarkPos = rMarkRange.aEnd;
4811 UpdateAutoFillOverlay();
4815 void ScGridWindow::UpdateListValPos( bool bVisible, const ScAddress& rPos )
4817 bool bOldButton = bListValButton;
4818 ScAddress aOldPos = aListValPos;
4820 bListValButton = bVisible;
4821 aListValPos = rPos;
4823 if ( bListValButton )
4825 if ( !bOldButton || aListValPos != aOldPos )
4827 // paint area of new button
4828 Invalidate( PixelToLogic( GetListValButtonRect( aListValPos ) ) );
4831 if ( bOldButton )
4833 if ( !bListValButton || aListValPos != aOldPos )
4835 // paint area of old button
4836 Invalidate( PixelToLogic( GetListValButtonRect( aOldPos ) ) );
4841 void ScGridWindow::HideCursor()
4843 ++nCursorHideCount;
4846 void ScGridWindow::ShowCursor()
4848 --nCursorHideCount;
4851 void ScGridWindow::GetFocus()
4853 ScTabViewShell* pViewShell = pViewData->GetViewShell();
4854 pViewShell->SetFormShellAtTop( false ); // focus in GridWindow -> FormShell no longer on top
4856 if (pViewShell->HasAccessibilityObjects())
4857 pViewShell->BroadcastAccessibility(ScAccGridWinFocusGotHint(eWhich, GetAccessible()));
4859 if ( !SC_MOD()->IsFormulaMode() )
4861 pViewShell->UpdateInputHandler();
4862 // StopMarking(); // falls Dialog (Fehler), weil dann kein ButtonUp
4863 // MO: nur wenn nicht im RefInput-Modus
4864 // -> GetFocus/MouseButtonDown-Reihenfolge
4865 // auf dem Mac
4868 pViewData->GetDocShell()->CheckConfigOptions();
4869 Window::GetFocus();
4872 void ScGridWindow::LoseFocus()
4874 ScTabViewShell* pViewShell = pViewData->GetViewShell();
4876 if (pViewShell && pViewShell->HasAccessibilityObjects())
4877 pViewShell->BroadcastAccessibility(ScAccGridWinFocusLostHint(eWhich, GetAccessible()));
4879 Window::LoseFocus();
4882 bool ScGridWindow::HitRangeFinder( const Point& rMouse, RfCorner& rCorner,
4883 sal_uInt16* pIndex, SCsCOL* pAddX, SCsROW* pAddY)
4885 bool bFound = false;
4886 ScInputHandler* pHdl = SC_MOD()->GetInputHdl( pViewData->GetViewShell() );
4887 if (pHdl)
4889 ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
4890 if ( pRangeFinder && !pRangeFinder->IsHidden() &&
4891 pRangeFinder->GetDocName() == pViewData->GetDocShell()->GetTitle() )
4893 ScDocument* pDoc = pViewData->GetDocument();
4894 SCTAB nTab = pViewData->GetTabNo();
4895 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
4896 long nLayoutSign = bLayoutRTL ? -1 : 1;
4898 SCsCOL nPosX;
4899 SCsROW nPosY;
4900 pViewData->GetPosFromPixel( rMouse.X(), rMouse.Y(), eWhich, nPosX, nPosY );
4901 // zusammengefasste (einzeln/Bereich) ???
4902 ScAddress aAddr( nPosX, nPosY, nTab );
4904 Point aCellStart = pViewData->GetScrPos( nPosX, nPosY, eWhich, true );
4905 Point aCellEnd = aCellStart;
4906 long nSizeXPix;
4907 long nSizeYPix;
4908 pViewData->GetMergeSizePixel( nPosX, nPosY, nSizeXPix, nSizeYPix );
4910 aCellEnd.X() += nSizeXPix * nLayoutSign;
4911 aCellEnd.Y() += nSizeYPix;
4913 bool bCornerHorizontalRight;
4914 bool bCornerHorizontalLeft;
4915 if ( bLayoutRTL )
4917 bCornerHorizontalRight = ( rMouse.X() >= aCellEnd.X() && rMouse.X() <= aCellEnd.X() + 8 );
4918 bCornerHorizontalLeft = ( rMouse.X() >= aCellStart.X() - 8 && rMouse.X() <= aCellStart.X() );
4920 else
4922 bCornerHorizontalRight = ( rMouse.X() >= aCellEnd.X() - 8 && rMouse.X() <= aCellEnd.X() );
4923 bCornerHorizontalLeft = ( rMouse.X() >= aCellStart.X() && rMouse.X() <= aCellStart.X() + 8 );
4926 bool bCornerVerticalDown = rMouse.Y() >= aCellEnd.Y() - 8 && rMouse.Y() <= aCellEnd.Y();
4927 bool bCornerVerticalUp = rMouse.Y() >= aCellStart.Y() && rMouse.Y() <= aCellStart.Y() + 8;
4929 // corner is hit only if the mouse is within the cell
4930 sal_uInt16 nCount = (sal_uInt16)pRangeFinder->Count();
4931 for (sal_uInt16 i=nCount; i;)
4933 // search backwards so that the last repainted frame is found
4934 --i;
4935 ScRangeFindData* pData = pRangeFinder->GetObject(i);
4936 if ( pData->aRef.In(aAddr) )
4938 if (pIndex)
4939 *pIndex = i;
4940 if (pAddX)
4941 *pAddX = nPosX - pData->aRef.aStart.Col();
4942 if (pAddY)
4943 *pAddY = nPosY - pData->aRef.aStart.Row();
4945 bFound = true;
4947 rCorner = NONE;
4949 ScAddress aEnd = pData->aRef.aEnd;
4950 ScAddress aStart = pData->aRef.aStart;
4952 if ( bCornerHorizontalLeft && bCornerVerticalUp &&
4953 aAddr == aStart)
4955 rCorner = LEFT_UP;
4957 else if (bCornerHorizontalRight && bCornerVerticalDown &&
4958 aAddr == aEnd)
4960 rCorner = RIGHT_DOWN;
4962 else if (bCornerHorizontalRight && bCornerVerticalUp &&
4963 aAddr == ScAddress(aEnd.Col(), aStart.Row(), aStart.Tab()))
4965 rCorner = RIGHT_UP;
4967 else if (bCornerHorizontalLeft && bCornerVerticalDown &&
4968 aAddr == ScAddress(aStart.Col(), aEnd.Row(), aStart.Tab()))
4970 rCorner = LEFT_DOWN;
4972 break;
4977 return bFound;
4980 #define SCE_TOP 1
4981 #define SCE_BOTTOM 2
4982 #define SCE_LEFT 4
4983 #define SCE_RIGHT 8
4984 #define SCE_ALL 15
4986 static void lcl_PaintOneRange( ScDocShell* pDocSh, const ScRange& rRange, sal_uInt16 nEdges )
4988 // der Range ist immer richtigherum
4990 SCCOL nCol1 = rRange.aStart.Col();
4991 SCROW nRow1 = rRange.aStart.Row();
4992 SCTAB nTab1 = rRange.aStart.Tab();
4993 SCCOL nCol2 = rRange.aEnd.Col();
4994 SCROW nRow2 = rRange.aEnd.Row();
4995 SCTAB nTab2 = rRange.aEnd.Tab();
4996 bool bHiddenEdge = false;
4997 SCROW nTmp;
4999 ScDocument& rDoc = pDocSh->GetDocument();
5000 while ( nCol1 > 0 && rDoc.ColHidden(nCol1, nTab1) )
5002 --nCol1;
5003 bHiddenEdge = true;
5005 while ( nCol2 < MAXCOL && rDoc.ColHidden(nCol2, nTab1) )
5007 ++nCol2;
5008 bHiddenEdge = true;
5010 nTmp = rDoc.FirstVisibleRow(0, nRow1, nTab1);
5011 if (!ValidRow(nTmp))
5012 nTmp = 0;
5013 if (nTmp < nRow1)
5015 nRow1 = nTmp;
5016 bHiddenEdge = true;
5018 nTmp = rDoc.FirstVisibleRow(nRow2, MAXROW, nTab1);
5019 if (!ValidRow(nTmp))
5020 nTmp = MAXROW;
5021 if (nTmp > nRow2)
5023 nRow2 = nTmp;
5024 bHiddenEdge = true;
5027 if ( nCol2 > nCol1 + 1 && nRow2 > nRow1 + 1 && !bHiddenEdge )
5029 // nur an den Raendern entlang
5030 // (die Ecken werden evtl. zweimal getroffen)
5032 if ( nEdges & SCE_TOP )
5033 pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow1, nTab2, PAINT_MARKS );
5034 if ( nEdges & SCE_LEFT )
5035 pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol1, nRow2, nTab2, PAINT_MARKS );
5036 if ( nEdges & SCE_RIGHT )
5037 pDocSh->PostPaint( nCol2, nRow1, nTab1, nCol2, nRow2, nTab2, PAINT_MARKS );
5038 if ( nEdges & SCE_BOTTOM )
5039 pDocSh->PostPaint( nCol1, nRow2, nTab1, nCol2, nRow2, nTab2, PAINT_MARKS );
5041 else // everything in one call
5042 pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, PAINT_MARKS );
5045 static void lcl_PaintRefChanged( ScDocShell* pDocSh, const ScRange& rOldUn, const ScRange& rNewUn )
5047 // Repaint fuer die Teile des Rahmens in Old, die bei New nicht mehr da sind
5049 ScRange aOld = rOldUn;
5050 ScRange aNew = rNewUn;
5051 aOld.Justify();
5052 aNew.Justify();
5054 if ( aOld.aStart == aOld.aEnd ) //! Tab ignorieren?
5055 pDocSh->GetDocument().ExtendMerge(aOld);
5056 if ( aNew.aStart == aNew.aEnd ) //! Tab ignorieren?
5057 pDocSh->GetDocument().ExtendMerge(aNew);
5059 SCCOL nOldCol1 = aOld.aStart.Col();
5060 SCROW nOldRow1 = aOld.aStart.Row();
5061 SCCOL nOldCol2 = aOld.aEnd.Col();
5062 SCROW nOldRow2 = aOld.aEnd.Row();
5063 SCCOL nNewCol1 = aNew.aStart.Col();
5064 SCROW nNewRow1 = aNew.aStart.Row();
5065 SCCOL nNewCol2 = aNew.aEnd.Col();
5066 SCROW nNewRow2 = aNew.aEnd.Row();
5067 SCTAB nTab1 = aOld.aStart.Tab(); // Tab aendert sich nicht
5068 SCTAB nTab2 = aOld.aEnd.Tab();
5070 if ( nNewRow2 < nOldRow1 || nNewRow1 > nOldRow2 ||
5071 nNewCol2 < nOldCol1 || nNewCol1 > nOldCol2 ||
5072 ( nNewCol1 != nOldCol1 && nNewRow1 != nOldRow1 &&
5073 nNewCol2 != nOldCol2 && nNewRow2 != nOldRow2 ) )
5075 // komplett weggeschoben oder alle Seiten veraendert
5076 // (Abfrage <= statt < geht schief bei einzelnen Zeilen/Spalten)
5078 lcl_PaintOneRange( pDocSh, aOld, SCE_ALL );
5080 else // alle vier Kanten einzeln testen
5082 // oberer Teil
5083 if ( nNewRow1 < nOldRow1 ) // nur obere Linie loeschen
5084 lcl_PaintOneRange( pDocSh, ScRange(
5085 nOldCol1, nOldRow1, nTab1, nOldCol2, nOldRow1, nTab2 ), SCE_ALL );
5086 else if ( nNewRow1 > nOldRow1 ) // den Teil, der oben wegkommt
5087 lcl_PaintOneRange( pDocSh, ScRange(
5088 nOldCol1, nOldRow1, nTab1, nOldCol2, nNewRow1-1, nTab2 ),
5089 SCE_ALL &~ SCE_BOTTOM );
5091 // unterer Teil
5092 if ( nNewRow2 > nOldRow2 ) // nur untere Linie loeschen
5093 lcl_PaintOneRange( pDocSh, ScRange(
5094 nOldCol1, nOldRow2, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL );
5095 else if ( nNewRow2 < nOldRow2 ) // den Teil, der unten wegkommt
5096 lcl_PaintOneRange( pDocSh, ScRange(
5097 nOldCol1, nNewRow2+1, nTab1, nOldCol2, nOldRow2, nTab2 ),
5098 SCE_ALL &~ SCE_TOP );
5100 // linker Teil
5101 if ( nNewCol1 < nOldCol1 ) // nur linke Linie loeschen
5102 lcl_PaintOneRange( pDocSh, ScRange(
5103 nOldCol1, nOldRow1, nTab1, nOldCol1, nOldRow2, nTab2 ), SCE_ALL );
5104 else if ( nNewCol1 > nOldCol1 ) // den Teil, der links wegkommt
5105 lcl_PaintOneRange( pDocSh, ScRange(
5106 nOldCol1, nOldRow1, nTab1, nNewCol1-1, nOldRow2, nTab2 ),
5107 SCE_ALL &~ SCE_RIGHT );
5109 // rechter Teil
5110 if ( nNewCol2 > nOldCol2 ) // nur rechte Linie loeschen
5111 lcl_PaintOneRange( pDocSh, ScRange(
5112 nOldCol2, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL );
5113 else if ( nNewCol2 < nOldCol2 ) // den Teil, der rechts wegkommt
5114 lcl_PaintOneRange( pDocSh, ScRange(
5115 nNewCol2+1, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ),
5116 SCE_ALL &~ SCE_LEFT );
5120 void ScGridWindow::RFMouseMove( const MouseEvent& rMEvt, bool bUp )
5122 ScInputHandler* pHdl = SC_MOD()->GetInputHdl( pViewData->GetViewShell() );
5123 if (!pHdl)
5124 return;
5125 ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
5126 if (!pRangeFinder || nRFIndex >= pRangeFinder->Count())
5127 return;
5128 ScRangeFindData* pData = pRangeFinder->GetObject( nRFIndex );
5130 // Mauszeiger
5132 if (bRFSize)
5133 SetPointer( Pointer( PointerStyle::Cross ) );
5134 else
5135 SetPointer( Pointer( PointerStyle::Hand ) );
5137 // Scrolling
5139 bool bTimer = false;
5140 Point aPos = rMEvt.GetPosPixel();
5141 SCsCOL nDx = 0;
5142 SCsROW nDy = 0;
5143 if ( aPos.X() < 0 ) nDx = -1;
5144 if ( aPos.Y() < 0 ) nDy = -1;
5145 Size aSize = GetOutputSizePixel();
5146 if ( aPos.X() >= aSize.Width() )
5147 nDx = 1;
5148 if ( aPos.Y() >= aSize.Height() )
5149 nDy = 1;
5150 if ( nDx != 0 || nDy != 0 )
5152 if ( nDx != 0) pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) );
5153 if ( nDy != 0 ) pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) );
5154 bTimer = true;
5157 // Umschalten bei Fixierung (damit Scrolling funktioniert)
5159 if ( eWhich == pViewData->GetActivePart() ) //??
5161 if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
5162 if ( nDx > 0 )
5164 if ( eWhich == SC_SPLIT_TOPLEFT )
5165 pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
5166 else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
5167 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
5170 if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
5171 if ( nDy > 0 )
5173 if ( eWhich == SC_SPLIT_TOPLEFT )
5174 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
5175 else if ( eWhich == SC_SPLIT_TOPRIGHT )
5176 pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
5180 // Verschieben
5182 SCsCOL nPosX;
5183 SCsROW nPosY;
5184 pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
5186 ScRange aOld = pData->aRef;
5187 ScRange aNew = aOld;
5188 if ( bRFSize )
5190 switch (aRFSelectedCorned)
5192 case LEFT_UP:
5193 aNew.aStart.SetCol((SCCOL)nPosX);
5194 aNew.aStart.SetRow((SCROW)nPosY);
5195 break;
5196 case LEFT_DOWN:
5197 aNew.aStart.SetCol((SCCOL)nPosX);
5198 aNew.aEnd.SetRow((SCROW)nPosY);
5199 break;
5200 case RIGHT_UP:
5201 aNew.aEnd.SetCol((SCCOL)nPosX);
5202 aNew.aStart.SetRow((SCROW)nPosY);
5203 break;
5204 case RIGHT_DOWN:
5205 aNew.aEnd.SetCol((SCCOL)nPosX);
5206 aNew.aEnd.SetRow((SCROW)nPosY);
5207 break;
5208 default:
5209 break;
5212 else
5214 long nStartX = nPosX - nRFAddX;
5215 if ( nStartX < 0 ) nStartX = 0;
5216 long nStartY = nPosY - nRFAddY;
5217 if ( nStartY < 0 ) nStartY = 0;
5218 long nEndX = nStartX + aOld.aEnd.Col() - aOld.aStart.Col();
5219 if ( nEndX > MAXCOL )
5221 nStartX -= ( nEndX - MAXROW );
5222 nEndX = MAXCOL;
5224 long nEndY = nStartY + aOld.aEnd.Row() - aOld.aStart.Row();
5225 if ( nEndY > MAXROW )
5227 nStartY -= ( nEndY - MAXROW );
5228 nEndY = MAXROW;
5231 aNew.aStart.SetCol((SCCOL)nStartX);
5232 aNew.aStart.SetRow((SCROW)nStartY);
5233 aNew.aEnd.SetCol((SCCOL)nEndX);
5234 aNew.aEnd.SetRow((SCROW)nEndY);
5237 if ( bUp )
5238 aNew.Justify(); // beim ButtonUp wieder richtigherum
5240 if ( aNew != aOld )
5242 pHdl->UpdateRange( nRFIndex, aNew );
5244 ScDocShell* pDocSh = pViewData->GetDocShell();
5246 // nur das neuzeichnen, was sich veraendert hat...
5247 lcl_PaintRefChanged( pDocSh, aOld, aNew );
5249 // neuen Rahmen nur drueberzeichnen (synchron)
5250 pDocSh->Broadcast( ScIndexHint( SC_HINT_SHOWRANGEFINDER, nRFIndex ) );
5252 Update(); // was man bewegt, will man auch sofort sehen
5255 // Timer fuer Scrolling
5257 if (bTimer)
5258 pViewData->GetView()->SetTimer( this, rMEvt ); // Event wiederholen
5259 else
5260 pViewData->GetView()->ResetTimer();
5263 namespace {
5265 SvxAdjust toSvxAdjust( const ScPatternAttr& rPat )
5267 SvxCellHorJustify eHorJust =
5268 static_cast<SvxCellHorJustify>(
5269 static_cast<const SvxHorJustifyItem&>(rPat.GetItem(ATTR_HOR_JUSTIFY)).GetValue());
5271 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
5272 switch (eHorJust)
5274 case SVX_HOR_JUSTIFY_LEFT:
5275 case SVX_HOR_JUSTIFY_REPEAT: // nicht implementiert
5276 case SVX_HOR_JUSTIFY_STANDARD: // always Text if an EditCell type
5277 eSvxAdjust = SVX_ADJUST_LEFT;
5278 break;
5279 case SVX_HOR_JUSTIFY_RIGHT:
5280 eSvxAdjust = SVX_ADJUST_RIGHT;
5281 break;
5282 case SVX_HOR_JUSTIFY_CENTER:
5283 eSvxAdjust = SVX_ADJUST_CENTER;
5284 break;
5285 case SVX_HOR_JUSTIFY_BLOCK:
5286 eSvxAdjust = SVX_ADJUST_BLOCK;
5287 break;
5290 return eSvxAdjust;
5293 boost::shared_ptr<ScFieldEditEngine> createEditEngine( ScDocShell* pDocSh, const ScPatternAttr& rPat )
5295 ScDocument& rDoc = pDocSh->GetDocument();
5297 boost::shared_ptr<ScFieldEditEngine> pEngine(new ScFieldEditEngine(&rDoc, rDoc.GetEditPool()));
5298 ScSizeDeviceProvider aProv(pDocSh);
5299 pEngine->SetRefDevice(aProv.GetDevice());
5300 pEngine->SetRefMapMode(MAP_100TH_MM);
5301 SfxItemSet aDefault = pEngine->GetEmptyItemSet();
5302 rPat.FillEditItemSet(&aDefault);
5303 aDefault.Put( SvxAdjustItem(toSvxAdjust(rPat), EE_PARA_JUST) );
5304 pEngine->SetDefaults(aDefault);
5306 return pEngine;
5309 bool extractURLInfo( const SvxFieldItem* pFieldItem, OUString* pName, OUString* pUrl, OUString* pTarget )
5311 if (!pFieldItem)
5312 return false;
5314 const SvxFieldData* pField = pFieldItem->GetField();
5315 if (pField->GetClassId() != text::textfield::Type::URL)
5316 return false;
5318 const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField);
5320 if (pName)
5321 *pName = pURLField->GetRepresentation();
5322 if (pUrl)
5323 *pUrl = pURLField->GetURL();
5324 if (pTarget)
5325 *pTarget = pURLField->GetTargetFrame();
5327 return true;
5332 bool ScGridWindow::GetEditUrl( const Point& rPos,
5333 OUString* pName, OUString* pUrl, OUString* pTarget )
5335 ScTabViewShell* pViewSh = pViewData->GetViewShell();
5336 ScInputHandler* pInputHdl = NULL;
5337 if (pViewSh)
5338 pInputHdl = pViewSh->GetInputHandler();
5339 EditView* pView = (pInputHdl && pInputHdl->IsInputMode()) ? pInputHdl->GetTableView() : NULL;
5340 if (pView)
5341 return extractURLInfo(pView->GetFieldUnderMousePointer(), pName, pUrl, pTarget);
5343 //! nPosX/Y mit uebergeben?
5344 SCsCOL nPosX;
5345 SCsROW nPosY;
5346 pViewData->GetPosFromPixel( rPos.X(), rPos.Y(), eWhich, nPosX, nPosY );
5348 SCTAB nTab = pViewData->GetTabNo();
5349 ScDocShell* pDocSh = pViewData->GetDocShell();
5350 ScDocument& rDoc = pDocSh->GetDocument();
5351 OUString sURL;
5352 ScRefCellValue aCell;
5353 bool bFound = lcl_GetHyperlinkCell(&rDoc, nPosX, nPosY, nTab, aCell, sURL);
5354 if( !bFound )
5355 return false;
5357 const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
5358 // bForceToTop = sal_False, use the cell's real position
5359 Rectangle aEditRect = pViewData->GetEditArea( eWhich, nPosX, nPosY, this, pPattern, false );
5360 if (rPos.Y() < aEditRect.Top())
5361 return false;
5363 // vertikal kann (noch) nicht angeklickt werden:
5365 if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
5366 return false;
5368 bool bBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
5369 ((SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
5370 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK);
5371 SvxCellHorJustify eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->
5372 GetItem(ATTR_HOR_JUSTIFY)).GetValue();
5374 // EditEngine
5376 boost::shared_ptr<ScFieldEditEngine> pEngine = createEditEngine(pDocSh, *pPattern);
5378 MapMode aEditMode = pViewData->GetLogicMode(eWhich); // ohne Drawing-Skalierung
5379 Rectangle aLogicEdit = PixelToLogic( aEditRect, aEditMode );
5380 long nThisColLogic = aLogicEdit.Right() - aLogicEdit.Left() + 1;
5381 Size aPaperSize = Size( 1000000, 1000000 );
5382 if (aCell.meType == CELLTYPE_FORMULA)
5384 long nSizeX = 0;
5385 long nSizeY = 0;
5386 pViewData->GetMergeSizePixel( nPosX, nPosY, nSizeX, nSizeY );
5387 aPaperSize = Size(nSizeX, nSizeY );
5388 aPaperSize = PixelToLogic(aPaperSize);
5391 if (bBreak)
5392 aPaperSize.Width() = nThisColLogic;
5393 pEngine->SetPaperSize( aPaperSize );
5395 std::unique_ptr<EditTextObject> pTextObj;
5396 if (aCell.meType == CELLTYPE_EDIT)
5398 if (aCell.mpEditText)
5399 pEngine->SetText(*aCell.mpEditText);
5401 else // Not an Edit cell and is a formula cell with 'Hyperlink'
5402 // function if we have no URL, otherwise it could be a formula
5403 // cell ( or other type ? ) with a hyperlink associated with it.
5405 if (sURL.isEmpty())
5406 pTextObj.reset(aCell.mpFormula->CreateURLObject());
5407 else
5408 pTextObj.reset(ScEditUtil::CreateURLObjectFromURL(rDoc, sURL, sURL));
5410 if (pTextObj.get())
5411 pEngine->SetText(*pTextObj);
5414 long nStartX = aLogicEdit.Left();
5416 long nTextWidth = pEngine->CalcTextWidth();
5417 long nTextHeight = pEngine->GetTextHeight();
5418 if ( nTextWidth < nThisColLogic )
5420 if (eHorJust == SVX_HOR_JUSTIFY_RIGHT)
5421 nStartX += nThisColLogic - nTextWidth;
5422 else if (eHorJust == SVX_HOR_JUSTIFY_CENTER)
5423 nStartX += (nThisColLogic - nTextWidth) / 2;
5426 aLogicEdit.Left() = nStartX;
5427 if (!bBreak)
5428 aLogicEdit.Right() = nStartX + nTextWidth;
5430 // There is one glitch when dealing with a hyperlink cell and
5431 // the cell content is NUMERIC. This defaults to right aligned and
5432 // we need to adjust accordingly.
5433 if (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->IsValue() &&
5434 eHorJust == SVX_HOR_JUSTIFY_STANDARD)
5436 aLogicEdit.Right() = aLogicEdit.Left() + nThisColLogic - 1;
5437 aLogicEdit.Left() = aLogicEdit.Right() - nTextWidth;
5439 aLogicEdit.Bottom() = aLogicEdit.Top() + nTextHeight;
5441 Point aLogicClick = PixelToLogic(rPos,aEditMode);
5442 if ( aLogicEdit.IsInside(aLogicClick) )
5444 EditView aTempView(pEngine.get(), this);
5445 aTempView.SetOutputArea( aLogicEdit );
5447 MapMode aOld = GetMapMode();
5448 SetMapMode(aEditMode); // kein return mehr
5449 bool bRet = extractURLInfo(aTempView.GetFieldUnderMousePointer(), pName, pUrl, pTarget);
5450 SetMapMode(aOld);
5452 return bRet;
5454 return false;
5457 bool ScGridWindow::IsSpellErrorAtPos( const Point& rPos, SCCOL nCol1, SCROW nRow )
5459 if (!mpSpellCheckCxt)
5460 return false;
5462 SCTAB nTab = pViewData->GetTabNo();
5463 ScDocShell* pDocSh = pViewData->GetDocShell();
5464 ScDocument& rDoc = pDocSh->GetDocument();
5466 ScAddress aCellPos(nCol1, nRow, nTab);
5467 ScRefCellValue aCell;
5468 aCell.assign(rDoc, aCellPos);
5469 if (aCell.meType != CELLTYPE_STRING && aCell.meType != CELLTYPE_EDIT)
5470 return false;
5472 const std::vector<editeng::MisspellRanges>* pRanges = mpSpellCheckCxt->getMisspellRanges(nCol1, nRow);
5473 if (!pRanges)
5474 return false;
5476 const ScPatternAttr* pPattern = rDoc.GetPattern(nCol1, nRow, nTab);
5478 Rectangle aEditRect = pViewData->GetEditArea(eWhich, nCol1, nRow, this, pPattern, false);
5479 if (rPos.Y() < aEditRect.Top())
5480 return false;
5482 boost::shared_ptr<ScFieldEditEngine> pEngine = createEditEngine(pDocSh, *pPattern);
5484 Size aPaperSize = Size(1000000, 1000000);
5485 pEngine->SetPaperSize(aPaperSize);
5487 if (aCell.meType == CELLTYPE_EDIT)
5488 pEngine->SetText(*aCell.mpEditText);
5489 else
5490 pEngine->SetText(aCell.mpString->getString());
5492 long nTextWidth = static_cast<long>(pEngine->CalcTextWidth());
5494 MapMode aEditMode = pViewData->GetLogicMode(eWhich);
5495 Rectangle aLogicEdit = PixelToLogic(aEditRect, aEditMode);
5496 Point aLogicClick = PixelToLogic(rPos, aEditMode);
5498 aLogicEdit.setWidth(nTextWidth + 1);
5500 if (!aLogicEdit.IsInside(aLogicClick))
5501 return false;
5503 pEngine->SetControlWord(pEngine->GetControlWord() | EEControlBits::ONLINESPELLING);
5504 pEngine->SetAllMisspellRanges(*pRanges);
5506 EditView aTempView(pEngine.get(), this);
5507 aTempView.SetOutputArea(aLogicEdit);
5509 return aTempView.IsWrongSpelledWordAtPos(rPos);
5512 bool ScGridWindow::HasScenarioButton( const Point& rPosPixel, ScRange& rScenRange )
5514 ScDocument* pDoc = pViewData->GetDocument();
5515 SCTAB nTab = pViewData->GetTabNo();
5516 SCTAB nTabCount = pDoc->GetTableCount();
5517 if ( nTab+1<nTabCount && pDoc->IsScenario(nTab+1) && !pDoc->IsScenario(nTab) )
5519 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
5521 Size aButSize = pViewData->GetScenButSize();
5522 long nBWidth = aButSize.Width();
5523 if (!nBWidth)
5524 return false; // noch kein Button gezeichnet -> da ist auch keiner
5525 long nBHeight = aButSize.Height();
5526 long nHSpace = (long)( SC_SCENARIO_HSPACE * pViewData->GetPPTX() );
5528 //! Ranges an der Table cachen!!!!
5530 ScMarkData aMarks;
5531 for (SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++)
5532 pDoc->MarkScenario( i, nTab, aMarks, false, SC_SCENARIO_SHOWFRAME );
5533 ScRangeList aRanges;
5534 aMarks.FillRangeListWithMarks( &aRanges, false );
5536 size_t nRangeCount = aRanges.size();
5537 for (size_t j=0; j< nRangeCount; ++j)
5539 ScRange aRange = *aRanges[j];
5540 // Szenario-Rahmen immer dann auf zusammengefasste Zellen erweitern, wenn
5541 // dadurch keine neuen nicht-ueberdeckten Zellen mit umrandet werden
5542 pDoc->ExtendTotalMerge( aRange );
5544 bool bTextBelow = ( aRange.aStart.Row() == 0 );
5546 Point aButtonPos;
5547 if ( bTextBelow )
5549 aButtonPos = pViewData->GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1,
5550 eWhich, true );
5552 else
5554 aButtonPos = pViewData->GetScrPos( aRange.aEnd.Col()+1, aRange.aStart.Row(),
5555 eWhich, true );
5556 aButtonPos.Y() -= nBHeight;
5558 if ( bLayoutRTL )
5559 aButtonPos.X() -= nHSpace - 1;
5560 else
5561 aButtonPos.X() -= nBWidth - nHSpace; // same for top or bottom
5563 Rectangle aButRect( aButtonPos, Size(nBWidth,nBHeight) );
5564 if ( aButRect.IsInside( rPosPixel ) )
5566 rScenRange = aRange;
5567 return true;
5572 return false;
5575 // #114409#
5576 void ScGridWindow::DrawLayerCreated()
5578 SetMapMode( GetDrawMapMode() );
5580 // initially create overlay objects
5581 ImpCreateOverlayObjects();
5584 namespace {
5586 struct SpellCheckStatus
5588 bool mbModified;
5590 SpellCheckStatus() : mbModified(false) {};
5592 DECL_LINK (EventHdl, EditStatus*);
5595 IMPL_LINK(SpellCheckStatus, EventHdl, EditStatus*, pStatus)
5597 EditStatusFlags nStatus = pStatus->GetStatusWord();
5598 if (nStatus & EditStatusFlags::WRONGWORDCHANGED)
5599 mbModified = true;
5601 return 0;
5606 bool ScGridWindow::ContinueOnlineSpelling()
5608 if (!mpSpellCheckCxt)
5609 return false;
5611 if (!mpSpellCheckCxt->maPos.isValid())
5612 return false;
5614 ScDocument* pDoc = pViewData->GetDocument();
5615 ScDPCollection* pDPs = NULL;
5616 if (pDoc->HasPivotTable())
5617 pDPs = pDoc->GetDPCollection();
5619 SCTAB nTab = pViewData->GetTabNo();
5620 SpellCheckStatus aStatus;
5622 ScHorizontalCellIterator aIter(
5623 pDoc, nTab, maVisibleRange.mnCol1, mpSpellCheckCxt->maPos.mnRow, maVisibleRange.mnCol2, maVisibleRange.mnRow2);
5625 ScRangeList aPivotRanges;
5626 if (pDPs)
5627 aPivotRanges = pDPs->GetAllTableRanges(nTab);
5629 SCCOL nCol;
5630 SCROW nRow;
5631 ScRefCellValue* pCell = aIter.GetNext(nCol, nRow);
5632 while (pCell && nRow < mpSpellCheckCxt->maPos.mnRow)
5633 pCell = aIter.GetNext(nCol, nRow);
5635 while (pCell && nCol < mpSpellCheckCxt->maPos.mnCol)
5636 pCell = aIter.GetNext(nCol, nRow);
5638 std::unique_ptr<ScTabEditEngine> pEngine;
5640 // Check only up to 256 cells at a time.
5641 size_t nTotalCellCount = 0;
5642 size_t nTextCellCount = 0;
5643 bool bSpellCheckPerformed = false;
5645 while (pCell)
5647 ++nTotalCellCount;
5649 if (aPivotRanges.In(ScAddress(nCol, nRow, nTab)))
5651 // Don't spell check within pivot tables.
5652 if (nTotalCellCount >= 255)
5653 break;
5655 pCell = aIter.GetNext(nCol, nRow);
5656 continue;
5659 CellType eType = pCell->meType;
5660 if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)
5662 ++nTextCellCount;
5664 if (!pEngine)
5666 // ScTabEditEngine is needed
5667 // because MapMode must be set for some old documents
5668 pEngine.reset(new ScTabEditEngine(pDoc));
5669 pEngine->SetControlWord(
5670 pEngine->GetControlWord() | (EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS));
5671 pEngine->SetStatusEventHdl(LINK(&aStatus, SpellCheckStatus, EventHdl));
5672 // Delimiters hier wie in inputhdl.cxx !!!
5673 pEngine->SetWordDelimiters(
5674 ScEditUtil::ModifyDelimiters(pEngine->GetWordDelimiters()));
5676 uno::Reference<linguistic2::XSpellChecker1> xXSpellChecker1(LinguMgr::GetSpellChecker());
5677 pEngine->SetSpeller(xXSpellChecker1);
5680 const ScPatternAttr* pPattern = pDoc->GetPattern(nCol, nRow, nTab);
5681 sal_uInt16 nCellLang =
5682 static_cast<const SvxLanguageItem&>(pPattern->GetItem(ATTR_FONT_LANGUAGE)).GetValue();
5683 if (nCellLang == LANGUAGE_SYSTEM)
5684 nCellLang = Application::GetSettings().GetLanguageTag().getLanguageType(); // never use SYSTEM for spelling
5685 pEngine->SetDefaultLanguage(nCellLang);
5687 if (eType == CELLTYPE_STRING)
5688 pEngine->SetText(pCell->mpString->getString());
5689 else
5690 pEngine->SetText(*pCell->mpEditText);
5692 aStatus.mbModified = false;
5693 pEngine->CompleteOnlineSpelling();
5694 if (aStatus.mbModified)
5696 std::vector<editeng::MisspellRanges> aRanges;
5697 pEngine->GetAllMisspellRanges(aRanges);
5698 if (!aRanges.empty())
5700 sc::SpellCheckContext::CellPos aPos(nCol, nRow);
5701 mpSpellCheckCxt->maMisspellCells.insert(
5702 sc::SpellCheckContext::CellMapType::value_type(aPos, aRanges));
5705 // Broadcast for re-paint.
5706 ScPaintHint aHint(ScRange(nCol, nRow, nTab), PAINT_GRID);
5707 aHint.SetPrintFlag(false);
5708 pDoc->GetDocumentShell()->Broadcast(aHint);
5711 bSpellCheckPerformed = true;
5714 if (nTotalCellCount >= 255 || nTextCellCount >= 1)
5715 break;
5717 pCell = aIter.GetNext(nCol, nRow);
5720 if (pCell)
5721 // Move to the next cell position for the next iteration.
5722 pCell = aIter.GetNext(nCol, nRow);
5724 if (pCell)
5726 // This will become the first cell position for the next time.
5727 mpSpellCheckCxt->maPos.mnCol = nCol;
5728 mpSpellCheckCxt->maPos.mnRow = nRow;
5730 else
5732 // No more cells to spell check.
5733 mpSpellCheckCxt->maPos.setInvalid();
5736 return bSpellCheckPerformed;
5739 void ScGridWindow::EnableAutoSpell( bool bEnable )
5741 if (bEnable)
5742 mpSpellCheckCxt.reset(new sc::SpellCheckContext);
5743 else
5744 mpSpellCheckCxt.reset();
5747 void ScGridWindow::ResetAutoSpell()
5749 if (mpSpellCheckCxt)
5751 mpSpellCheckCxt->reset();
5752 mpSpellCheckCxt->maPos.mnCol = maVisibleRange.mnCol1;
5753 mpSpellCheckCxt->maPos.mnRow = maVisibleRange.mnRow1;
5757 void ScGridWindow::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges )
5759 if (!mpSpellCheckCxt)
5760 return;
5762 if (!maVisibleRange.isInside(nPosX, nPosY))
5763 return;
5765 mpSpellCheckCxt->setMisspellRanges(nPosX, nPosY, pRanges);
5768 const std::vector<editeng::MisspellRanges>* ScGridWindow::GetAutoSpellData( SCCOL nPosX, SCROW nPosY )
5770 if (!mpSpellCheckCxt)
5771 return NULL;
5773 if (!maVisibleRange.isInside(nPosX, nPosY))
5774 return NULL;
5776 return mpSpellCheckCxt->getMisspellRanges(nPosX, nPosY);
5779 bool ScGridWindow::InsideVisibleRange( SCCOL nPosX, SCROW nPosY )
5781 return maVisibleRange.isInside(nPosX, nPosY);
5784 // #114409#
5785 void ScGridWindow::CursorChanged()
5787 // here the created OverlayObjects may be transformed in later versions. For
5788 // now, just re-create them
5790 UpdateCursorOverlay();
5793 // #114409#
5794 void ScGridWindow::ImpCreateOverlayObjects()
5796 UpdateCursorOverlay();
5797 UpdateCopySourceOverlay();
5798 UpdateSelectionOverlay();
5799 UpdateAutoFillOverlay();
5800 UpdateDragRectOverlay();
5801 UpdateHeaderOverlay();
5802 UpdateShrinkOverlay();
5805 // #114409#
5806 void ScGridWindow::ImpDestroyOverlayObjects()
5808 DeleteCursorOverlay();
5809 DeleteCopySourceOverlay();
5810 DeleteSelectionOverlay();
5811 DeleteAutoFillOverlay();
5812 DeleteDragRectOverlay();
5813 DeleteHeaderOverlay();
5814 DeleteShrinkOverlay();
5817 void ScGridWindow::UpdateAllOverlays()
5819 // delete and re-allocate all overlay objects
5821 ImpDestroyOverlayObjects();
5822 ImpCreateOverlayObjects();
5825 void ScGridWindow::DeleteCursorOverlay()
5827 mpOOCursors.reset();
5830 void ScGridWindow::DeleteCopySourceOverlay()
5832 mpOOSelectionBorder.reset();
5835 void ScGridWindow::UpdateCopySourceOverlay()
5837 MapMode aDrawMode = GetDrawMapMode();
5838 MapMode aOldMode = GetMapMode();
5839 if ( aOldMode != aDrawMode )
5840 SetMapMode( aDrawMode );
5842 DeleteCopySourceOverlay();
5844 if (!pViewData->ShowPasteSource())
5845 return;
5846 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
5847 if (!xOverlayManager.is())
5848 return;
5849 ScTransferObj* pTransObj = ScTransferObj::GetOwnClipboard( pViewData->GetActiveWin() );
5850 if (!pTransObj)
5851 return;
5852 ScDocument* pClipDoc = pTransObj->GetDocument();
5853 if (!pClipDoc)
5854 return;
5856 SCTAB nCurTab = pViewData->GetCurPos().Tab();
5858 ScClipParam& rClipParam = pClipDoc->GetClipParam();
5859 mpOOSelectionBorder.reset(new sdr::overlay::OverlayObjectList);
5860 for ( size_t i = 0; i < rClipParam.maRanges.size(); ++i )
5862 ScRange* p = rClipParam.maRanges[i];
5863 if (p->aStart.Tab() != nCurTab)
5864 continue;
5866 SCCOL nClipStartX = p->aStart.Col();
5867 SCROW nClipStartY = p->aStart.Row();
5868 SCCOL nClipEndX = p->aEnd.Col();
5869 SCROW nClipEndY = p->aEnd.Row();
5871 Point aClipStartScrPos = pViewData->GetScrPos( nClipStartX, nClipStartY, eWhich );
5872 Point aClipEndScrPos = pViewData->GetScrPos( nClipEndX + 1, nClipEndY + 1, eWhich );
5873 aClipStartScrPos -= Point(1, 1);
5874 long nSizeXPix = aClipEndScrPos.X() - aClipStartScrPos.X();
5875 long nSizeYPix = aClipEndScrPos.Y() - aClipStartScrPos.Y();
5877 Rectangle aRect( aClipStartScrPos, Size(nSizeXPix, nSizeYPix) );
5879 Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor();
5881 Rectangle aLogic = PixelToLogic(aRect, aDrawMode);
5882 ::basegfx::B2DRange aRange(aLogic.Left(), aLogic.Top(), aLogic.Right(), aLogic.Bottom());
5883 ScOverlayDashedBorder* pDashedBorder = new ScOverlayDashedBorder(aRange, aHighlight);
5884 xOverlayManager->add(*pDashedBorder);
5885 mpOOSelectionBorder->append(*pDashedBorder);
5888 if ( aOldMode != aDrawMode )
5889 SetMapMode( aOldMode );
5892 /// Turn the selection ranges rRectangles into the LibreOfficeKit selection, and call the callback.
5893 static void updateLibreOfficeKitSelection(ScViewData* pViewData, ScDrawLayer* pDrawLayer, const std::vector<Rectangle>& rRectangles)
5895 if (!pDrawLayer->isTiledRendering())
5896 return;
5898 double nPPTX = pViewData->GetPPTX();
5899 double nPPTY = pViewData->GetPPTY();
5901 Rectangle aBoundingBox;
5902 std::stringstream ss;
5904 bool bIsFirst = true;
5905 for (auto aRectangle : rRectangles)
5907 aRectangle.Right() += 1;
5908 aRectangle.Bottom() += 1;
5910 aBoundingBox.Union(aRectangle);
5912 if (bIsFirst)
5913 bIsFirst = false;
5914 else
5915 ss << "; ";
5917 Rectangle aRect(aRectangle.Left() / nPPTX, aRectangle.Top() / nPPTY,
5918 aRectangle.Right() / nPPTX, aRectangle.Bottom() / nPPTY);
5919 ss << aRect.toString().getStr();
5922 // selection start handle
5923 Rectangle aStart(aBoundingBox.Left() / nPPTX, aBoundingBox.Top() / nPPTY,
5924 aBoundingBox.Left() / nPPTX, (aBoundingBox.Top() / nPPTY) + 256);
5925 pDrawLayer->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_START, aStart.toString().getStr());
5927 // selection end handle
5928 Rectangle aEnd(aBoundingBox.Right() / nPPTX, (aBoundingBox.Bottom() / nPPTY) - 256,
5929 aBoundingBox.Right() / nPPTX, aBoundingBox.Bottom() / nPPTY);
5930 pDrawLayer->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION_END, aEnd.toString().getStr());
5932 // the selection itself
5933 pDrawLayer->libreOfficeKitCallback(LOK_CALLBACK_TEXT_SELECTION, ss.str().c_str());
5936 void ScGridWindow::UpdateCursorOverlay()
5938 ScDocument* pDoc = pViewData->GetDocument();
5940 // never show the cell cursor when the tiled rendering is going on; either
5941 // we want to show the editeng selection, or the cell selection, but not
5942 // the cell cursor by itself
5943 if (pDoc->GetDrawLayer()->isTiledRendering())
5944 return;
5946 MapMode aDrawMode = GetDrawMapMode();
5947 MapMode aOldMode = GetMapMode();
5948 if ( aOldMode != aDrawMode )
5949 SetMapMode( aDrawMode );
5951 // Existing OverlayObjects may be transformed in later versions.
5952 // For now, just re-create them.
5954 DeleteCursorOverlay();
5956 std::vector<Rectangle> aPixelRects;
5958 // determine the cursor rectangles in pixels (moved from ScGridWindow::DrawCursor)
5960 SCTAB nTab = pViewData->GetTabNo();
5961 SCCOL nX = pViewData->GetCurX();
5962 SCROW nY = pViewData->GetCurY();
5964 const ScPatternAttr* pPattern = pDoc->GetPattern(nX,nY,nTab);
5966 if (!maVisibleRange.isInside(nX, nY))
5968 if (maVisibleRange.mnCol2 < nX || maVisibleRange.mnRow2 < nY)
5969 return; // no further check needed, nothing visible
5971 // fdo#87382 Also display the cell cursor for the visible part of
5972 // merged cells if the view position is part of merged cells.
5973 const ScMergeAttr& rMerge = static_cast<const ScMergeAttr&>(pPattern->GetItem(ATTR_MERGE));
5974 if (rMerge.GetColMerge() <= 1 && rMerge.GetRowMerge() <= 1)
5975 return; // not merged and invisible
5977 SCCOL nX2 = nX + rMerge.GetColMerge() - 1;
5978 SCROW nY2 = nY + rMerge.GetRowMerge() - 1;
5979 // Check if the middle or tail of the merged range is visible.
5980 if (!(maVisibleRange.mnCol1 <= nX2 && maVisibleRange.mnRow1 <= nY2))
5981 return; // no visible part
5984 // don't show the cursor in overlapped cells
5986 const ScMergeFlagAttr& rMergeFlag = static_cast<const ScMergeFlagAttr&>( pPattern->GetItem(ATTR_MERGE_FLAG) );
5987 bool bOverlapped = rMergeFlag.IsOverlapped();
5989 // left or above of the screen?
5991 bool bVis = ( nX>=pViewData->GetPosX(eHWhich) && nY>=pViewData->GetPosY(eVWhich) );
5992 if (!bVis)
5994 SCCOL nEndX = nX;
5995 SCROW nEndY = nY;
5996 const ScMergeAttr& rMerge = static_cast<const ScMergeAttr&>( pPattern->GetItem(ATTR_MERGE) );
5997 if (rMerge.GetColMerge() > 1)
5998 nEndX += rMerge.GetColMerge()-1;
5999 if (rMerge.GetRowMerge() > 1)
6000 nEndY += rMerge.GetRowMerge()-1;
6001 bVis = ( nEndX>=pViewData->GetPosX(eHWhich) && nEndY>=pViewData->GetPosY(eVWhich) );
6004 if ( bVis && !bOverlapped && !pViewData->HasEditView(eWhich) && pViewData->IsActive() )
6006 Point aScrPos = pViewData->GetScrPos( nX, nY, eWhich, true );
6007 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
6009 // completely right of/below the screen?
6010 // (test with logical start position in aScrPos)
6011 bool bMaybeVisible;
6012 if ( bLayoutRTL )
6013 bMaybeVisible = ( aScrPos.X() >= -2 && aScrPos.Y() >= -2 );
6014 else
6016 Size aOutSize = GetOutputSizePixel();
6017 bMaybeVisible = ( aScrPos.X() <= aOutSize.Width() + 2 && aScrPos.Y() <= aOutSize.Height() + 2 );
6020 // in the tiled rendering case, don't limit to the screen size
6021 if (bMaybeVisible)
6023 long nSizeXPix;
6024 long nSizeYPix;
6025 pViewData->GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
6027 if (bLayoutRTL)
6028 aScrPos.X() -= nSizeXPix - 2; // move instead of mirroring
6030 // show the cursor as 4 (thin) rectangles
6031 Rectangle aRect(aScrPos, Size(nSizeXPix - 1, nSizeYPix - 1));
6033 sal_Int32 nScale = GetDPIScaleFactor();
6035 long aCursorWidth = 1 * nScale;
6037 Rectangle aLeft = Rectangle(aRect);
6038 aLeft.Top() -= aCursorWidth;
6039 aLeft.Bottom() += aCursorWidth;
6040 aLeft.Right() = aLeft.Left();
6041 aLeft.Left() -= aCursorWidth;
6043 Rectangle aRight = Rectangle(aRect);
6044 aRight.Top() -= aCursorWidth;
6045 aRight.Bottom() += aCursorWidth;
6046 aRight.Left() = aRight.Right();
6047 aRight.Right() += aCursorWidth;
6049 Rectangle aTop = Rectangle(aRect);
6050 aTop.Bottom() = aTop.Top();
6051 aTop.Top() -= aCursorWidth;
6053 Rectangle aBottom = Rectangle(aRect);
6054 aBottom.Top() = aBottom.Bottom();
6055 aBottom.Bottom() += aCursorWidth;
6057 aPixelRects.push_back(aLeft);
6058 aPixelRects.push_back(aRight);
6059 aPixelRects.push_back(aTop);
6060 aPixelRects.push_back(aBottom);
6064 if ( !aPixelRects.empty() )
6066 // #i70788# get the OverlayManager safely
6067 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6069 if (xOverlayManager.is())
6071 Color aCursorColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
6072 if (pViewData->GetActivePart() != eWhich)
6073 // non-active pane uses a different color.
6074 aCursorColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
6075 std::vector< basegfx::B2DRange > aRanges;
6076 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6078 for(sal_uInt32 a(0); a < aPixelRects.size(); a++)
6080 const Rectangle aRA(aPixelRects[a]);
6081 basegfx::B2DRange aRB(aRA.Left(), aRA.Top(), aRA.Right() + 1, aRA.Bottom() + 1);
6082 aRB.transform(aTransform);
6083 aRanges.push_back(aRB);
6086 sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection(
6087 sdr::overlay::OVERLAY_SOLID,
6088 aCursorColor,
6089 aRanges,
6090 false);
6092 xOverlayManager->add(*pOverlay);
6093 mpOOCursors.reset(new sdr::overlay::OverlayObjectList);
6094 mpOOCursors->append(*pOverlay);
6096 // notify the LibreOfficeKit too
6097 updateLibreOfficeKitSelection(pViewData, pDoc->GetDrawLayer(), aPixelRects);
6101 if ( aOldMode != aDrawMode )
6102 SetMapMode( aOldMode );
6105 void ScGridWindow::DeleteSelectionOverlay()
6107 mpOOSelection.reset();
6110 void ScGridWindow::UpdateSelectionOverlay()
6112 MapMode aDrawMode = GetDrawMapMode();
6113 MapMode aOldMode = GetMapMode();
6114 if ( aOldMode != aDrawMode )
6115 SetMapMode( aDrawMode );
6117 DeleteSelectionOverlay();
6118 std::vector<Rectangle> aPixelRects;
6119 GetSelectionRects( aPixelRects );
6121 if (!aPixelRects.empty() && pViewData->IsActive())
6123 // #i70788# get the OverlayManager safely
6124 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6126 if (xOverlayManager.is())
6128 std::vector< basegfx::B2DRange > aRanges;
6129 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6130 ScDocument* pDoc = pViewData->GetDocument();
6131 SCTAB nTab = pViewData->GetTabNo();
6132 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
6134 for(sal_uInt32 a(0); a < aPixelRects.size(); a++)
6136 const Rectangle aRA(aPixelRects[a]);
6137 if (bLayoutRTL)
6139 basegfx::B2DRange aRB(aRA.Left(), aRA.Top() - 1, aRA.Right() + 1, aRA.Bottom());
6140 aRB.transform(aTransform);
6141 aRanges.push_back(aRB);
6143 else
6145 basegfx::B2DRange aRB(aRA.Left() - 1, aRA.Top() - 1, aRA.Right(), aRA.Bottom());
6146 aRB.transform(aTransform);
6147 aRanges.push_back(aRB);
6151 // get the system's highlight color
6152 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
6153 const Color aHighlight(aSvtOptionsDrawinglayer.getHilightColor());
6155 sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection(
6156 sdr::overlay::OVERLAY_TRANSPARENT,
6157 aHighlight,
6158 aRanges,
6159 true);
6161 xOverlayManager->add(*pOverlay);
6162 mpOOSelection.reset(new sdr::overlay::OverlayObjectList);
6163 mpOOSelection->append(*pOverlay);
6165 // notify the LibreOfficeKit too
6166 updateLibreOfficeKitSelection(pViewData, pDoc->GetDrawLayer(), aPixelRects);
6170 if ( aOldMode != aDrawMode )
6171 SetMapMode( aOldMode );
6174 void ScGridWindow::DeleteAutoFillOverlay()
6176 mpOOAutoFill.reset();
6177 mpAutoFillRect.reset();
6180 void ScGridWindow::UpdateAutoFillOverlay()
6182 MapMode aDrawMode = GetDrawMapMode();
6183 MapMode aOldMode = GetMapMode();
6184 if ( aOldMode != aDrawMode )
6185 SetMapMode( aDrawMode );
6187 DeleteAutoFillOverlay();
6189 // get the AutoFill handle rectangle in pixels
6191 if ( bAutoMarkVisible && aAutoMarkPos.Tab() == pViewData->GetTabNo() &&
6192 !pViewData->HasEditView(eWhich) && pViewData->IsActive() )
6194 SCCOL nX = aAutoMarkPos.Col();
6195 SCROW nY = aAutoMarkPos.Row();
6197 if (!maVisibleRange.isInside(nX, nY))
6198 // Autofill mark is not visible. Bail out.
6199 return;
6201 SCTAB nTab = pViewData->GetTabNo();
6202 ScDocument* pDoc = pViewData->GetDocument();
6203 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
6205 sal_Int32 nScale = GetDPIScaleFactor();
6206 // Size should be even
6207 Size aFillHandleSize = Size(6 * nScale, 6 * nScale);
6209 Point aFillPos = pViewData->GetScrPos( nX, nY, eWhich, true );
6210 long nSizeXPix;
6211 long nSizeYPix;
6212 pViewData->GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
6214 if (bLayoutRTL)
6215 aFillPos.X() -= nSizeXPix - 2 + (aFillHandleSize.Width() / 2);
6216 else
6217 aFillPos.X() += nSizeXPix - (aFillHandleSize.Width() / 2);
6219 aFillPos.Y() += nSizeYPix;
6220 aFillPos.Y() -= (aFillHandleSize.Height() / 2);
6222 Rectangle aFillRect(aFillPos, aFillHandleSize);
6224 // expand rect to increase hit area
6225 mpAutoFillRect.reset(new Rectangle(aFillRect.Left() - nScale,
6226 aFillRect.Top() - nScale,
6227 aFillRect.Right() + nScale,
6228 aFillRect.Bottom() + nScale));
6230 // #i70788# get the OverlayManager safely
6231 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6233 if (xOverlayManager.is())
6235 Color aHandleColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
6236 if (pViewData->GetActivePart() != eWhich)
6237 // non-active pane uses a different color.
6238 aHandleColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
6239 std::vector< basegfx::B2DRange > aRanges;
6240 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6241 basegfx::B2DRange aRB(aFillRect.Left(), aFillRect.Top(), aFillRect.Right(), aFillRect.Bottom());
6243 aRB.transform(aTransform);
6244 aRanges.push_back(aRB);
6246 sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection(
6247 sdr::overlay::OVERLAY_SOLID,
6248 aHandleColor,
6249 aRanges,
6250 false);
6252 xOverlayManager->add(*pOverlay);
6253 mpOOAutoFill.reset(new sdr::overlay::OverlayObjectList);
6254 mpOOAutoFill->append(*pOverlay);
6257 if ( aOldMode != aDrawMode )
6258 SetMapMode( aOldMode );
6262 void ScGridWindow::DeleteDragRectOverlay()
6264 mpOODragRect.reset();
6267 void ScGridWindow::UpdateDragRectOverlay()
6269 MapMode aDrawMode = GetDrawMapMode();
6270 MapMode aOldMode = GetMapMode();
6271 if ( aOldMode != aDrawMode )
6272 SetMapMode( aDrawMode );
6274 DeleteDragRectOverlay();
6276 // get the rectangles in pixels (moved from DrawDragRect)
6278 if ( bDragRect || bPagebreakDrawn )
6280 std::vector<Rectangle> aPixelRects;
6282 SCCOL nX1 = bDragRect ? nDragStartX : aPagebreakDrag.aStart.Col();
6283 SCROW nY1 = bDragRect ? nDragStartY : aPagebreakDrag.aStart.Row();
6284 SCCOL nX2 = bDragRect ? nDragEndX : aPagebreakDrag.aEnd.Col();
6285 SCROW nY2 = bDragRect ? nDragEndY : aPagebreakDrag.aEnd.Row();
6287 SCTAB nTab = pViewData->GetTabNo();
6289 SCCOL nPosX = pViewData->GetPosX(WhichH(eWhich));
6290 SCROW nPosY = pViewData->GetPosY(WhichV(eWhich));
6291 if (nX1 < nPosX) nX1 = nPosX;
6292 if (nX2 < nPosX) nX2 = nPosX;
6293 if (nY1 < nPosY) nY1 = nPosY;
6294 if (nY2 < nPosY) nY2 = nPosY;
6296 Point aScrPos( pViewData->GetScrPos( nX1, nY1, eWhich ) );
6298 long nSizeXPix=0;
6299 long nSizeYPix=0;
6300 ScDocument* pDoc = pViewData->GetDocument();
6301 double nPPTX = pViewData->GetPPTX();
6302 double nPPTY = pViewData->GetPPTY();
6303 SCCOLROW i;
6305 bool bLayoutRTL = pDoc->IsLayoutRTL( nTab );
6306 long nLayoutSign = bLayoutRTL ? -1 : 1;
6308 if (ValidCol(nX2) && nX2>=nX1)
6309 for (i=nX1; i<=nX2; i++)
6310 nSizeXPix += ScViewData::ToPixel( pDoc->GetColWidth( static_cast<SCCOL>(i), nTab ), nPPTX );
6311 else
6313 aScrPos.X() -= nLayoutSign;
6314 nSizeXPix += 2;
6317 if (ValidRow(nY2) && nY2>=nY1)
6318 for (i=nY1; i<=nY2; i++)
6319 nSizeYPix += ScViewData::ToPixel( pDoc->GetRowHeight( i, nTab ), nPPTY );
6320 else
6322 aScrPos.Y() -= 1;
6323 nSizeYPix += 2;
6326 aScrPos.X() -= 2 * nLayoutSign;
6327 aScrPos.Y() -= 2;
6328 Rectangle aRect( aScrPos.X(), aScrPos.Y(),
6329 aScrPos.X() + ( nSizeXPix + 2 ) * nLayoutSign, aScrPos.Y() + nSizeYPix + 2 );
6330 if ( bLayoutRTL )
6332 aRect.Left() = aRect.Right(); // end position is left
6333 aRect.Right() = aScrPos.X();
6336 if ( meDragInsertMode == INS_CELLSDOWN )
6338 aPixelRects.push_back( Rectangle( aRect.Left()+1, aRect.Top()+3, aRect.Left()+1, aRect.Bottom()-2 ) );
6339 aPixelRects.push_back( Rectangle( aRect.Right()-1, aRect.Top()+3, aRect.Right()-1, aRect.Bottom()-2 ) );
6340 aPixelRects.push_back( Rectangle( aRect.Left()+1, aRect.Top(), aRect.Right()-1, aRect.Top()+2 ) );
6341 aPixelRects.push_back( Rectangle( aRect.Left()+1, aRect.Bottom()-1, aRect.Right()-1, aRect.Bottom()-1 ) );
6343 else if ( meDragInsertMode == INS_CELLSRIGHT )
6345 aPixelRects.push_back( Rectangle( aRect.Left(), aRect.Top()+1, aRect.Left()+2, aRect.Bottom()-1 ) );
6346 aPixelRects.push_back( Rectangle( aRect.Right()-1, aRect.Top()+1, aRect.Right()-1, aRect.Bottom()-1 ) );
6347 aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Top()+1, aRect.Right()-2, aRect.Top()+1 ) );
6348 aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Bottom()-1, aRect.Right()-2, aRect.Bottom()-1 ) );
6350 else
6352 aPixelRects.push_back( Rectangle( aRect.Left(), aRect.Top(), aRect.Left()+2, aRect.Bottom() ) );
6353 aPixelRects.push_back( Rectangle( aRect.Right()-2, aRect.Top(), aRect.Right(), aRect.Bottom() ) );
6354 aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Top(), aRect.Right()-3, aRect.Top()+2 ) );
6355 aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Bottom()-2, aRect.Right()-3, aRect.Bottom() ) );
6358 // #i70788# get the OverlayManager safely
6359 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6361 if (xOverlayManager.is())
6363 std::vector< basegfx::B2DRange > aRanges;
6364 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6366 for(sal_uInt32 a(0); a < aPixelRects.size(); a++)
6368 const Rectangle aRA(aPixelRects[a]);
6369 basegfx::B2DRange aRB(aRA.Left(), aRA.Top(), aRA.Right() + 1, aRA.Bottom() + 1);
6370 aRB.transform(aTransform);
6371 aRanges.push_back(aRB);
6374 sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection(
6375 sdr::overlay::OVERLAY_INVERT,
6376 Color(COL_BLACK),
6377 aRanges,
6378 false);
6380 xOverlayManager->add(*pOverlay);
6381 mpOODragRect.reset(new sdr::overlay::OverlayObjectList);
6382 mpOODragRect->append(*pOverlay);
6386 if ( aOldMode != aDrawMode )
6387 SetMapMode( aOldMode );
6390 void ScGridWindow::DeleteHeaderOverlay()
6392 mpOOHeader.reset();
6395 void ScGridWindow::UpdateHeaderOverlay()
6397 MapMode aDrawMode = GetDrawMapMode();
6398 MapMode aOldMode = GetMapMode();
6399 if ( aOldMode != aDrawMode )
6400 SetMapMode( aDrawMode );
6402 DeleteHeaderOverlay();
6404 // Pixel rectangle is in aInvertRect
6405 if ( !aInvertRect.IsEmpty() )
6407 // #i70788# get the OverlayManager safely
6408 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6410 if (xOverlayManager.is())
6412 // Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor();
6413 std::vector< basegfx::B2DRange > aRanges;
6414 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6415 basegfx::B2DRange aRB(aInvertRect.Left(), aInvertRect.Top(), aInvertRect.Right() + 1, aInvertRect.Bottom() + 1);
6417 aRB.transform(aTransform);
6418 aRanges.push_back(aRB);
6420 sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection(
6421 sdr::overlay::OVERLAY_INVERT,
6422 Color(COL_BLACK),
6423 aRanges,
6424 false);
6426 xOverlayManager->add(*pOverlay);
6427 mpOOHeader.reset(new sdr::overlay::OverlayObjectList);
6428 mpOOHeader->append(*pOverlay);
6432 if ( aOldMode != aDrawMode )
6433 SetMapMode( aOldMode );
6436 void ScGridWindow::DeleteShrinkOverlay()
6438 mpOOShrink.reset();
6441 void ScGridWindow::UpdateShrinkOverlay()
6443 MapMode aDrawMode = GetDrawMapMode();
6444 MapMode aOldMode = GetMapMode();
6445 if ( aOldMode != aDrawMode )
6446 SetMapMode( aDrawMode );
6448 DeleteShrinkOverlay();
6450 // get the rectangle in pixels
6452 Rectangle aPixRect;
6453 ScRange aRange;
6454 SCTAB nTab = pViewData->GetTabNo();
6455 if ( pViewData->IsRefMode() && nTab >= pViewData->GetRefStartZ() && nTab <= pViewData->GetRefEndZ() &&
6456 pViewData->GetDelMark( aRange ) )
6458 //! limit to visible area
6459 if ( aRange.aStart.Col() <= aRange.aEnd.Col() &&
6460 aRange.aStart.Row() <= aRange.aEnd.Row() )
6462 Point aStart = pViewData->GetScrPos( aRange.aStart.Col(),
6463 aRange.aStart.Row(), eWhich );
6464 Point aEnd = pViewData->GetScrPos( aRange.aEnd.Col()+1,
6465 aRange.aEnd.Row()+1, eWhich );
6466 aEnd.X() -= 1;
6467 aEnd.Y() -= 1;
6469 aPixRect = Rectangle( aStart,aEnd );
6473 if ( !aPixRect.IsEmpty() )
6475 // #i70788# get the OverlayManager safely
6476 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6478 if (xOverlayManager.is())
6480 std::vector< basegfx::B2DRange > aRanges;
6481 const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation());
6482 basegfx::B2DRange aRB(aPixRect.Left(), aPixRect.Top(), aPixRect.Right() + 1, aPixRect.Bottom() + 1);
6484 aRB.transform(aTransform);
6485 aRanges.push_back(aRB);
6487 sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection(
6488 sdr::overlay::OVERLAY_INVERT,
6489 Color(COL_BLACK),
6490 aRanges,
6491 false);
6493 xOverlayManager->add(*pOverlay);
6494 mpOOShrink.reset(new sdr::overlay::OverlayObjectList);
6495 mpOOShrink->append(*pOverlay);
6499 if ( aOldMode != aDrawMode )
6500 SetMapMode( aOldMode );
6503 // #i70788# central method to get the OverlayManager safely
6504 rtl::Reference<sdr::overlay::OverlayManager> ScGridWindow::getOverlayManager()
6506 SdrPageView* pPV = pViewData->GetView()->GetScDrawView()->GetSdrPageView();
6508 if(pPV)
6510 SdrPageWindow* pPageWin = pPV->FindPageWindow( *this );
6512 if ( pPageWin )
6514 return (pPageWin->GetOverlayManager());
6518 return rtl::Reference<sdr::overlay::OverlayManager>();
6521 void ScGridWindow::flushOverlayManager()
6523 // #i70788# get the OverlayManager safely
6524 rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
6526 if (xOverlayManager.is())
6527 xOverlayManager->flush();
6530 void ScGridWindow::SetInRefMode( bool bInRefMode )
6532 WinBits nBits = GetStyle();
6533 if(bInRefMode)
6534 nBits |= WB_REFMODE;
6535 else
6536 nBits &= ~WB_REFMODE;
6538 SetStyle( nBits );
6541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */