/* -*- 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 <config_wasm_strip.h>
#include "SidebarTxtControl.hxx"
#include <docsh.hxx>
#include <doc.hxx>
#include <PostItMgr.hxx>
#include <cmdid.h>
#include <strings.hrc>
#include <unotools/securityoptions.hxx>
#include <officecfg/Office/Common.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/sfxhelp.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/event.hxx>
#include <vcl/ptrstyle.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <vcl/gradient.hxx>
#include <vcl/settings.hxx>
#include <editeng/outliner.hxx>
#include <editeng/editeng.hxx>
#include <editeng/editview.hxx>
#include <editeng/flditem.hxx>
#include <uitool.hxx>
#include <view.hxx>
#include <wrtsh.hxx>
#include <AnnotationWin.hxx>
#include <IDocumentDeviceAccess.hxx>
#include <redline.hxx>
#include <memory>
namespace sw::sidebarwindows {
SidebarTextControl::SidebarTextControl(sw::annotation::SwAnnotationWin& rSidebarWin,
SwView& rDocView,
SwPostItMgr& rPostItMgr)
: mrSidebarWin(rSidebarWin)
, mrDocView(rDocView)
, mrPostItMgr(rPostItMgr)
, mbMouseDownGainingFocus(false)
{
}
EditView* SidebarTextControl::GetEditView() const
{
OutlinerView* pOutlinerView = mrSidebarWin.GetOutlinerView();
if (!pOutlinerView)
return nullptr;
return &pOutlinerView->GetEditView();
}
EditEngine* SidebarTextControl::GetEditEngine() const
{
OutlinerView* pOutlinerView = mrSidebarWin.GetOutlinerView();
if (!pOutlinerView)
return nullptr;
return &pOutlinerView->GetEditView().getEditEngine();
}
void SidebarTextControl::SetDrawingArea(weld::DrawingArea* pDrawingArea)
{
Size aSize(0, 0);
pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
SetOutputSizePixel(aSize);
weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
EnableRTL(false);
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
Color aBgColor = rStyleSettings.GetWindowColor();
OutputDevice& rDevice = pDrawingArea->get_ref_device();
rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
rDevice.SetBackground(aBgColor);
Size aOutputSize(rDevice.PixelToLogic(aSize));
EditView* pEditView = GetEditView();
pEditView->setEditViewCallbacks(this);
EditEngine& rEditEngine = pEditView->getEditEngine();
// For tdf#143443 note we want an 'infinite' height initially (which is the
// editengines default). For tdf#144686 it is helpful if the initial width
// is the "SidebarWidth" so the calculated text height is always meaningful
// for layout in the sidebar.
Size aPaperSize(mrPostItMgr.GetSidebarWidth(), rEditEngine.GetPaperSize().Height());
rEditEngine.SetPaperSize(aPaperSize);
rEditEngine.SetRefDevice(mrDocView.GetWrtShell().getIDocumentDeviceAccess().getReferenceDevice(false));
pEditView->SetOutputArea(tools::Rectangle(Point(0, 0), aOutputSize));
pEditView->SetBackgroundColor(aBgColor);
pDrawingArea->set_cursor(PointerStyle::Text);
#if !ENABLE_WASM_STRIP_ACCESSIBILITY
InitAccessible();
#endif
}
void SidebarTextControl::SetCursorLogicPosition(const Point& rPosition, bool bPoint, bool bClearMark)
{
Point aMousePos = EditViewOutputDevice().PixelToLogic(rPosition);
m_xEditView->SetCursorLogicPosition(aMousePos, bPoint, bClearMark);
}
void SidebarTextControl::GetFocus()
{
WeldEditView::GetFocus();
if ( !mrSidebarWin.IsMouseOver() )
Invalidate();
mrSidebarWin.SetActiveSidebarWin();
}
void SidebarTextControl::LoseFocus()
{
// write the visible text back into the SwField
mrSidebarWin.UpdateData();
WeldEditView::LoseFocus();
if ( !mrSidebarWin.IsMouseOver() )
{
Invalidate();
}
// set false for autoscroll to typing location
mrSidebarWin.LockView(false);
}
OUString SidebarTextControl::RequestHelp(tools::Rectangle& rHelpRect)
{
if (EditView* pEditView = GetEditView())
{
Point aPos = rHelpRect.TopLeft();
const OutputDevice& rOutDev = pEditView->GetOutputDevice();
Point aLogicClick = rOutDev.PixelToLogic(aPos);
const SvxFieldItem* pItem = pEditView->GetField(aLogicClick);
if (pItem)
{
const SvxFieldData* pField = pItem->GetField();
const SvxURLField* pURL = dynamic_cast<const SvxURLField*>( pField );
if (pURL)
{
rHelpRect = tools::Rectangle(aPos, Size(50, 10));
return SfxHelp::GetURLHelpText(pURL->GetURL());
}
}
}
TranslateId pResId;
switch( mrSidebarWin.GetLayoutStatus() )
{
case SwPostItHelper::INSERTED: pResId = STR_REDLINE_INSERT; break;
case SwPostItHelper::DELETED: pResId = STR_REDLINE_DELETE; break;
default: break;
}
SwContentAtPos aContentAtPos( IsAttrAtPos::Redline );
if ( pResId &&
mrDocView.GetWrtShell().GetContentAtPos( mrSidebarWin.GetAnchorPos(), aContentAtPos ) )
{
OUString sText = SwResId(pResId) + ": " +
aContentAtPos.aFnd.pRedl->GetAuthorString() + " - " +
GetAppLangDateTimeString( aContentAtPos.aFnd.pRedl->GetTimeStamp() );
return sText;
}
return OUString();
}
void SidebarTextControl::EditViewScrollStateChange()
{
mrSidebarWin.SetScrollbar();
}
void SidebarTextControl::DrawForPage(OutputDevice* pDev, const Point& rPt)
{
//Take the control's height, but overwrite the scrollbar area if there was one
OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
Size aSize(rDevice.PixelToLogic(GetOutputSizePixel()));
if (OutlinerView* pOutlinerView = mrSidebarWin.GetOutlinerView())
{
pOutlinerView->GetOutliner()->Draw(*pDev, tools::Rectangle(rPt, aSize));
}
if ( mrSidebarWin.GetLayoutStatus()!=SwPostItHelper::DELETED )
return;
pDev->Push(vcl::PushFlags::LINECOLOR);
pDev->SetLineColor(mrSidebarWin.GetChangeColor());
Point aBottomRight(rPt);
aBottomRight.Move(aSize);
pDev->DrawLine(rPt, aBottomRight);
Point aTopRight(rPt);
aTopRight.Move(Size(aSize.Width(), 0));
Point aBottomLeft(rPt);
aBottomLeft.Move(Size(0, aSize.Height()));
pDev->DrawLine(aTopRight, aBottomLeft);
pDev->Pop();
}
void SidebarTextControl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
{
Size aSize = GetOutputSizePixel();
Point aPos;
if (!rRenderContext.GetSettings().GetStyleSettings().GetHighContrastMode())
{
if (mrSidebarWin.IsMouseOverSidebarWin() || HasFocus())
{
rRenderContext.DrawGradient(tools::Rectangle(aPos, rRenderContext.PixelToLogic(aSize)),
Gradient(css::awt::GradientStyle_LINEAR, mrSidebarWin.ColorDark(), mrSidebarWin.ColorDark()));
}
else
{
rRenderContext.DrawGradient(tools::Rectangle(aPos, rRenderContext.PixelToLogic(aSize)),
Gradient(css::awt::GradientStyle_LINEAR, mrSidebarWin.ColorLight(), mrSidebarWin.ColorDark()));
}
}
DoPaint(rRenderContext, rRect);
if (mrSidebarWin.GetLayoutStatus() != SwPostItHelper::DELETED)
return;
const AntialiasingFlags nFormerAntialiasing( rRenderContext.GetAntialiasing() );
const bool bIsAntiAliasing = officecfg::Office::Common::Drawinglayer::AntiAliasing::get();
if ( bIsAntiAliasing )
rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
rRenderContext.SetLineColor(mrSidebarWin.GetChangeColor());
rRenderContext.DrawLine(rRenderContext.PixelToLogic(aPos),
rRenderContext.PixelToLogic(aPos + Point(aSize.Width(),
aSize.Height() * 0.95)));
rRenderContext.DrawLine(rRenderContext.PixelToLogic(aPos + Point(aSize.Width(),
0)),
rRenderContext.PixelToLogic(aPos + Point(0,
aSize.Height() * 0.95)));
if ( bIsAntiAliasing )
rRenderContext.SetAntialiasing(nFormerAntialiasing);
}
void SidebarTextControl::MakeVisible()
{
//let's make sure we see our note
mrPostItMgr.MakeVisible(&mrSidebarWin);
}
bool SidebarTextControl::KeyInput( const KeyEvent& rKeyEvt )
{
const vcl::KeyCode& rKeyCode = rKeyEvt.GetKeyCode();
const sal_uInt16 nKey = rKeyCode.GetCode();
if (nKey == KEY_F12 && getenv("SW_DEBUG"))
{
if (rKeyEvt.GetKeyCode().IsShift())
{
mrDocView.GetDocShell()->GetDoc()->dumpAsXml();
return true;
}
}
bool bDone = false;
if ( ( rKeyCode.IsMod1() && rKeyCode.IsMod2() ) &&
( (nKey == KEY_PAGEUP) || (nKey == KEY_PAGEDOWN) ) )
{
mrSidebarWin.SwitchToPostIt(nKey);
bDone = true;
}
else if ( nKey == KEY_ESCAPE ||
( rKeyCode.IsMod1() &&
( nKey == KEY_PAGEUP ||
nKey == KEY_PAGEDOWN ) ) )
{
mrSidebarWin.SwitchToFieldPos();
bDone = true;
}
else if ( rKeyCode.GetFullCode() == KEY_INSERT )
{
mrSidebarWin.ToggleInsMode();
bDone = true;
}
else
{
MakeVisible();
tools::Long aOldHeight = mrSidebarWin.GetPostItTextHeight();
/// HACK: need to switch off processing of Undo/Redo in Outliner
if ( !( (nKey == KEY_Z || nKey == KEY_Y) && rKeyCode.IsMod1()) )
{
bool bIsProtected = mrSidebarWin.IsReadOnlyOrProtected();
if ( !bIsProtected || !EditEngine::DoesKeyChangeText(rKeyEvt) )
{
EditView* pEditView = GetEditView();
bDone = pEditView && pEditView->PostKeyEvent(rKeyEvt);
}
else
mrDocView.GetWrtShell().InfoReadOnlyDialog(false);
}
if (bDone)
mrSidebarWin.ResizeIfNecessary( aOldHeight, mrSidebarWin.GetPostItTextHeight() );
else
{
// write back data first when showing navigator
if ( nKey==KEY_F5 )
mrSidebarWin.UpdateData();
bDone = mrDocView.KeyInput(rKeyEvt);
}
}
mrDocView.GetViewFrame().GetBindings().InvalidateAll(false);
return bDone;
}
bool SidebarTextControl::MouseButtonDown(const MouseEvent& rMEvt)
{
if (EditView* pEditView = GetEditView())
{
bool bExecuteMod = SvtSecurityOptions::IsOptionSet( SvtSecurityOptions::EOption::CtrlClickHyperlink);
if ( !bExecuteMod || (rMEvt.GetModifier() == KEY_MOD1))
{
const OutputDevice& rOutDev = pEditView->GetOutputDevice();
Point aLogicClick = rOutDev.PixelToLogic(rMEvt.GetPosPixel());
if (const SvxFieldItem* pItem = pEditView->GetField(aLogicClick))
{
const SvxFieldData* pField = pItem->GetField();
const SvxURLField* pURL = dynamic_cast<const SvxURLField*>( pField );
if ( pURL )
{
pEditView->MouseButtonDown( rMEvt );
SwWrtShell &rSh = mrDocView.GetWrtShell();
const OUString& sURL( pURL->GetURL() );
const OUString& sTarget( pURL->GetTargetFrame() );
::LoadURL(rSh, sURL, LoadUrlFlags::NONE, sTarget);
return true;
}
}
}
}
mbMouseDownGainingFocus = !HasFocus();
GrabFocus();
bool bRet = WeldEditView::MouseButtonDown(rMEvt);
mrDocView.GetViewFrame().GetBindings().InvalidateAll(false);
return bRet;
}
bool SidebarTextControl::MouseButtonUp(const MouseEvent& rMEvt)
{
bool bRet = WeldEditView::MouseButtonUp(rMEvt);
if (mbMouseDownGainingFocus)
{
MakeVisible();
mbMouseDownGainingFocus = false;
}
return bRet;
}
bool SidebarTextControl::MouseMove(const MouseEvent& rMEvt)
{
if (rMEvt.IsEnterWindow())
GetDrawingArea()->set_cursor(PointerStyle::Text);
return WeldEditView::MouseMove(rMEvt);
}
IMPL_LINK( SidebarTextControl, OnlineSpellCallback, SpellCallbackInfo&, rInfo, void )
{
if ( rInfo.nCommand == SpellCallbackCommand::STARTSPELLDLG )
{
mrDocView.GetViewFrame().GetDispatcher()->Execute( FN_SPELL_GRAMMAR_DIALOG, SfxCallMode::ASYNCHRON);
}
}
bool SidebarTextControl::Command( const CommandEvent& rCEvt )
{
EditView* pEditView = GetEditView();
if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
{
if (IsMouseCaptured())
ReleaseMouse();
if ( !mrSidebarWin.IsReadOnlyOrProtected() &&
pEditView &&
pEditView->IsWrongSpelledWordAtPos( rCEvt.GetMousePosPixel(), true ))
{
Link<SpellCallbackInfo&,void> aLink = LINK(this, SidebarTextControl, OnlineSpellCallback);
pEditView->ExecuteSpellPopup(rCEvt.GetMousePosPixel(), aLink);
}
else
{
Point aPos;
if (rCEvt.IsMouseEvent())
aPos = rCEvt.GetMousePosPixel();
else
{
const Size aSize = GetOutputSizePixel();
aPos = Point( aSize.getWidth()/2, aSize.getHeight()/2 );
}
SfxDispatcher::ExecutePopup(&mrSidebarWin, &aPos);
}
return true;
}
else if (rCEvt.GetCommand() == CommandEventId::Wheel)
{
// if no scrollbar, or extra keys held scroll the document and consume
// this event, otherwise don't consume and let the event get to the
// surrounding scrolled window
if (!mrSidebarWin.IsScrollbarVisible())
{
mrDocView.HandleWheelCommands(rCEvt);
return true;
}
else
{
const CommandWheelData* pData = rCEvt.GetWheelData();
if (pData->IsShift() || pData->IsMod1() || pData->IsMod2())
{
mrDocView.HandleWheelCommands(rCEvt);
return true;
}
}
}
return WeldEditView::Command(rCEvt);
}
} // end of namespace sw::sidebarwindows
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'Execute' is required to be utilized.