diff options
Diffstat (limited to 'sc/source/ui/view/gridwin.cxx')
-rw-r--r-- | sc/source/ui/view/gridwin.cxx | 5706 |
1 files changed, 5706 insertions, 0 deletions
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx new file mode 100644 index 000000000000..d350da754433 --- /dev/null +++ b/sc/source/ui/view/gridwin.cxx @@ -0,0 +1,5706 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sc.hxx" + +#include "scitems.hxx" + +#include <memory> //auto_ptr +#include <editeng/adjitem.hxx> +#include <svx/algitem.hxx> +#include <svx/dbexch.hrc> +#include <editeng/editview.hxx> +#include <editeng/editstat.hxx> +#include <editeng/flditem.hxx> +#include <svx/svdetc.hxx> +#include <editeng/editobj.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <sfx2/docfile.hxx> +#include <svl/stritem.hxx> +#include <svtools/svlbox.hxx> +#include <svtools/svtabbx.hxx> +#include <svl/urlbmk.hxx> +#include <tools/urlobj.hxx> +#include <vcl/cursor.hxx> +#include <vcl/sound.hxx> +#include <vcl/graph.hxx> +#include <vcl/hatch.hxx> +#include <sot/formats.hxx> +#include <sot/clsids.hxx> + +#include <svx/svdview.hxx> // fuer Command-Handler (COMMAND_INSERTTEXT) +#include <editeng/outliner.hxx> // fuer Command-Handler (COMMAND_INSERTTEXT) +#include <svx/svditer.hxx> +#include <svx/svdocapt.hxx> +#include <svx/svdpagv.hxx> + +#include <com/sun/star/sheet/DataPilotFieldFilter.hpp> +#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp> +#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp> +#include <com/sun/star/sheet/DataPilotTableResultData.hpp> +#include <com/sun/star/sheet/DataPilotTablePositionData.hpp> +#include <com/sun/star/sheet/DataPilotTablePositionType.hpp> +#include <com/sun/star/sheet/MemberResultFlags.hpp> +#include <com/sun/star/awt/KeyModifier.hpp> +#include <com/sun/star/awt/MouseButton.hpp> +#include <com/sun/star/script/vba/VBAEventId.hpp> +#include <com/sun/star/script/vba/XVBAEventProcessor.hpp> + +#include "gridwin.hxx" +#include "tabvwsh.hxx" +#include "docsh.hxx" +#include "viewdata.hxx" +#include "tabview.hxx" +#include "select.hxx" +#include "scmod.hxx" +#include "document.hxx" +#include "attrib.hxx" +#include "dbcolect.hxx" +#include "stlpool.hxx" +#include "printfun.hxx" +#include "cbutton.hxx" +#include "sc.hrc" +#include "globstr.hrc" +#include "editutil.hxx" +#include "scresid.hxx" +#include "inputhdl.hxx" +#include "uiitems.hxx" // Filter-Dialog - auslagern !!! +#include "filtdlg.hxx" +#include "impex.hxx" // Sylk-ID fuer CB +#include "cell.hxx" // fuer Edit-Felder +#include "patattr.hxx" +#include "notemark.hxx" +#include "rfindlst.hxx" +#include "docpool.hxx" +#include "output.hxx" +#include "docfunc.hxx" +#include "dbdocfun.hxx" +#include "dpobject.hxx" +#include "dpoutput.hxx" +#include "transobj.hxx" +#include "drwtrans.hxx" +#include "seltrans.hxx" +#include "sizedev.hxx" +#include "AccessibilityHints.hxx" +#include "dpsave.hxx" +#include "viewuno.hxx" +#include "compiler.hxx" +#include "editable.hxx" +#include "fillinfo.hxx" +#include "scitems.hxx" +#include "userdat.hxx" +#include "drwlayer.hxx" +#include "attrib.hxx" +#include "validat.hxx" +#include "tabprotection.hxx" +#include "postit.hxx" +#include "dpcontrol.hxx" +#include "cellsuno.hxx" + +#include "drawview.hxx" +#include <svx/sdrpagewindow.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <vcl/svapp.hxx> +#include <svx/sdr/overlay/overlayselection.hxx> + +using namespace com::sun::star; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; + +const sal_uInt8 SC_NESTEDBUTTON_NONE = 0; +const sal_uInt8 SC_NESTEDBUTTON_DOWN = 1; +const sal_uInt8 SC_NESTEDBUTTON_UP = 2; + +#define SC_AUTOFILTER_ALL 0 +#define SC_AUTOFILTER_TOP10 1 +#define SC_AUTOFILTER_CUSTOM 2 + +// Modi fuer die FilterListBox +enum ScFilterBoxMode +{ + SC_FILTERBOX_FILTER, + SC_FILTERBOX_DATASELECT, + SC_FILTERBOX_SCENARIO, + SC_FILTERBOX_PAGEFIELD +}; + +extern SfxViewShell* pScActiveViewShell; // global.cxx +extern sal_uInt16 nScClickMouseModifier; // global.cxx +extern sal_uInt16 nScFillModeMouseModifier; // global.cxx + +#define SC_FILTERLISTBOX_LINES 12 + +// ============================================================================ + +ScGridWindow::VisibleRange::VisibleRange() : + mnCol1(0), mnCol2(MAXCOL), mnRow1(0), mnRow2(MAXROW) +{ +} + +bool ScGridWindow::VisibleRange::isInside(SCCOL nCol, SCROW nRow) const +{ + return mnCol1 <= nCol && nCol <= mnCol2 && mnRow1 <= nRow && nRow <= mnRow2; +} + +// ============================================================================ + +class ScFilterListBox : public ListBox +{ +private: + ScGridWindow* pGridWin; + SCCOL nCol; + SCROW nRow; + sal_Bool bButtonDown; + sal_Bool bInit; + sal_Bool bCancelled; + sal_Bool bInSelect; + bool mbListHasDates; + sal_uLong nSel; + ScFilterBoxMode eMode; + +protected: + virtual void LoseFocus(); + void SelectHdl(); + +public: + ScFilterListBox( Window* pParent, ScGridWindow* pGrid, + SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode ); + ~ScFilterListBox(); + + virtual long PreNotify( NotifyEvent& rNEvt ); + virtual void Select(); + + SCCOL GetCol() const { return nCol; } + SCROW GetRow() const { return nRow; } + ScFilterBoxMode GetMode() const { return eMode; } + sal_Bool IsDataSelect() const { return (eMode == SC_FILTERBOX_DATASELECT); } + void EndInit(); + sal_Bool IsInInit() const { return bInit; } + void SetCancelled() { bCancelled = sal_True; } + sal_Bool IsInSelect() const { return bInSelect; } + void SetListHasDates(bool b) { mbListHasDates = b; } + bool HasDates() const { return mbListHasDates; } +}; + +//------------------------------------------------------------------- + +// ListBox in einem FloatingWindow (pParent) +ScFilterListBox::ScFilterListBox( Window* pParent, ScGridWindow* pGrid, + SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode ) : + ListBox( pParent, WB_AUTOHSCROLL ), + pGridWin( pGrid ), + nCol( nNewCol ), + nRow( nNewRow ), + bButtonDown( sal_False ), + bInit( sal_True ), + bCancelled( sal_False ), + bInSelect( sal_False ), + mbListHasDates(false), + nSel( 0 ), + eMode( eNewMode ) +{ +} + +__EXPORT ScFilterListBox::~ScFilterListBox() +{ + if (IsMouseCaptured()) + ReleaseMouse(); +} + +void ScFilterListBox::EndInit() +{ + sal_uInt16 nPos = GetSelectEntryPos(); + if ( LISTBOX_ENTRY_NOTFOUND == nPos ) + nSel = 0; + else + nSel = nPos; + + bInit = sal_False; +} + +void __EXPORT ScFilterListBox::LoseFocus() +{ +#ifndef UNX + Hide(); +#endif +} + +// ----------------------------------------------------------------------- + +long ScFilterListBox::PreNotify( NotifyEvent& rNEvt ) +{ + long nDone = 0; + if ( rNEvt.GetType() == EVENT_KEYINPUT ) + { + KeyEvent aKeyEvt = *rNEvt.GetKeyEvent(); + KeyCode aCode = aKeyEvt.GetKeyCode(); + if ( !aCode.GetModifier() ) // ohne alle Modifiers + { + sal_uInt16 nKey = aCode.GetCode(); + if ( nKey == KEY_RETURN ) + { + SelectHdl(); // auswaehlen + nDone = 1; + } + else if ( nKey == KEY_ESCAPE ) + { + pGridWin->ClickExtern(); // loescht die List-Box !!! + nDone = 1; + } + } + } + + return nDone ? nDone : ListBox::PreNotify( rNEvt ); +} + +void __EXPORT ScFilterListBox::Select() +{ + ListBox::Select(); + SelectHdl(); +} + +void __EXPORT ScFilterListBox::SelectHdl() +{ + if ( !IsTravelSelect() && !bInit && !bCancelled ) + { + sal_uInt16 nPos = GetSelectEntryPos(); + if ( LISTBOX_ENTRY_NOTFOUND != nPos ) + { + nSel = nPos; + if (!bButtonDown) + { + // #i81298# set bInSelect flag, so the box isn't deleted from modifications within FilterSelect + bInSelect = sal_True; + pGridWin->FilterSelect( nSel ); + bInSelect = sal_False; + } + } + } +} + +// ============================================================================ + +// use a System floating window for the above filter listbox +class ScFilterFloatingWindow : public FloatingWindow +{ +public: + ScFilterFloatingWindow( Window* pParent, WinBits nStyle = WB_STDFLOATWIN ); + virtual ~ScFilterFloatingWindow(); + // required for System FloatingWindows that will not process KeyInput by themselves + virtual Window* GetPreferredKeyInputWindow(); +}; + +ScFilterFloatingWindow::ScFilterFloatingWindow( Window* pParent, WinBits nStyle ) : + FloatingWindow( pParent, nStyle|WB_SYSTEMWINDOW ) // make it a system floater + {} + +ScFilterFloatingWindow::~ScFilterFloatingWindow() +{ + EndPopupMode(); +} + +Window* ScFilterFloatingWindow::GetPreferredKeyInputWindow() +{ + // redirect keyinput in the child window + return GetWindow(WINDOW_FIRSTCHILD) ? GetWindow(WINDOW_FIRSTCHILD)->GetPreferredKeyInputWindow() : NULL; // will be the FilterBox +} + +// ============================================================================ + +sal_Bool lcl_IsEditableMatrix( ScDocument* pDoc, const ScRange& rRange ) +{ + // wenn es ein editierbarer Bereich ist, und rechts unten eine Matrix-Zelle + // mit Origin links oben liegt, enthaelt der Bereich genau die Matrix. + //! Direkt die MatrixEdges Funktionen von der Column herausreichen ??? + + if ( !pDoc->IsBlockEditable( rRange.aStart.Tab(), rRange.aStart.Col(),rRange.aStart.Row(), + rRange.aEnd.Col(),rRange.aEnd.Row() ) ) + return sal_False; + + ScAddress aPos; + const ScBaseCell* pCell = pDoc->GetCell( rRange.aEnd ); + return ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA && + ((ScFormulaCell*)pCell)->GetMatrixOrigin(aPos) && aPos == rRange.aStart ); + +} + +void lcl_UnLockComment( ScDrawView* pView, SdrPageView* pPV, SdrModel* pDrDoc, const Point& rPos, ScViewData* pViewData ) +{ + if (!pView && !pPV && !pDrDoc && !pViewData) + return; + + ScDocument& rDoc = *pViewData->GetDocument(); + ScAddress aCellPos( pViewData->GetCurX(), pViewData->GetCurY(), pViewData->GetTabNo() ); + ScPostIt* pNote = rDoc.GetNote( aCellPos ); + SdrObject* pObj = pNote ? pNote->GetCaption() : 0; + if( pObj && pObj->GetLogicRect().IsInside( rPos ) && ScDrawLayer::IsNoteCaption( pObj ) ) + { + const ScProtectionAttr* pProtAttr = static_cast< const ScProtectionAttr* > (rDoc.GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_PROTECTION ) ); + bool bProtectAttr = pProtAttr->GetProtection() || pProtAttr->GetHideCell() ; + bool bProtectDoc = rDoc.IsTabProtected( aCellPos.Tab() ) || pViewData->GetSfxDocShell()->IsReadOnly() ; + // unlock internal layer (if not protected), will be relocked in ScDrawView::MarkListHasChanged() + pView->LockInternalLayer( bProtectDoc && bProtectAttr ); + } +} + +sal_Bool lcl_GetHyperlinkCell(ScDocument* pDoc, SCCOL& rPosX, SCROW& rPosY, SCTAB nTab, ScBaseCell*& rpCell ) +{ + sal_Bool bFound = sal_False; + do + { + pDoc->GetCell( rPosX, rPosY, nTab, rpCell ); + if ( !rpCell || rpCell->GetCellType() == CELLTYPE_NOTE ) + { + if ( rPosX <= 0 ) + return sal_False; // alles leer bis links + else + --rPosX; // weitersuchen + } + else if ( rpCell->GetCellType() == CELLTYPE_EDIT) + bFound = sal_True; + else if (rpCell->GetCellType() == CELLTYPE_FORMULA && + static_cast<ScFormulaCell*>(rpCell)->IsHyperLinkCell()) + bFound = sal_True; + else + return sal_False; // andere Zelle + } + while ( !bFound ); + + return bFound; +} + +// --------------------------------------------------------------------------- +// WB_DIALOGCONTROL noetig fuer UNO-Controls +ScGridWindow::ScGridWindow( Window* pParent, ScViewData* pData, ScSplitPos eWhichPos ) +: Window( pParent, WB_CLIPCHILDREN | WB_DIALOGCONTROL ), + DropTargetHelper( this ), + DragSourceHelper( this ), + mpOOCursors( NULL ), + mpOOSelection( NULL ), + mpOOAutoFill( NULL ), + mpOODragRect( NULL ), + mpOOHeader( NULL ), + mpOOShrink( NULL ), + mpAutoFillRect(static_cast<Rectangle*>(NULL)), + pViewData( pData ), + eWhich( eWhichPos ), + pNoteMarker( NULL ), + pFilterBox( NULL ), + pFilterFloat( NULL ), + mpDPFieldPopup(NULL), + mpFilterButton(NULL), + nCursorHideCount( 0 ), + bMarking( sal_False ), + nButtonDown( 0 ), + bEEMouse( sal_False ), + nMouseStatus( SC_GM_NONE ), + nNestedButtonState( SC_NESTEDBUTTON_NONE ), + bDPMouse( sal_False ), + bRFMouse( sal_False ), + nPagebreakMouse( SC_PD_NONE ), + bPagebreakDrawn( sal_False ), + nPageScript( 0 ), + bDragRect( sal_False ), + meDragInsertMode( INS_NONE ), + nCurrentPointer( 0 ), + bIsInScroll( sal_False ), + bIsInPaint( sal_False ), + aComboButton( this ), + aCurMousePos( 0,0 ), + nPaintCount( 0 ), + bNeedsRepaint( sal_False ), + bAutoMarkVisible( sal_False ), + bListValButton( sal_False ) +{ + switch(eWhich) + { + case SC_SPLIT_TOPLEFT: + eHWhich = SC_SPLIT_LEFT; + eVWhich = SC_SPLIT_TOP; + break; + case SC_SPLIT_TOPRIGHT: + eHWhich = SC_SPLIT_RIGHT; + eVWhich = SC_SPLIT_TOP; + break; + case SC_SPLIT_BOTTOMLEFT: + eHWhich = SC_SPLIT_LEFT; + eVWhich = SC_SPLIT_BOTTOM; + break; + case SC_SPLIT_BOTTOMRIGHT: + eHWhich = SC_SPLIT_RIGHT; + eVWhich = SC_SPLIT_BOTTOM; + break; + default: + DBG_ERROR("GridWindow: falsche Position"); + } + + SetBackground(); + + SetMapMode(pViewData->GetLogicMode(eWhich)); +// EnableDrop(); + EnableChildTransparentMode(); + SetDialogControlFlags( WINDOW_DLGCTRL_RETURN | WINDOW_DLGCTRL_WANTFOCUS ); + + SetHelpId( HID_SC_WIN_GRIDWIN ); + SetUniqueId( HID_SC_WIN_GRIDWIN ); + + SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() ); + EnableRTL( sal_False ); +} + +__EXPORT ScGridWindow::~ScGridWindow() +{ + // #114409# + ImpDestroyOverlayObjects(); + + delete pFilterBox; + delete pFilterFloat; + delete pNoteMarker; +} + +void __EXPORT ScGridWindow::Resize( const Size& ) +{ + // gar nix +} + +void ScGridWindow::ClickExtern() +{ + do + { + // #i81298# don't delete the filter box when called from its select handler + // (possible through row header size update) + // #i84277# when initializing the filter box, a Basic error can deactivate the view + if ( pFilterBox && ( pFilterBox->IsInSelect() || pFilterBox->IsInInit() ) ) + { + break; + } + + DELETEZ(pFilterBox); + DELETEZ(pFilterFloat); + } + while (false); + + if (mpDPFieldPopup.get()) + { + mpDPFieldPopup->close(false); + mpDPFieldPopup.reset(); + } +} + +IMPL_LINK( ScGridWindow, PopupModeEndHdl, FloatingWindow*, EMPTYARG ) +{ + if (pFilterBox) + pFilterBox->SetCancelled(); // nicht mehr auswaehlen + GrabFocus(); + return 0; +} + +IMPL_LINK( ScGridWindow, PopupSpellingHdl, SpellCallbackInfo*, pInfo ) +{ + if( pInfo->nCommand == SPELLCMD_STARTSPELLDLG ) + pViewData->GetDispatcher().Execute( SID_SPELL_DIALOG, SFX_CALLMODE_ASYNCHRON ); + return 0; +} + +void ScGridWindow::ExecPageFieldSelect( SCCOL nCol, SCROW nRow, sal_Bool bHasSelection, const String& rStr ) +{ + //! gridwin2 ? + + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab); + if ( pDPObj && nCol > 0 ) + { + // look for the dimension header left of the drop-down arrow + sal_uInt16 nOrient = sheet::DataPilotFieldOrientation_HIDDEN; + long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient ); + if ( nField >= 0 && nOrient == sheet::DataPilotFieldOrientation_PAGE ) + { + ScDPSaveData aSaveData( *pDPObj->GetSaveData() ); + + sal_Bool bIsDataLayout; + String aDimName = pDPObj->GetDimName( nField, bIsDataLayout ); + if ( !bIsDataLayout ) + { + ScDPSaveDimension* pDim = aSaveData.GetDimensionByName(aDimName); + + if ( bHasSelection ) + pDim->SetCurrentPage( &rStr ); + else + pDim->SetCurrentPage( NULL ); + + ScDPObject aNewObj( *pDPObj ); + aNewObj.SetSaveData( aSaveData ); + ScDBDocFunc aFunc( *pViewData->GetDocShell() ); + aFunc.DataPilotUpdate( pDPObj, &aNewObj, sal_True, sal_False ); + pViewData->GetView()->CursorPosChanged(); // shells may be switched + } + } + } +} + +void ScGridWindow::LaunchPageFieldMenu( SCCOL nCol, SCROW nRow ) +{ + //! merge position/size handling with DoAutoFilterMenue + + delete pFilterBox; + delete pFilterFloat; + + sal_uInt16 i; + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + + long nSizeX = 0; + long nSizeY = 0; + long nHeight = 0; + pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); + Point aPos = pViewData->GetScrPos( nCol, nRow, eWhich ); + if ( bLayoutRTL ) + aPos.X() -= nSizeX; + + Rectangle aCellRect( OutputToScreenPixel(aPos), Size(nSizeX,nSizeY) ); + + aPos.X() -= 1; + aPos.Y() += nSizeY - 1; + + pFilterFloat = new ScFilterFloatingWindow( this, WinBits(WB_BORDER) ); // not resizable etc. + pFilterFloat->SetPopupModeEndHdl( LINK( this, ScGridWindow, PopupModeEndHdl ) ); + pFilterBox = new ScFilterListBox( pFilterFloat, this, nCol, nRow, SC_FILTERBOX_PAGEFIELD ); + if ( bLayoutRTL ) + pFilterBox->EnableMirroring(); + + nSizeX += 1; + + { + Font aOldFont = GetFont(); SetFont( pFilterBox->GetFont() ); + MapMode aOldMode = GetMapMode(); SetMapMode( MAP_PIXEL ); + + nHeight = GetTextHeight(); + nHeight *= SC_FILTERLISTBOX_LINES; + + SetMapMode( aOldMode ); + SetFont( aOldFont ); + } + + // SetSize comes later + + TypedScStrCollection aStrings( 128, 128 ); + + // get list box entries and selection + sal_Bool bHasCurrentPage = sal_False; + String aCurrentPage; + ScDPObject* pDPObj = pDoc->GetDPAtCursor(nCol, nRow, nTab); + if ( pDPObj && nCol > 0 ) + { + // look for the dimension header left of the drop-down arrow + sal_uInt16 nOrient = sheet::DataPilotFieldOrientation_HIDDEN; + long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient ); + if ( nField >= 0 && nOrient == sheet::DataPilotFieldOrientation_PAGE ) + { + pDPObj->FillPageList( aStrings, nField ); + + // get current page from SaveData + + ScDPSaveData* pSaveData = pDPObj->GetSaveData(); + sal_Bool bIsDataLayout; + String aDimName = pDPObj->GetDimName( nField, bIsDataLayout ); + if ( pSaveData && !bIsDataLayout ) + { + ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName(aDimName); + if ( pDim && pDim->HasCurrentPage() ) + { + aCurrentPage = pDim->GetCurrentPage(); + bHasCurrentPage = sal_True; + } + } + } + } + + // include all entry widths for the size of the drop-down + long nMaxText = 0; + sal_uInt16 nCount = aStrings.GetCount(); + for (i=0; i<nCount; i++) + { + TypedStrData* pData = aStrings[i]; + long nTextWidth = pFilterBox->GetTextWidth( pData->GetString() ); + if ( nTextWidth > nMaxText ) + nMaxText = nTextWidth; + } + + // add scrollbar width if needed (string entries are counted here) + // (scrollbar is shown if the box is exactly full?) + if ( nCount >= SC_FILTERLISTBOX_LINES ) + nMaxText += GetSettings().GetStyleSettings().GetScrollBarSize(); + + nMaxText += 4; // for borders + + if ( nMaxText > nSizeX ) + nSizeX = nMaxText; // just modify width - starting position is unchanged + + // adjust position and size to window + + Size aParentSize = GetParent()->GetOutputSizePixel(); + Size aSize( nSizeX, nHeight ); + + if ( aSize.Height() > aParentSize.Height() ) + aSize.Height() = aParentSize.Height(); + if ( aPos.Y() + aSize.Height() > aParentSize.Height() ) + aPos.Y() = aParentSize.Height() - aSize.Height(); + + pFilterBox->SetSizePixel( aSize ); + pFilterBox->Show(); // Show must be called before SetUpdateMode + pFilterBox->SetUpdateMode(sal_False); + + pFilterFloat->SetOutputSizePixel( aSize ); + pFilterFloat->StartPopupMode( aCellRect, FLOATWIN_POPUPMODE_DOWN|FLOATWIN_POPUPMODE_GRABFOCUS); + + // fill the list box + sal_Bool bWait = ( nCount > 100 ); + + if (bWait) + EnterWait(); + + for (i=0; i<nCount; i++) + pFilterBox->InsertEntry( aStrings[i]->GetString() ); + + pFilterBox->SetSeparatorPos( 0 ); + + if (bWait) + LeaveWait(); + + pFilterBox->SetUpdateMode(sal_True); + + sal_uInt16 nSelPos = LISTBOX_ENTRY_NOTFOUND; + if (bHasCurrentPage) + nSelPos = pFilterBox->GetEntryPos( aCurrentPage ); + + if ( nSelPos == LISTBOX_ENTRY_NOTFOUND ) + nSelPos = 0; // first entry + + pFilterBox->GrabFocus(); + + // call Select after GrabFocus, so the focus rectangle ends up in the right position + if ( nSelPos != LISTBOX_ENTRY_NOTFOUND ) + pFilterBox->SelectEntryPos( nSelPos ); + + pFilterBox->EndInit(); + + nMouseStatus = SC_GM_FILTER; + CaptureMouse(); +} + +void ScGridWindow::LaunchDPFieldMenu( SCCOL nCol, SCROW nRow ) +{ + SCTAB nTab = pViewData->GetTabNo(); + ScDPObject* pDPObj = pViewData->GetDocument()->GetDPAtCursor(nCol, nRow, nTab); + if (!pDPObj) + return; + + // Get the geometry of the cell. + Point aScrPos = pViewData->GetScrPos(nCol, nRow, eWhich); + long nSizeX, nSizeY; + pViewData->GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY); + Size aScrSize(nSizeX-1, nSizeY-1); + + DPLaunchFieldPopupMenu(OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol, nRow, nTab), pDPObj); +} + +void ScGridWindow::DoScenarioMenue( const ScRange& rScenRange ) +{ + delete pFilterBox; + delete pFilterFloat; + + SCCOL nCol = rScenRange.aEnd.Col(); // Zelle unterhalb des Buttons + SCROW nRow = rScenRange.aStart.Row(); + if (nRow == 0) + { + nRow = rScenRange.aEnd.Row() + 1; // Bereich ganz oben -> Button unterhalb + if (nRow>MAXROW) nRow = MAXROW; + //! Texthoehe addieren (wenn sie an der View gespeichert ist...) + } + + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + + long nSizeX = 0; + long nSizeY = 0; + long nHeight = 0; + pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); + Point aPos = pViewData->GetScrPos( nCol, nRow, eWhich ); + if ( bLayoutRTL ) + aPos.X() -= nSizeX; + Rectangle aCellRect( OutputToScreenPixel(aPos), Size(nSizeX,nSizeY) ); + aCellRect.Top() -= nSizeY; + aCellRect.Bottom() -= nSizeY - 1; + // Die ListBox direkt unter der schwarzen Linie auf dem Zellgitter + // (wenn die Linie verdeckt wird, sieht es komisch aus...) + + pFilterFloat = new ScFilterFloatingWindow( this, WinBits(WB_BORDER) ); // nicht resizable etc. + pFilterFloat->SetPopupModeEndHdl( LINK( this, ScGridWindow, PopupModeEndHdl ) ); + pFilterBox = new ScFilterListBox( pFilterFloat, this, nCol, nRow, SC_FILTERBOX_SCENARIO ); + if ( bLayoutRTL ) + pFilterBox->EnableMirroring(); + + nSizeX += 1; + + { + Font aOldFont = GetFont(); SetFont( pFilterBox->GetFont() ); + MapMode aOldMode = GetMapMode(); SetMapMode( MAP_PIXEL ); + + nHeight = GetTextHeight(); + nHeight *= SC_FILTERLISTBOX_LINES; + + SetMapMode( aOldMode ); + SetFont( aOldFont ); + } + + // SetSize spaeter +/* + pFilterBox->SetSelectionMode( SINGLE_SELECTION ); + pFilterBox->SetTabs( nFilterBoxTabs, MapUnit( MAP_APPFONT )); + pFilterBox->SetTabJustify( 1, bLayoutRTL ? AdjustRight : AdjustLeft ); +*/ + + // ParentSize Abfrage fehlt + Size aSize( nSizeX, nHeight ); + pFilterBox->SetSizePixel( aSize ); + pFilterBox->Show(); // Show muss vor SetUpdateMode kommen !!! + pFilterBox->SetUpdateMode(sal_False); + + // SetOutputSizePixel/StartPopupMode erst unten, wenn die Groesse feststeht + + // Listbox fuellen + + long nMaxText = 0; + String aCurrent; + String aTabName; + SCTAB nTabCount = pDoc->GetTableCount(); + SCTAB nEntryCount = 0; + for (SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++) + { + if (pDoc->HasScenarioRange( i, rScenRange )) + if (pDoc->GetName( i, aTabName )) + { + pFilterBox->InsertEntry( aTabName ); + if (pDoc->IsActiveScenario(i)) + aCurrent = aTabName; + long nTextWidth = pFilterBox->GetTextWidth( aTabName ); + if ( nTextWidth > nMaxText ) + nMaxText = nTextWidth; + ++nEntryCount; + } + } + if (nEntryCount > SC_FILTERLISTBOX_LINES) + nMaxText += GetSettings().GetStyleSettings().GetScrollBarSize(); + nMaxText += 4; // fuer Rand + if ( nMaxText > 300 ) + nMaxText = 300; // auch nicht uebertreiben (Pixel) + + if (nMaxText > nSizeX) // Groesse auf benoetigte Groesse anpassen + { + long nDiff = nMaxText - nSizeX; + aSize = Size( nMaxText, nHeight ); + pFilterBox->SetSizePixel( aSize ); + pFilterFloat->SetOutputSizePixel( aSize ); + + if ( !bLayoutRTL ) + { + // also move popup position + long nNewX = aCellRect.Left() - nDiff; + if ( nNewX < 0 ) + nNewX = 0; + aCellRect.Left() = nNewX; + } + } + + pFilterFloat->SetOutputSizePixel( aSize ); + pFilterFloat->StartPopupMode( aCellRect, FLOATWIN_POPUPMODE_DOWN|FLOATWIN_POPUPMODE_GRABFOCUS ); + + pFilterBox->SetUpdateMode(sal_True); + pFilterBox->GrabFocus(); + + // Select erst nach GrabFocus, damit das Focus-Rechteck richtig landet +//! SvLBoxEntry* pSelect = NULL; + sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND; + if (aCurrent.Len()) + { + nPos = pFilterBox->GetEntryPos( aCurrent ); +//! pSelect = pFilterBox->GetEntry( nPos ); + } + if (/*!pSelect*/ LISTBOX_ENTRY_NOTFOUND == nPos && pFilterBox->GetEntryCount() > 0 ) + nPos = 0; +//! pSelect = pFilterBox->GetEntry(0); // einer sollte immer selektiert sein + if (/*pSelect*/ LISTBOX_ENTRY_NOTFOUND != nPos ) + pFilterBox->SelectEntryPos(nPos); + + pFilterBox->EndInit(); + + // Szenario-Auswahl kommt aus MouseButtonDown: + // der naechste MouseMove auf die Filterbox ist wie ein ButtonDown + + nMouseStatus = SC_GM_FILTER; + CaptureMouse(); +} + +void ScGridWindow::DoAutoFilterMenue( SCCOL nCol, SCROW nRow, sal_Bool bDataSelect ) +{ + delete pFilterBox; + delete pFilterFloat; + + sal_uInt16 i; + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + + long nSizeX = 0; + long nSizeY = 0; + long nHeight = 0; + pViewData->GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY ); + Point aPos = pViewData->GetScrPos( nCol, nRow, eWhich ); + if ( bLayoutRTL ) + aPos.X() -= nSizeX; + + Rectangle aCellRect( OutputToScreenPixel(aPos), Size(nSizeX,nSizeY) ); + + aPos.X() -= 1; + aPos.Y() += nSizeY - 1; + + pFilterFloat = new ScFilterFloatingWindow( this, WinBits(WB_BORDER) ); // nicht resizable etc. + pFilterFloat->SetPopupModeEndHdl( LINK( this, ScGridWindow, PopupModeEndHdl ) ); + pFilterBox = new ScFilterListBox( + pFilterFloat, this, nCol, nRow, bDataSelect ? SC_FILTERBOX_DATASELECT : SC_FILTERBOX_FILTER ); + if ( bLayoutRTL ) + pFilterBox->EnableMirroring(); + + nSizeX += 1; + + { + Font aOldFont = GetFont(); SetFont( pFilterBox->GetFont() ); + MapMode aOldMode = GetMapMode(); SetMapMode( MAP_PIXEL ); + + nHeight = GetTextHeight(); + nHeight *= SC_FILTERLISTBOX_LINES; + + SetMapMode( aOldMode ); + SetFont( aOldFont ); + } + + // SetSize spaeter +/* + pFilterBox->SetSelectionMode( SINGLE_SELECTION ); + pFilterBox->SetTabs( nFilterBoxTabs, MapUnit( MAP_APPFONT )); + pFilterBox->SetTabJustify( 1, bLayoutRTL ? AdjustRight : AdjustLeft ); +*/ + + sal_Bool bEmpty = sal_False; + TypedScStrCollection aStrings( 128, 128 ); + if ( bDataSelect ) // Auswahl-Liste + { + // Liste fuellen + aStrings.SetCaseSensitive( sal_True ); + pDoc->GetDataEntries( nCol, nRow, nTab, aStrings ); + if ( aStrings.GetCount() == 0 ) + bEmpty = sal_True; + } + else // AutoFilter + { + //! wird der Titel ueberhaupt ausgewertet ??? + String aString; + pDoc->GetString( nCol, nRow, nTab, aString ); + pFilterBox->SetText( aString ); + + long nMaxText = 0; + + // default entries + static const sal_uInt16 nDefIDs[] = { SCSTR_ALLFILTER, SCSTR_TOP10FILTER, SCSTR_STDFILTER }; + const sal_uInt16 nDefCount = sizeof(nDefIDs) / sizeof(sal_uInt16); + for (i=0; i<nDefCount; i++) + { + String aEntry( (ScResId) nDefIDs[i] ); + pFilterBox->InsertEntry( aEntry ); + long nTextWidth = pFilterBox->GetTextWidth( aEntry ); + if ( nTextWidth > nMaxText ) + nMaxText = nTextWidth; + } + pFilterBox->SetSeparatorPos( nDefCount - 1 ); + + // get list entries + bool bHasDates = false; + pDoc->GetFilterEntries( nCol, nRow, nTab, true, aStrings, bHasDates); + pFilterBox->SetListHasDates(bHasDates); + + // check widths of numerical entries (string entries are not included) + // so all numbers are completely visible + sal_uInt16 nCount = aStrings.GetCount(); + for (i=0; i<nCount; i++) + { + TypedStrData* pData = aStrings[i]; + if ( !pData->IsStrData() ) // only numerical entries + { + long nTextWidth = pFilterBox->GetTextWidth( pData->GetString() ); + if ( nTextWidth > nMaxText ) + nMaxText = nTextWidth; + } + } + + // add scrollbar width if needed (string entries are counted here) + // (scrollbar is shown if the box is exactly full?) + if ( nCount + nDefCount >= SC_FILTERLISTBOX_LINES ) + nMaxText += GetSettings().GetStyleSettings().GetScrollBarSize(); + + nMaxText += 4; // for borders + + if ( nMaxText > nSizeX ) + nSizeX = nMaxText; // just modify width - starting position is unchanged + } + + if (!bEmpty) + { + // Position und Groesse an Fenster anpassen + //! vorher Abfrage, ob die Eintraege hineinpassen (Breite) + + Size aParentSize = GetParent()->GetOutputSizePixel(); + Size aSize( nSizeX, nHeight ); + + if ( aSize.Height() > aParentSize.Height() ) + aSize.Height() = aParentSize.Height(); + if ( aPos.Y() + aSize.Height() > aParentSize.Height() ) + aPos.Y() = aParentSize.Height() - aSize.Height(); + + pFilterBox->SetSizePixel( aSize ); + pFilterBox->Show(); // Show muss vor SetUpdateMode kommen !!! + pFilterBox->SetUpdateMode(sal_False); + + pFilterFloat->SetOutputSizePixel( aSize ); + pFilterFloat->StartPopupMode( aCellRect, FLOATWIN_POPUPMODE_DOWN|FLOATWIN_POPUPMODE_GRABFOCUS); + + // Listbox fuellen + sal_uInt16 nCount = aStrings.GetCount(); + sal_Bool bWait = ( nCount > 100 ); + + if (bWait) + EnterWait(); + + for (i=0; i<nCount; i++) + pFilterBox->InsertEntry( aStrings[i]->GetString() ); + + if (bWait) + LeaveWait(); + + pFilterBox->SetUpdateMode(sal_True); + } + +//! SvLBoxEntry* pSelect = NULL; + sal_uInt16 nSelPos = LISTBOX_ENTRY_NOTFOUND; + + if (!bDataSelect) // AutoFilter: aktiven Eintrag selektieren + { + ScDBData* pDBData = pDoc->GetDBAtCursor( nCol, nRow, nTab ); + if (pDBData) + { + ScQueryParam aParam; + pDBData->GetQueryParam( aParam ); // kann nur MAXQUERY Eintraege ergeben + + sal_Bool bValid = sal_True; + for (SCSIZE j=0; j<MAXQUERY && bValid; j++) // bisherige Filter-Einstellungen + if (aParam.GetEntry(j).bDoQuery) + { + //! Abfrage mit DrawButtons zusammenfassen! + + ScQueryEntry& rEntry = aParam.GetEntry(j); + if (j>0) + if (rEntry.eConnect != SC_AND) + bValid = sal_False; + if (rEntry.nField == nCol) + { + if (rEntry.eOp == SC_EQUAL) + { + String* pStr = rEntry.pStr; + if (pStr) + { + nSelPos = pFilterBox->GetEntryPos( *pStr ); +//! pSelect = pFilterBox->GetEntry( nPos ); + } + } + else if (rEntry.eOp == SC_TOPVAL && rEntry.pStr && + rEntry.pStr->EqualsAscii("10")) + nSelPos = SC_AUTOFILTER_TOP10; + else + nSelPos = SC_AUTOFILTER_CUSTOM; + } + } + + if (!bValid) + nSelPos = SC_AUTOFILTER_CUSTOM; + } + } + else + { + + sal_uLong nIndex = ((SfxUInt32Item*)pDoc->GetAttr( + nCol, nRow, nTab, ATTR_VALIDDATA ))->GetValue(); + if ( nIndex ) + { + const ScValidationData* pData = pDoc->GetValidationEntry( nIndex ); + if (pData) + { + TypedStrData* pNew = NULL; + String aDocStr; + pDoc->GetString( nCol, nRow, nTab, aDocStr ); + if ( pDoc->HasValueData( nCol, nRow, nTab ) ) + { + double fVal = pDoc->GetValue(ScAddress(nCol, nRow, nTab)); + pNew = new TypedStrData( aDocStr, fVal, SC_STRTYPE_VALUE ); + } + else + pNew = new TypedStrData( aDocStr, 0.0, SC_STRTYPE_STANDARD ); + + bool bSortList = ( pData->GetListType() == ValidListType::SORTEDASCENDING); + if ( bSortList ) + { + sal_uInt16 nStrIndex; + if (aStrings.Search(pNew,nStrIndex)) + nSelPos = nStrIndex; + } + else + { + sal_uInt16 nCount = aStrings.GetCount(); + for (i = 0; ((i < nCount) && ( LISTBOX_ENTRY_NOTFOUND == nSelPos)); i++) + { + if ( aStrings.Compare(aStrings[i], pNew)==0 ) + nSelPos = i; + } + } + delete pNew; + } + } + } + + // neu (309): irgendwas muss immer selektiert sein: + if ( LISTBOX_ENTRY_NOTFOUND == nSelPos && pFilterBox->GetEntryCount() > 0 && !bDataSelect) + nSelPos = 0; + + // keine leere Auswahl-Liste anzeigen: + + if ( bEmpty ) + { + DELETEZ(pFilterBox); // war nix + DELETEZ(pFilterFloat); + Sound::Beep(); // bemerkbar machen + } + else + { +// pFilterBox->Show(); // schon vorne + pFilterBox->GrabFocus(); + + // Select erst nach GrabFocus, damit das Focus-Rechteck richtig landet + if ( LISTBOX_ENTRY_NOTFOUND != nSelPos ) + pFilterBox->SelectEntryPos( nSelPos ); + else + { + if (bDataSelect) + pFilterBox->SetNoSelection(); + } + + pFilterBox->EndInit(); + + if (!bDataSelect) + { + // AutoFilter (aus MouseButtonDown): + // der naechste MouseMove auf die Filterbox ist wie ein ButtonDown + + nMouseStatus = SC_GM_FILTER; + CaptureMouse(); + } + } +} + +void ScGridWindow::FilterSelect( sal_uLong nSel ) +{ + String aString; +/* + SvLBoxEntry* pEntry = pFilterBox->GetEntry( nSel ); + if (pEntry) + { + SvLBoxString* pStringEntry = (SvLBoxString*) pEntry->GetFirstItem( SV_ITEM_ID_LBOXSTRING ); + if ( pStringEntry ) + aString = pStringEntry->GetText(); + } +*/ + aString = pFilterBox->GetEntry( static_cast< sal_uInt16 >( nSel ) ); + + SCCOL nCol = pFilterBox->GetCol(); + SCROW nRow = pFilterBox->GetRow(); + switch ( pFilterBox->GetMode() ) + { + case SC_FILTERBOX_DATASELECT: + ExecDataSelect( nCol, nRow, aString ); + break; + case SC_FILTERBOX_FILTER: + ExecFilter( nSel, nCol, nRow, aString, pFilterBox->HasDates() ); + break; + case SC_FILTERBOX_SCENARIO: + pViewData->GetView()->UseScenario( aString ); + break; + case SC_FILTERBOX_PAGEFIELD: + // first entry is "all" + ExecPageFieldSelect( nCol, nRow, (nSel != 0), aString ); + break; + } + + if (pFilterFloat) + pFilterFloat->EndPopupMode(); + + GrabFocus(); // unter OS/2 stimmt der Focus sonst nicht +} + +void ScGridWindow::ExecDataSelect( SCCOL nCol, SCROW nRow, const String& rStr ) +{ + if ( rStr.Len() ) + { + SCTAB nTab = pViewData->GetTabNo(); + ScViewFunc* pView = pViewData->GetView(); + pView->EnterData( nCol, nRow, nTab, rStr ); + + // #i52307# CellContentChanged is not in EnterData so it isn't called twice + // if the cursor is moved afterwards. + pView->CellContentChanged(); + } +} + +void ScGridWindow::ExecFilter( sal_uLong nSel, + SCCOL nCol, SCROW nRow, + const String& aValue, bool bCheckForDates ) +{ + SCTAB nTab = pViewData->GetTabNo(); + ScDocument* pDoc = pViewData->GetDocument(); + + ScDBData* pDBData = pDoc->GetDBAtCursor( nCol, nRow, nTab ); + if (pDBData) + { + ScQueryParam aParam; + pDBData->GetQueryParam( aParam ); // kann nur MAXQUERY Eintraege ergeben + + if (SC_AUTOFILTER_CUSTOM == nSel) + { + SCTAB nAreaTab; + SCCOL nStartCol; + SCROW nStartRow; + SCCOL nEndCol; + SCROW nEndRow; + pDBData->GetArea( nAreaTab, nStartCol,nStartRow,nEndCol,nEndRow ); + pViewData->GetView()->MarkRange( ScRange( nStartCol,nStartRow,nAreaTab,nEndCol,nEndRow,nAreaTab)); + pViewData->GetView()->SetCursor(nCol,nRow); //! auch ueber Slot ?? + pViewData->GetDispatcher().Execute( SID_FILTER, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD ); + } + else + { + sal_Bool bDeleteOld = sal_False; + SCSIZE nQueryPos = 0; + sal_Bool bFound = sal_False; + if (!aParam.bInplace) + bDeleteOld = sal_True; + if (aParam.bRegExp) + bDeleteOld = sal_True; + for (SCSIZE i=0; i<MAXQUERY && !bDeleteOld; i++) // bisherige Filter-Einstellungen + if (aParam.GetEntry(i).bDoQuery) + { + //! Abfrage mit DrawButtons zusammenfassen! + + ScQueryEntry& rEntry = aParam.GetEntry(i); + if (i>0) + if (rEntry.eConnect != SC_AND) + bDeleteOld = sal_True; + + if (rEntry.nField == nCol) + { + if (bFound) // diese Spalte zweimal? + bDeleteOld = sal_True; + nQueryPos = i; + bFound = sal_True; + } + if (!bFound) + nQueryPos = i + 1; + } + + if (bDeleteOld) + { + SCSIZE nEC = aParam.GetEntryCount(); + for (SCSIZE i=0; i<nEC; i++) + aParam.GetEntry(i).Clear(); + nQueryPos = 0; + aParam.bInplace = sal_True; + aParam.bRegExp = sal_False; + } + + if ( nQueryPos < MAXQUERY || SC_AUTOFILTER_ALL == nSel ) // loeschen geht immer + { + if (nSel) + { + ScQueryEntry& rNewEntry = aParam.GetEntry(nQueryPos); + + rNewEntry.bDoQuery = sal_True; + rNewEntry.bQueryByString = sal_True; + rNewEntry.nField = nCol; + rNewEntry.bQueryByDate = bCheckForDates; + if ( nSel == SC_AUTOFILTER_TOP10 ) + { + rNewEntry.eOp = SC_TOPVAL; + *rNewEntry.pStr = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("10")); + } + else + { + rNewEntry.eOp = SC_EQUAL; + *rNewEntry.pStr = aValue; + } + if (nQueryPos > 0) + rNewEntry.eConnect = SC_AND; + } + else + { + if (bFound) + aParam.DeleteQuery(nQueryPos); + } + + // #100597# end edit mode - like in ScCellShell::ExecuteDB + if ( pViewData->HasEditView( pViewData->GetActivePart() ) ) + { + SC_MOD()->InputEnterHandler(); + pViewData->GetViewShell()->UpdateInputHandler(); + } + + pViewData->GetView()->Query( aParam, NULL, sal_True ); + pDBData->SetQueryParam( aParam ); // speichern + } + else // "Zuviele Bedingungen" + pViewData->GetView()->ErrorMessage( STR_FILTER_TOOMANY ); + } + } + else + { + DBG_ERROR("Wo ist der Datenbankbereich?"); + } +} + +void ScGridWindow::SetPointer( const Pointer& rPointer ) +{ + nCurrentPointer = 0; + Window::SetPointer( rPointer ); +} + +void ScGridWindow::MoveMouseStatus( ScGridWindow& rDestWin ) +{ + if (nButtonDown) + { + rDestWin.nButtonDown = nButtonDown; + rDestWin.nMouseStatus = nMouseStatus; + } + + if (bRFMouse) + { + rDestWin.bRFMouse = bRFMouse; + rDestWin.bRFSize = bRFSize; + rDestWin.nRFIndex = nRFIndex; + rDestWin.nRFAddX = nRFAddX; + rDestWin.nRFAddY = nRFAddY; + bRFMouse = sal_False; + } + + if (nPagebreakMouse) + { + rDestWin.nPagebreakMouse = nPagebreakMouse; + rDestWin.nPagebreakBreak = nPagebreakBreak; + rDestWin.nPagebreakPrev = nPagebreakPrev; + rDestWin.aPagebreakSource = aPagebreakSource; + rDestWin.aPagebreakDrag = aPagebreakDrag; + nPagebreakMouse = SC_PD_NONE; + } +} + +sal_Bool ScGridWindow::TestMouse( const MouseEvent& rMEvt, sal_Bool bAction ) +{ + // MouseEvent buttons must only be checked if bAction==TRUE + // to allow changing the mouse pointer in MouseMove, + // but not start AutoFill with right button (#74229#). + // with bAction==sal_True, SetFillMode / SetDragMode is called + + if ( bAction && !rMEvt.IsLeft() ) + return sal_False; + + sal_Bool bNewPointer = sal_False; + + SfxInPlaceClient* pClient = pViewData->GetViewShell()->GetIPClient(); + sal_Bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() ); + + if ( pViewData->IsActive() && !bOleActive ) + { + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + + // Auto-Fill + + ScRange aMarkRange; + if (pViewData->GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE) + { + if (aMarkRange.aStart.Tab() == pViewData->GetTabNo() && mpAutoFillRect) + { + Point aMousePos = rMEvt.GetPosPixel(); + if (mpAutoFillRect->IsInside(aMousePos)) + { + SetPointer( Pointer( POINTER_CROSS ) ); //! dickeres Kreuz ? + if (bAction) + { + SCCOL nX = aMarkRange.aEnd.Col(); + SCROW nY = aMarkRange.aEnd.Row(); + + if ( lcl_IsEditableMatrix( pViewData->GetDocument(), aMarkRange ) ) + pViewData->SetDragMode( + aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY, SC_FILL_MATRIX ); + else + pViewData->SetFillMode( + aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY ); + + // #108266# The simple selection must also be recognized when dragging, + // where the Marking flag is set and MarkToSimple won't work anymore. + pViewData->GetMarkData().MarkToSimple(); + } + bNewPointer = sal_True; + } + } + } + + // Embedded-Rechteck + + if (pDoc->IsEmbedded()) + { + ScRange aRange; + pDoc->GetEmbedded( aRange ); + if ( pViewData->GetTabNo() == aRange.aStart.Tab() ) + { + Point aStartPos = pViewData->GetScrPos( aRange.aStart.Col(), aRange.aStart.Row(), eWhich ); + Point aEndPos = pViewData->GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich ); + Point aMousePos = rMEvt.GetPosPixel(); + if ( bLayoutRTL ) + { + aStartPos.X() += 2; + aEndPos.X() += 2; + } + sal_Bool bTop = ( aMousePos.X() >= aStartPos.X()-3 && aMousePos.X() <= aStartPos.X()+1 && + aMousePos.Y() >= aStartPos.Y()-3 && aMousePos.Y() <= aStartPos.Y()+1 ); + sal_Bool bBottom = ( aMousePos.X() >= aEndPos.X()-3 && aMousePos.X() <= aEndPos.X()+1 && + aMousePos.Y() >= aEndPos.Y()-3 && aMousePos.Y() <= aEndPos.Y()+1 ); + if ( bTop || bBottom ) + { + SetPointer( Pointer( POINTER_CROSS ) ); + if (bAction) + { + sal_uInt8 nMode = bTop ? SC_FILL_EMBED_LT : SC_FILL_EMBED_RB; + pViewData->SetDragMode( + aRange.aStart.Col(), aRange.aStart.Row(), + aRange.aEnd.Col(), aRange.aEnd.Row(), nMode ); + } + bNewPointer = sal_True; + } + } + } + } + + if (!bNewPointer && bAction) + { +// SetPointer( POINTER_ARROW ); // in Fu... + pViewData->ResetFillMode(); + } + + return bNewPointer; +} + +void __EXPORT ScGridWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + nNestedButtonState = SC_NESTEDBUTTON_DOWN; + + HandleMouseButtonDown( rMEvt ); + + if ( nNestedButtonState == SC_NESTEDBUTTON_UP ) + { + // #i41690# If an object is deactivated from MouseButtonDown, it might reschedule, + // so MouseButtonUp comes before the MouseButtonDown call is finished. In this case, + // simulate another MouseButtonUp call, so the selection state is consistent. + + nButtonDown = rMEvt.GetButtons(); + FakeButtonUp(); + + if ( IsTracking() ) + EndTracking(); // normally done in VCL as part of MouseButtonUp handling + } + nNestedButtonState = SC_NESTEDBUTTON_NONE; +} + +void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt ) +{ + // We have to check if a context menu is shown and we have an UI + // active inplace client. In that case we have to ignore the event. + // Otherwise we would crash (context menu has been + // opened by inplace client and we would deactivate the inplace client, + // the contex menu is closed by VCL asynchronously which in the end + // would work on deleted objects or the context menu has no parent anymore) + // See #126086# and #128122# + SfxViewShell* pViewSh = pViewData->GetViewShell(); + SfxInPlaceClient* pClient = pViewSh->GetIPClient(); + if ( pClient && + pClient->IsObjectInPlaceActive() && + PopupMenu::IsInExecute() ) + return; + + aCurMousePos = rMEvt.GetPosPixel(); + + // Filter-Popup beendet sich mit eigenem Mausklick, nicht erst beim Klick + // in das GridWindow, darum ist die folgende Abfrage nicht mehr noetig: +#if 0 + // merken, dass FilterBox geloescht wird, damit sichergestellt + // ist, dass in diesem Handler nicht an gleicher Stelle wieder + // eine neue geoeffnet wird. + sal_Bool bWasFilterBox = ( pFilterBox != NULL && + ((Window*)pFilterBox)->IsVisible() && + !pFilterBox->IsDataSelect() ); + SCCOL nOldColFBox = bWasFilterBox ? pFilterBox->GetCol() : 0; + SCROW nOldRowFBox = bWasFilterBox ? pFilterBox->GetRow() : 0; +#endif + + ClickExtern(); // loescht FilterBox, wenn vorhanden + + HideNoteMarker(); // Notiz-Anzeige + + bEEMouse = sal_False; + + ScModule* pScMod = SC_MOD(); + if (pScMod->IsModalMode(pViewData->GetSfxDocShell())) + { + Sound::Beep(); + return; + } + + pScActiveViewShell = pViewData->GetViewShell(); // falls auf Link geklickt wird + nScClickMouseModifier = rMEvt.GetModifier(); // um Control-Klick immer zu erkennen + + sal_Bool bDetective = pViewData->GetViewShell()->IsAuditShell(); + sal_Bool bRefMode = pViewData->IsRefMode(); // Referenz angefangen + sal_Bool bFormulaMode = pScMod->IsFormulaMode(); // naechster Klick -> Referenz + sal_Bool bEditMode = pViewData->HasEditView(eWhich); // auch bei Mode==SC_INPUT_TYPE + sal_Bool bDouble = (rMEvt.GetClicks() == 2); + + // DeactivateIP passiert nur noch bei MarkListHasChanged + + // im GrabFocus Aufruf kann eine Fehlermeldung hochkommen + // (z.B. beim Umbenennen von Tabellen per Tab-Reiter) + + if ( !nButtonDown || !bDouble ) // single (first) click is always valid + nButtonDown = rMEvt.GetButtons(); // set nButtonDown first, so StopMarking works + +// pViewData->GetViewShell()->GetViewFrame()->GetWindow().GrabFocus(); + if ( ( bEditMode && pViewData->GetActivePart() == eWhich ) || !bFormulaMode ) + GrabFocus(); + + // #i31846# need to cancel a double click if the first click has set the "ignore" state, + // but a single (first) click is always valid + if ( nMouseStatus == SC_GM_IGNORE && bDouble ) + { + nButtonDown = 0; + nMouseStatus = SC_GM_NONE; + return; + } + + if ( bDetective ) // Detektiv-Fuell-Modus + { + if ( rMEvt.IsLeft() && !rMEvt.GetModifier() ) + { + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + + SfxInt16Item aPosXItem( SID_RANGE_COL, nPosX ); + SfxInt32Item aPosYItem( SID_RANGE_ROW, nPosY ); + pViewData->GetDispatcher().Execute( SID_FILL_SELECT, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD, + &aPosXItem, &aPosYItem, (void*)0L ); + + } + nButtonDown = 0; + nMouseStatus = SC_GM_NONE; + return; + } + + if (!bDouble) + nMouseStatus = SC_GM_NONE; + + if (!bFormulaMode) + { + if ( pViewData->GetActivePart() != eWhich ) + pViewData->GetView()->ActivatePart( eWhich ); + } + else + { + ScViewSelectionEngine* pSelEng = pViewData->GetView()->GetSelEngine(); + pSelEng->SetWindow(this); + pSelEng->SetWhich(eWhich); + pSelEng->SetVisibleArea( Rectangle(Point(), GetOutputSizePixel()) ); + } + + if (bEditMode && (pViewData->GetRefTabNo() == pViewData->GetTabNo())) + { + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + + EditView* pEditView; + SCCOL nEditCol; + SCROW nEditRow; + pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow ); + SCCOL nEndCol = pViewData->GetEditEndCol(); + SCROW nEndRow = pViewData->GetEditEndRow(); + + if ( nPosX >= (SCsCOL) nEditCol && nPosX <= (SCsCOL) nEndCol && + nPosY >= (SCsROW) nEditRow && nPosY <= (SCsROW) nEndRow ) + { + // #53966# beim Klick in die Tabellen-EditView immer den Focus umsetzen + if (bFormulaMode) // sonst ist es oben schon passiert + GrabFocus(); + + pScMod->SetInputMode( SC_INPUT_TABLE ); + bEEMouse = sal_True; + bEditMode = pEditView->MouseButtonDown( rMEvt ); + return; + } + } + + if (pScMod->GetIsWaterCan()) + { + //! was is mit'm Mac ??? + if ( rMEvt.GetModifier() + rMEvt.GetButtons() == MOUSE_RIGHT ) + { + nMouseStatus = SC_GM_WATERUNDO; + return; + } + } + + // Reihenfolge passend zum angezeigten Cursor: + // RangeFinder, AutoFill, PageBreak, Drawing + + if ( HitRangeFinder( rMEvt.GetPosPixel(), bRFSize, &nRFIndex, &nRFAddX, &nRFAddY ) ) + { + bRFMouse = sal_True; // die anderen Variablen sind oben initialisiert + + if ( pViewData->GetActivePart() != eWhich ) + pViewData->GetView()->ActivatePart( eWhich ); //! schon oben immer ??? + + // CaptureMouse(); + StartTracking(); + return; + } + + sal_Bool bCrossPointer = TestMouse( rMEvt, sal_True ); + if ( bCrossPointer ) + { + if ( bDouble ) + pViewData->GetView()->FillCrossDblClick(); + else + pScMod->InputEnterHandler(); // Autofill etc. + } + + if ( !bCrossPointer ) + { + nPagebreakMouse = HitPageBreak( rMEvt.GetPosPixel(), &aPagebreakSource, + &nPagebreakBreak, &nPagebreakPrev ); + if (nPagebreakMouse) + { + bPagebreakDrawn = sal_False; + // CaptureMouse(); + StartTracking(); + PagebreakMove( rMEvt, sal_False ); + return; + } + } + + if (!bFormulaMode && !bEditMode && rMEvt.IsLeft()) + { + if ( !bCrossPointer && DrawMouseButtonDown(rMEvt) ) + { + //if (DrawHasMarkedObj()) + // pViewData->GetViewShell()->SetDrawShellOrSub(); // Draw-Objekt selektiert + return; + } + + pViewData->GetViewShell()->SetDrawShell( sal_False ); // kein Draw-Objekt selektiert + + // TestMouse schon oben passiert + } + + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + SCTAB nTab = pViewData->GetTabNo(); + ScDocument* pDoc = pViewData->GetDocument(); + + + // + // AutoFilter buttons + // + + if ( !bDouble && !bFormulaMode && rMEvt.IsLeft() ) + { + ScMergeFlagAttr* pAttr = (ScMergeFlagAttr*) + pDoc->GetAttr( nPosX, nPosY, nTab, ATTR_MERGE_FLAG ); + if (pAttr->HasAutoFilter()) + { + if (DoAutoFilterButton(nPosX, nPosY, rMEvt)) + return; + } + if (pAttr->HasButton()) + { + DoPushButton( nPosX, nPosY, rMEvt ); // setzt evtl. bPivotMouse / bDPMouse + return; + } + + // List Validity drop-down button + + if ( bListValButton ) + { + Rectangle aButtonRect = GetListValButtonRect( aListValPos ); + if ( aButtonRect.IsInside( aPos ) ) + { + DoAutoFilterMenue( aListValPos.Col(), aListValPos.Row(), sal_True ); + + nMouseStatus = SC_GM_FILTER; // not set in DoAutoFilterMenue for bDataSelect + CaptureMouse(); + return; + } + } + } + + // + // scenario selection + // + + ScRange aScenRange; + if ( rMEvt.IsLeft() && HasScenarioButton( aPos, aScenRange ) ) + { + DoScenarioMenue( aScenRange ); + return; + } + + // + // Doppelklick angefangen ? + // + + // StopMarking kann aus DrawMouseButtonDown gerufen werden + + if ( nMouseStatus != SC_GM_IGNORE && !bRefMode ) + { + if ( bDouble && !bCrossPointer ) + { + if (nMouseStatus == SC_GM_TABDOWN) + nMouseStatus = SC_GM_DBLDOWN; + } + else + nMouseStatus = SC_GM_TABDOWN; + } + + // + // Links in Edit-Zellen + // + + sal_Bool bAlt = rMEvt.IsMod2(); + if ( !bAlt && rMEvt.IsLeft() && + GetEditUrl(rMEvt.GetPosPixel()) ) // Klick auf Link: Cursor nicht bewegen + { + SetPointer( Pointer( POINTER_REFHAND ) ); + nMouseStatus = SC_GM_URLDOWN; // auch nur dann beim ButtonUp ausfuehren + return; + } + + // + // Gridwin - SelectionEngine + // + + if ( rMEvt.IsLeft() ) + { + ScViewSelectionEngine* pSelEng = pViewData->GetView()->GetSelEngine(); + pSelEng->SetWindow(this); + pSelEng->SetWhich(eWhich); + pSelEng->SetVisibleArea( Rectangle(Point(), GetOutputSizePixel()) ); + + // SelMouseButtonDown an der View setzt noch das bMoveIsShift Flag + if ( pViewData->GetView()->SelMouseButtonDown( rMEvt ) ) + { + if (IsMouseCaptured()) + { + // Tracking statt CaptureMouse, damit sauber abgebrochen werden kann + //! Irgendwann sollte die SelectionEngine selber StartTracking rufen!?! + ReleaseMouse(); + StartTracking(); + } + pViewData->GetMarkData().SetMarking(sal_True); + return; + } + } +} + +void __EXPORT ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + aCurMousePos = rMEvt.GetPosPixel(); + ScDocument* pDoc = pViewData->GetDocument(); + ScMarkData& rMark = pViewData->GetMarkData(); + + // #i41690# detect a MouseButtonUp call from within MouseButtonDown + // (possible through Reschedule from storing an OLE object that is deselected) + + if ( nNestedButtonState == SC_NESTEDBUTTON_DOWN ) + nNestedButtonState = SC_NESTEDBUTTON_UP; + + if (nButtonDown != rMEvt.GetButtons()) + nMouseStatus = SC_GM_IGNORE; // reset und return + + nButtonDown = 0; + + if (nMouseStatus == SC_GM_IGNORE) + { + nMouseStatus = SC_GM_NONE; + // Selection-Engine: Markieren abbrechen + pViewData->GetView()->GetSelEngine()->Reset(); + rMark.SetMarking(sal_False); + if (pViewData->IsAnyFillMode()) + { + pViewData->GetView()->StopRefMode(); + pViewData->ResetFillMode(); + } + StopMarking(); + DrawEndAction(); // Markieren/Verschieben auf Drawing-Layer abbrechen + ReleaseMouse(); + return; + } + + if (nMouseStatus == SC_GM_FILTER) + { + if ( pFilterBox && pFilterBox->GetMode() == SC_FILTERBOX_FILTER ) + { + if (mpFilterButton.get()) + { + bool bFilterActive = IsAutoFilterActive( + pFilterBox->GetCol(), pFilterBox->GetRow(), pViewData->GetTabNo() ); + + mpFilterButton->setHasHiddenMember(bFilterActive); + mpFilterButton->setPopupPressed(false); + HideCursor(); + mpFilterButton->draw(); + ShowCursor(); + } + } + nMouseStatus = SC_GM_NONE; + ReleaseMouse(); + return; // da muss nix mehr passieren + } + + ScModule* pScMod = SC_MOD(); + if (pScMod->IsModalMode(pViewData->GetSfxDocShell())) + return; + + SfxBindings& rBindings = pViewData->GetBindings(); + if (bEEMouse && pViewData->HasEditView( eWhich )) + { + EditView* pEditView; + SCCOL nEditCol; + SCROW nEditRow; + pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow ); + pEditView->MouseButtonUp( rMEvt ); + + if ( rMEvt.IsMiddle() && + GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) + { + // EditView may have pasted from selection + pScMod->InputChanged( pEditView ); + } + else + pScMod->InputSelection( pEditView ); // parentheses etc. + + pViewData->GetView()->InvalidateAttribs(); + rBindings.Invalidate( SID_HYPERLINK_GETLINK ); + bEEMouse = sal_False; + return; + } + + if (bDPMouse) + { + DPMouseButtonUp( rMEvt ); // resets bDPMouse + return; + } + + if (bRFMouse) + { + RFMouseMove( rMEvt, sal_True ); // Range wieder richtigherum + bRFMouse = sal_False; + SetPointer( Pointer( POINTER_ARROW ) ); + ReleaseMouse(); + return; + } + + if (nPagebreakMouse) + { + PagebreakMove( rMEvt, sal_True ); + nPagebreakMouse = SC_PD_NONE; + SetPointer( Pointer( POINTER_ARROW ) ); + ReleaseMouse(); + return; + } + + if (nMouseStatus == SC_GM_WATERUNDO) // Undo im Giesskannenmodus + { + ::svl::IUndoManager* pMgr = pViewData->GetDocShell()->GetUndoManager(); + if ( pMgr->GetUndoActionCount() && pMgr->GetUndoActionId() == STR_UNDO_APPLYCELLSTYLE ) + pMgr->Undo(); + else + Sound::Beep(); + return; + } + + if (DrawMouseButtonUp(rMEvt)) // includes format paint brush handling for drawing objects + return; + + rMark.SetMarking(sal_False); + + SetPointer( Pointer( POINTER_ARROW ) ); + + if (pViewData->IsFillMode() || + ( pViewData->GetFillMode() == SC_FILL_MATRIX && rMEvt.IsMod1() )) + { + nScFillModeMouseModifier = rMEvt.GetModifier(); + SCCOL nStartCol; + SCROW nStartRow; + SCCOL nEndCol; + SCROW nEndRow; + pViewData->GetFillData( nStartCol, nStartRow, nEndCol, nEndRow ); +// DBG_ASSERT( nStartCol==pViewData->GetRefStartX() && nStartRow==pViewData->GetRefStartY(), +// "Block falsch fuer AutoFill" ); + ScRange aDelRange; + sal_Bool bIsDel = pViewData->GetDelMark( aDelRange ); + + ScViewFunc* pView = pViewData->GetView(); + pView->StopRefMode(); + pViewData->ResetFillMode(); + pView->GetFunctionSet()->SetAnchorFlag( sal_False ); // #i5819# don't use AutoFill anchor flag for selection + + if ( bIsDel ) + { + pView->MarkRange( aDelRange, sal_False ); + pView->DeleteContents( IDF_CONTENTS ); + SCTAB nTab = pViewData->GetTabNo(); + ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab ); + if ( aBlockRange != aDelRange ) + { + if ( aDelRange.aStart.Row() == nStartRow ) + aBlockRange.aEnd.SetCol( aDelRange.aStart.Col() - 1 ); + else + aBlockRange.aEnd.SetRow( aDelRange.aStart.Row() - 1 ); + pView->MarkRange( aBlockRange, sal_False ); + } + } + else + pViewData->GetDispatcher().Execute( FID_FILL_AUTO, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD ); + } + else if (pViewData->GetFillMode() == SC_FILL_MATRIX) + { + SCTAB nTab = pViewData->GetTabNo(); + SCCOL nStartCol; + SCROW nStartRow; + SCCOL nEndCol; + SCROW nEndRow; + pViewData->GetFillData( nStartCol, nStartRow, nEndCol, nEndRow ); + ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab ); + SCCOL nFillCol = pViewData->GetRefEndX(); + SCROW nFillRow = pViewData->GetRefEndY(); + ScAddress aEndPos( nFillCol, nFillRow, nTab ); + + ScTabView* pView = pViewData->GetView(); + pView->StopRefMode(); + pViewData->ResetFillMode(); + pView->GetFunctionSet()->SetAnchorFlag( sal_False ); + + if ( aEndPos != aBlockRange.aEnd ) + { + pViewData->GetDocShell()->GetDocFunc().ResizeMatrix( aBlockRange, aEndPos, sal_False ); + pViewData->GetView()->MarkRange( ScRange( aBlockRange.aStart, aEndPos ) ); + } + } + else if (pViewData->IsAnyFillMode()) + { + // Embedded-Area has been changed + ScTabView* pView = pViewData->GetView(); + pView->StopRefMode(); + pViewData->ResetFillMode(); + pView->GetFunctionSet()->SetAnchorFlag( sal_False ); + pViewData->GetDocShell()->UpdateOle(pViewData); + } + + sal_Bool bRefMode = pViewData->IsRefMode(); + if (bRefMode) + pScMod->EndReference(); + + // + // Giesskannen-Modus (Gestalter) + // + + if (pScMod->GetIsWaterCan()) + { + // Abfrage auf Undo schon oben + + ScStyleSheetPool* pStylePool = (ScStyleSheetPool*) + (pViewData->GetDocument()-> + GetStyleSheetPool()); + if ( pStylePool ) + { + SfxStyleSheet* pStyleSheet = (SfxStyleSheet*) + pStylePool->GetActualStyleSheet(); + + if ( pStyleSheet ) + { + SfxStyleFamily eFamily = pStyleSheet->GetFamily(); + + switch ( eFamily ) + { + case SFX_STYLE_FAMILY_PARA: + pViewData->GetView()->SetStyleSheetToMarked( pStyleSheet ); + pViewData->GetView()->DoneBlockMode(); + break; + + case SFX_STYLE_FAMILY_PAGE: + pViewData->GetDocument()->SetPageStyle( pViewData->GetTabNo(), + pStyleSheet->GetName() ); + + ScPrintFunc( pViewData->GetDocShell(), + pViewData->GetViewShell()->GetPrinter(sal_True), + pViewData->GetTabNo() ).UpdatePages(); + + rBindings.Invalidate( SID_STATUS_PAGESTYLE ); + break; + + default: + break; + } + } + } + } + + ScDBFunc* pView = pViewData->GetView(); + ScDocument* pBrushDoc = pView->GetBrushDocument(); + if ( pBrushDoc ) + { + pView->PasteFromClip( IDF_ATTRIB, pBrushDoc ); + if ( !pView->IsPaintBrushLocked() ) + pView->ResetBrushDocument(); // invalidates pBrushDoc pointer + } + + // + // double click (only left button) + // + + sal_Bool bDouble = ( rMEvt.GetClicks() == 2 && rMEvt.IsLeft() ); + if ( bDouble && !bRefMode && nMouseStatus == SC_GM_DBLDOWN && !pScMod->IsRefDialogOpen() ) + { + // data pilot table + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nPosX; + SCsROW nPosY; + SCTAB nTab = pViewData->GetTabNo(); + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + ScDPObject* pDPObj = pDoc->GetDPAtCursor( nPosX, nPosY, nTab ); + if ( pDPObj && pDPObj->GetSaveData()->GetDrillDown() ) + { + ScAddress aCellPos( nPosX, nPosY, pViewData->GetTabNo() ); + + // Check for header drill-down first. + sheet::DataPilotTableHeaderData aData; + pDPObj->GetHeaderPositionData(aCellPos, aData); + + if ( ( aData.Flags & sheet::MemberResultFlags::HASMEMBER ) && + ! ( aData.Flags & sheet::MemberResultFlags::SUBTOTAL ) ) + { + sal_uInt16 nDummy; + if ( pView->HasSelectionForDrillDown( nDummy ) ) + { + // execute slot to show dialog + pViewData->GetDispatcher().Execute( SID_OUTLINE_SHOW, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD ); + } + else + { + // toggle single entry + ScDPObject aNewObj( *pDPObj ); + pDPObj->ToggleDetails( aData, &aNewObj ); + ScDBDocFunc aFunc( *pViewData->GetDocShell() ); + aFunc.DataPilotUpdate( pDPObj, &aNewObj, sal_True, sal_False ); + pViewData->GetView()->CursorPosChanged(); // shells may be switched + } + } + else + { + // Check if the data area is double-clicked. + + Sequence<sheet::DataPilotFieldFilter> aFilters; + if ( pDPObj->GetDataFieldPositionData(aCellPos, aFilters) ) + pViewData->GetView()->ShowDataPilotSourceData( *pDPObj, aFilters ); + else + Sound::Beep(); // nothing to expand/collapse/show + } + + return; + } + + // Check for cell protection attribute. + ScTableProtection* pProtect = pDoc->GetTabProtection( nTab ); + bool bEditAllowed = true; + if ( pProtect && pProtect->isProtected() ) + { + bool bCellProtected = pDoc->HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HASATTR_PROTECTED); + bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + + if ( bSkipProtected && bSkipUnprotected ) + bEditAllowed = false; + else if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) ) + bEditAllowed = false; + } + + if ( bEditAllowed ) + { + // edit cell contents + pViewData->GetViewShell()->UpdateInputHandler(); + pScMod->SetInputMode( SC_INPUT_TABLE ); + if (pViewData->HasEditView(eWhich)) + { + // Text-Cursor gleich an die geklickte Stelle setzen + EditView* pEditView = pViewData->GetEditView( eWhich ); + MouseEvent aEditEvt( rMEvt.GetPosPixel(), 1, MOUSE_SYNTHETIC, MOUSE_LEFT, 0 ); + pEditView->MouseButtonDown( aEditEvt ); + pEditView->MouseButtonUp( aEditEvt ); + } + } + return; + } + + // + // Links in edit cells + // + + sal_Bool bAlt = rMEvt.IsMod2(); + if ( !bAlt && !bRefMode && !bDouble && nMouseStatus == SC_GM_URLDOWN ) + { + // beim ButtonUp nur ausfuehren, wenn ButtonDown auch ueber einer URL war + + String aName, aUrl, aTarget; + if ( GetEditUrl( rMEvt.GetPosPixel(), &aName, &aUrl, &aTarget ) ) + { + nMouseStatus = SC_GM_NONE; // keinen Doppelklick anfangen + ScGlobal::OpenURL( aUrl, aTarget ); + + // fire worksheet_followhyperlink event + uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = pDoc->GetVbaEventProcessor(); + if( xVbaEvents.is() ) try + { + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nPosX; + SCsROW nPosY; + SCTAB nTab = pViewData->GetTabNo(); + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + ScBaseCell* pCell = NULL; + if( lcl_GetHyperlinkCell( pDoc, nPosX, nPosY, nTab, pCell ) ) + { + ScAddress aCellPos( nPosX, nPosY, nTab ); + uno::Reference< table::XCell > xCell( new ScCellObj( pViewData->GetDocShell(), aCellPos ) ); + uno::Sequence< uno::Any > aArgs(1); + aArgs[0] <<= xCell; + xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_FOLLOWHYPERLINK, aArgs ); + } + } + catch( uno::Exception& ) + { + } + + return; + } + } + + // + // Gridwin - SelectionEngine + // + + // SelMouseButtonDown is called only for left button, but SelMouseButtonUp would return + // sal_True for any call, so IsLeft must be checked here, too. + + if ( rMEvt.IsLeft() && pViewData->GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt ) ) + { +// rMark.MarkToSimple(); + pViewData->GetView()->UpdateAutoFillMark(); + + SfxDispatcher* pDisp = pViewData->GetViewShell()->GetDispatcher(); + sal_Bool bFormulaMode = pScMod->IsFormulaMode(); + DBG_ASSERT( pDisp || bFormulaMode, "Cursor auf nicht aktiver View bewegen ?" ); + + // #i14927# execute SID_CURRENTCELL (for macro recording) only if there is no + // multiple selection, so the argument string completely describes the selection, + // and executing the slot won't change the existing selection (executing the slot + // here and from a recorded macro is treated equally) + + if ( pDisp && !bFormulaMode && !rMark.IsMultiMarked() ) + { + String aAddr; // CurrentCell + if( rMark.IsMarked() ) + { +// sal_Bool bKeep = rMark.IsMultiMarked(); //! wohin damit ??? + + ScRange aScRange; + rMark.GetMarkArea( aScRange ); + aScRange.Format( aAddr, SCR_ABS ); + if ( aScRange.aStart == aScRange.aEnd ) + { + // make sure there is a range selection string even for a single cell + String aSingle = aAddr; + aAddr.Append( (sal_Char) ':' ); + aAddr.Append( aSingle ); + } + + //! SID_MARKAREA gibts nicht mehr ??? + //! was passiert beim Markieren mit dem Cursor ??? + } + else // nur Cursor bewegen + { + ScAddress aScAddress( pViewData->GetCurX(), pViewData->GetCurY(), 0 ); + aScAddress.Format( aAddr, SCA_ABS ); + } + + SfxStringItem aPosItem( SID_CURRENTCELL, aAddr ); + pDisp->Execute( SID_CURRENTCELL, SFX_CALLMODE_SLOT | SFX_CALLMODE_RECORD, + &aPosItem, (void*)0L ); + + pViewData->GetView()->InvalidateAttribs(); + } + return; + } +} + +void ScGridWindow::FakeButtonUp() +{ + if ( nButtonDown ) + { + MouseEvent aEvent( aCurMousePos ); // nButtons = 0 -> ignore + MouseButtonUp( aEvent ); + } +} + +void __EXPORT ScGridWindow::MouseMove( const MouseEvent& rMEvt ) +{ + aCurMousePos = rMEvt.GetPosPixel(); + + if ( rMEvt.IsLeaveWindow() && pNoteMarker && !pNoteMarker->IsByKeyboard() ) + HideNoteMarker(); + + ScModule* pScMod = SC_MOD(); + if (pScMod->IsModalMode(pViewData->GetSfxDocShell())) + return; + + // Ob aus dem Edit-Modus Drag&Drop gestartet wurde, bekommt man leider + // nicht anders mit: + + if (bEEMouse && nButtonDown && !rMEvt.GetButtons()) + { + bEEMouse = sal_False; + nButtonDown = 0; + nMouseStatus = SC_GM_NONE; + return; + } + + if (nMouseStatus == SC_GM_IGNORE) + return; + + if (nMouseStatus == SC_GM_WATERUNDO) // Undo im Giesskannenmodus -> nur auf Up warten + return; + + if ( pViewData->GetViewShell()->IsAuditShell() ) // Detektiv-Fuell-Modus + { + SetPointer( Pointer( POINTER_FILL ) ); + return; + } + + if (nMouseStatus == SC_GM_FILTER && pFilterBox) + { + Point aRelPos = pFilterBox->ScreenToOutputPixel( OutputToScreenPixel( rMEvt.GetPosPixel() ) ); + if ( Rectangle(Point(),pFilterBox->GetOutputSizePixel()).IsInside(aRelPos) ) + { + nButtonDown = 0; + nMouseStatus = SC_GM_NONE; + if ( pFilterBox->GetMode() == SC_FILTERBOX_FILTER ) + { + if (mpFilterButton.get()) + { + mpFilterButton->setHasHiddenMember(false); + mpFilterButton->setPopupPressed(false); + HideCursor(); + mpFilterButton->draw(); + ShowCursor(); + } + } + ReleaseMouse(); + pFilterBox->MouseButtonDown( MouseEvent( aRelPos, 1, MOUSE_SIMPLECLICK, MOUSE_LEFT ) ); + return; + } + } + + sal_Bool bFormulaMode = pScMod->IsFormulaMode(); // naechster Klick -> Referenz + + if (bEEMouse && pViewData->HasEditView( eWhich )) + { + EditView* pEditView; + SCCOL nEditCol; + SCROW nEditRow; + pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow ); + pEditView->MouseMove( rMEvt ); + return; + } + + if (bDPMouse) + { + DPMouseMove( rMEvt ); + return; + } + + if (bRFMouse) + { + RFMouseMove( rMEvt, sal_False ); + return; + } + + if (nPagebreakMouse) + { + PagebreakMove( rMEvt, sal_False ); + return; + } + + // anderen Mauszeiger anzeigen? + + sal_Bool bEditMode = pViewData->HasEditView(eWhich); + + //! Testen ob RefMode-Dragging !!! + if ( bEditMode && (pViewData->GetRefTabNo() == pViewData->GetTabNo()) ) + { + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + + EditView* pEditView; + SCCOL nEditCol; + SCROW nEditRow; + pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow ); + SCCOL nEndCol = pViewData->GetEditEndCol(); + SCROW nEndRow = pViewData->GetEditEndRow(); + + if ( nPosX >= (SCsCOL) nEditCol && nPosX <= (SCsCOL) nEndCol && + nPosY >= (SCsROW) nEditRow && nPosY <= (SCsROW) nEndRow ) + { + // Field can only be URL field + sal_Bool bAlt = rMEvt.IsMod2(); + if ( !bAlt && !nButtonDown && pEditView && pEditView->GetFieldUnderMousePointer() ) + SetPointer( Pointer( POINTER_REFHAND ) ); + else if ( pEditView && pEditView->GetEditEngine()->IsVertical() ) + SetPointer( Pointer( POINTER_TEXT_VERTICAL ) ); + else + SetPointer( Pointer( POINTER_TEXT ) ); + return; + } + } + + sal_Bool bWater = SC_MOD()->GetIsWaterCan() || pViewData->GetView()->HasPaintBrush(); + if (bWater) + SetPointer( Pointer(POINTER_FILL) ); + + if (!bWater) + { + sal_Bool bCross = sal_False; + + // Range-Finder + + sal_Bool bCorner; + if ( HitRangeFinder( rMEvt.GetPosPixel(), bCorner ) ) + { + if (bCorner) + SetPointer( Pointer( POINTER_CROSS ) ); + else + SetPointer( Pointer( POINTER_HAND ) ); + bCross = sal_True; + } + + // Page-Break-Modus + + sal_uInt16 nBreakType; + if ( !nButtonDown && pViewData->IsPagebreakMode() && + ( nBreakType = HitPageBreak( rMEvt.GetPosPixel() ) ) != 0 ) + { + PointerStyle eNew = POINTER_ARROW; + switch ( nBreakType ) + { + case SC_PD_RANGE_L: + case SC_PD_RANGE_R: + case SC_PD_BREAK_H: + eNew = POINTER_ESIZE; + break; + case SC_PD_RANGE_T: + case SC_PD_RANGE_B: + case SC_PD_BREAK_V: + eNew = POINTER_SSIZE; + break; + case SC_PD_RANGE_TL: + case SC_PD_RANGE_BR: + eNew = POINTER_SESIZE; + break; + case SC_PD_RANGE_TR: + case SC_PD_RANGE_BL: + eNew = POINTER_NESIZE; + break; + } + SetPointer( Pointer( eNew ) ); + bCross = sal_True; + } + + // Fill-Cursor anzeigen ? + + if ( !bFormulaMode && !nButtonDown ) + if (TestMouse( rMEvt, sal_False )) + bCross = sal_True; + + if ( nButtonDown && pViewData->IsAnyFillMode() ) + { + SetPointer( Pointer( POINTER_CROSS ) ); + bCross = sal_True; + nScFillModeMouseModifier = rMEvt.GetModifier(); // ausgewertet bei AutoFill und Matrix + } + + if (!bCross) + { + sal_Bool bAlt = rMEvt.IsMod2(); + + if (bEditMode) // Edit-Mode muss zuerst kommen! + SetPointer( Pointer( POINTER_ARROW ) ); + else if ( !bAlt && !nButtonDown && + GetEditUrl(rMEvt.GetPosPixel()) ) + SetPointer( Pointer( POINTER_REFHAND ) ); + else if ( DrawMouseMove(rMEvt) ) // setzt Pointer um + return; + } + } + + if ( pViewData->GetView()->GetSelEngine()->SelMouseMove( rMEvt ) ) + return; +} + +void lcl_InitMouseEvent( ::com::sun::star::awt::MouseEvent& rEvent, const MouseEvent& rEvt ) +{ + rEvent.Modifiers = 0; + if ( rEvt.IsShift() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::SHIFT; + if ( rEvt.IsMod1() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD1; + if ( rEvt.IsMod2() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD2; + if ( rEvt.IsMod3() ) + rEvent.Modifiers |= ::com::sun::star::awt::KeyModifier::MOD3; + + rEvent.Buttons = 0; + if ( rEvt.IsLeft() ) + rEvent.Buttons |= ::com::sun::star::awt::MouseButton::LEFT; + if ( rEvt.IsRight() ) + rEvent.Buttons |= ::com::sun::star::awt::MouseButton::RIGHT; + if ( rEvt.IsMiddle() ) + rEvent.Buttons |= ::com::sun::star::awt::MouseButton::MIDDLE; + + rEvent.X = rEvt.GetPosPixel().X(); + rEvent.Y = rEvt.GetPosPixel().Y(); + rEvent.ClickCount = rEvt.GetClicks(); + rEvent.PopupTrigger = sal_False; +} + +long ScGridWindow::PreNotify( NotifyEvent& rNEvt ) +{ + bool bDone = false; + sal_uInt16 nType = rNEvt.GetType(); + if ( nType == EVENT_MOUSEBUTTONUP || nType == EVENT_MOUSEBUTTONDOWN ) + { + Window* pWindow = rNEvt.GetWindow(); + if (pWindow == this && pViewData) + { + SfxViewFrame* pViewFrame = pViewData->GetViewShell()->GetViewFrame(); + if (pViewFrame) + { + com::sun::star::uno::Reference<com::sun::star::frame::XController> xController = pViewFrame->GetFrame().GetController(); + if (xController.is()) + { + ScTabViewObj* pImp = ScTabViewObj::getImplementation( xController ); + if (pImp && pImp->IsMouseListening()) + { + ::com::sun::star::awt::MouseEvent aEvent; + lcl_InitMouseEvent( aEvent, *rNEvt.GetMouseEvent() ); + if ( rNEvt.GetWindow() ) + aEvent.Source = rNEvt.GetWindow()->GetComponentInterface(); + if ( nType == EVENT_MOUSEBUTTONDOWN) + bDone = pImp->MousePressed( aEvent ); + else + bDone = pImp->MouseReleased( aEvent ); + } + } + } + } + } + if (bDone) // event consumed by a listener + { + if ( nType == EVENT_MOUSEBUTTONDOWN ) + { + const MouseEvent* pMouseEvent = rNEvt.GetMouseEvent(); + if ( pMouseEvent->IsRight() && pMouseEvent->GetClicks() == 1 ) + { + // If a listener returned true for a right-click call, also prevent opening the context menu + // (this works only if the context menu is opened on mouse-down) + nMouseStatus = SC_GM_IGNORE; + } + } + + return 1; + } + else + return Window::PreNotify( rNEvt ); +} + +void ScGridWindow::Tracking( const TrackingEvent& rTEvt ) +{ + // Weil die SelectionEngine kein Tracking kennt, die Events nur auf + // die verschiedenen MouseHandler verteilen... + + const MouseEvent& rMEvt = rTEvt.GetMouseEvent(); + + if ( rTEvt.IsTrackingCanceled() ) // alles abbrechen... + { + if (!pViewData->GetView()->IsInActivatePart()) + { + if (bDPMouse) + bDPMouse = sal_False; // gezeichnet wird per bDragRect + if (bDragRect) + { + // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + bDragRect = sal_False; + UpdateDragRectOverlay(); + } + if (bRFMouse) + { + RFMouseMove( rMEvt, sal_True ); // richtig abbrechen geht dabei nicht... + bRFMouse = sal_False; + } + if (nPagebreakMouse) + { + // if (bPagebreakDrawn) + // DrawDragRect( aPagebreakDrag.aStart.Col(), aPagebreakDrag.aStart.Row(), + // aPagebreakDrag.aEnd.Col(), aPagebreakDrag.aEnd.Row(), sal_False ); + bPagebreakDrawn = sal_False; + UpdateDragRectOverlay(); + nPagebreakMouse = SC_PD_NONE; + } + + SetPointer( Pointer( POINTER_ARROW ) ); + StopMarking(); + MouseButtonUp( rMEvt ); // mit Status SC_GM_IGNORE aus StopMarking + + sal_Bool bRefMode = pViewData->IsRefMode(); + if (bRefMode) + SC_MOD()->EndReference(); // #63148# Dialog nicht verkleinert lassen + } + } + else if ( rTEvt.IsTrackingEnded() ) + { + // MouseButtonUp immer mit passenden Buttons (z.B. wegen Testtool, #63148#) + // Schliesslich behauptet der Tracking-Event ja, dass normal beendet und nicht + // abgebrochen wurde. + + MouseEvent aUpEvt( rMEvt.GetPosPixel(), rMEvt.GetClicks(), + rMEvt.GetMode(), nButtonDown, rMEvt.GetModifier() ); + MouseButtonUp( aUpEvt ); + } + else + MouseMove( rMEvt ); +} + +void ScGridWindow::StartDrag( sal_Int8 /* nAction */, const Point& rPosPixel ) +{ + if ( pFilterBox || nPagebreakMouse ) + return; + + HideNoteMarker(); + + CommandEvent aDragEvent( rPosPixel, COMMAND_STARTDRAG, sal_True ); + + if (bEEMouse && pViewData->HasEditView( eWhich )) + { + EditView* pEditView; + SCCOL nEditCol; + SCROW nEditRow; + pViewData->GetEditView( eWhich, pEditView, nEditCol, nEditRow ); + + // #63263# don't remove the edit view while switching views + ScModule* pScMod = SC_MOD(); + pScMod->SetInEditCommand( sal_True ); + + pEditView->Command( aDragEvent ); + + ScInputHandler* pHdl = pScMod->GetInputHdl(); + if (pHdl) + pHdl->DataChanged(); + + pScMod->SetInEditCommand( sal_False ); + if (!pViewData->IsActive()) // dropped to different view? + { + ScInputHandler* pViewHdl = pScMod->GetInputHdl( pViewData->GetViewShell() ); + if ( pViewHdl && pViewData->HasEditView( eWhich ) ) + { + pViewHdl->CancelHandler(); + ShowCursor(); // missing from KillEditView + } + } + } + else + if ( !DrawCommand(aDragEvent) ) + pViewData->GetView()->GetSelEngine()->Command( aDragEvent ); +} + +void lcl_SetTextCursorPos( ScViewData* pViewData, ScSplitPos eWhich, Window* pWin ) +{ + SCCOL nCol = pViewData->GetCurX(); + SCROW nRow = pViewData->GetCurY(); + Rectangle aEditArea = pViewData->GetEditArea( eWhich, nCol, nRow, pWin, NULL, sal_True ); + aEditArea.Right() = aEditArea.Left(); + aEditArea = pWin->PixelToLogic( aEditArea ); + pWin->SetCursorRect( &aEditArea ); +} + +void __EXPORT ScGridWindow::Command( const CommandEvent& rCEvt ) +{ + // The command event is send to the window after a possible context + // menu from an inplace client is closed. Now we have the chance to + // deactivate the inplace client without any problem regarding parent + // windows and code on the stack. + // For more information, see #126086# and #128122# + sal_uInt16 nCmd = rCEvt.GetCommand(); + ScTabViewShell* pTabViewSh = pViewData->GetViewShell(); + SfxInPlaceClient* pClient = pTabViewSh->GetIPClient(); + if ( pClient && + pClient->IsObjectInPlaceActive() && + nCmd == COMMAND_CONTEXTMENU ) + { + pTabViewSh->DeactivateOle(); + return; + } + + ScModule* pScMod = SC_MOD(); + DBG_ASSERT( nCmd != COMMAND_STARTDRAG, "ScGridWindow::Command called with COMMAND_STARTDRAG" ); + + if ( nCmd == COMMAND_STARTEXTTEXTINPUT || + nCmd == COMMAND_ENDEXTTEXTINPUT || + nCmd == COMMAND_EXTTEXTINPUT || + nCmd == COMMAND_CURSORPOS ) + { + sal_Bool bEditView = pViewData->HasEditView( eWhich ); + if (!bEditView) + { + // only if no cell editview is active, look at drawview + SdrView* pSdrView = pViewData->GetView()->GetSdrView(); + if ( pSdrView ) + { + OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView(); + if ( pOlView && pOlView->GetWindow() == this ) + { + pOlView->Command( rCEvt ); + return; // done + } + } + } + + if ( nCmd == COMMAND_CURSORPOS && !bEditView ) + { + // #88458# CURSORPOS may be called without following text input, + // to set the input method window position + // -> input mode must not be started, + // manually calculate text insert position if not in input mode + + lcl_SetTextCursorPos( pViewData, eWhich, this ); + return; + } + + ScInputHandler* pHdl = pScMod->GetInputHdl( pViewData->GetViewShell() ); + if ( pHdl ) + { + pHdl->InputCommand( rCEvt, sal_True ); + return; // done + } + + Window::Command( rCEvt ); + return; + } + + if ( nCmd == COMMAND_VOICE ) + { + // Der Handler wird nur gerufen, wenn ein Text-Cursor aktiv ist, + // also muss es eine EditView oder ein editiertes Zeichenobjekt geben + + ScInputHandler* pHdl = pScMod->GetInputHdl( pViewData->GetViewShell() ); + if ( pHdl && pViewData->HasEditView( eWhich ) ) + { + EditView* pEditView = pViewData->GetEditView( eWhich ); // ist dann nicht 0 + pHdl->DataChanging(); + pEditView->Command( rCEvt ); + pHdl->DataChanged(); + return; // erledigt + } + SdrView* pSdrView = pViewData->GetView()->GetSdrView(); + if ( pSdrView ) + { + OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView(); + if ( pOlView && pOlView->GetWindow() == this ) + { + pOlView->Command( rCEvt ); + return; // erledigt + } + } + Window::Command(rCEvt); // sonst soll sich die Basisklasse drum kuemmern... + return; + } + + if ( nCmd == COMMAND_PASTESELECTION ) + { + if ( bEEMouse ) + { + // EditEngine handles selection in MouseButtonUp - no action + // needed in command handler + } + else + { + PasteSelection( rCEvt.GetMousePosPixel() ); + } + return; + } + + if ( nCmd == COMMAND_INPUTLANGUAGECHANGE ) + { + // #i55929# Font and font size state depends on input language if nothing is selected, + // so the slots have to be invalidated when the input language is changed. + + SfxBindings& rBindings = pViewData->GetBindings(); + rBindings.Invalidate( SID_ATTR_CHAR_FONT ); + rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT ); + return; + } + + if ( nCmd == COMMAND_WHEEL || nCmd == COMMAND_STARTAUTOSCROLL || nCmd == COMMAND_AUTOSCROLL ) + { + sal_Bool bDone = pViewData->GetView()->ScrollCommand( rCEvt, eWhich ); + if (!bDone) + Window::Command(rCEvt); + return; + } + // #i7560# FormulaMode check is below scrolling - scrolling is allowed during formula input + sal_Bool bDisable = pScMod->IsFormulaMode() || + pScMod->IsModalMode(pViewData->GetSfxDocShell()); + if (bDisable) + return; + + if ( nCmd == COMMAND_CONTEXTMENU && !SC_MOD()->GetIsWaterCan() ) + { + sal_Bool bMouse = rCEvt.IsMouseEvent(); + if ( bMouse && nMouseStatus == SC_GM_IGNORE ) + return; + + if (pViewData->IsAnyFillMode()) + { + pViewData->GetView()->StopRefMode(); + pViewData->ResetFillMode(); + } + ReleaseMouse(); + StopMarking(); + + Point aPosPixel = rCEvt.GetMousePosPixel(); + Point aMenuPos = aPosPixel; + + if ( bMouse ) + { + SCsCOL nCellX = -1; + SCsROW nCellY = -1; + pViewData->GetPosFromPixel(aPosPixel.X(), aPosPixel.Y(), eWhich, nCellX, nCellY); + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + const ScTableProtection* pProtect = pDoc->GetTabProtection(nTab); + bool bSelectAllowed = true; + if ( pProtect && pProtect->isProtected() ) + { + // This sheet is protected. Check if a context menu is allowed on this cell. + bool bCellProtected = pDoc->HasAttrib(nCellX, nCellY, nTab, nCellX, nCellY, nTab, HASATTR_PROTECTED); + bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); + bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); + + if (bCellProtected) + bSelectAllowed = bSelProtected; + else + bSelectAllowed = bSelUnprotected; + } + if (!bSelectAllowed) + // Selecting this cell is not allowed, neither is context menu. + return; + + // #i18735# First select the item under the mouse pointer. + // This can change the selection, and the view state (edit mode, etc). + SelectForContextMenu( aPosPixel, nCellX, nCellY ); + } + + sal_Bool bDone = sal_False; + sal_Bool bEdit = pViewData->HasEditView(eWhich); + if ( !bEdit ) + { + // Edit-Zelle mit Spelling-Errors ? + if ( bMouse && GetEditUrlOrError( sal_True, aPosPixel ) ) + { + // GetEditUrlOrError hat den Cursor schon bewegt + + pScMod->SetInputMode( SC_INPUT_TABLE ); + bEdit = pViewData->HasEditView(eWhich); // hat's geklappt ? + + DBG_ASSERT( bEdit, "kann nicht in Edit-Modus schalten" ); + } + } + if ( bEdit ) + { + EditView* pEditView = pViewData->GetEditView( eWhich ); // ist dann nicht 0 + + if ( !bMouse ) + { + Cursor* pCur = pEditView->GetCursor(); + if ( pCur ) + { + Point aLogicPos = pCur->GetPos(); + // use the position right of the cursor (spell popup is opened if + // the cursor is before the word, but not if behind it) + aLogicPos.X() += pCur->GetWidth(); + aLogicPos.Y() += pCur->GetHeight() / 2; // center vertically + aMenuPos = LogicToPixel( aLogicPos ); + } + } + + // if edit mode was just started above, online spelling may be incomplete + pEditView->GetEditEngine()->CompleteOnlineSpelling(); + + // IsCursorAtWrongSpelledWord could be used for !bMouse + // if there was a corresponding ExecuteSpellPopup call + + if( pEditView->IsWrongSpelledWordAtPos( aMenuPos ) ) + { + // Wenn man unter OS/2 neben das Popupmenue klickt, kommt MouseButtonDown + // vor dem Ende des Menue-Execute, darum muss SetModified vorher kommen + // (Bug #40968#) + ScInputHandler* pHdl = pScMod->GetInputHdl(); + if (pHdl) + pHdl->SetModified(); + + Link aLink = LINK( this, ScGridWindow, PopupSpellingHdl ); + pEditView->ExecuteSpellPopup( aMenuPos, &aLink ); + + bDone = sal_True; + } + } + else if ( !bMouse ) + { + // non-edit menu by keyboard -> use lower right of cell cursor position + + SCCOL nCurX = pViewData->GetCurX(); + SCROW nCurY = pViewData->GetCurY(); + aMenuPos = pViewData->GetScrPos( nCurX, nCurY, eWhich, sal_True ); + long nSizeXPix; + long nSizeYPix; + pViewData->GetMergeSizePixel( nCurX, nCurY, nSizeXPix, nSizeYPix ); + aMenuPos.X() += nSizeXPix; + aMenuPos.Y() += nSizeYPix; + + if (pViewData) + { + ScTabViewShell* pViewSh = pViewData->GetViewShell(); + if (pViewSh) + { + // Is a draw object selected? + + SdrView* pDrawView = pViewSh->GetSdrView(); + if (pDrawView && pDrawView->AreObjectsMarked()) + { + // #100442#; the conext menu should open in the middle of the selected objects + Rectangle aSelectRect(LogicToPixel(pDrawView->GetAllMarkedBoundRect())); + aMenuPos = aSelectRect.Center(); + } + } + } + } + + if (!bDone) + { + SfxDispatcher::ExecutePopup( 0, this, &aMenuPos ); + } + } +} + +void ScGridWindow::SelectForContextMenu( const Point& rPosPixel, SCsCOL nCellX, SCsROW nCellY ) +{ + // #i18735# if the click was outside of the current selection, + // the cursor is moved or an object at the click position selected. + // (see SwEditWin::SelectMenuPosition in Writer) + + ScTabView* pView = pViewData->GetView(); + ScDrawView* pDrawView = pView->GetScDrawView(); + + // check cell edit mode + + if ( pViewData->HasEditView(eWhich) ) + { + ScModule* pScMod = SC_MOD(); + SCCOL nEditStartCol = pViewData->GetEditViewCol(); //! change to GetEditStartCol after calcrtl is integrated + SCROW nEditStartRow = pViewData->GetEditViewRow(); + SCCOL nEditEndCol = pViewData->GetEditEndCol(); + SCROW nEditEndRow = pViewData->GetEditEndRow(); + + if ( nCellX >= (SCsCOL) nEditStartCol && nCellX <= (SCsCOL) nEditEndCol && + nCellY >= (SCsROW) nEditStartRow && nCellY <= (SCsROW) nEditEndRow ) + { + // handle selection within the EditView + + EditView* pEditView = pViewData->GetEditView( eWhich ); // not NULL (HasEditView) + EditEngine* pEditEngine = pEditView->GetEditEngine(); + Rectangle aOutputArea = pEditView->GetOutputArea(); + Rectangle aVisArea = pEditView->GetVisArea(); + + Point aTextPos = PixelToLogic( rPosPixel ); + if ( pEditEngine->IsVertical() ) // have to manually transform position + { + aTextPos -= aOutputArea.TopRight(); + long nTemp = -aTextPos.X(); + aTextPos.X() = aTextPos.Y(); + aTextPos.Y() = nTemp; + } + else + aTextPos -= aOutputArea.TopLeft(); + aTextPos += aVisArea.TopLeft(); // position in the edit document + + EPosition aDocPosition = pEditEngine->FindDocPosition(aTextPos); + ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex); + ESelection aSelection = pEditView->GetSelection(); + aSelection.Adjust(); // needed for IsLess/IsGreater + if ( aCompare.IsLess(aSelection) || aCompare.IsGreater(aSelection) ) + { + // clicked outside the selected text - deselect and move text cursor + MouseEvent aEvent( rPosPixel ); + pEditView->MouseButtonDown( aEvent ); + pEditView->MouseButtonUp( aEvent ); + pScMod->InputSelection( pEditView ); + } + + return; // clicked within the edit view - keep edit mode + } + else + { + // outside of the edit view - end edit mode, regardless of cell selection, then continue + pScMod->InputEnterHandler(); + } + } + + // check draw text edit mode + + Point aLogicPos = PixelToLogic( rPosPixel ); // after cell edit mode is ended + if ( pDrawView && pDrawView->GetTextEditObject() && pDrawView->GetTextEditOutlinerView() ) + { + OutlinerView* pOlView = pDrawView->GetTextEditOutlinerView(); + Rectangle aOutputArea = pOlView->GetOutputArea(); + if ( aOutputArea.IsInside( aLogicPos ) ) + { + // handle selection within the OutlinerView + + Outliner* pOutliner = pOlView->GetOutliner(); + const EditEngine& rEditEngine = pOutliner->GetEditEngine(); + Rectangle aVisArea = pOlView->GetVisArea(); + + Point aTextPos = aLogicPos; + if ( pOutliner->IsVertical() ) // have to manually transform position + { + aTextPos -= aOutputArea.TopRight(); + long nTemp = -aTextPos.X(); + aTextPos.X() = aTextPos.Y(); + aTextPos.Y() = nTemp; + } + else + aTextPos -= aOutputArea.TopLeft(); + aTextPos += aVisArea.TopLeft(); // position in the edit document + + EPosition aDocPosition = rEditEngine.FindDocPosition(aTextPos); + ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex); + ESelection aSelection = pOlView->GetSelection(); + aSelection.Adjust(); // needed for IsLess/IsGreater + if ( aCompare.IsLess(aSelection) || aCompare.IsGreater(aSelection) ) + { + // clicked outside the selected text - deselect and move text cursor + // use DrawView to allow extra handling there (none currently) + MouseEvent aEvent( rPosPixel ); + pDrawView->MouseButtonDown( aEvent, this ); + pDrawView->MouseButtonUp( aEvent, this ); + } + + return; // clicked within the edit area - keep edit mode + } + else + { + // Outside of the edit area - end text edit mode, then continue. + // DrawDeselectAll also ends text edit mode and updates the shells. + // If the click was on the edited object, it will be selected again below. + pView->DrawDeselectAll(); + } + } + + // look for existing selection + + sal_Bool bHitSelected = sal_False; + if ( pDrawView && pDrawView->IsMarkedObjHit( aLogicPos ) ) + { + // clicked on selected object -> don't change anything + bHitSelected = sal_True; + } + else if ( pViewData->GetMarkData().IsCellMarked(nCellX, nCellY) ) + { + // clicked on selected cell -> don't change anything + bHitSelected = sal_True; + } + + // select drawing object or move cell cursor + + if ( !bHitSelected ) + { + sal_Bool bWasDraw = ( pDrawView && pDrawView->AreObjectsMarked() ); + sal_Bool bHitDraw = sal_False; + if ( pDrawView ) + { + pDrawView->UnmarkAllObj(); + // Unlock the Internal Layer in order to activate the context menu. + // re-lock in ScDrawView::MarkListHasChanged() + lcl_UnLockComment( pDrawView, pDrawView->GetSdrPageView(), pDrawView->GetModel(), aLogicPos ,pViewData); + bHitDraw = pDrawView->MarkObj( aLogicPos ); + // draw shell is activated in MarkListHasChanged + } + if ( !bHitDraw ) + { + pView->Unmark(); + pView->SetCursor(nCellX, nCellY); + if ( bWasDraw ) + pViewData->GetViewShell()->SetDrawShell( sal_False ); // switch shells + } + } +} + +void __EXPORT ScGridWindow::KeyInput(const KeyEvent& rKEvt) +{ + // #96965# Cursor control for ref input dialog + if( SC_MOD()->IsRefDialogOpen() ) + { + const KeyCode& rKeyCode = rKEvt.GetKeyCode(); + if( !rKeyCode.GetModifier() && (rKeyCode.GetCode() == KEY_F2) ) + { + SC_MOD()->EndReference(); + return; + } + else if( pViewData->GetViewShell()->MoveCursorKeyInput( rKEvt ) ) + { + ScRange aRef( + pViewData->GetRefStartX(), pViewData->GetRefStartY(), pViewData->GetRefStartZ(), + pViewData->GetRefEndX(), pViewData->GetRefEndY(), pViewData->GetRefEndZ() ); + SC_MOD()->SetReference( aRef, pViewData->GetDocument() ); + return; + } + } + // wenn semi-Modeless-SfxChildWindow-Dialog oben, keine KeyInputs: + else if( !pViewData->IsAnyFillMode() ) + { + // query for existing note marker before calling ViewShell's keyboard handling + // which may remove the marker + sal_Bool bHadKeyMarker = ( pNoteMarker && pNoteMarker->IsByKeyboard() ); + ScTabViewShell* pViewSh = pViewData->GetViewShell(); + + if (pViewData->GetDocShell()->GetProgress()) + return; + + if (DrawKeyInput(rKEvt)) + return; + + if (!pViewData->GetView()->IsDrawSelMode() && !DrawHasMarkedObj()) // keine Eingaben im Zeichenmodus + { //! DrawShell abfragen !!! + if (pViewSh->TabKeyInput(rKEvt)) + return; + } + else + if (pViewSh->SfxViewShell::KeyInput(rKEvt)) // von SfxViewShell + return; + + KeyCode aCode = rKEvt.GetKeyCode(); + if ( aCode.GetCode() == KEY_ESCAPE && aCode.GetModifier() == 0 ) + { + if ( bHadKeyMarker ) + HideNoteMarker(); + else + pViewSh->Escape(); + return; + } + if ( aCode.GetCode() == KEY_F1 && aCode.GetModifier() == KEY_MOD1 ) + { + // ctrl-F1 shows or hides the note or redlining info for the cursor position + // (hard-coded because F1 can't be configured) + + if ( bHadKeyMarker ) + HideNoteMarker(); // hide when previously visible + else + ShowNoteMarker( pViewData->GetCurX(), pViewData->GetCurY(), sal_True ); + return; + } + } + + Window::KeyInput(rKEvt); +} + +void ScGridWindow::StopMarking() +{ + DrawEndAction(); // Markieren/Verschieben auf Drawing-Layer abbrechen + + if (nButtonDown) + { + pViewData->GetMarkData().SetMarking(sal_False); + nMouseStatus = SC_GM_IGNORE; + } +} + +void ScGridWindow::UpdateInputContext() +{ + sal_Bool bReadOnly = pViewData->GetDocShell()->IsReadOnly(); + sal_uLong nOptions = bReadOnly ? 0 : ( INPUTCONTEXT_TEXT | INPUTCONTEXT_EXTTEXTINPUT ); + + // when font from InputContext is used, + // it must be taken from the cursor position's cell attributes + + InputContext aContext; + aContext.SetOptions( nOptions ); + SetInputContext( aContext ); +} + +//-------------------------------------------------------- + + // sensitiver Bereich (Pixel) +#define SCROLL_SENSITIVE 20 + +sal_Bool ScGridWindow::DropScroll( const Point& rMousePos ) +{ +/* doch auch auf nicht aktiven Views... + if ( !pViewData->IsActive() ) + return sal_False; +*/ + SCsCOL nDx = 0; + SCsROW nDy = 0; + Size aSize = GetOutputSizePixel(); + + if (aSize.Width() > SCROLL_SENSITIVE * 3) + { + if ( rMousePos.X() < SCROLL_SENSITIVE && pViewData->GetPosX(WhichH(eWhich)) > 0 ) + nDx = -1; + if ( rMousePos.X() >= aSize.Width() - SCROLL_SENSITIVE + && pViewData->GetPosX(WhichH(eWhich)) < MAXCOL ) + nDx = 1; + } + if (aSize.Height() > SCROLL_SENSITIVE * 3) + { + if ( rMousePos.Y() < SCROLL_SENSITIVE && pViewData->GetPosY(WhichV(eWhich)) > 0 ) + nDy = -1; + if ( rMousePos.Y() >= aSize.Height() - SCROLL_SENSITIVE + && pViewData->GetPosY(WhichV(eWhich)) < MAXROW ) + nDy = 1; + } + + if ( nDx != 0 || nDy != 0 ) + { +// if (bDragRect) +// pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + + if ( nDx != 0 ) + pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) ); + if ( nDy != 0 ) + pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) ); + +// if (bDragRect) +// pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + } + + return sal_False; +} + +sal_Bool lcl_TestScenarioRedliningDrop( ScDocument* pDoc, const ScRange& aDragRange) +{ + // Testet, ob bei eingeschalteten RedLining, + // bei einem Drop ein Scenario betroffen ist. + + sal_Bool bReturn = sal_False; + SCTAB nTab = aDragRange.aStart.Tab(); + SCTAB nTabCount = pDoc->GetTableCount(); + + if(pDoc->GetChangeTrack()!=NULL) + { + if( pDoc->IsScenario(nTab) && pDoc->HasScenarioRange(nTab, aDragRange)) + { + bReturn = sal_True; + } + else + { + for(SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++) + { + if(pDoc->HasScenarioRange(i, aDragRange)) + { + bReturn = sal_True; + break; + } + } + } + } + return bReturn; +} + +ScRange lcl_MakeDropRange( SCCOL nPosX, SCROW nPosY, SCTAB nTab, const ScRange& rSource ) +{ + SCCOL nCol1 = nPosX; + SCCOL nCol2 = nCol1 + ( rSource.aEnd.Col() - rSource.aStart.Col() ); + if ( nCol2 > MAXCOL ) + { + nCol1 -= nCol2 - MAXCOL; + nCol2 = MAXCOL; + } + SCROW nRow1 = nPosY; + SCROW nRow2 = nRow1 + ( rSource.aEnd.Row() - rSource.aStart.Row() ); + if ( nRow2 > MAXROW ) + { + nRow1 -= nRow2 - MAXROW; + nRow2 = MAXROW; + } + + return ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ); +} + +//-------------------------------------------------------- + +extern sal_Bool bPasteIsDrop; // viewfun4 -> move to header +extern sal_Bool bPasteIsMove; // viewfun7 -> move to header + +//-------------------------------------------------------- + +sal_Int8 ScGridWindow::AcceptPrivateDrop( const AcceptDropEvent& rEvt ) +{ + if ( rEvt.mbLeaving ) + { + // if (bDragRect) + // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + bDragRect = sal_False; + UpdateDragRectOverlay(); + return rEvt.mnAction; + } + + const ScDragData& rData = SC_MOD()->GetDragData(); + if ( rData.pCellTransfer ) + { + // Don't move source that would include filtered rows. + if ((rEvt.mnAction & DND_ACTION_MOVE) && rData.pCellTransfer->HasFilteredRows()) + { + if (bDragRect) + { + bDragRect = sal_False; + UpdateDragRectOverlay(); + } + return DND_ACTION_NONE; + } + + Point aPos = rEvt.maPosPixel; + + ScDocument* pSourceDoc = rData.pCellTransfer->GetSourceDocument(); + ScDocument* pThisDoc = pViewData->GetDocument(); + if (pSourceDoc == pThisDoc) + { + if ( pThisDoc->HasChartAtPoint(pViewData->GetTabNo(), PixelToLogic(aPos)) ) + { + if (bDragRect) // Rechteck loeschen + { + // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + bDragRect = sal_False; + UpdateDragRectOverlay(); + } + + //! highlight chart? (selection border?) + + sal_Int8 nRet = rEvt.mnAction; +//! if ( rEvt.GetAction() == DROP_LINK ) +//! bOk = rEvt.SetAction( DROP_COPY ); // can't link onto chart + return nRet; + } + } +//! else +//! if ( rEvt.GetAction() == DROP_MOVE ) +//! rEvt.SetAction( DROP_COPY ); // different doc: default=COPY + + + if ( rData.pCellTransfer->GetDragSourceFlags() & SC_DROP_TABLE ) // whole sheet? + { + sal_Bool bOk = pThisDoc->IsDocEditable(); + return bOk ? rEvt.mnAction : 0; // don't draw selection frame + } + + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + + ScRange aSourceRange = rData.pCellTransfer->GetRange(); + SCCOL nSourceStartX = aSourceRange.aStart.Col(); + SCROW nSourceStartY = aSourceRange.aStart.Row(); + SCCOL nSourceEndX = aSourceRange.aEnd.Col(); + SCROW nSourceEndY = aSourceRange.aEnd.Row(); + SCCOL nSizeX = nSourceEndX - nSourceStartX + 1; + SCROW nSizeY = nSourceEndY - nSourceStartY + 1; + + if ( rEvt.mnAction != DND_ACTION_MOVE ) + nSizeY = rData.pCellTransfer->GetNonFilteredRows(); // copy/link: no filtered rows + + SCsCOL nNewDragX = nPosX - rData.pCellTransfer->GetDragHandleX(); + if (nNewDragX<0) nNewDragX=0; + if (nNewDragX+(nSizeX-1) > MAXCOL) + nNewDragX = MAXCOL-(nSizeX-1); + SCsROW nNewDragY = nPosY - rData.pCellTransfer->GetDragHandleY(); + if (nNewDragY<0) nNewDragY=0; + if (nNewDragY+(nSizeY-1) > MAXROW) + nNewDragY = MAXROW-(nSizeY-1); + + // don't break scenario ranges, don't drop on filtered + SCTAB nTab = pViewData->GetTabNo(); + ScRange aDropRange = lcl_MakeDropRange( nNewDragX, nNewDragY, nTab, aSourceRange ); + if ( lcl_TestScenarioRedliningDrop( pThisDoc, aDropRange ) || + lcl_TestScenarioRedliningDrop( pSourceDoc, aSourceRange ) || + ScViewUtil::HasFiltered( aDropRange, pThisDoc) ) + { + if (bDragRect) + { + // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + bDragRect = sal_False; + UpdateDragRectOverlay(); + } + return DND_ACTION_NONE; + } + + InsCellCmd eDragInsertMode = INS_NONE; + Window::PointerState aState = GetPointerState(); + + // check for datapilot item sorting + ScDPObject* pDPObj = NULL; + if ( pThisDoc == pSourceDoc && ( pDPObj = pThisDoc->GetDPAtCursor( nNewDragX, nNewDragY, nTab ) ) != NULL ) + { + // drop on DataPilot table: sort or nothing + + bool bDPSort = false; + if ( pThisDoc->GetDPAtCursor( nSourceStartX, nSourceStartY, aSourceRange.aStart.Tab() ) == pDPObj ) + { + sheet::DataPilotTableHeaderData aDestData; + pDPObj->GetHeaderPositionData( ScAddress(nNewDragX, nNewDragY, nTab), aDestData ); + bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field + + // look through the source range + for (SCROW nRow = aSourceRange.aStart.Row(); bValid && nRow <= aSourceRange.aEnd.Row(); ++nRow ) + for (SCCOL nCol = aSourceRange.aStart.Col(); bValid && nCol <= aSourceRange.aEnd.Col(); ++nCol ) + { + sheet::DataPilotTableHeaderData aSourceData; + pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, aSourceRange.aStart.Tab() ), aSourceData ); + if ( aSourceData.Dimension != aDestData.Dimension || !aSourceData.MemberName.getLength() ) + bValid = false; // empty (subtotal) or different field + } + + if ( bValid ) + { + sal_Bool bIsDataLayout; + String aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout ); + const ScDPSaveDimension* pDim = pDPObj->GetSaveData()->GetExistingDimensionByName( aDimName ); + if ( pDim ) + { + ScRange aOutRange = pDPObj->GetOutRange(); + + sal_uInt16 nOrient = pDim->GetOrientation(); + if ( nOrient == sheet::DataPilotFieldOrientation_COLUMN ) + { + eDragInsertMode = INS_CELLSRIGHT; + nSizeY = aOutRange.aEnd.Row() - nNewDragY + 1; + bDPSort = true; + } + else if ( nOrient == sheet::DataPilotFieldOrientation_ROW ) + { + eDragInsertMode = INS_CELLSDOWN; + nSizeX = aOutRange.aEnd.Col() - nNewDragX + 1; + bDPSort = true; + } + } + } + } + + if ( !bDPSort ) + { + // no valid sorting in a DataPilot table -> disallow + if ( bDragRect ) + { + bDragRect = sal_False; + UpdateDragRectOverlay(); + } + return DND_ACTION_NONE; + } + } + else if ( aState.mnState & KEY_MOD2 ) + { + if ( pThisDoc == pSourceDoc && nTab == aSourceRange.aStart.Tab() ) + { + long nDeltaX = labs( static_cast< long >( nNewDragX - nSourceStartX ) ); + long nDeltaY = labs( static_cast< long >( nNewDragY - nSourceStartY ) ); + if ( nDeltaX <= nDeltaY ) + { + eDragInsertMode = INS_CELLSDOWN; + } + else + { + eDragInsertMode = INS_CELLSRIGHT; + } + + if ( ( eDragInsertMode == INS_CELLSDOWN && nNewDragY <= nSourceEndY && + ( nNewDragX + nSizeX - 1 ) >= nSourceStartX && nNewDragX <= nSourceEndX && + ( nNewDragX != nSourceStartX || nNewDragY >= nSourceStartY ) ) || + ( eDragInsertMode == INS_CELLSRIGHT && nNewDragX <= nSourceEndX && + ( nNewDragY + nSizeY - 1 ) >= nSourceStartY && nNewDragY <= nSourceEndY && + ( nNewDragY != nSourceStartY || nNewDragX >= nSourceStartX ) ) ) + { + if ( bDragRect ) + { + bDragRect = sal_False; + UpdateDragRectOverlay(); + } + return DND_ACTION_NONE; + } + } + else + { + if ( static_cast< long >( nSizeX ) >= static_cast< long >( nSizeY ) ) + { + eDragInsertMode = INS_CELLSDOWN; + + } + else + { + eDragInsertMode = INS_CELLSRIGHT; + } + } + } + + if ( nNewDragX != (SCsCOL) nDragStartX || nNewDragY != (SCsROW) nDragStartY || + nDragStartX+nSizeX-1 != nDragEndX || nDragStartY+nSizeY-1 != nDragEndY || + !bDragRect || eDragInsertMode != meDragInsertMode ) + { + // if (bDragRect) + // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + + nDragStartX = nNewDragX; + nDragStartY = nNewDragY; + nDragEndX = nDragStartX+nSizeX-1; + nDragEndY = nDragStartY+nSizeY-1; + bDragRect = sal_True; + meDragInsertMode = eDragInsertMode; + + // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + + UpdateDragRectOverlay(); + + // show target position as tip help +#if 0 + if (Help::IsQuickHelpEnabled()) + { + ScRange aRange( nDragStartX, nDragStartY, nTab, nDragEndX, nDragEndY, nTab ); + String aHelpStr; + aRange.Format( aHelpStr, SCA_VALID ); // non-3D + + Point aPos = Pointer::GetPosPixel(); + sal_uInt16 nAlign = QUICKHELP_BOTTOM|QUICKHELP_RIGHT; + Rectangle aRect( aPos, aPos ); + Help::ShowQuickHelp(aRect, aHelpStr, nAlign); + } +#endif + } + } + + return rEvt.mnAction; +} + +sal_Int8 ScGridWindow::AcceptDrop( const AcceptDropEvent& rEvt ) +{ + const ScDragData& rData = SC_MOD()->GetDragData(); + if ( rEvt.mbLeaving ) + { + DrawMarkDropObj( NULL ); + if ( rData.pCellTransfer ) + return AcceptPrivateDrop( rEvt ); // hide drop marker for internal D&D + else + return rEvt.mnAction; + } + + if ( pViewData->GetDocShell()->IsReadOnly() ) + return DND_ACTION_NONE; + + + sal_Int8 nRet = DND_ACTION_NONE; + + if (rData.pCellTransfer) + { + ScRange aSource = rData.pCellTransfer->GetRange(); + if ( aSource.aStart.Col() != 0 || aSource.aEnd.Col() != MAXCOL || + aSource.aStart.Row() != 0 || aSource.aEnd.Row() != MAXROW ) + DropScroll( rEvt.maPosPixel ); + + nRet = AcceptPrivateDrop( rEvt ); + } + else + { + if ( rData.aLinkDoc.Len() ) + { + String aThisName; + ScDocShell* pDocSh = pViewData->GetDocShell(); + if (pDocSh && pDocSh->HasName()) + aThisName = pDocSh->GetMedium()->GetName(); + + if ( rData.aLinkDoc != aThisName ) + nRet = rEvt.mnAction; + } + else if (rData.aJumpTarget.Len()) + { + // internal bookmarks (from Navigator) + // local jumps from an unnamed document are possible only within a document + + if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == pViewData->GetDocument() ) + nRet = rEvt.mnAction; + } + else + { + sal_Int8 nMyAction = rEvt.mnAction; + + if ( !rData.pDrawTransfer || + !IsMyModel(rData.pDrawTransfer->GetDragSourceView()) ) // drawing within the document + if ( rEvt.mbDefault && nMyAction == DND_ACTION_MOVE ) + nMyAction = DND_ACTION_COPY; + + ScDocument* pThisDoc = pViewData->GetDocument(); + SdrObject* pHitObj = pThisDoc->GetObjectAtPoint( + pViewData->GetTabNo(), PixelToLogic(rEvt.maPosPixel) ); + if ( pHitObj && nMyAction == DND_ACTION_LINK && !rData.pDrawTransfer ) + { + if ( IsDropFormatSupported(SOT_FORMATSTR_ID_SVXB) + || IsDropFormatSupported(SOT_FORMAT_GDIMETAFILE) + || IsDropFormatSupported(SOT_FORMAT_BITMAP) ) + { + // graphic dragged onto drawing object + DrawMarkDropObj( pHitObj ); + nRet = nMyAction; + } + } + if (!nRet) + DrawMarkDropObj( NULL ); + + if (!nRet) + { + switch ( nMyAction ) + { + case DND_ACTION_COPY: + case DND_ACTION_MOVE: + case DND_ACTION_COPYMOVE: + { + sal_Bool bMove = ( nMyAction == DND_ACTION_MOVE ); + if ( IsDropFormatSupported( SOT_FORMATSTR_ID_EMBED_SOURCE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_LINK_SOURCE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE ) || + IsDropFormatSupported( SOT_FORMAT_STRING ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_SYLK ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_LINK ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_HTML ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_HTML_SIMPLE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_DIF ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_DRAWING ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_SVXB ) || + IsDropFormatSupported( SOT_FORMAT_RTF ) || + IsDropFormatSupported( SOT_FORMAT_GDIMETAFILE ) || + IsDropFormatSupported( SOT_FORMAT_BITMAP ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_SBA_DATAEXCHANGE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_SBA_FIELDDATAEXCHANGE ) || + ( !bMove && ( + IsDropFormatSupported( SOT_FORMAT_FILE_LIST ) || + IsDropFormatSupported( SOT_FORMAT_FILE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_SOLK ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR ) ) ) ) + { + nRet = nMyAction; + } + } + break; + case DND_ACTION_LINK: + if ( IsDropFormatSupported( SOT_FORMATSTR_ID_LINK_SOURCE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_LINK ) || + IsDropFormatSupported( SOT_FORMAT_FILE_LIST ) || + IsDropFormatSupported( SOT_FORMAT_FILE ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_SOLK ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK ) || + IsDropFormatSupported( SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR ) ) + { + nRet = nMyAction; + } + break; + } + + if ( nRet ) + { + // Simple check for protection: It's not known here if the drop will result + // in cells or drawing objects (some formats can be both) and how many cells + // the result will be. But if IsFormatEditable for the drop cell position + // is sal_False (ignores matrix formulas), nothing can be pasted, so the drop + // can already be rejected here. + + Point aPos = rEvt.maPosPixel; + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + SCTAB nTab = pViewData->GetTabNo(); + ScDocument* pDoc = pViewData->GetDocument(); + + ScEditableTester aTester( pDoc, nTab, nPosX,nPosY, nPosX,nPosY ); + if ( !aTester.IsFormatEditable() ) + nRet = DND_ACTION_NONE; // forbidden + } + } + } + + // scroll only for accepted formats + if (nRet) + DropScroll( rEvt.maPosPixel ); + } + + return nRet; +} + +sal_uLong lcl_GetDropFormatId( const uno::Reference<datatransfer::XTransferable>& xTransfer, bool bPreferText = false ) +{ + TransferableDataHelper aDataHelper( xTransfer ); + + if ( !aDataHelper.HasFormat( SOT_FORMATSTR_ID_SBA_DATAEXCHANGE ) ) + { + // use bookmark formats if no sba is present + + if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SOLK ) ) + return SOT_FORMATSTR_ID_SOLK; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR ) ) + return SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK ) ) + return SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR ) ) + return SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR; + } + + sal_uLong nFormatId = 0; + if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_DRAWING ) ) + nFormatId = SOT_FORMATSTR_ID_DRAWING; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SVXB ) ) + nFormatId = SOT_FORMATSTR_ID_SVXB; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE ) ) + { + // If it's a Writer object, insert RTF instead of OLE + + sal_Bool bDoRtf = sal_False; + SotStorageStreamRef xStm; + TransferableObjectDescriptor aObjDesc; + if( aDataHelper.GetTransferableObjectDescriptor( SOT_FORMATSTR_ID_OBJECTDESCRIPTOR, aObjDesc ) && + aDataHelper.GetSotStorageStream( SOT_FORMATSTR_ID_EMBED_SOURCE, xStm ) ) + { + SotStorageRef xStore( new SotStorage( *xStm ) ); + bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) || + aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) ) + && aDataHelper.HasFormat( SOT_FORMAT_RTF ) ); + } + if ( bDoRtf ) + nFormatId = FORMAT_RTF; + else + nFormatId = SOT_FORMATSTR_ID_EMBED_SOURCE; + } + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE ) ) + nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SBA_DATAEXCHANGE ) ) + nFormatId = SOT_FORMATSTR_ID_SBA_DATAEXCHANGE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SBA_FIELDDATAEXCHANGE ) ) + nFormatId = SOT_FORMATSTR_ID_SBA_FIELDDATAEXCHANGE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_BIFF_8 ) ) + nFormatId = SOT_FORMATSTR_ID_BIFF_8; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_BIFF_5 ) ) + nFormatId = SOT_FORMATSTR_ID_BIFF_5; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBED_SOURCE_OLE ) ) + nFormatId = SOT_FORMATSTR_ID_EMBED_SOURCE_OLE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE ) ) + nFormatId = SOT_FORMATSTR_ID_EMBEDDED_OBJ_OLE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ) ) + nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE_OLE; + else if ( aDataHelper.HasFormat( SOT_FORMAT_RTF ) ) + nFormatId = SOT_FORMAT_RTF; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_HTML ) ) + nFormatId = SOT_FORMATSTR_ID_HTML; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_HTML_SIMPLE ) ) + nFormatId = SOT_FORMATSTR_ID_HTML_SIMPLE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SYLK ) ) + nFormatId = SOT_FORMATSTR_ID_SYLK; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK ) ) + nFormatId = SOT_FORMATSTR_ID_LINK; + else if ( bPreferText && aDataHelper.HasFormat( SOT_FORMAT_STRING ) ) // #i86734# the behaviour introduced in #i62773# is wrong when pasting + nFormatId = SOT_FORMAT_STRING; + else if ( aDataHelper.HasFormat( SOT_FORMAT_FILE_LIST ) ) + nFormatId = SOT_FORMAT_FILE_LIST; + else if ( aDataHelper.HasFormat( SOT_FORMAT_FILE ) ) // #i62773# FILE_LIST/FILE before STRING (Unix file managers) + nFormatId = SOT_FORMAT_FILE; + else if ( aDataHelper.HasFormat( SOT_FORMAT_STRING ) ) + nFormatId = SOT_FORMAT_STRING; + else if ( aDataHelper.HasFormat( SOT_FORMAT_GDIMETAFILE ) ) + nFormatId = SOT_FORMAT_GDIMETAFILE; + else if ( aDataHelper.HasFormat( SOT_FORMAT_BITMAP ) ) + nFormatId = SOT_FORMAT_BITMAP; + + return nFormatId; +} + +sal_uLong lcl_GetDropLinkId( const uno::Reference<datatransfer::XTransferable>& xTransfer ) +{ + TransferableDataHelper aDataHelper( xTransfer ); + + sal_uLong nFormatId = 0; + if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE ) ) + nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK_SOURCE_OLE ) ) + nFormatId = SOT_FORMATSTR_ID_LINK_SOURCE_OLE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_LINK ) ) + nFormatId = SOT_FORMATSTR_ID_LINK; + else if ( aDataHelper.HasFormat( SOT_FORMAT_FILE_LIST ) ) + nFormatId = SOT_FORMAT_FILE_LIST; + else if ( aDataHelper.HasFormat( SOT_FORMAT_FILE ) ) + nFormatId = SOT_FORMAT_FILE; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_SOLK ) ) + nFormatId = SOT_FORMATSTR_ID_SOLK; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR ) ) + nFormatId = SOT_FORMATSTR_ID_UNIFORMRESOURCELOCATOR; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK ) ) + nFormatId = SOT_FORMATSTR_ID_NETSCAPE_BOOKMARK; + else if ( aDataHelper.HasFormat( SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR ) ) + nFormatId = SOT_FORMATSTR_ID_FILEGRPDESCRIPTOR; + + return nFormatId; +} + + +sal_Int8 ScGridWindow::ExecutePrivateDrop( const ExecuteDropEvent& rEvt ) +{ + // hide drop marker + // if (bDragRect) + // pViewData->GetView()->DrawDragRect( nDragStartX, nDragStartY, nDragEndX, nDragEndY, eWhich ); + bDragRect = sal_False; + UpdateDragRectOverlay(); + + ScModule* pScMod = SC_MOD(); + const ScDragData& rData = pScMod->GetDragData(); + + return DropTransferObj( rData.pCellTransfer, nDragStartX, nDragStartY, + PixelToLogic(rEvt.maPosPixel), rEvt.mnAction ); +} + +sal_Int8 ScGridWindow::DropTransferObj( ScTransferObj* pTransObj, SCCOL nDestPosX, SCROW nDestPosY, + const Point& rLogicPos, sal_Int8 nDndAction ) +{ + if ( !pTransObj ) + return 0; + + ScDocument* pSourceDoc = pTransObj->GetSourceDocument(); + ScDocShell* pDocSh = pViewData->GetDocShell(); + ScDocument* pThisDoc = pViewData->GetDocument(); + ScViewFunc* pView = pViewData->GetView(); + SCTAB nThisTab = pViewData->GetTabNo(); + sal_uInt16 nFlags = pTransObj->GetDragSourceFlags(); + + sal_Bool bIsNavi = ( nFlags & SC_DROP_NAVIGATOR ) != 0; + sal_Bool bIsMove = ( nDndAction == DND_ACTION_MOVE && !bIsNavi ); + + // workaround for wrong nDndAction on Windows when pressing solely + // the Alt key during drag and drop; + // can be removed after #i79215# has been fixed + if ( meDragInsertMode != INS_NONE ) + { + bIsMove = ( nDndAction & DND_ACTION_MOVE && !bIsNavi ); + } + + sal_Bool bIsLink = ( nDndAction == DND_ACTION_LINK ); + + ScRange aSource = pTransObj->GetRange(); + + // only use visible tab from source range - when dragging within one table, + // all selected tables at the time of dropping are used (handled in MoveBlockTo) + SCTAB nSourceTab = pTransObj->GetVisibleTab(); + aSource.aStart.SetTab( nSourceTab ); + aSource.aEnd.SetTab( nSourceTab ); + + SCCOL nSizeX = aSource.aEnd.Col() - aSource.aStart.Col() + 1; + SCROW nSizeY = (bIsMove ? (aSource.aEnd.Row() - aSource.aStart.Row() + 1) : + pTransObj->GetNonFilteredRows()); // copy/link: no filtered rows + ScRange aDest( nDestPosX, nDestPosY, nThisTab, + nDestPosX + nSizeX - 1, nDestPosY + nSizeY - 1, nThisTab ); + + + /* NOTE: AcceptPrivateDrop() already checked for filtered conditions during + * dragging and adapted drawing of the selection frame. We check here + * (again) because this may actually also be called from PasteSelection(), + * we would have to duplicate determination of flags and destination range + * and would lose the context of the "filtered destination is OK" cases + * below, which is already awkward enough as is. */ + + // Don't move filtered source. + bool bFiltered = (bIsMove && pTransObj->HasFilteredRows()); + if (!bFiltered) + { + if (pSourceDoc != pThisDoc && ((nFlags & SC_DROP_TABLE) || + (!bIsLink && meDragInsertMode == INS_NONE))) + { + // Nothing. Either entire sheet to be dropped, or the one case + // where PasteFromClip() is to be called that handles a filtered + // destination itself. Drag-copy from another document without + // inserting cells. + } + else + // Don't copy or move to filtered destination. + bFiltered = ScViewUtil::HasFiltered( aDest, pThisDoc); + } + + sal_Bool bDone = sal_False; + + if (!bFiltered && pSourceDoc == pThisDoc) + { + if ( nFlags & SC_DROP_TABLE ) // whole sheet? + { + if ( pThisDoc->IsDocEditable() ) + { + SCTAB nSrcTab = aSource.aStart.Tab(); + pViewData->GetDocShell()->MoveTable( nSrcTab, nThisTab, !bIsMove, sal_True ); // with Undo + pView->SetTabNo( nThisTab, sal_True ); + bDone = sal_True; + } + } + else // move/copy block + { + String aChartName; + if (pThisDoc->HasChartAtPoint( nThisTab, rLogicPos, &aChartName )) + { + String aRangeName; + aSource.Format( aRangeName, SCR_ABS_3D, pThisDoc ); + SfxStringItem aNameItem( SID_CHART_NAME, aChartName ); + SfxStringItem aRangeItem( SID_CHART_SOURCE, aRangeName ); + sal_uInt16 nId = bIsMove ? SID_CHART_SOURCE : SID_CHART_ADDSOURCE; + pViewData->GetDispatcher().Execute( nId, SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD, + &aRangeItem, &aNameItem, (void*) NULL ); + bDone = sal_True; + } + else if ( pThisDoc->GetDPAtCursor( nDestPosX, nDestPosY, nThisTab ) ) + { + // drop on DataPilot table: try to sort, fail if that isn't possible + + ScAddress aDestPos( nDestPosX, nDestPosY, nThisTab ); + if ( aDestPos != aSource.aStart ) + bDone = pViewData->GetView()->DataPilotMove( aSource, aDestPos ); + else + bDone = sal_True; // same position: nothing + } + else if ( nDestPosX != aSource.aStart.Col() || nDestPosY != aSource.aStart.Row() || + nSourceTab != nThisTab ) + { + String aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY ); + pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo ); + + bDone = sal_True; + if ( meDragInsertMode != INS_NONE ) + { + // call with bApi = sal_True to avoid error messages in drop handler + bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, sal_True /*bRecord*/, sal_True /*bApi*/, sal_True /*bPartOfPaste*/ ); + if ( bDone ) + { + if ( nThisTab == nSourceTab ) + { + if ( meDragInsertMode == INS_CELLSDOWN && + nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() ) + { + bDone = aSource.Move( 0, nSizeY, 0, pSourceDoc ); + } + else if ( meDragInsertMode == INS_CELLSRIGHT && + nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() ) + { + bDone = aSource.Move( nSizeX, 0, 0, pSourceDoc ); + } + } + pDocSh->UpdateOle( pViewData ); + pView->CellContentChanged(); + } + } + + if ( bDone ) + { + if ( bIsLink ) + { + // call with bApi = sal_True to avoid error messages in drop handler + bDone = pView->LinkBlock( aSource, aDest.aStart, sal_True /*bApi*/ ); + } + else + { + // call with bApi = sal_True to avoid error messages in drop handler + bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove, sal_True /*bRecord*/, sal_True /*bPaint*/, sal_True /*bApi*/ ); + } + } + + if ( bDone && meDragInsertMode != INS_NONE && bIsMove && nThisTab == nSourceTab ) + { + DelCellCmd eCmd = DEL_NONE; + if ( meDragInsertMode == INS_CELLSDOWN ) + { + eCmd = DEL_CELLSUP; + } + else if ( meDragInsertMode == INS_CELLSRIGHT ) + { + eCmd = DEL_CELLSLEFT; + } + + if ( ( eCmd == DEL_CELLSUP && nDestPosX == aSource.aStart.Col() ) || + ( eCmd == DEL_CELLSLEFT && nDestPosY == aSource.aStart.Row() ) ) + { + // call with bApi = sal_True to avoid error messages in drop handler + bDone = pDocSh->GetDocFunc().DeleteCells( aSource, NULL, eCmd, sal_True /*bRecord*/, sal_True /*bApi*/ ); + if ( bDone ) + { + if ( eCmd == DEL_CELLSUP && nDestPosY > aSource.aEnd.Row() ) + { + bDone = aDest.Move( 0, -nSizeY, 0, pThisDoc ); + } + else if ( eCmd == DEL_CELLSLEFT && nDestPosX > aSource.aEnd.Col() ) + { + bDone = aDest.Move( -nSizeX, 0, 0, pThisDoc ); + } + pDocSh->UpdateOle( pViewData ); + pView->CellContentChanged(); + } + } + } + + if ( bDone ) + { + pView->MarkRange( aDest, sal_False, sal_False ); + pView->SetCursor( aDest.aEnd.Col(), aDest.aEnd.Row() ); + } + + pDocSh->GetUndoManager()->LeaveListAction(); + + if (!bDone) + Sound::Beep(); // instead of error message in drop handler + } + else + bDone = sal_True; // nothing to do + } + + if (bDone) + pTransObj->SetDragWasInternal(); // don't delete source in DragFinished + } + else if ( !bFiltered && pSourceDoc ) // between documents + { + if ( nFlags & SC_DROP_TABLE ) // copy/link sheets between documents + { + if ( pThisDoc->IsDocEditable() ) + { + ScDocShell* pSrcShell = pTransObj->GetSourceDocShell(); + + SCTAB nTabs[MAXTABCOUNT]; + + ScMarkData aMark = pTransObj->GetSourceMarkData(); + SCTAB nTabCount = pSourceDoc->GetTableCount(); + SCTAB nTabSelCount = 0; + + for(SCTAB i=0; i<nTabCount; i++) + { + if(aMark.GetTableSelect(i)) + { + nTabs[nTabSelCount++]=i; + for(SCTAB j=i+1;j<nTabCount;j++) + { + if((!pSourceDoc->IsVisible(j))&&(pSourceDoc->IsScenario(j))) + { + nTabs[nTabSelCount++]=j; + i=j; + } + else break; + } + } + } + + pView->ImportTables( pSrcShell,nTabSelCount, nTabs, bIsLink, nThisTab ); + bDone = sal_True; + } + } + else if ( bIsLink ) + { + // as in PasteDDE + // (external references might be used instead?) + + SfxObjectShell* pSourceSh = pSourceDoc->GetDocumentShell(); + DBG_ASSERT(pSourceSh, "drag document has no shell"); + if (pSourceSh) + { + String aUndo = ScGlobal::GetRscString( STR_UNDO_COPY ); + pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo ); + + bDone = sal_True; + if ( meDragInsertMode != INS_NONE ) + { + // call with bApi = sal_True to avoid error messages in drop handler + bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, sal_True /*bRecord*/, sal_True /*bApi*/, sal_True /*bPartOfPaste*/ ); + if ( bDone ) + { + pDocSh->UpdateOle( pViewData ); + pView->CellContentChanged(); + } + } + + if ( bDone ) + { + String aApp = Application::GetAppName(); + String aTopic = pSourceSh->GetTitle( SFX_TITLE_FULLNAME ); + String aItem; + aSource.Format( aItem, SCA_VALID | SCA_TAB_3D, pSourceDoc ); + + // TODO: we could define ocQuote for " + const String aQuote( '"' ); + const String& sSep = ScCompiler::GetNativeSymbol( ocSep); + String aFormula( '=' ); + aFormula += ScCompiler::GetNativeSymbol( ocDde); + aFormula += ScCompiler::GetNativeSymbol( ocOpen); + aFormula += aQuote; + aFormula += aApp; + aFormula += aQuote; + aFormula += sSep; + aFormula += aQuote; + aFormula += aTopic; + aFormula += aQuote; + aFormula += sSep; + aFormula += aQuote; + aFormula += aItem; + aFormula += aQuote; + aFormula += ScCompiler::GetNativeSymbol( ocClose); + + pView->DoneBlockMode(); + pView->InitBlockMode( nDestPosX, nDestPosY, nThisTab ); + pView->MarkCursor( nDestPosX + nSizeX - 1, + nDestPosY + nSizeY - 1, nThisTab ); + + pView->EnterMatrix( aFormula ); + + pView->MarkRange( aDest, sal_False, sal_False ); + pView->SetCursor( aDest.aEnd.Col(), aDest.aEnd.Row() ); + } + + pDocSh->GetUndoManager()->LeaveListAction(); + } + } + else + { + //! HasSelectedBlockMatrixFragment without selected sheet? + //! or don't start dragging on a part of a matrix + + String aUndo = ScGlobal::GetRscString( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY ); + pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo ); + + bDone = sal_True; + if ( meDragInsertMode != INS_NONE ) + { + // call with bApi = sal_True to avoid error messages in drop handler + bDone = pDocSh->GetDocFunc().InsertCells( aDest, NULL, meDragInsertMode, sal_True /*bRecord*/, sal_True /*bApi*/, sal_True /*bPartOfPaste*/ ); + if ( bDone ) + { + pDocSh->UpdateOle( pViewData ); + pView->CellContentChanged(); + } + } + + if ( bDone ) + { + pView->Unmark(); // before SetCursor, so CheckSelectionTransfer isn't called with a selection + pView->SetCursor( nDestPosX, nDestPosY ); + bDone = pView->PasteFromClip( IDF_ALL, pTransObj->GetDocument() ); // clip-doc + if ( bDone ) + { + pView->MarkRange( aDest, sal_False, sal_False ); + pView->SetCursor( aDest.aEnd.Col(), aDest.aEnd.Row() ); + } + } + + pDocSh->GetUndoManager()->LeaveListAction(); + + // no longer call ResetMark here - the inserted block has been selected + // and may have been copied to primary selection + } + } + + sal_Int8 nRet = bDone ? nDndAction : DND_ACTION_NONE; + return nRet; +} + +sal_Int8 ScGridWindow::ExecuteDrop( const ExecuteDropEvent& rEvt ) +{ + DrawMarkDropObj( NULL ); // drawing layer + + ScModule* pScMod = SC_MOD(); + const ScDragData& rData = pScMod->GetDragData(); + if (rData.pCellTransfer) + return ExecutePrivateDrop( rEvt ); + + Point aPos = rEvt.maPosPixel; + + if ( rData.aLinkDoc.Len() ) + { + // try to insert a link + + sal_Bool bOk = sal_True; + String aThisName; + ScDocShell* pDocSh = pViewData->GetDocShell(); + if (pDocSh && pDocSh->HasName()) + aThisName = pDocSh->GetMedium()->GetName(); + + if ( rData.aLinkDoc == aThisName ) // error - no link within a document + bOk = sal_False; + else + { + ScViewFunc* pView = pViewData->GetView(); + if ( rData.aLinkTable.Len() ) + pView->InsertTableLink( rData.aLinkDoc, EMPTY_STRING, EMPTY_STRING, + rData.aLinkTable ); + else if ( rData.aLinkArea.Len() ) + { + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + pView->MoveCursorAbs( nPosX, nPosY, SC_FOLLOW_NONE, sal_False, sal_False ); + + pView->InsertAreaLink( rData.aLinkDoc, EMPTY_STRING, EMPTY_STRING, + rData.aLinkArea, 0 ); + } + else + { + DBG_ERROR("drop with link: no sheet nor area"); + bOk = sal_False; + } + } + + return bOk ? rEvt.mnAction : DND_ACTION_NONE; // don't try anything else + } + + Point aLogicPos = PixelToLogic(aPos); + + if (rData.pDrawTransfer) + { + sal_uInt16 nFlags = rData.pDrawTransfer->GetDragSourceFlags(); + + sal_Bool bIsNavi = ( nFlags & SC_DROP_NAVIGATOR ) != 0; + sal_Bool bIsMove = ( rEvt.mnAction == DND_ACTION_MOVE && !bIsNavi ); + + bPasteIsMove = bIsMove; + + pViewData->GetView()->PasteDraw( aLogicPos, rData.pDrawTransfer->GetModel() ); + + if (bPasteIsMove) + rData.pDrawTransfer->SetDragWasInternal(); + bPasteIsMove = sal_False; + + return rEvt.mnAction; + } + + + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + + if (rData.aJumpTarget.Len()) + { + // internal bookmark (from Navigator) + // bookmark clipboard formats are in PasteScDataObject + + if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == pViewData->GetDocument() ) + { + pViewData->GetViewShell()->InsertBookmark( rData.aJumpText, rData.aJumpTarget, + nPosX, nPosY ); + return rEvt.mnAction; + } + } + + sal_Bool bIsLink = ( rEvt.mnAction == DND_ACTION_LINK ); + + ScDocument* pThisDoc = pViewData->GetDocument(); + SdrObject* pHitObj = pThisDoc->GetObjectAtPoint( pViewData->GetTabNo(), PixelToLogic(aPos) ); + if ( pHitObj && bIsLink ) + { + // dropped on drawing object + // PasteOnDrawObject checks for valid formats + if ( pViewData->GetView()->PasteOnDrawObject( rEvt.maDropEvent.Transferable, pHitObj, sal_True ) ) + return rEvt.mnAction; + } + + sal_Bool bDone = sal_False; + + sal_uLong nFormatId = bIsLink ? + lcl_GetDropLinkId( rEvt.maDropEvent.Transferable ) : + lcl_GetDropFormatId( rEvt.maDropEvent.Transferable ); + if ( nFormatId ) + { + pScMod->SetInExecuteDrop( sal_True ); // #i28468# prevent error messages from PasteDataFormat + bPasteIsDrop = sal_True; + bDone = pViewData->GetView()->PasteDataFormat( + nFormatId, rEvt.maDropEvent.Transferable, nPosX, nPosY, &aLogicPos, bIsLink ); + bPasteIsDrop = sal_False; + pScMod->SetInExecuteDrop( sal_False ); + } + + sal_Int8 nRet = bDone ? rEvt.mnAction : DND_ACTION_NONE; + return nRet; +} + +//-------------------------------------------------------- + +void ScGridWindow::PasteSelection( const Point& rPosPixel ) +{ + Point aLogicPos = PixelToLogic( rPosPixel ); + + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( rPosPixel.X(), rPosPixel.Y(), eWhich, nPosX, nPosY ); + + ScSelectionTransferObj* pOwnSelection = SC_MOD()->GetSelectionTransfer(); + if ( pOwnSelection ) + { + // within Calc + + ScTransferObj* pCellTransfer = pOwnSelection->GetCellData(); + if ( pCellTransfer ) + { + // keep a reference to the data in case the selection is changed during paste + uno::Reference<datatransfer::XTransferable> xRef( pCellTransfer ); + DropTransferObj( pCellTransfer, nPosX, nPosY, aLogicPos, DND_ACTION_COPY ); + } + else + { + ScDrawTransferObj* pDrawTransfer = pOwnSelection->GetDrawData(); + if ( pDrawTransfer ) + { + // keep a reference to the data in case the selection is changed during paste + uno::Reference<datatransfer::XTransferable> xRef( pDrawTransfer ); + + // #96821# bSameDocClipboard argument for PasteDraw is needed + // because only DragData is checked directly inside PasteDraw + pViewData->GetView()->PasteDraw( aLogicPos, pDrawTransfer->GetModel(), sal_False, + pDrawTransfer->GetSourceDocID() == pViewData->GetDocument()->GetDocumentID() ); + } + } + } + else + { + // get selection from system + + TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSelection( this ) ); + uno::Reference<datatransfer::XTransferable> xTransferable = aDataHelper.GetTransferable(); + if ( xTransferable.is() ) + { + sal_uLong nFormatId = lcl_GetDropFormatId( xTransferable, true ); + if ( nFormatId ) + { + bPasteIsDrop = sal_True; + pViewData->GetView()->PasteDataFormat( nFormatId, xTransferable, nPosX, nPosY, &aLogicPos ); + bPasteIsDrop = sal_False; + } + } + } +} + +//-------------------------------------------------------- + +void ScGridWindow::UpdateEditViewPos() +{ + if (pViewData->HasEditView(eWhich)) + { + EditView* pView; + SCCOL nCol; + SCROW nRow; + pViewData->GetEditView( eWhich, pView, nCol, nRow ); + SCCOL nEndCol = pViewData->GetEditEndCol(); + SCROW nEndRow = pViewData->GetEditEndRow(); + + // hide EditView? + + sal_Bool bHide = ( nEndCol<pViewData->GetPosX(eHWhich) || nEndRow<pViewData->GetPosY(eVWhich) ); + if ( SC_MOD()->IsFormulaMode() ) + if ( pViewData->GetTabNo() != pViewData->GetRefTabNo() ) + bHide = sal_True; + + if (bHide) + { + Rectangle aRect = pView->GetOutputArea(); + long nHeight = aRect.Bottom() - aRect.Top(); + aRect.Top() = PixelToLogic(GetOutputSizePixel(), pViewData->GetLogicMode()). + Height() * 2; + aRect.Bottom() = aRect.Top() + nHeight; + pView->SetOutputArea( aRect ); + pView->HideCursor(); + } + else + { + // bForceToTop = sal_True for editing + Rectangle aPixRect = pViewData->GetEditArea( eWhich, nCol, nRow, this, NULL, sal_True ); + Point aScrPos = PixelToLogic( aPixRect.TopLeft(), pViewData->GetLogicMode() ); + + Rectangle aRect = pView->GetOutputArea(); + aRect.SetPos( aScrPos ); + pView->SetOutputArea( aRect ); + pView->ShowCursor(); + } + } +} + +void ScGridWindow::ScrollPixel( long nDifX, long nDifY ) +{ + ClickExtern(); + HideNoteMarker(); + + bIsInScroll = sal_True; + //sal_Bool bXor=DrawBeforeScroll(); + + SetMapMode(MAP_PIXEL); + Scroll( nDifX, nDifY, SCROLL_CHILDREN ); + SetMapMode( GetDrawMapMode() ); // verschobenen MapMode erzeugen + + UpdateEditViewPos(); + + DrawAfterScroll(); //bXor); + bIsInScroll = sal_False; +} + +// Formeln neu zeichnen ------------------------------------------------- + +void ScGridWindow::UpdateFormulas() +{ + if (pViewData->GetView()->IsMinimized()) + return; + + if ( nPaintCount ) + { + // nicht anfangen, verschachtelt zu painten + // (dann wuerde zumindest der MapMode nicht mehr stimmen) + + bNeedsRepaint = sal_True; // -> am Ende vom Paint nochmal Invalidate auf alles + aRepaintPixel = Rectangle(); // alles + return; + } + + SCCOL nX1 = pViewData->GetPosX( eHWhich ); + SCROW nY1 = pViewData->GetPosY( eVWhich ); + SCCOL nX2 = nX1 + pViewData->VisibleCellsX( eHWhich ); + SCROW nY2 = nY1 + pViewData->VisibleCellsY( eVWhich ); + + if (nX2 > MAXCOL) nX2 = MAXCOL; + if (nY2 > MAXROW) nY2 = MAXROW; + + // Draw( nX1, nY1, nX2, nY2, SC_UPDATE_CHANGED ); + + // don't draw directly - instead use OutputData to find changed area and invalidate + + SCROW nPosY = nY1; + + ScDocShell* pDocSh = pViewData->GetDocShell(); + ScDocument* pDoc = pDocSh->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + + pDoc->ExtendHidden( nX1, nY1, nX2, nY2, nTab ); + + Point aScrPos = pViewData->GetScrPos( nX1, nY1, eWhich ); + long nMirrorWidth = GetSizePixel().Width(); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + // unused variable long nLayoutSign = bLayoutRTL ? -1 : 1; + if ( bLayoutRTL ) + { + long nEndPixel = pViewData->GetScrPos( nX2+1, nPosY, eWhich ).X(); + nMirrorWidth = aScrPos.X() - nEndPixel; + aScrPos.X() = nEndPixel + 1; + } + + long nScrX = aScrPos.X(); + long nScrY = aScrPos.Y(); + + double nPPTX = pViewData->GetPPTX(); + double nPPTY = pViewData->GetPPTY(); + + ScTableInfo aTabInfo; + pDoc->FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab, nPPTX, nPPTY, sal_False, sal_False ); + + Fraction aZoomX = pViewData->GetZoomX(); + Fraction aZoomY = pViewData->GetZoomY(); + ScOutputData aOutputData( this, OUTTYPE_WINDOW, aTabInfo, pDoc, nTab, + nScrX, nScrY, nX1, nY1, nX2, nY2, nPPTX, nPPTY, + &aZoomX, &aZoomY ); + aOutputData.SetMirrorWidth( nMirrorWidth ); + + aOutputData.FindChanged(); + + PolyPolygon aChangedPoly( aOutputData.GetChangedArea() ); // logic (PixelToLogic) + if ( aChangedPoly.Count() ) + { + Invalidate( aChangedPoly ); + } + + CheckNeedsRepaint(); // #i90362# used to be called via Draw() - still needed here +} + +void ScGridWindow::UpdateAutoFillMark(sal_Bool bMarked, const ScRange& rMarkRange) +{ + if ( bMarked != bAutoMarkVisible || ( bMarked && rMarkRange.aEnd != aAutoMarkPos ) ) + { + HideCursor(); + bAutoMarkVisible = bMarked; + if ( bMarked ) + aAutoMarkPos = rMarkRange.aEnd; + ShowCursor(); + + UpdateAutoFillOverlay(); + } +} + +void ScGridWindow::UpdateListValPos( sal_Bool bVisible, const ScAddress& rPos ) +{ + sal_Bool bOldButton = bListValButton; + ScAddress aOldPos = aListValPos; + + bListValButton = bVisible; + aListValPos = rPos; + + if ( bListValButton ) + { + if ( !bOldButton || aListValPos != aOldPos ) + { + // paint area of new button + Invalidate( PixelToLogic( GetListValButtonRect( aListValPos ) ) ); + } + } + if ( bOldButton ) + { + if ( !bListValButton || aListValPos != aOldPos ) + { + // paint area of old button + Invalidate( PixelToLogic( GetListValButtonRect( aOldPos ) ) ); + } + } +} + +void ScGridWindow::HideCursor() +{ + ++nCursorHideCount; + if (nCursorHideCount==1) + { + DrawCursor(); + DrawAutoFillMark(); + } +} + +void ScGridWindow::ShowCursor() +{ + if (nCursorHideCount==0) + { + DBG_ERROR("zuviel ShowCursor"); + return; + } + + if (nCursorHideCount==1) + { + // #i57745# Draw the cursor before setting the variable, in case the + // GetSizePixel call from drawing causes a repaint (resize handler is called) + DrawAutoFillMark(); + DrawCursor(); + } + + --nCursorHideCount; +} + +void __EXPORT ScGridWindow::GetFocus() +{ + ScTabViewShell* pViewShell = pViewData->GetViewShell(); + pViewShell->GotFocus(); + pViewShell->SetFormShellAtTop( sal_False ); // focus in GridWindow -> FormShell no longer on top + + if (pViewShell->HasAccessibilityObjects()) + pViewShell->BroadcastAccessibility(ScAccGridWinFocusGotHint(eWhich, GetAccessible())); + + + if ( !SC_MOD()->IsFormulaMode() ) + { + pViewShell->UpdateInputHandler(); +// StopMarking(); // falls Dialog (Fehler), weil dann kein ButtonUp + // MO: nur wenn nicht im RefInput-Modus + // -> GetFocus/MouseButtonDown-Reihenfolge + // auf dem Mac + } + + Window::GetFocus(); +} + +void __EXPORT ScGridWindow::LoseFocus() +{ + ScTabViewShell* pViewShell = pViewData->GetViewShell(); + pViewShell->LostFocus(); + + if (pViewShell->HasAccessibilityObjects()) + pViewShell->BroadcastAccessibility(ScAccGridWinFocusLostHint(eWhich, GetAccessible())); + + Window::LoseFocus(); +} + +Point ScGridWindow::GetMousePosPixel() const { return aCurMousePos; } + +//------------------------------------------------------------------------ + +sal_Bool ScGridWindow::HitRangeFinder( const Point& rMouse, sal_Bool& rCorner, + sal_uInt16* pIndex, SCsCOL* pAddX, SCsROW* pAddY ) +{ + sal_Bool bFound = sal_False; + ScInputHandler* pHdl = SC_MOD()->GetInputHdl( pViewData->GetViewShell() ); + if (pHdl) + { + ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList(); + if ( pRangeFinder && !pRangeFinder->IsHidden() && + pRangeFinder->GetDocName() == pViewData->GetDocShell()->GetTitle() ) + { + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + long nLayoutSign = bLayoutRTL ? -1 : 1; + + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( rMouse.X(), rMouse.Y(), eWhich, nPosX, nPosY ); + // zusammengefasste (einzeln/Bereich) ??? + ScAddress aAddr( nPosX, nPosY, nTab ); + +// Point aNext = pViewData->GetScrPos( nPosX+1, nPosY+1, eWhich ); + + Point aNext = pViewData->GetScrPos( nPosX, nPosY, eWhich, sal_True ); + long nSizeXPix; + long nSizeYPix; + pViewData->GetMergeSizePixel( nPosX, nPosY, nSizeXPix, nSizeYPix ); + aNext.X() += nSizeXPix * nLayoutSign; + aNext.Y() += nSizeYPix; + + sal_Bool bCornerHor; + if ( bLayoutRTL ) + bCornerHor = ( rMouse.X() >= aNext.X() && rMouse.X() <= aNext.X() + 8 ); + else + bCornerHor = ( rMouse.X() >= aNext.X() - 8 && rMouse.X() <= aNext.X() ); + + sal_Bool bCellCorner = ( bCornerHor && + rMouse.Y() >= aNext.Y() - 8 && rMouse.Y() <= aNext.Y() ); + // corner is hit only if the mouse is within the cell + + sal_uInt16 nCount = (sal_uInt16)pRangeFinder->Count(); + for (sal_uInt16 i=nCount; i;) + { + // rueckwaerts suchen, damit der zuletzt gepaintete Rahmen gefunden wird + --i; + ScRangeFindData* pData = pRangeFinder->GetObject(i); + if ( pData && pData->aRef.In(aAddr) ) + { + if (pIndex) *pIndex = i; + if (pAddX) *pAddX = nPosX - pData->aRef.aStart.Col(); + if (pAddY) *pAddY = nPosY - pData->aRef.aStart.Row(); + bFound = sal_True; + rCorner = ( bCellCorner && aAddr == pData->aRef.aEnd ); + break; + } + } + } + } + return bFound; +} + +#define SCE_TOP 1 +#define SCE_BOTTOM 2 +#define SCE_LEFT 4 +#define SCE_RIGHT 8 +#define SCE_ALL 15 + +void lcl_PaintOneRange( ScDocShell* pDocSh, const ScRange& rRange, sal_uInt16 nEdges ) +{ + // der Range ist immer richtigherum + + SCCOL nCol1 = rRange.aStart.Col(); + SCROW nRow1 = rRange.aStart.Row(); + SCTAB nTab1 = rRange.aStart.Tab(); + SCCOL nCol2 = rRange.aEnd.Col(); + SCROW nRow2 = rRange.aEnd.Row(); + SCTAB nTab2 = rRange.aEnd.Tab(); + sal_Bool bHiddenEdge = sal_False; + SCROW nTmp; + + ScDocument* pDoc = pDocSh->GetDocument(); + while ( nCol1 > 0 && pDoc->ColHidden(nCol1, nTab1) ) + { + --nCol1; + bHiddenEdge = sal_True; + } + while ( nCol2 < MAXCOL && pDoc->ColHidden(nCol2, nTab1) ) + { + ++nCol2; + bHiddenEdge = sal_True; + } + nTmp = pDoc->FirstVisibleRow(0, nRow1, nTab1); + if (!ValidRow(nTmp)) + nTmp = 0; + if (nTmp < nRow1) + { + nRow1 = nTmp; + bHiddenEdge = sal_True; + } + nTmp = pDoc->FirstVisibleRow(nRow2, MAXROW, nTab1); + if (!ValidRow(nTmp)) + nTmp = MAXROW; + if (nTmp > nRow2) + { + nRow2 = nTmp; + bHiddenEdge = sal_True; + } + + if ( nCol2 > nCol1 + 1 && nRow2 > nRow1 + 1 && !bHiddenEdge ) + { + // nur an den Raendern entlang + // (die Ecken werden evtl. zweimal getroffen) + + if ( nEdges & SCE_TOP ) + pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow1, nTab2, PAINT_MARKS ); + if ( nEdges & SCE_LEFT ) + pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol1, nRow2, nTab2, PAINT_MARKS ); + if ( nEdges & SCE_RIGHT ) + pDocSh->PostPaint( nCol2, nRow1, nTab1, nCol2, nRow2, nTab2, PAINT_MARKS ); + if ( nEdges & SCE_BOTTOM ) + pDocSh->PostPaint( nCol1, nRow2, nTab1, nCol2, nRow2, nTab2, PAINT_MARKS ); + } + else // everything in one call + pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, PAINT_MARKS ); +} + +void lcl_PaintRefChanged( ScDocShell* pDocSh, const ScRange& rOldUn, const ScRange& rNewUn ) +{ + // Repaint fuer die Teile des Rahmens in Old, die bei New nicht mehr da sind + + ScRange aOld = rOldUn; + ScRange aNew = rNewUn; + aOld.Justify(); + aNew.Justify(); + + if ( aOld.aStart == aOld.aEnd ) //! Tab ignorieren? + pDocSh->GetDocument()->ExtendMerge(aOld); + if ( aNew.aStart == aNew.aEnd ) //! Tab ignorieren? + pDocSh->GetDocument()->ExtendMerge(aNew); + + SCCOL nOldCol1 = aOld.aStart.Col(); + SCROW nOldRow1 = aOld.aStart.Row(); + SCCOL nOldCol2 = aOld.aEnd.Col(); + SCROW nOldRow2 = aOld.aEnd.Row(); + SCCOL nNewCol1 = aNew.aStart.Col(); + SCROW nNewRow1 = aNew.aStart.Row(); + SCCOL nNewCol2 = aNew.aEnd.Col(); + SCROW nNewRow2 = aNew.aEnd.Row(); + SCTAB nTab1 = aOld.aStart.Tab(); // Tab aendert sich nicht + SCTAB nTab2 = aOld.aEnd.Tab(); + + if ( nNewRow2 < nOldRow1 || nNewRow1 > nOldRow2 || + nNewCol2 < nOldCol1 || nNewCol1 > nOldCol2 || + ( nNewCol1 != nOldCol1 && nNewRow1 != nOldRow1 && + nNewCol2 != nOldCol2 && nNewRow2 != nOldRow2 ) ) + { + // komplett weggeschoben oder alle Seiten veraendert + // (Abfrage <= statt < geht schief bei einzelnen Zeilen/Spalten) + + lcl_PaintOneRange( pDocSh, aOld, SCE_ALL ); + } + else // alle vier Kanten einzeln testen + { + // oberer Teil + if ( nNewRow1 < nOldRow1 ) // nur obere Linie loeschen + lcl_PaintOneRange( pDocSh, ScRange( + nOldCol1, nOldRow1, nTab1, nOldCol2, nOldRow1, nTab2 ), SCE_ALL ); + else if ( nNewRow1 > nOldRow1 ) // den Teil, der oben wegkommt + lcl_PaintOneRange( pDocSh, ScRange( + nOldCol1, nOldRow1, nTab1, nOldCol2, nNewRow1-1, nTab2 ), + SCE_ALL &~ SCE_BOTTOM ); + + // unterer Teil + if ( nNewRow2 > nOldRow2 ) // nur untere Linie loeschen + lcl_PaintOneRange( pDocSh, ScRange( + nOldCol1, nOldRow2, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL ); + else if ( nNewRow2 < nOldRow2 ) // den Teil, der unten wegkommt + lcl_PaintOneRange( pDocSh, ScRange( + nOldCol1, nNewRow2+1, nTab1, nOldCol2, nOldRow2, nTab2 ), + SCE_ALL &~ SCE_TOP ); + + // linker Teil + if ( nNewCol1 < nOldCol1 ) // nur linke Linie loeschen + lcl_PaintOneRange( pDocSh, ScRange( + nOldCol1, nOldRow1, nTab1, nOldCol1, nOldRow2, nTab2 ), SCE_ALL ); + else if ( nNewCol1 > nOldCol1 ) // den Teil, der links wegkommt + lcl_PaintOneRange( pDocSh, ScRange( + nOldCol1, nOldRow1, nTab1, nNewCol1-1, nOldRow2, nTab2 ), + SCE_ALL &~ SCE_RIGHT ); + + // rechter Teil + if ( nNewCol2 > nOldCol2 ) // nur rechte Linie loeschen + lcl_PaintOneRange( pDocSh, ScRange( + nOldCol2, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL ); + else if ( nNewCol2 < nOldCol2 ) // den Teil, der rechts wegkommt + lcl_PaintOneRange( pDocSh, ScRange( + nNewCol2+1, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ), + SCE_ALL &~ SCE_LEFT ); + } +} + +void ScGridWindow::RFMouseMove( const MouseEvent& rMEvt, sal_Bool bUp ) +{ + ScInputHandler* pHdl = SC_MOD()->GetInputHdl( pViewData->GetViewShell() ); + if (!pHdl) + return; + ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList(); + if (!pRangeFinder || nRFIndex >= pRangeFinder->Count()) + return; + ScRangeFindData* pData = pRangeFinder->GetObject( nRFIndex ); + if (!pData) + return; + + // Mauszeiger + + if (bRFSize) + SetPointer( Pointer( POINTER_CROSS ) ); + else + SetPointer( Pointer( POINTER_HAND ) ); + + // Scrolling + + sal_Bool bTimer = sal_False; + Point aPos = rMEvt.GetPosPixel(); + SCsCOL nDx = 0; + SCsROW nDy = 0; + if ( aPos.X() < 0 ) nDx = -1; + if ( aPos.Y() < 0 ) nDy = -1; + Size aSize = GetOutputSizePixel(); + if ( aPos.X() >= aSize.Width() ) + nDx = 1; + if ( aPos.Y() >= aSize.Height() ) + nDy = 1; + if ( nDx != 0 || nDy != 0 ) + { + if ( nDx != 0) pViewData->GetView()->ScrollX( nDx, WhichH(eWhich) ); + if ( nDy != 0 ) pViewData->GetView()->ScrollY( nDy, WhichV(eWhich) ); + bTimer = sal_True; + } + + // Umschalten bei Fixierung (damit Scrolling funktioniert) + + if ( eWhich == pViewData->GetActivePart() ) //?? + { + if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX ) + if ( nDx > 0 ) + { + if ( eWhich == SC_SPLIT_TOPLEFT ) + pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT ); + else if ( eWhich == SC_SPLIT_BOTTOMLEFT ) + pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ); + } + + if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX ) + if ( nDy > 0 ) + { + if ( eWhich == SC_SPLIT_TOPLEFT ) + pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT ); + else if ( eWhich == SC_SPLIT_TOPRIGHT ) + pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT ); + } + } + + // Verschieben + + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY ); + + ScRange aOld = pData->aRef; + ScRange aNew = aOld; + if ( bRFSize ) + { + aNew.aEnd.SetCol((SCCOL)nPosX); + aNew.aEnd.SetRow((SCROW)nPosY); + } + else + { + long nStartX = nPosX - nRFAddX; + if ( nStartX < 0 ) nStartX = 0; + long nStartY = nPosY - nRFAddY; + if ( nStartY < 0 ) nStartY = 0; + long nEndX = nStartX + aOld.aEnd.Col() - aOld.aStart.Col(); + if ( nEndX > MAXCOL ) + { + nStartX -= ( nEndX - MAXROW ); + nEndX = MAXCOL; + } + long nEndY = nStartY + aOld.aEnd.Row() - aOld.aStart.Row(); + if ( nEndY > MAXROW ) + { + nStartY -= ( nEndY - MAXROW ); + nEndY = MAXROW; + } + + aNew.aStart.SetCol((SCCOL)nStartX); + aNew.aStart.SetRow((SCROW)nStartY); + aNew.aEnd.SetCol((SCCOL)nEndX); + aNew.aEnd.SetRow((SCROW)nEndY); + } + + if ( bUp ) + aNew.Justify(); // beim ButtonUp wieder richtigherum + + if ( aNew != aOld ) + { + pHdl->UpdateRange( nRFIndex, aNew ); + + ScDocShell* pDocSh = pViewData->GetDocShell(); + + // nur das neuzeichnen, was sich veraendert hat... + lcl_PaintRefChanged( pDocSh, aOld, aNew ); + + // neuen Rahmen nur drueberzeichnen (synchron) + pDocSh->Broadcast( ScIndexHint( SC_HINT_SHOWRANGEFINDER, nRFIndex ) ); + + Update(); // was man bewegt, will man auch sofort sehen + } + + // Timer fuer Scrolling + + if (bTimer) + pViewData->GetView()->SetTimer( this, rMEvt ); // Event wiederholen + else + pViewData->GetView()->ResetTimer(); +} + +//------------------------------------------------------------------------ + +sal_Bool ScGridWindow::GetEditUrl( const Point& rPos, + String* pName, String* pUrl, String* pTarget ) +{ + return GetEditUrlOrError( sal_False, rPos, pName, pUrl, pTarget ); +} + +sal_Bool ScGridWindow::GetEditUrlOrError( sal_Bool bSpellErr, const Point& rPos, + String* pName, String* pUrl, String* pTarget ) +{ + //! nPosX/Y mit uebergeben? + SCsCOL nPosX; + SCsROW nPosY; + pViewData->GetPosFromPixel( rPos.X(), rPos.Y(), eWhich, nPosX, nPosY ); + + SCTAB nTab = pViewData->GetTabNo(); + ScDocShell* pDocSh = pViewData->GetDocShell(); + ScDocument* pDoc = pDocSh->GetDocument(); + ScBaseCell* pCell = NULL; + + sal_Bool bFound = lcl_GetHyperlinkCell( pDoc, nPosX, nPosY, nTab, pCell ); + if( !bFound ) + return sal_False; + + ScHideTextCursor aHideCursor( pViewData, eWhich ); // before GetEditArea (MapMode is changed) + + const ScPatternAttr* pPattern = pDoc->GetPattern( nPosX, nPosY, nTab ); + // bForceToTop = sal_False, use the cell's real position + Rectangle aEditRect = pViewData->GetEditArea( eWhich, nPosX, nPosY, this, pPattern, sal_False ); + if (rPos.Y() < aEditRect.Top()) + return sal_False; + + // vertikal kann (noch) nicht angeklickt werden: + + if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD) + return sal_False; + + sal_Bool bBreak = ((SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue() || + ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern-> + GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK); + SvxCellHorJustify eHorJust = (SvxCellHorJustify)((SvxHorJustifyItem&)pPattern-> + GetItem(ATTR_HOR_JUSTIFY)).GetValue(); + + // EditEngine + + ScFieldEditEngine aEngine( pDoc->GetEditPool() ); + ScSizeDeviceProvider aProv(pDocSh); + aEngine.SetRefDevice( aProv.GetDevice() ); + aEngine.SetRefMapMode( MAP_100TH_MM ); + SfxItemSet aDefault( aEngine.GetEmptyItemSet() ); + pPattern->FillEditItemSet( &aDefault ); + SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT; + switch (eHorJust) + { + case SVX_HOR_JUSTIFY_LEFT: + case SVX_HOR_JUSTIFY_REPEAT: // nicht implementiert + case SVX_HOR_JUSTIFY_STANDARD: // always Text if an EditCell type + eSvxAdjust = SVX_ADJUST_LEFT; + break; + case SVX_HOR_JUSTIFY_RIGHT: + eSvxAdjust = SVX_ADJUST_RIGHT; + break; + case SVX_HOR_JUSTIFY_CENTER: + eSvxAdjust = SVX_ADJUST_CENTER; + break; + case SVX_HOR_JUSTIFY_BLOCK: + eSvxAdjust = SVX_ADJUST_BLOCK; + break; + } + aDefault.Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) ); + aEngine.SetDefaults( aDefault ); + if (bSpellErr) + aEngine.SetControlWord( aEngine.GetControlWord() | EE_CNTRL_ONLINESPELLING ); + + MapMode aEditMode = pViewData->GetLogicMode(eWhich); // ohne Drawing-Skalierung + Rectangle aLogicEdit = PixelToLogic( aEditRect, aEditMode ); + long nThisColLogic = aLogicEdit.Right() - aLogicEdit.Left() + 1; + Size aPaperSize = Size( 1000000, 1000000 ); + if(pCell->GetCellType() == CELLTYPE_FORMULA) + { + long nSizeX = 0; + long nSizeY = 0; + pViewData->GetMergeSizePixel( nPosX, nPosY, nSizeX, nSizeY ); + aPaperSize = Size(nSizeX, nSizeY ); + aPaperSize = PixelToLogic(aPaperSize); + } + + if (bBreak) + aPaperSize.Width() = nThisColLogic; + aEngine.SetPaperSize( aPaperSize ); + + ::std::auto_ptr< EditTextObject > pTextObj; + const EditTextObject* pData; + if(pCell->GetCellType() == CELLTYPE_EDIT) + { + ((ScEditCell*)pCell)->GetData(pData); + if (pData) + aEngine.SetText(*pData); + } + else // HyperLink Formula cell + { + pTextObj.reset((static_cast<ScFormulaCell*>(pCell))->CreateURLObject()); + if (pTextObj.get()) + aEngine.SetText(*pTextObj); + } + + long nStartX = aLogicEdit.Left(); + + long nTextWidth = aEngine.CalcTextWidth(); + long nTextHeight = aEngine.GetTextHeight(); + if ( nTextWidth < nThisColLogic ) + { + if (eHorJust == SVX_HOR_JUSTIFY_RIGHT) + nStartX += nThisColLogic - nTextWidth; + else if (eHorJust == SVX_HOR_JUSTIFY_CENTER) + nStartX += (nThisColLogic - nTextWidth) / 2; + } + + aLogicEdit.Left() = nStartX; + if (!bBreak) + aLogicEdit.Right() = nStartX + nTextWidth; + + // There is one glitch when dealing with a hyperlink cell and + // the cell content is NUMERIC. This defaults to right aligned and + // we need to adjust accordingly. + if(pCell->GetCellType() == CELLTYPE_FORMULA && + static_cast<ScFormulaCell*>(pCell)->IsValue() && + eHorJust == SVX_HOR_JUSTIFY_STANDARD) + { + aLogicEdit.Right() = aLogicEdit.Left() + nThisColLogic - 1; + aLogicEdit.Left() = aLogicEdit.Right() - nTextWidth; + } + aLogicEdit.Bottom() = aLogicEdit.Top() + nTextHeight; + + + Point aLogicClick = PixelToLogic(rPos,aEditMode); + if ( aLogicEdit.IsInside(aLogicClick) ) + { +// aEngine.SetUpdateMode(sal_False); + EditView aTempView( &aEngine, this ); + aTempView.SetOutputArea( aLogicEdit ); + + sal_Bool bRet = sal_False; + MapMode aOld = GetMapMode(); + SetMapMode(aEditMode); // kein return mehr + + if (bSpellErr) // Spelling-Fehler suchen + { + bRet = aTempView.IsWrongSpelledWordAtPos( rPos ); + if ( bRet ) + pViewData->GetView()->SetCursor( nPosX, nPosY ); // Cursor setzen + } + else // URL suchen + { + const SvxFieldItem* pFieldItem = aTempView.GetFieldUnderMousePointer(); + + if (pFieldItem) + { + const SvxFieldData* pField = pFieldItem->GetField(); + if ( pField && pField->ISA(SvxURLField) ) + { + if ( pName || pUrl || pTarget ) + { + const SvxURLField* pURLField = (const SvxURLField*)pField; + if (pName) + *pName = pURLField->GetRepresentation(); + if (pUrl) + *pUrl = pURLField->GetURL(); + if (pTarget) + *pTarget = pURLField->GetTargetFrame(); + } + bRet = sal_True; + } + } + } + + SetMapMode(aOld); + + // text cursor is restored in ScHideTextCursor dtor + + return bRet; + } + return sal_False; +} + +sal_Bool ScGridWindow::HasScenarioButton( const Point& rPosPixel, ScRange& rScenRange ) +{ + ScDocument* pDoc = pViewData->GetDocument(); + SCTAB nTab = pViewData->GetTabNo(); + SCTAB nTabCount = pDoc->GetTableCount(); + if ( nTab+1<nTabCount && pDoc->IsScenario(nTab+1) && !pDoc->IsScenario(nTab) ) + { + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + + Size aButSize = pViewData->GetScenButSize(); + long nBWidth = aButSize.Width(); + if (!nBWidth) + return sal_False; // noch kein Button gezeichnet -> da ist auch keiner + long nBHeight = aButSize.Height(); + long nHSpace = (long)( SC_SCENARIO_HSPACE * pViewData->GetPPTX() ); + + //! Ranges an der Table cachen!!!! + + ScMarkData aMarks; + for (SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++) + pDoc->MarkScenario( i, nTab, aMarks, sal_False, SC_SCENARIO_SHOWFRAME ); + ScRangeList aRanges; + aMarks.FillRangeListWithMarks( &aRanges, sal_False ); + + + sal_uLong nRangeCount = aRanges.Count(); + for (sal_uLong j=0; j<nRangeCount; j++) + { + ScRange aRange = *aRanges.GetObject(j); + // Szenario-Rahmen immer dann auf zusammengefasste Zellen erweitern, wenn + // dadurch keine neuen nicht-ueberdeckten Zellen mit umrandet werden + pDoc->ExtendTotalMerge( aRange ); + + sal_Bool bTextBelow = ( aRange.aStart.Row() == 0 ); + + Point aButtonPos; + if ( bTextBelow ) + { + aButtonPos = pViewData->GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, + eWhich, sal_True ); + } + else + { + aButtonPos = pViewData->GetScrPos( aRange.aEnd.Col()+1, aRange.aStart.Row(), + eWhich, sal_True ); + aButtonPos.Y() -= nBHeight; + } + if ( bLayoutRTL ) + aButtonPos.X() -= nHSpace - 1; + else + aButtonPos.X() -= nBWidth - nHSpace; // same for top or bottom + + Rectangle aButRect( aButtonPos, Size(nBWidth,nBHeight) ); + if ( aButRect.IsInside( rPosPixel ) ) + { + rScenRange = aRange; + return sal_True; + } + } + } + + return sal_False; +} + +// #114409# +void ScGridWindow::DrawLayerCreated() +{ + SetMapMode( GetDrawMapMode() ); + + // initially create overlay objects + ImpCreateOverlayObjects(); +} + +// #114409# +void ScGridWindow::CursorChanged() +{ + // here the created OverlayObjects may be transformed in later versions. For + // now, just re-create them + + UpdateCursorOverlay(); +} + +// #114409# +void ScGridWindow::ImpCreateOverlayObjects() +{ + UpdateCursorOverlay(); + UpdateSelectionOverlay(); + UpdateAutoFillOverlay(); + UpdateDragRectOverlay(); + UpdateHeaderOverlay(); + UpdateShrinkOverlay(); +} + +// #114409# +void ScGridWindow::ImpDestroyOverlayObjects() +{ + DeleteCursorOverlay(); + DeleteSelectionOverlay(); + DeleteAutoFillOverlay(); + DeleteDragRectOverlay(); + DeleteHeaderOverlay(); + DeleteShrinkOverlay(); +} + +void ScGridWindow::UpdateAllOverlays() +{ + // delete and re-allocate all overlay objects + + ImpDestroyOverlayObjects(); + ImpCreateOverlayObjects(); +} + +void ScGridWindow::DeleteCursorOverlay() +{ + DELETEZ( mpOOCursors ); +} + +void ScGridWindow::UpdateCursorOverlay() +{ + MapMode aDrawMode = GetDrawMapMode(); + MapMode aOldMode = GetMapMode(); + if ( aOldMode != aDrawMode ) + SetMapMode( aDrawMode ); + + // Existing OverlayObjects may be transformed in later versions. + // For now, just re-create them. + + DeleteCursorOverlay(); + + std::vector<Rectangle> aPixelRects; + + // + // determine the cursor rectangles in pixels (moved from ScGridWindow::DrawCursor) + // + + SCTAB nTab = pViewData->GetTabNo(); + SCCOL nX = pViewData->GetCurX(); + SCROW nY = pViewData->GetCurY(); + + if (!maVisibleRange.isInside(nX, nY)) + return; + + // don't show the cursor in overlapped cells + + ScDocument* pDoc = pViewData->GetDocument(); + const ScPatternAttr* pPattern = pDoc->GetPattern(nX,nY,nTab); + const ScMergeFlagAttr& rMergeFlag = (const ScMergeFlagAttr&) pPattern->GetItem(ATTR_MERGE_FLAG); + sal_Bool bOverlapped = rMergeFlag.IsOverlapped(); + + // left or above of the screen? + + sal_Bool bVis = ( nX>=pViewData->GetPosX(eHWhich) && nY>=pViewData->GetPosY(eVWhich) ); + if (!bVis) + { + SCCOL nEndX = nX; + SCROW nEndY = nY; + const ScMergeAttr& rMerge = (const ScMergeAttr&) pPattern->GetItem(ATTR_MERGE); + if (rMerge.GetColMerge() > 1) + nEndX += rMerge.GetColMerge()-1; + if (rMerge.GetRowMerge() > 1) + nEndY += rMerge.GetRowMerge()-1; + bVis = ( nEndX>=pViewData->GetPosX(eHWhich) && nEndY>=pViewData->GetPosY(eVWhich) ); + } + + if ( bVis && !bOverlapped && !pViewData->HasEditView(eWhich) && pViewData->IsActive() ) + { + Point aScrPos = pViewData->GetScrPos( nX, nY, eWhich, sal_True ); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + + // completely right of/below the screen? + // (test with logical start position in aScrPos) + sal_Bool bMaybeVisible; + if ( bLayoutRTL ) + bMaybeVisible = ( aScrPos.X() >= -2 && aScrPos.Y() >= -2 ); + else + { + Size aOutSize = GetOutputSizePixel(); + bMaybeVisible = ( aScrPos.X() <= aOutSize.Width() + 2 && aScrPos.Y() <= aOutSize.Height() + 2 ); + } + if ( bMaybeVisible ) + { + long nSizeXPix; + long nSizeYPix; + pViewData->GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix ); + + if ( bLayoutRTL ) + aScrPos.X() -= nSizeXPix - 2; // move instead of mirroring + + sal_Bool bFix = ( pViewData->GetHSplitMode() == SC_SPLIT_FIX || + pViewData->GetVSplitMode() == SC_SPLIT_FIX ); + if ( pViewData->GetActivePart()==eWhich || bFix ) + { + aScrPos.X() -= 2; + aScrPos.Y() -= 2; + Rectangle aRect( aScrPos, Size( nSizeXPix + 3, nSizeYPix + 3 ) ); + + aPixelRects.push_back(Rectangle( aRect.Left(), aRect.Top(), aRect.Left()+2, aRect.Bottom() )); + aPixelRects.push_back(Rectangle( aRect.Right()-2, aRect.Top(), aRect.Right(), aRect.Bottom() )); + aPixelRects.push_back(Rectangle( aRect.Left()+3, aRect.Top(), aRect.Right()-3, aRect.Top()+2 )); + aPixelRects.push_back(Rectangle( aRect.Left()+3, aRect.Bottom()-2, aRect.Right()-3, aRect.Bottom() )); + } + else + { + Rectangle aRect( aScrPos, Size( nSizeXPix - 1, nSizeYPix - 1 ) ); + aPixelRects.push_back( aRect ); + } + } + } + + if ( aPixelRects.size() ) + { + // #i70788# get the OverlayManager safely + ::sdr::overlay::OverlayManager* pOverlayManager = getOverlayManager(); + + if(pOverlayManager) + { + const Color aCursorColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor ); + std::vector< basegfx::B2DRange > aRanges; + const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation()); + + for(sal_uInt32 a(0); a < aPixelRects.size(); a++) + { + const Rectangle aRA(aPixelRects[a]); + basegfx::B2DRange aRB(aRA.Left(), aRA.Top(), aRA.Right() + 1, aRA.Bottom() + 1); + aRB.transform(aTransform); + aRanges.push_back(aRB); + } + + sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection( + sdr::overlay::OVERLAY_SOLID, + aCursorColor, + aRanges, + false); + + pOverlayManager->add(*pOverlay); + mpOOCursors = new ::sdr::overlay::OverlayObjectList; + mpOOCursors->append(*pOverlay); + } + } + + if ( aOldMode != aDrawMode ) + SetMapMode( aOldMode ); +} + +void ScGridWindow::DeleteSelectionOverlay() +{ + DELETEZ( mpOOSelection ); +} + +void ScGridWindow::UpdateSelectionOverlay() +{ + MapMode aDrawMode = GetDrawMapMode(); + MapMode aOldMode = GetMapMode(); + if ( aOldMode != aDrawMode ) + SetMapMode( aDrawMode ); + + DeleteSelectionOverlay(); + std::vector<Rectangle> aPixelRects; + GetSelectionRects( aPixelRects ); + + if ( aPixelRects.size() && pViewData->IsActive() ) + { + // #i70788# get the OverlayManager safely + ::sdr::overlay::OverlayManager* pOverlayManager = getOverlayManager(); + + if(pOverlayManager) + { + std::vector< basegfx::B2DRange > aRanges; + const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation()); + + for(sal_uInt32 a(0); a < aPixelRects.size(); a++) + { + const Rectangle aRA(aPixelRects[a]); + basegfx::B2DRange aRB(aRA.Left() - 1, aRA.Top() - 1, aRA.Right(), aRA.Bottom()); + aRB.transform(aTransform); + aRanges.push_back(aRB); + } + + // #i97672# get the system's hilight color and limit it to the maximum + // allowed luminance. This is needed to react on too bright hilight colors + // which would otherwise vive a bad visualisation + Color aHighlight(GetSettings().GetStyleSettings().GetHighlightColor()); + const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer; + const basegfx::BColor aSelection(aHighlight.getBColor()); + const double fLuminance(aSelection.luminance()); + const double fMaxLum(aSvtOptionsDrawinglayer.GetSelectionMaximumLuminancePercent() / 100.0); + + if(fLuminance > fMaxLum) + { + const double fFactor(fMaxLum / fLuminance); + const basegfx::BColor aNewSelection( + aSelection.getRed() * fFactor, + aSelection.getGreen() * fFactor, + aSelection.getBlue() * fFactor); + + aHighlight = Color(aNewSelection); + } + + sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection( + sdr::overlay::OVERLAY_TRANSPARENT, + aHighlight, + aRanges, + true); + + pOverlayManager->add(*pOverlay); + mpOOSelection = new ::sdr::overlay::OverlayObjectList; + mpOOSelection->append(*pOverlay); + } + } + + if ( aOldMode != aDrawMode ) + SetMapMode( aOldMode ); +} + +void ScGridWindow::DeleteAutoFillOverlay() +{ + DELETEZ( mpOOAutoFill ); + mpAutoFillRect.reset(); +} + +void ScGridWindow::UpdateAutoFillOverlay() +{ + MapMode aDrawMode = GetDrawMapMode(); + MapMode aOldMode = GetMapMode(); + if ( aOldMode != aDrawMode ) + SetMapMode( aDrawMode ); + + DeleteAutoFillOverlay(); + + // + // get the AutoFill handle rectangle in pixels (moved from ScGridWindow::DrawAutoFillMark) + // + + if ( bAutoMarkVisible && aAutoMarkPos.Tab() == pViewData->GetTabNo() && + !pViewData->HasEditView(eWhich) && pViewData->IsActive() ) + { + SCCOL nX = aAutoMarkPos.Col(); + SCROW nY = aAutoMarkPos.Row(); + + if (!maVisibleRange.isInside(nX, nY)) + // Autofill mark is not visible. Bail out. + return; + + SCTAB nTab = pViewData->GetTabNo(); + ScDocument* pDoc = pViewData->GetDocument(); + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + + Point aFillPos = pViewData->GetScrPos( nX, nY, eWhich, sal_True ); + long nSizeXPix; + long nSizeYPix; + pViewData->GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix ); + if ( bLayoutRTL ) + aFillPos.X() -= nSizeXPix + 3; + else + aFillPos.X() += nSizeXPix - 2; + + aFillPos.Y() += nSizeYPix; + aFillPos.Y() -= 2; + mpAutoFillRect.reset(new Rectangle(aFillPos, Size(6, 6))); + + // #i70788# get the OverlayManager safely + ::sdr::overlay::OverlayManager* pOverlayManager = getOverlayManager(); + + if(pOverlayManager) + { + const Color aHandleColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor ); + std::vector< basegfx::B2DRange > aRanges; + const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation()); + basegfx::B2DRange aRB(mpAutoFillRect->Left(), mpAutoFillRect->Top(), mpAutoFillRect->Right() + 1, mpAutoFillRect->Bottom() + 1); + + aRB.transform(aTransform); + aRanges.push_back(aRB); + + sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection( + sdr::overlay::OVERLAY_SOLID, + aHandleColor, + aRanges, + false); + + pOverlayManager->add(*pOverlay); + mpOOAutoFill = new ::sdr::overlay::OverlayObjectList; + mpOOAutoFill->append(*pOverlay); + } + + if ( aOldMode != aDrawMode ) + SetMapMode( aOldMode ); + } +} + +void ScGridWindow::DeleteDragRectOverlay() +{ + DELETEZ( mpOODragRect ); +} + +void ScGridWindow::UpdateDragRectOverlay() +{ + MapMode aDrawMode = GetDrawMapMode(); + MapMode aOldMode = GetMapMode(); + if ( aOldMode != aDrawMode ) + SetMapMode( aDrawMode ); + + DeleteDragRectOverlay(); + + // + // get the rectangles in pixels (moved from DrawDragRect) + // + + if ( bDragRect || bPagebreakDrawn ) + { + std::vector<Rectangle> aPixelRects; + + SCCOL nX1 = bDragRect ? nDragStartX : aPagebreakDrag.aStart.Col(); + SCROW nY1 = bDragRect ? nDragStartY : aPagebreakDrag.aStart.Row(); + SCCOL nX2 = bDragRect ? nDragEndX : aPagebreakDrag.aEnd.Col(); + SCROW nY2 = bDragRect ? nDragEndY : aPagebreakDrag.aEnd.Row(); + + SCTAB nTab = pViewData->GetTabNo(); + + SCCOL nPosX = pViewData->GetPosX(WhichH(eWhich)); + SCROW nPosY = pViewData->GetPosY(WhichV(eWhich)); + if (nX1 < nPosX) nX1 = nPosX; + if (nX2 < nPosX) nX2 = nPosX; + if (nY1 < nPosY) nY1 = nPosY; + if (nY2 < nPosY) nY2 = nPosY; + + Point aScrPos( pViewData->GetScrPos( nX1, nY1, eWhich ) ); + + long nSizeXPix=0; + long nSizeYPix=0; + ScDocument* pDoc = pViewData->GetDocument(); + double nPPTX = pViewData->GetPPTX(); + double nPPTY = pViewData->GetPPTY(); + SCCOLROW i; + + sal_Bool bLayoutRTL = pDoc->IsLayoutRTL( nTab ); + long nLayoutSign = bLayoutRTL ? -1 : 1; + + if (ValidCol(nX2) && nX2>=nX1) + for (i=nX1; i<=nX2; i++) + nSizeXPix += ScViewData::ToPixel( pDoc->GetColWidth( static_cast<SCCOL>(i), nTab ), nPPTX ); + else + { + aScrPos.X() -= nLayoutSign; + nSizeXPix += 2; + } + + if (ValidRow(nY2) && nY2>=nY1) + for (i=nY1; i<=nY2; i++) + nSizeYPix += ScViewData::ToPixel( pDoc->GetRowHeight( i, nTab ), nPPTY ); + else + { + aScrPos.Y() -= 1; + nSizeYPix += 2; + } + + aScrPos.X() -= 2 * nLayoutSign; + aScrPos.Y() -= 2; +// Rectangle aRect( aScrPos, Size( nSizeXPix + 3, nSizeYPix + 3 ) ); + Rectangle aRect( aScrPos.X(), aScrPos.Y(), + aScrPos.X() + ( nSizeXPix + 2 ) * nLayoutSign, aScrPos.Y() + nSizeYPix + 2 ); + if ( bLayoutRTL ) + { + aRect.Left() = aRect.Right(); // end position is left + aRect.Right() = aScrPos.X(); + } + + if ( meDragInsertMode == INS_CELLSDOWN ) + { + aPixelRects.push_back( Rectangle( aRect.Left()+1, aRect.Top()+3, aRect.Left()+1, aRect.Bottom()-2 ) ); + aPixelRects.push_back( Rectangle( aRect.Right()-1, aRect.Top()+3, aRect.Right()-1, aRect.Bottom()-2 ) ); + aPixelRects.push_back( Rectangle( aRect.Left()+1, aRect.Top(), aRect.Right()-1, aRect.Top()+2 ) ); + aPixelRects.push_back( Rectangle( aRect.Left()+1, aRect.Bottom()-1, aRect.Right()-1, aRect.Bottom()-1 ) ); + } + else if ( meDragInsertMode == INS_CELLSRIGHT ) + { + aPixelRects.push_back( Rectangle( aRect.Left(), aRect.Top()+1, aRect.Left()+2, aRect.Bottom()-1 ) ); + aPixelRects.push_back( Rectangle( aRect.Right()-1, aRect.Top()+1, aRect.Right()-1, aRect.Bottom()-1 ) ); + aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Top()+1, aRect.Right()-2, aRect.Top()+1 ) ); + aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Bottom()-1, aRect.Right()-2, aRect.Bottom()-1 ) ); + } + else + { + aPixelRects.push_back( Rectangle( aRect.Left(), aRect.Top(), aRect.Left()+2, aRect.Bottom() ) ); + aPixelRects.push_back( Rectangle( aRect.Right()-2, aRect.Top(), aRect.Right(), aRect.Bottom() ) ); + aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Top(), aRect.Right()-3, aRect.Top()+2 ) ); + aPixelRects.push_back( Rectangle( aRect.Left()+3, aRect.Bottom()-2, aRect.Right()-3, aRect.Bottom() ) ); + } + + // #i70788# get the OverlayManager safely + ::sdr::overlay::OverlayManager* pOverlayManager = getOverlayManager(); + + if(pOverlayManager) + { + // Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor(); + std::vector< basegfx::B2DRange > aRanges; + const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation()); + + for(sal_uInt32 a(0); a < aPixelRects.size(); a++) + { + const Rectangle aRA(aPixelRects[a]); + basegfx::B2DRange aRB(aRA.Left(), aRA.Top(), aRA.Right() + 1, aRA.Bottom() + 1); + aRB.transform(aTransform); + aRanges.push_back(aRB); + } + + sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection( + sdr::overlay::OVERLAY_INVERT, + Color(COL_BLACK), + aRanges, + false); + + pOverlayManager->add(*pOverlay); + mpOODragRect = new ::sdr::overlay::OverlayObjectList; + mpOODragRect->append(*pOverlay); + } + } + + if ( aOldMode != aDrawMode ) + SetMapMode( aOldMode ); +} + +void ScGridWindow::DeleteHeaderOverlay() +{ + DELETEZ( mpOOHeader ); +} + +void ScGridWindow::UpdateHeaderOverlay() +{ + MapMode aDrawMode = GetDrawMapMode(); + MapMode aOldMode = GetMapMode(); + if ( aOldMode != aDrawMode ) + SetMapMode( aDrawMode ); + + DeleteHeaderOverlay(); + + // Pixel rectangle is in aInvertRect + if ( !aInvertRect.IsEmpty() ) + { + // #i70788# get the OverlayManager safely + ::sdr::overlay::OverlayManager* pOverlayManager = getOverlayManager(); + + if(pOverlayManager) + { + // Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor(); + std::vector< basegfx::B2DRange > aRanges; + const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation()); + basegfx::B2DRange aRB(aInvertRect.Left(), aInvertRect.Top(), aInvertRect.Right() + 1, aInvertRect.Bottom() + 1); + + aRB.transform(aTransform); + aRanges.push_back(aRB); + + sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection( + sdr::overlay::OVERLAY_INVERT, + Color(COL_BLACK), + aRanges, + false); + + pOverlayManager->add(*pOverlay); + mpOOHeader = new ::sdr::overlay::OverlayObjectList; + mpOOHeader->append(*pOverlay); + } + } + + if ( aOldMode != aDrawMode ) + SetMapMode( aOldMode ); +} + +void ScGridWindow::DeleteShrinkOverlay() +{ + DELETEZ( mpOOShrink ); +} + +void ScGridWindow::UpdateShrinkOverlay() +{ + MapMode aDrawMode = GetDrawMapMode(); + MapMode aOldMode = GetMapMode(); + if ( aOldMode != aDrawMode ) + SetMapMode( aDrawMode ); + + DeleteShrinkOverlay(); + + // + // get the rectangle in pixels + // + + Rectangle aPixRect; + ScRange aRange; + SCTAB nTab = pViewData->GetTabNo(); + if ( pViewData->IsRefMode() && nTab >= pViewData->GetRefStartZ() && nTab <= pViewData->GetRefEndZ() && + pViewData->GetDelMark( aRange ) ) + { + //! limit to visible area + if ( aRange.aStart.Col() <= aRange.aEnd.Col() && + aRange.aStart.Row() <= aRange.aEnd.Row() ) + { + Point aStart = pViewData->GetScrPos( aRange.aStart.Col(), + aRange.aStart.Row(), eWhich ); + Point aEnd = pViewData->GetScrPos( aRange.aEnd.Col()+1, + aRange.aEnd.Row()+1, eWhich ); + aEnd.X() -= 1; + aEnd.Y() -= 1; + + aPixRect = Rectangle( aStart,aEnd ); + } + } + + if ( !aPixRect.IsEmpty() ) + { + // #i70788# get the OverlayManager safely + ::sdr::overlay::OverlayManager* pOverlayManager = getOverlayManager(); + + if(pOverlayManager) + { + // Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor(); + std::vector< basegfx::B2DRange > aRanges; + const basegfx::B2DHomMatrix aTransform(GetInverseViewTransformation()); + basegfx::B2DRange aRB(aPixRect.Left(), aPixRect.Top(), aPixRect.Right() + 1, aPixRect.Bottom() + 1); + + aRB.transform(aTransform); + aRanges.push_back(aRB); + + sdr::overlay::OverlayObject* pOverlay = new sdr::overlay::OverlaySelection( + sdr::overlay::OVERLAY_INVERT, + Color(COL_BLACK), + aRanges, + false); + + pOverlayManager->add(*pOverlay); + mpOOShrink = new ::sdr::overlay::OverlayObjectList; + mpOOShrink->append(*pOverlay); + } + } + + if ( aOldMode != aDrawMode ) + SetMapMode( aOldMode ); +} + +// #i70788# central method to get the OverlayManager safely +::sdr::overlay::OverlayManager* ScGridWindow::getOverlayManager() +{ + SdrPageView* pPV = pViewData->GetView()->GetScDrawView()->GetSdrPageView(); + + if(pPV) + { + SdrPageWindow* pPageWin = pPV->FindPageWindow( *this ); + + if ( pPageWin ) + { + return (pPageWin->GetOverlayManager()); + } + } + + return 0L; +} + +void ScGridWindow::flushOverlayManager() +{ + // #i70788# get the OverlayManager safely + ::sdr::overlay::OverlayManager* pOverlayManager = getOverlayManager(); + + if(pOverlayManager) + { + pOverlayManager->flush(); + } +} + +// --------------------------------------------------------------------------- +// eof |