420 lines
16 KiB
C++
420 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <editeng/flditem.hxx>
|
|
|
|
#include <svx/fmpage.hxx>
|
|
#include <svx/svdobj.hxx>
|
|
#include <svx/svdpagv.hxx>
|
|
#include <svx/ImageMapInfo.hxx>
|
|
#include <vcl/imapobj.hxx>
|
|
#include <vcl/help.hxx>
|
|
#include <tools/urlobj.hxx>
|
|
#include <sfx2/sfxhelp.hxx>
|
|
|
|
#include <AccessibleDocument.hxx>
|
|
#include <com/sun/star/accessibility/XAccessible.hpp>
|
|
|
|
#include <gridwin.hxx>
|
|
#include <viewdata.hxx>
|
|
#include <drawview.hxx>
|
|
#include <drwlayer.hxx>
|
|
#include <document.hxx>
|
|
#include <notemark.hxx>
|
|
#include <chgtrack.hxx>
|
|
#include <chgviset.hxx>
|
|
#include <dbfunc.hxx>
|
|
#include <postit.hxx>
|
|
#include <global.hxx>
|
|
|
|
bool ScGridWindow::ShowNoteMarker( SCCOL nPosX, SCROW nPosY, bool bKeyboard )
|
|
{
|
|
bool bDone = false;
|
|
|
|
ScDocument& rDoc = mrViewData.GetDocument();
|
|
SCTAB nTab = mrViewData.GetTabNo();
|
|
ScAddress aCellPos( nPosX, nPosY, nTab );
|
|
|
|
OUString aTrackText;
|
|
bool bLeftEdge = false;
|
|
|
|
// change tracking
|
|
|
|
ScChangeTrack* pTrack = rDoc.GetChangeTrack();
|
|
ScChangeViewSettings* pSettings = rDoc.GetChangeViewSettings();
|
|
if ( pTrack && pTrack->GetFirst() && pSettings && pSettings->ShowChanges())
|
|
{
|
|
const ScChangeAction* pFound = nullptr;
|
|
const ScChangeAction* pFoundContent = nullptr;
|
|
const ScChangeAction* pFoundMove = nullptr;
|
|
const ScChangeAction* pAction = pTrack->GetFirst();
|
|
while (pAction)
|
|
{
|
|
if ( pAction->IsVisible() &&
|
|
ScViewUtil::IsActionShown( *pAction, *pSettings, rDoc ) )
|
|
{
|
|
ScChangeActionType eType = pAction->GetType();
|
|
const ScBigRange& rBig = pAction->GetBigRange();
|
|
if ( rBig.aStart.Tab() == nTab )
|
|
{
|
|
ScRange aRange = rBig.MakeRange( rDoc );
|
|
|
|
if ( eType == SC_CAT_DELETE_ROWS )
|
|
aRange.aEnd.SetRow( aRange.aStart.Row() );
|
|
else if ( eType == SC_CAT_DELETE_COLS )
|
|
aRange.aEnd.SetCol( aRange.aStart.Col() );
|
|
|
|
if ( aRange.Contains( aCellPos ) )
|
|
{
|
|
pFound = pAction; // the last one wins
|
|
switch ( eType )
|
|
{
|
|
case SC_CAT_CONTENT :
|
|
pFoundContent = pAction;
|
|
break;
|
|
case SC_CAT_MOVE :
|
|
pFoundMove = pAction;
|
|
break;
|
|
default:
|
|
{
|
|
// added to avoid warnings
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( eType == SC_CAT_MOVE )
|
|
{
|
|
ScRange aRange =
|
|
static_cast<const ScChangeActionMove*>(pAction)->
|
|
GetFromRange().MakeRange( rDoc );
|
|
if ( aRange.Contains( aCellPos ) )
|
|
{
|
|
pFound = pAction;
|
|
}
|
|
}
|
|
}
|
|
pAction = pAction->GetNext();
|
|
}
|
|
|
|
if ( pFound )
|
|
{
|
|
if ( pFoundContent && pFound->GetType() != SC_CAT_CONTENT )
|
|
pFound = pFoundContent; // content wins
|
|
if ( pFoundMove && pFound->GetType() != SC_CAT_MOVE &&
|
|
pFoundMove->GetActionNumber() >
|
|
pFound->GetActionNumber() )
|
|
pFound = pFoundMove; // move wins
|
|
|
|
// for deleted columns: Arrow on the left side of the cell
|
|
if ( pFound->GetType() == SC_CAT_DELETE_COLS )
|
|
bLeftEdge = true;
|
|
|
|
DateTime aDT = pFound->GetDateTime();
|
|
aTrackText = pFound->GetUser()
|
|
+ ", "
|
|
+ ScGlobal::getLocaleData().getDate(aDT)
|
|
+ " "
|
|
+ ScGlobal::getLocaleData().getTime(aDT)
|
|
+ ":\n";
|
|
OUString aComStr=pFound->GetComment();
|
|
if(!aComStr.isEmpty())
|
|
{
|
|
aTrackText += aComStr + "\n( ";
|
|
}
|
|
OUString aTmp = pFound->GetDescription(rDoc);
|
|
aTrackText += aTmp;
|
|
if(!aComStr.isEmpty())
|
|
{
|
|
aTrackText += ")";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Note, only if it is not already displayed on the Drawing Layer:
|
|
const ScPostIt* pNote = rDoc.GetNote( aCellPos );
|
|
if ( (!aTrackText.isEmpty()) || (pNote && !pNote->IsCaptionShown()) )
|
|
{
|
|
bool bNew = true;
|
|
bool bFast = false;
|
|
if (mpNoteMarker) // A note already shown
|
|
{
|
|
if (mpNoteMarker->GetDocPos() == aCellPos)
|
|
bNew = false; // then stop
|
|
else
|
|
bFast = true; // otherwise, at once
|
|
|
|
// marker which was shown for ctrl-F1 isn't removed by mouse events
|
|
if (mpNoteMarker->IsByKeyboard() && !bKeyboard)
|
|
bNew = false;
|
|
}
|
|
if (bNew)
|
|
{
|
|
if (bKeyboard)
|
|
bFast = true; // keyboard also shows the marker immediately
|
|
|
|
mpNoteMarker.reset();
|
|
|
|
bool bHSplit = mrViewData.GetHSplitMode() != SC_SPLIT_NONE;
|
|
bool bVSplit = mrViewData.GetVSplitMode() != SC_SPLIT_NONE;
|
|
|
|
vcl::Window* pLeft = mrViewData.GetView()->GetWindowByPos( bVSplit ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT );
|
|
vcl::Window* pRight = bHSplit ? mrViewData.GetView()->GetWindowByPos( bVSplit ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT ) : nullptr;
|
|
vcl::Window* pBottom = bVSplit ? mrViewData.GetView()->GetWindowByPos( SC_SPLIT_BOTTOMLEFT ) : nullptr;
|
|
vcl::Window* pDiagonal = (bHSplit && bVSplit) ? mrViewData.GetView()->GetWindowByPos( SC_SPLIT_BOTTOMRIGHT ) : nullptr;
|
|
assert(pLeft && "ScGridWindow::ShowNoteMarker - missing top-left grid window");
|
|
|
|
/* If caption is shown from right or bottom windows, adjust
|
|
mapmode to include size of top-left window. */
|
|
MapMode aMapMode = GetDrawMapMode( true );
|
|
Size aLeftSize = pLeft->PixelToLogic( pLeft->GetOutputSizePixel(), aMapMode );
|
|
Point aOrigin = aMapMode.GetOrigin();
|
|
if( (this == pRight) || (this == pDiagonal) )
|
|
aOrigin.AdjustX(aLeftSize.Width() );
|
|
if( (this == pBottom) || (this == pDiagonal) )
|
|
aOrigin.AdjustY(aLeftSize.Height() );
|
|
aMapMode.SetOrigin( aOrigin );
|
|
|
|
mpNoteMarker.reset(new ScNoteMarker(pLeft, pRight, pBottom, pDiagonal,
|
|
&rDoc, aCellPos, aTrackText,
|
|
aMapMode, bLeftEdge, bFast, bKeyboard));
|
|
}
|
|
|
|
bDone = true; // something is shown (old or new)
|
|
}
|
|
|
|
return bDone;
|
|
}
|
|
|
|
void ScGridWindow::RequestHelp(const HelpEvent& rHEvt)
|
|
{
|
|
bool bDone = false;
|
|
OUString aFormulaText;
|
|
tools::Rectangle aFormulaPixRect;
|
|
bool bHelpEnabled = bool(rHEvt.GetMode() & ( HelpEventMode::BALLOON | HelpEventMode::QUICK ));
|
|
SdrView* pDrView = mrViewData.GetScDrawView();
|
|
bool bDrawTextEdit = false;
|
|
if (pDrView)
|
|
bDrawTextEdit = pDrView->IsTextEdit();
|
|
// notes or change tracking
|
|
if ( bHelpEnabled && !bDrawTextEdit )
|
|
{
|
|
Point aPosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
|
|
SCCOL nPosX;
|
|
SCROW nPosY;
|
|
ScDocument& rDoc = mrViewData.GetDocument();
|
|
SCTAB nTab = mrViewData.GetTabNo();
|
|
const ScViewOptions& rOpts = mrViewData.GetOptions();
|
|
mrViewData.GetPosFromPixel( aPosPixel.X(), aPosPixel.Y(), eWhich, nPosX, nPosY );
|
|
|
|
if ( ShowNoteMarker( nPosX, nPosY, false ) )
|
|
{
|
|
Window::RequestHelp( rHEvt ); // turn off old Tip/Balloon
|
|
bDone = true;
|
|
}
|
|
|
|
if ( rOpts.GetOption( VOPT_FORMULAS_MARKS ) )
|
|
{
|
|
aFormulaText = rDoc.GetFormula( nPosX, nPosY, nTab );
|
|
if ( !aFormulaText.isEmpty() ) {
|
|
const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
|
|
aFormulaPixRect = mrViewData.GetEditArea( eWhich, nPosX, nPosY, this, pPattern, true );
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bDone && mpNoteMarker)
|
|
{
|
|
if (mpNoteMarker->IsByKeyboard())
|
|
{
|
|
// marker which was shown for ctrl-F1 isn't removed by mouse events
|
|
}
|
|
else
|
|
{
|
|
mpNoteMarker.reset();
|
|
}
|
|
}
|
|
|
|
if ( !aFormulaText.isEmpty() )
|
|
{
|
|
tools::Rectangle aScreenRect(OutputToScreenPixel(aFormulaPixRect.TopLeft()),
|
|
OutputToScreenPixel(aFormulaPixRect.BottomRight()));
|
|
if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
|
|
Help::ShowBalloon(this, rHEvt.GetMousePosPixel(), aScreenRect, aFormulaText);
|
|
else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
|
|
Help::ShowQuickHelp(this, aScreenRect, aFormulaText);
|
|
bDone = true;
|
|
}
|
|
|
|
// Image-Map / Text-URL
|
|
|
|
if ( bHelpEnabled && !bDone && !nButtonDown ) // only without pressed button
|
|
{
|
|
OUString aHelpText;
|
|
tools::Rectangle aPixRect;
|
|
Point aPosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
|
|
|
|
if ( pDrView ) // URL / Image-Map
|
|
{
|
|
SdrViewEvent aVEvt;
|
|
MouseEvent aMEvt( aPosPixel, 1, MouseEventModifiers::NONE, MOUSE_LEFT );
|
|
SdrHitKind eHit = pDrView->PickAnything( aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
|
|
|
|
if ( eHit != SdrHitKind::NONE && aVEvt.mpObj != nullptr )
|
|
{
|
|
// URL for IMapObject below Pointer is help text
|
|
if (SvxIMapInfo::GetIMapInfo(aVEvt.mpObj))
|
|
{
|
|
Point aLogicPos = PixelToLogic( aPosPixel );
|
|
IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(
|
|
aVEvt.mpObj, aLogicPos, GetOutDev() );
|
|
|
|
if ( pIMapObj )
|
|
{
|
|
// For image maps show the description, if available
|
|
aHelpText = pIMapObj->GetAltText();
|
|
if (aHelpText.isEmpty())
|
|
aHelpText = SfxHelp::GetURLHelpText(pIMapObj->GetURL());
|
|
aPixRect = LogicToPixel(aVEvt.mpObj->GetLogicRect());
|
|
}
|
|
}
|
|
// URL in shape text or at shape itself (URL in text overrides object URL)
|
|
if ( aHelpText.isEmpty() )
|
|
{
|
|
if( aVEvt.meEvent == SdrEventKind::ExecuteUrl )
|
|
{
|
|
if (aVEvt.mpURLField && !aVEvt.mpURLField->GetURL().startsWith("#"))
|
|
{
|
|
aHelpText = SfxHelp::GetURLHelpText(aVEvt.mpURLField->GetURL());
|
|
aPixRect = LogicToPixel(aVEvt.mpObj->GetLogicRect());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SdrPageView* pPV = nullptr;
|
|
Point aMDPos = PixelToLogic( aPosPixel );
|
|
SdrObject* pObj = pDrView->PickObj(aMDPos, pDrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
|
|
if (pObj)
|
|
{
|
|
if ( pObj->IsGroupObject() )
|
|
{
|
|
SdrObject* pHit = pDrView->PickObj(aMDPos, pDrView->getHitTolLog(), pPV, SdrSearchOptions::DEEP);
|
|
if (pHit)
|
|
pObj = pHit;
|
|
}
|
|
// Fragments pointing into the current document need no tooltip
|
|
// describing the ctrl-click functionality.
|
|
if ( !pObj->getHyperlink().isEmpty() && !pObj->getHyperlink().startsWith("#") )
|
|
{
|
|
aPixRect = LogicToPixel(aVEvt.mpObj->GetLogicRect());
|
|
aHelpText = SfxHelp::GetURLHelpText(pObj->getHyperlink());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( aHelpText.isEmpty() ) // Text-URL
|
|
{
|
|
OUString aUrl;
|
|
if ( GetEditUrl( aPosPixel, nullptr, &aUrl ) )
|
|
{
|
|
aHelpText = SfxHelp::GetURLHelpText(
|
|
INetURLObject::decode(aUrl, INetURLObject::DecodeMechanism::Unambiguous));
|
|
|
|
ScDocument& rDoc = mrViewData.GetDocument();
|
|
SCCOL nPosX;
|
|
SCROW nPosY;
|
|
SCTAB nTab = mrViewData.GetTabNo();
|
|
mrViewData.GetPosFromPixel( aPosPixel.X(), aPosPixel.Y(), eWhich, nPosX, nPosY );
|
|
const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
|
|
|
|
// bForceToTop = sal_False, use the cell's real position
|
|
aPixRect = mrViewData.GetEditArea( eWhich, nPosX, nPosY, this, pPattern, false );
|
|
}
|
|
}
|
|
|
|
if ( !aHelpText.isEmpty() )
|
|
{
|
|
tools::Rectangle aScreenRect(OutputToScreenPixel(aPixRect.TopLeft()),
|
|
OutputToScreenPixel(aPixRect.BottomRight()));
|
|
|
|
if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
|
|
Help::ShowBalloon(this,rHEvt.GetMousePosPixel(), aScreenRect, aHelpText);
|
|
else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
|
|
Help::ShowQuickHelp(this,aScreenRect, aHelpText);
|
|
|
|
bDone = true;
|
|
}
|
|
}
|
|
|
|
// basic controls
|
|
|
|
if ( pDrView && bHelpEnabled && !bDone )
|
|
{
|
|
SdrPageView* pPV = pDrView->GetSdrPageView();
|
|
OSL_ENSURE( pPV, "SdrPageView* is NULL" );
|
|
if (pPV)
|
|
bDone = FmFormPage::RequestHelp( this, pDrView, rHEvt );
|
|
}
|
|
|
|
// If QuickHelp for AutoFill is shown, do not allow it to be removed
|
|
|
|
if ( nMouseStatus == SC_GM_TABDOWN && mrViewData.GetRefType() == SC_REFTYPE_FILL &&
|
|
Help::IsQuickHelpEnabled() )
|
|
bDone = true;
|
|
|
|
if (!bDone)
|
|
Window::RequestHelp( rHEvt );
|
|
}
|
|
|
|
bool ScGridWindow::IsMyModel(const SdrEditView* pSdrView)
|
|
{
|
|
return pSdrView &&
|
|
&pSdrView->GetModel() == mrViewData.GetDocument().GetDrawLayer();
|
|
}
|
|
|
|
void ScGridWindow::HideNoteMarker()
|
|
{
|
|
mpNoteMarker.reset();
|
|
}
|
|
|
|
css::uno::Reference< css::accessibility::XAccessible >
|
|
ScGridWindow::CreateAccessible()
|
|
{
|
|
css::uno::Reference< css::accessibility::XAccessible > xAcc= GetAccessible(false);
|
|
if (xAcc.is())
|
|
{
|
|
return xAcc;
|
|
}
|
|
|
|
rtl::Reference<ScAccessibleDocument> pAccessibleDocument =
|
|
new ScAccessibleDocument(GetAccessibleParentWindow()->GetAccessible(),
|
|
mrViewData.GetViewShell(), eWhich);
|
|
pAccessibleDocument->PreInit();
|
|
|
|
xAcc = pAccessibleDocument;
|
|
SetAccessible(xAcc);
|
|
|
|
pAccessibleDocument->Init();
|
|
|
|
return xAcc;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|