6a5ef1a2b0
Change-Id: I222240dc1715604ad1e82e1062b34d116b2840f7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162367 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
2244 lines
73 KiB
C++
2244 lines
73 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 <sal/config.h>
|
|
|
|
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
|
|
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
|
|
#include <com/sun/star/frame/Desktop.hpp>
|
|
#include <com/sun/star/frame/XFramesSupplier.hpp>
|
|
#include <com/sun/star/frame/XModel.hpp>
|
|
#include <com/sun/star/container/XChild.hpp>
|
|
|
|
#include <comphelper/lok.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <comphelper/servicehelper.hxx>
|
|
#include <comphelper/storagehelper.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <i18nutil/unicode.hxx>
|
|
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
|
|
#include <officecfg/Office/Common.hxx>
|
|
#include <sfx2/dispatch.hxx>
|
|
#include <sfx2/docfile.hxx>
|
|
#include <sfx2/docfilt.hxx>
|
|
#include <sfx2/docinsert.hxx>
|
|
#include <sfx2/filedlghelper.hxx>
|
|
#include <sfx2/infobar.hxx>
|
|
#include <sfx2/lokcomponenthelpers.hxx>
|
|
#include <sfx2/lokhelper.hxx>
|
|
#include <sfx2/msg.hxx>
|
|
#include <sfx2/objface.hxx>
|
|
#include <sfx2/printer.hxx>
|
|
#include <sfx2/request.hxx>
|
|
#include <sfx2/sfxbasecontroller.hxx>
|
|
#include <sfx2/sidebar/Sidebar.hxx>
|
|
#include <sfx2/sidebar/SidebarChildWindow.hxx>
|
|
#include <sfx2/sidebar/SidebarController.hxx>
|
|
#include <sfx2/viewfac.hxx>
|
|
#include <svl/eitem.hxx>
|
|
#include <svl/itemset.hxx>
|
|
#include <svl/poolitem.hxx>
|
|
#include <svl/stritem.hxx>
|
|
#include <svl/voiditem.hxx>
|
|
#include <vcl/transfer.hxx>
|
|
#include <svtools/colorcfg.hxx>
|
|
#include <svl/whiter.hxx>
|
|
#include <svx/sidebar/SelectionChangeHandler.hxx>
|
|
#include <svx/zoomslideritem.hxx>
|
|
#include <editeng/editeng.hxx>
|
|
#include <editeng/editview.hxx>
|
|
#include <editeng/editund2.hxx>
|
|
#include <svx/svxdlg.hxx>
|
|
#include <sfx2/zoomitem.hxx>
|
|
#include <vcl/commandevent.hxx>
|
|
#include <vcl/event.hxx>
|
|
#include <vcl/help.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <tools/svborder.hxx>
|
|
#include <o3tl/string_view.hxx>
|
|
#include <o3tl/temporary.hxx>
|
|
|
|
#include <unotools/streamwrap.hxx>
|
|
|
|
#include <unomodel.hxx>
|
|
#include <view.hxx>
|
|
#include <cfgitem.hxx>
|
|
#include <dialog.hxx>
|
|
#include <document.hxx>
|
|
#include <starmath.hrc>
|
|
#include <strings.hrc>
|
|
#include <smmod.hxx>
|
|
#include <mathmlimport.hxx>
|
|
#include <cursor.hxx>
|
|
#include "accessibility.hxx"
|
|
#include <ElementsDockingWindow.hxx>
|
|
#include <helpids.h>
|
|
|
|
// space around the edit window, in pixels
|
|
// fdo#69111: Increased border on the top so that the window is
|
|
// easier to tear off.
|
|
#define CMD_BOX_PADDING 3
|
|
#define CMD_BOX_PADDING_TOP 11
|
|
|
|
#define ShellClass_SmViewShell
|
|
#include <smslots.hxx>
|
|
|
|
using namespace css;
|
|
using namespace css::accessibility;
|
|
using namespace css::uno;
|
|
|
|
SmGraphicWindow::SmGraphicWindow(SmViewShell& rShell)
|
|
: InterimItemWindow(&rShell.GetViewFrame().GetWindow(), "modules/smath/ui/mathwindow.ui", "MathWindow")
|
|
, nLinePixH(GetSettings().GetStyleSettings().GetScrollBarSize())
|
|
, nColumnPixW(nLinePixH)
|
|
, nZoom(100)
|
|
// continue to use user-scrolling to make this work equivalent to how it 'always' worked
|
|
, mxScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow", true))
|
|
, mxGraphic(new SmGraphicWidget(rShell, *this))
|
|
, mxGraphicWin(new weld::CustomWeld(*m_xBuilder, "mathview", *mxGraphic))
|
|
{
|
|
InitControlBase(mxGraphic->GetDrawingArea());
|
|
|
|
mxScrolledWindow->connect_hadjustment_changed(LINK(this, SmGraphicWindow, ScrollHdl));
|
|
mxScrolledWindow->connect_vadjustment_changed(LINK(this, SmGraphicWindow, ScrollHdl));
|
|
|
|
// docking windows are usually hidden (often already done in the
|
|
// resource) and will be shown by the sfx framework.
|
|
Hide();
|
|
}
|
|
|
|
void SmGraphicWindow::dispose()
|
|
{
|
|
InitControlBase(nullptr);
|
|
mxGraphicWin.reset();
|
|
mxGraphic.reset();
|
|
mxScrolledWindow.reset();
|
|
InterimItemWindow::dispose();
|
|
}
|
|
|
|
SmGraphicWindow::~SmGraphicWindow()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void SmGraphicWindow::Resize()
|
|
{
|
|
InterimItemWindow::Resize();
|
|
|
|
// get the new output-size in pixel
|
|
Size aOutPixSz = GetOutputSizePixel();
|
|
|
|
// determine the size of the output-area and if we need scrollbars
|
|
const auto nScrSize = mxScrolledWindow->get_scroll_thickness();
|
|
bool bVVisible = false; // by default no vertical-ScrollBar
|
|
bool bHVisible = false; // by default no horizontal-ScrollBar
|
|
bool bChanged; // determines if a visibility was changed
|
|
do
|
|
{
|
|
bChanged = false;
|
|
|
|
// does we need a vertical ScrollBar
|
|
if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible )
|
|
{
|
|
bHVisible = true;
|
|
aOutPixSz.AdjustHeight( -nScrSize );
|
|
bChanged = true;
|
|
}
|
|
|
|
// does we need a horizontal ScrollBar
|
|
if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible )
|
|
{
|
|
bVVisible = true;
|
|
aOutPixSz.AdjustWidth( -nScrSize );
|
|
bChanged = true;
|
|
}
|
|
|
|
}
|
|
while ( bChanged ); // until no visibility has changed
|
|
|
|
// store the old offset and map-mode
|
|
MapMode aMap(GetGraphicMapMode());
|
|
Point aOldPixOffset(aPixOffset);
|
|
|
|
// justify (right/bottom borders should never exceed the virtual window)
|
|
Size aPixDelta;
|
|
if ( aPixOffset.X() < 0 &&
|
|
aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() )
|
|
aPixDelta.setWidth(
|
|
aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() ) );
|
|
if ( aPixOffset.Y() < 0 &&
|
|
aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() )
|
|
aPixDelta.setHeight(
|
|
aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() ) );
|
|
if ( aPixDelta.Width() || aPixDelta.Height() )
|
|
{
|
|
aPixOffset.AdjustX(aPixDelta.Width() );
|
|
aPixOffset.AdjustY(aPixDelta.Height() );
|
|
}
|
|
|
|
// for axis without scrollbar restore the origin
|
|
if ( !bVVisible || !bHVisible )
|
|
{
|
|
aPixOffset = Point(
|
|
bHVisible
|
|
? aPixOffset.X()
|
|
: (aOutPixSz.Width()-aTotPixSz.Width()) / 2,
|
|
bVVisible
|
|
? aPixOffset.Y()
|
|
: (aOutPixSz.Height()-aTotPixSz.Height()) / 2 );
|
|
}
|
|
if (bHVisible && mxScrolledWindow->get_hpolicy() == VclPolicyType::NEVER)
|
|
aPixOffset.setX( 0 );
|
|
if (bVVisible && mxScrolledWindow->get_vpolicy() == VclPolicyType::NEVER)
|
|
aPixOffset.setY( 0 );
|
|
|
|
// select the shifted map-mode
|
|
if (aPixOffset != aOldPixOffset)
|
|
SetGraphicMapMode(aMap);
|
|
|
|
// show or hide scrollbars
|
|
mxScrolledWindow->set_vpolicy(bVVisible ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);
|
|
mxScrolledWindow->set_hpolicy(bHVisible ? VclPolicyType::ALWAYS : VclPolicyType::NEVER);
|
|
|
|
// resize scrollbars and set their ranges
|
|
if ( bHVisible )
|
|
{
|
|
mxScrolledWindow->hadjustment_configure(-aPixOffset.X(), 0, aTotPixSz.Width(), nColumnPixW,
|
|
aOutPixSz.Width(), aOutPixSz.Width());
|
|
}
|
|
if ( bVVisible )
|
|
{
|
|
mxScrolledWindow->vadjustment_configure(-aPixOffset.Y(), 0, aTotPixSz.Height(), nLinePixH,
|
|
aOutPixSz.Height(), aOutPixSz.Height());
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SmGraphicWindow, ScrollHdl, weld::ScrolledWindow&, void)
|
|
{
|
|
MapMode aMap(GetGraphicMapMode());
|
|
Point aNewPixOffset(aPixOffset);
|
|
|
|
// scrolling horizontally?
|
|
if (mxScrolledWindow->get_hpolicy() == VclPolicyType::ALWAYS)
|
|
aNewPixOffset.setX(-mxScrolledWindow->hadjustment_get_value());
|
|
|
|
// scrolling vertically?
|
|
if (mxScrolledWindow->get_vpolicy() == VclPolicyType::ALWAYS)
|
|
aNewPixOffset.setY(-mxScrolledWindow->vadjustment_get_value());
|
|
|
|
// scrolling?
|
|
if (aPixOffset == aNewPixOffset)
|
|
return;
|
|
|
|
// recompute the logical scroll units
|
|
aPixOffset = aNewPixOffset;
|
|
|
|
SetGraphicMapMode(aMap);
|
|
}
|
|
|
|
void SmGraphicWindow::SetGraphicMapMode(const MapMode& rNewMapMode)
|
|
{
|
|
OutputDevice& rDevice = mxGraphic->GetOutputDevice();
|
|
MapMode aMap( rNewMapMode );
|
|
aMap.SetOrigin( aMap.GetOrigin() + rDevice.PixelToLogic( aPixOffset, aMap ) );
|
|
rDevice.SetMapMode( aMap );
|
|
mxGraphic->Invalidate();
|
|
}
|
|
|
|
MapMode SmGraphicWindow::GetGraphicMapMode() const
|
|
{
|
|
OutputDevice& rDevice = mxGraphic->GetOutputDevice();
|
|
MapMode aMap(rDevice.GetMapMode());
|
|
aMap.SetOrigin( aMap.GetOrigin() - rDevice.PixelToLogic( aPixOffset ) );
|
|
return aMap;
|
|
}
|
|
|
|
void SmGraphicWindow::SetTotalSize( const Size& rNewSize )
|
|
{
|
|
aTotPixSz = mxGraphic->GetOutputDevice().LogicToPixel(rNewSize);
|
|
Resize();
|
|
}
|
|
|
|
Size SmGraphicWindow::GetTotalSize() const
|
|
{
|
|
return mxGraphic->GetOutputDevice().PixelToLogic(aTotPixSz);
|
|
}
|
|
|
|
void SmGraphicWindow::ShowContextMenu(const CommandEvent& rCEvt)
|
|
{
|
|
GetParent()->ToTop();
|
|
Point aPos(5, 5);
|
|
if (rCEvt.IsMouseEvent())
|
|
aPos = rCEvt.GetMousePosPixel();
|
|
|
|
// added for replaceability of context menus
|
|
SfxDispatcher::ExecutePopup( this, &aPos );
|
|
}
|
|
|
|
SmGraphicWidget::SmGraphicWidget(SmViewShell& rShell, SmGraphicWindow& rGraphicWindow)
|
|
: mrGraphicWindow(rGraphicWindow)
|
|
, bIsCursorVisible(false)
|
|
, bIsLineVisible(false)
|
|
, aCaretBlinkTimer("SmGraphicWidget aCaretBlinkTimer")
|
|
, mrViewShell(rShell)
|
|
{
|
|
}
|
|
|
|
void SmGraphicWidget::SetDrawingArea(weld::DrawingArea* pDrawingArea)
|
|
{
|
|
weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
|
|
|
|
OutputDevice& rDevice = GetOutputDevice();
|
|
|
|
rDevice.EnableRTL(GetDoc()->GetFormat().IsRightToLeft());
|
|
rDevice.SetBackground(SM_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor);
|
|
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
// Disable map mode, so that it's possible to send mouse event coordinates
|
|
// directly in twips.
|
|
rDevice.EnableMapMode(false);
|
|
}
|
|
else
|
|
{
|
|
const Fraction aFraction(1, 1);
|
|
rDevice.SetMapMode(MapMode(SmMapUnit(), Point(), aFraction, aFraction));
|
|
}
|
|
|
|
SetTotalSize();
|
|
|
|
SetHelpId(HID_SMA_WIN_DOCUMENT);
|
|
|
|
ShowLine(false);
|
|
CaretBlinkInit();
|
|
}
|
|
|
|
SmGraphicWidget::~SmGraphicWidget()
|
|
{
|
|
if (mxAccessible.is())
|
|
mxAccessible->ClearWin(); // make Accessible nonfunctional
|
|
mxAccessible.clear();
|
|
CaretBlinkStop();
|
|
}
|
|
|
|
SmDocShell* SmGraphicWidget::GetDoc() { return GetView().GetDoc(); }
|
|
|
|
SmCursor& SmGraphicWidget::GetCursor()
|
|
{
|
|
assert(GetDoc());
|
|
return GetDoc()->GetCursor();
|
|
}
|
|
|
|
bool SmGraphicWidget::MouseButtonDown(const MouseEvent& rMEvt)
|
|
{
|
|
GrabFocus();
|
|
|
|
// set formula-cursor and selection of edit window according to the
|
|
// position clicked at
|
|
|
|
SAL_WARN_IF( rMEvt.GetClicks() == 0, "starmath", "0 clicks" );
|
|
if ( !rMEvt.IsLeft() )
|
|
return true;
|
|
|
|
OutputDevice& rDevice = GetOutputDevice();
|
|
// get click position relative to formula
|
|
Point aPos(rDevice.PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());
|
|
|
|
const SmNode *pTree = GetDoc()->GetFormulaTree();
|
|
if (!pTree)
|
|
return true;
|
|
|
|
SmEditWindow* pEdit = GetView().GetEditWindow();
|
|
|
|
if (SmViewShell::IsInlineEditEnabled()) {
|
|
GetCursor().MoveTo(&rDevice, aPos, !rMEvt.IsShift());
|
|
GetView().InvalidateSlots();
|
|
// 'on grab' window events are missing in lok, do it explicitly
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
SetIsCursorVisible(true);
|
|
return true;
|
|
}
|
|
const SmNode *pNode = nullptr;
|
|
// if it was clicked inside the formula then get the appropriate node
|
|
if (pTree->OrientedDist(aPos) <= 0)
|
|
pNode = pTree->FindRectClosestTo(aPos);
|
|
|
|
if (!pNode)
|
|
return true;
|
|
|
|
if (!pEdit)
|
|
return true;
|
|
|
|
// set selection to the beginning of the token
|
|
pEdit->SetSelection(pNode->GetSelection());
|
|
SetCursor(pNode);
|
|
|
|
// allow for immediate editing and
|
|
//! implicitly synchronize the cursor position mark in this window
|
|
pEdit->GrabFocus();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SmGraphicWidget::MouseMove(const MouseEvent &rMEvt)
|
|
{
|
|
if (rMEvt.IsLeft() && SmViewShell::IsInlineEditEnabled())
|
|
{
|
|
OutputDevice& rDevice = GetOutputDevice();
|
|
Point aPos(rDevice.PixelToLogic(rMEvt.GetPosPixel()) - GetFormulaDrawPos());
|
|
GetCursor().MoveTo(&rDevice, aPos, false);
|
|
|
|
CaretBlinkStop();
|
|
SetIsCursorVisible(true);
|
|
CaretBlinkStart();
|
|
RepaintViewShellDoc();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void SmGraphicWidget::GetFocus()
|
|
{
|
|
if (!SmViewShell::IsInlineEditEnabled())
|
|
return;
|
|
if (SmEditWindow* pEdit = GetView().GetEditWindow())
|
|
pEdit->Flush();
|
|
SetIsCursorVisible(true);
|
|
ShowLine(true);
|
|
CaretBlinkStart();
|
|
RepaintViewShellDoc();
|
|
}
|
|
|
|
void SmGraphicWidget::LoseFocus()
|
|
{
|
|
if (mxAccessible.is())
|
|
{
|
|
uno::Any aOldValue, aNewValue;
|
|
aOldValue <<= AccessibleStateType::FOCUSED;
|
|
// aNewValue remains empty
|
|
mxAccessible->LaunchEvent( AccessibleEventId::STATE_CHANGED,
|
|
aOldValue, aNewValue );
|
|
}
|
|
if (!SmViewShell::IsInlineEditEnabled())
|
|
return;
|
|
SetIsCursorVisible(false);
|
|
ShowLine(false);
|
|
CaretBlinkStop();
|
|
RepaintViewShellDoc();
|
|
}
|
|
|
|
void SmGraphicWidget::RepaintViewShellDoc()
|
|
{
|
|
if (SmDocShell* pDoc = GetDoc())
|
|
pDoc->Repaint();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SmGraphicWidget, CaretBlinkTimerHdl, Timer *, void)
|
|
{
|
|
if (IsCursorVisible())
|
|
SetIsCursorVisible(false);
|
|
else
|
|
SetIsCursorVisible(true);
|
|
|
|
RepaintViewShellDoc();
|
|
}
|
|
|
|
void SmGraphicWidget::CaretBlinkInit()
|
|
{
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
return; // No blinking in lok case
|
|
aCaretBlinkTimer.SetInvokeHandler(LINK(this, SmGraphicWidget, CaretBlinkTimerHdl));
|
|
aCaretBlinkTimer.SetTimeout(Application::GetSettings().GetStyleSettings().GetCursorBlinkTime());
|
|
}
|
|
|
|
void SmGraphicWidget::CaretBlinkStart()
|
|
{
|
|
if (!SmViewShell::IsInlineEditEnabled() || comphelper::LibreOfficeKit::isActive())
|
|
return;
|
|
if (aCaretBlinkTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME)
|
|
aCaretBlinkTimer.Start();
|
|
}
|
|
|
|
void SmGraphicWidget::CaretBlinkStop()
|
|
{
|
|
if (!SmViewShell::IsInlineEditEnabled() || comphelper::LibreOfficeKit::isActive())
|
|
return;
|
|
aCaretBlinkTimer.Stop();
|
|
}
|
|
|
|
// shows or hides the formula-cursor depending on 'bShow' is true or not
|
|
void SmGraphicWidget::ShowCursor(bool bShow)
|
|
{
|
|
if (SmViewShell::IsInlineEditEnabled())
|
|
return;
|
|
|
|
bool bInvert = bShow != IsCursorVisible();
|
|
if (bInvert)
|
|
InvertFocusRect(GetOutputDevice(), aCursorRect);
|
|
|
|
SetIsCursorVisible(bShow);
|
|
}
|
|
|
|
void SmGraphicWidget::ShowLine(bool bShow)
|
|
{
|
|
if (!SmViewShell::IsInlineEditEnabled())
|
|
return;
|
|
|
|
bIsLineVisible = bShow;
|
|
}
|
|
|
|
void SmGraphicWidget::SetIsCursorVisible(bool bVis)
|
|
{
|
|
bIsCursorVisible = bVis;
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
mrViewShell.SendCaretToLOK();
|
|
mrViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE,
|
|
OString::boolean(bVis));
|
|
}
|
|
}
|
|
|
|
void SmGraphicWidget::SetCursor(const SmNode *pNode)
|
|
{
|
|
if (SmViewShell::IsInlineEditEnabled())
|
|
return;
|
|
|
|
const SmNode *pTree = GetDoc()->GetFormulaTree();
|
|
|
|
// get appropriate rectangle
|
|
Point aOffset (pNode->GetTopLeft() - pTree->GetTopLeft()),
|
|
aTLPos (GetFormulaDrawPos() + aOffset);
|
|
aTLPos.AdjustX( -(pNode->GetItalicLeftSpace()) );
|
|
Size aSize (pNode->GetItalicSize());
|
|
|
|
SetCursor(tools::Rectangle(aTLPos, aSize));
|
|
}
|
|
|
|
void SmGraphicWidget::SetCursor(const tools::Rectangle &rRect)
|
|
// sets cursor to new position (rectangle) 'rRect'.
|
|
// The old cursor will be removed, and the new one will be shown if
|
|
// that is activated in the ConfigItem
|
|
{
|
|
if (SmViewShell::IsInlineEditEnabled())
|
|
return;
|
|
|
|
SmModule *pp = SM_MOD();
|
|
|
|
if (IsCursorVisible())
|
|
ShowCursor(false); // clean up remainings of old cursor
|
|
aCursorRect = rRect;
|
|
if (pp->GetConfig()->IsShowFormulaCursor())
|
|
ShowCursor(true); // draw new cursor
|
|
}
|
|
|
|
const SmNode * SmGraphicWidget::SetCursorPos(sal_uInt16 nRow, sal_uInt16 nCol)
|
|
// looks for a VISIBLE node in the formula tree with its token at
|
|
// (or around) the position 'nRow', 'nCol' in the edit window
|
|
// (row and column numbering starts with 1 there!).
|
|
// If there is such a node the formula-cursor is set to cover that nodes
|
|
// rectangle. If not the formula-cursor will be hidden.
|
|
// In any case the search result is being returned.
|
|
{
|
|
if (SmViewShell::IsInlineEditEnabled())
|
|
return nullptr;
|
|
|
|
// find visible node with token at nRow, nCol
|
|
const SmNode *pTree = GetDoc()->GetFormulaTree(),
|
|
*pNode = nullptr;
|
|
if (pTree)
|
|
pNode = pTree->FindTokenAt(nRow, nCol);
|
|
|
|
if (pNode)
|
|
SetCursor(pNode);
|
|
else
|
|
ShowCursor(false);
|
|
|
|
return pNode;
|
|
}
|
|
|
|
void SmGraphicWidget::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
|
|
{
|
|
assert(GetDoc());
|
|
SmDocShell& rDoc = *GetDoc();
|
|
Point aPoint;
|
|
|
|
rDoc.DrawFormula(rRenderContext, aPoint, true); //! modifies aPoint to be the topleft
|
|
//! corner of the formula
|
|
aFormulaDrawPos = aPoint;
|
|
if (SmViewShell::IsInlineEditEnabled())
|
|
{
|
|
//Draw cursor if any...
|
|
if (rDoc.HasCursor() && IsLineVisible())
|
|
rDoc.GetCursor().Draw(rRenderContext, aPoint, IsCursorVisible());
|
|
}
|
|
else
|
|
{
|
|
SetIsCursorVisible(false); // (old) cursor must be drawn again
|
|
|
|
if (const SmEditWindow* pEdit = GetView().GetEditWindow())
|
|
{ // get new position for formula-cursor (for possible altered formula)
|
|
sal_Int32 nRow;
|
|
sal_uInt16 nCol;
|
|
SmGetLeftSelectionPart(pEdit->GetSelection(), nRow, nCol);
|
|
const SmNode *pFound = SetCursorPos(static_cast<sal_uInt16>(nRow), nCol);
|
|
|
|
SmModule *pp = SM_MOD();
|
|
if (pFound && pp->GetConfig()->IsShowFormulaCursor())
|
|
ShowCursor(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SmGraphicWidget::SetTotalSize()
|
|
{
|
|
assert(GetDoc());
|
|
OutputDevice& rDevice = GetOutputDevice();
|
|
const Size aTmp(rDevice.PixelToLogic(rDevice.LogicToPixel(GetDoc()->GetSize())));
|
|
if (aTmp != mrGraphicWindow.GetTotalSize())
|
|
mrGraphicWindow.SetTotalSize(aTmp);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
SmBracketType BracketTypeOf(sal_uInt32 c)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '(':
|
|
case ')':
|
|
return SmBracketType::Round;
|
|
case '[':
|
|
case ']':
|
|
return SmBracketType::Square;
|
|
case '{':
|
|
case '}':
|
|
return SmBracketType::Curly;
|
|
}
|
|
assert(false); // Unreachable
|
|
return SmBracketType::Round;
|
|
}
|
|
|
|
bool CharInput(sal_uInt32 c, SmCursor& rCursor, OutputDevice& rDevice)
|
|
{
|
|
switch (c)
|
|
{
|
|
case 0:
|
|
return false;
|
|
case ' ':
|
|
rCursor.InsertElement(BlankElement);
|
|
break;
|
|
case '!':
|
|
rCursor.InsertElement(FactorialElement);
|
|
break;
|
|
case '%':
|
|
rCursor.InsertElement(PercentElement);
|
|
break;
|
|
case '*':
|
|
rCursor.InsertElement(CDotElement);
|
|
break;
|
|
case '+':
|
|
rCursor.InsertElement(PlusElement);
|
|
break;
|
|
case '-':
|
|
rCursor.InsertElement(MinusElement);
|
|
break;
|
|
case '<':
|
|
rCursor.InsertElement(LessThanElement);
|
|
break;
|
|
case '=':
|
|
rCursor.InsertElement(EqualElement);
|
|
break;
|
|
case '>':
|
|
rCursor.InsertElement(GreaterThanElement);
|
|
break;
|
|
case '^':
|
|
rCursor.InsertSubSup(RSUP);
|
|
break;
|
|
case '_':
|
|
rCursor.InsertSubSup(RSUB);
|
|
break;
|
|
case '/':
|
|
rCursor.InsertFraction();
|
|
break;
|
|
case '(':
|
|
case '[':
|
|
case '{':
|
|
rCursor.InsertBrackets(BracketTypeOf(c));
|
|
break;
|
|
case ')':
|
|
case ']':
|
|
case '}':
|
|
if (rCursor.IsAtTailOfBracket(BracketTypeOf(c)))
|
|
{
|
|
rCursor.Move(&rDevice, MoveRight);
|
|
break;
|
|
}
|
|
[[fallthrough]];
|
|
default:
|
|
rCursor.InsertText(OUString(&c, 1));
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool SmGraphicWidget::KeyInput(const KeyEvent& rKEvt)
|
|
{
|
|
if (rKEvt.GetKeyCode().GetCode() == KEY_F1)
|
|
{
|
|
GetView().StartMainHelp();
|
|
return true;
|
|
}
|
|
|
|
if (rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
|
|
{
|
|
// Terminate possible InPlace mode
|
|
return GetView().Escape();
|
|
}
|
|
|
|
if (!SmViewShell::IsInlineEditEnabled())
|
|
return GetView().KeyInput(rKEvt);
|
|
|
|
bool bConsumed = true;
|
|
|
|
SmCursor& rCursor = GetCursor();
|
|
switch (rKEvt.GetKeyCode().GetFunction())
|
|
{
|
|
case KeyFuncType::COPY:
|
|
rCursor.Copy(&mrGraphicWindow);
|
|
break;
|
|
case KeyFuncType::CUT:
|
|
rCursor.Cut(&mrGraphicWindow);
|
|
break;
|
|
case KeyFuncType::PASTE:
|
|
rCursor.Paste(&mrGraphicWindow);
|
|
break;
|
|
case KeyFuncType::UNDO:
|
|
GetDoc()->Execute(o3tl::temporary(SfxRequest(*GetView().GetFrame(), SID_UNDO)));
|
|
break;
|
|
case KeyFuncType::REDO:
|
|
GetDoc()->Execute(o3tl::temporary(SfxRequest(*GetView().GetFrame(), SID_REDO)));
|
|
break;
|
|
default:
|
|
switch (rKEvt.GetKeyCode().GetCode())
|
|
{
|
|
case KEY_LEFT:
|
|
rCursor.Move(&GetOutputDevice(), MoveLeft, !rKEvt.GetKeyCode().IsShift());
|
|
break;
|
|
case KEY_RIGHT:
|
|
rCursor.Move(&GetOutputDevice(), MoveRight, !rKEvt.GetKeyCode().IsShift());
|
|
break;
|
|
case KEY_UP:
|
|
rCursor.Move(&GetOutputDevice(), MoveUp, !rKEvt.GetKeyCode().IsShift());
|
|
break;
|
|
case KEY_DOWN:
|
|
rCursor.Move(&GetOutputDevice(), MoveDown, !rKEvt.GetKeyCode().IsShift());
|
|
break;
|
|
case KEY_RETURN:
|
|
if (!rKEvt.GetKeyCode().IsShift())
|
|
rCursor.InsertRow();
|
|
break;
|
|
case KEY_DELETE:
|
|
if (!rCursor.HasSelection())
|
|
{
|
|
rCursor.Move(&GetOutputDevice(), MoveRight, false);
|
|
if (rCursor.HasComplexSelection())
|
|
break;
|
|
}
|
|
rCursor.Delete();
|
|
break;
|
|
case KEY_BACKSPACE:
|
|
rCursor.DeletePrev(&GetOutputDevice());
|
|
break;
|
|
default:
|
|
if (!CharInput(rKEvt.GetCharCode(), rCursor, GetOutputDevice()))
|
|
bConsumed = GetView().KeyInput(rKEvt);
|
|
}
|
|
}
|
|
|
|
GetView().InvalidateSlots();
|
|
CaretBlinkStop();
|
|
CaretBlinkStart();
|
|
SetIsCursorVisible(true);
|
|
RepaintViewShellDoc();
|
|
|
|
return bConsumed;
|
|
}
|
|
|
|
bool SmGraphicWidget::Command(const CommandEvent& rCEvt)
|
|
{
|
|
bool bCallBase = true;
|
|
if (!GetView().GetViewFrame().GetFrame().IsInPlace())
|
|
{
|
|
switch ( rCEvt.GetCommand() )
|
|
{
|
|
case CommandEventId::ContextMenu:
|
|
// purely for "ExecutePopup" taking a vcl::Window and
|
|
// we assume SmGraphicWindow 0,0 is at SmEditWindow 0,0
|
|
mrGraphicWindow.ShowContextMenu(rCEvt);
|
|
bCallBase = false;
|
|
break;
|
|
|
|
case CommandEventId::Wheel:
|
|
{
|
|
const CommandWheelData* pWData = rCEvt.GetWheelData();
|
|
if ( pWData && CommandWheelMode::ZOOM == pWData->GetMode() )
|
|
{
|
|
sal_uInt16 nTmpZoom = mrGraphicWindow.GetZoom();
|
|
if( 0 > pWData->GetDelta() )
|
|
nTmpZoom -= 10;
|
|
else
|
|
nTmpZoom += 10;
|
|
mrGraphicWindow.SetZoom(nTmpZoom);
|
|
bCallBase = false;
|
|
}
|
|
break;
|
|
}
|
|
case CommandEventId::GestureZoom:
|
|
{
|
|
const CommandGestureZoomData* pData = rCEvt.GetGestureZoomData();
|
|
if (pData)
|
|
{
|
|
if (pData->meEventType == GestureEventZoomType::Begin)
|
|
{
|
|
mfLastZoomScale = pData->mfScaleDelta;
|
|
}
|
|
else if (pData->meEventType == GestureEventZoomType::Update)
|
|
{
|
|
double deltaBetweenEvents = (pData->mfScaleDelta - mfLastZoomScale) / mfLastZoomScale;
|
|
mfLastZoomScale = pData->mfScaleDelta;
|
|
|
|
// Accumulate fractional zoom to avoid small zoom changes from being ignored
|
|
mfAccumulatedZoom += deltaBetweenEvents;
|
|
int nZoomChangePercent = mfAccumulatedZoom * 100;
|
|
mfAccumulatedZoom -= nZoomChangePercent / 100.0;
|
|
|
|
sal_uInt16 nZoom = mrGraphicWindow.GetZoom();
|
|
nZoom += nZoomChangePercent;
|
|
mrGraphicWindow.SetZoom(nZoom);
|
|
}
|
|
bCallBase = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
switch (rCEvt.GetCommand())
|
|
{
|
|
case CommandEventId::ExtTextInput:
|
|
if (SmViewShell::IsInlineEditEnabled())
|
|
{
|
|
const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
|
|
assert(pData);
|
|
const OUString& rText = pData->GetText();
|
|
SmCursor& rCursor = GetCursor();
|
|
OutputDevice& rDevice = GetOutputDevice();
|
|
for (sal_Int32 i = 0; i < rText.getLength();)
|
|
CharInput(rText.iterateCodePoints(&i), rCursor, rDevice);
|
|
bCallBase = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return !bCallBase;
|
|
}
|
|
|
|
void SmGraphicWindow::SetZoom(sal_uInt16 Factor)
|
|
{
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
return;
|
|
nZoom = std::clamp(Factor, MINZOOM, MAXZOOM);
|
|
Fraction aFraction(nZoom, 100);
|
|
SetGraphicMapMode(MapMode(SmMapUnit(), Point(), aFraction, aFraction));
|
|
mxGraphic->SetTotalSize();
|
|
SmViewShell& rViewSh = mxGraphic->GetView();
|
|
rViewSh.GetViewFrame().GetBindings().Invalidate(SID_ATTR_ZOOM);
|
|
rViewSh.GetViewFrame().GetBindings().Invalidate(SID_ATTR_ZOOMSLIDER);
|
|
}
|
|
|
|
void SmGraphicWindow::ZoomToFitInWindow()
|
|
{
|
|
// set defined mapmode before calling 'LogicToPixel' below
|
|
SetGraphicMapMode(MapMode(SmMapUnit()));
|
|
|
|
assert(mxGraphic->GetDoc());
|
|
Size aSize(mxGraphic->GetOutputDevice().LogicToPixel(mxGraphic->GetDoc()->GetSize()));
|
|
Size aWindowSize(GetSizePixel());
|
|
|
|
if (!aSize.IsEmpty())
|
|
{
|
|
tools::Long nVal = std::min ((85 * aWindowSize.Width()) / aSize.Width(),
|
|
(85 * aWindowSize.Height()) / aSize.Height());
|
|
SetZoom ( sal::static_int_cast< sal_uInt16 >(nVal) );
|
|
}
|
|
}
|
|
|
|
uno::Reference< XAccessible > SmGraphicWidget::CreateAccessible()
|
|
{
|
|
if (!mxAccessible.is())
|
|
{
|
|
mxAccessible = new SmGraphicAccessible( this );
|
|
}
|
|
return mxAccessible;
|
|
}
|
|
|
|
/**************************************************************************/
|
|
SmGraphicController::SmGraphicController(SmGraphicWidget &rSmGraphic,
|
|
sal_uInt16 nId_,
|
|
SfxBindings &rBindings) :
|
|
SfxControllerItem(nId_, rBindings),
|
|
rGraphic(rSmGraphic)
|
|
{
|
|
}
|
|
|
|
void SmGraphicController::StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
|
|
{
|
|
rGraphic.SetTotalSize();
|
|
rGraphic.Invalidate();
|
|
SfxControllerItem::StateChangedAtToolBoxControl (nSID, eState, pState);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
SmEditController::SmEditController(SmEditWindow &rSmEdit,
|
|
sal_uInt16 nId_,
|
|
SfxBindings &rBindings) :
|
|
SfxControllerItem(nId_, rBindings),
|
|
rEdit(rSmEdit)
|
|
{
|
|
}
|
|
|
|
void SmEditController::StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
|
|
{
|
|
const SfxStringItem *pItem = dynamic_cast<const SfxStringItem*>( pState);
|
|
|
|
if ((pItem != nullptr) && (rEdit.GetText() != pItem->GetValue()))
|
|
rEdit.SetText(pItem->GetValue());
|
|
SfxControllerItem::StateChangedAtToolBoxControl (nSID, eState, pState);
|
|
}
|
|
|
|
/**************************************************************************/
|
|
SmCmdBoxWindow::SmCmdBoxWindow(SfxBindings *pBindings_, SfxChildWindow *pChildWindow,
|
|
vcl::Window *pParent)
|
|
: SfxDockingWindow(pBindings_, pChildWindow, pParent, "EditWindow", "modules/smath/ui/editwindow.ui")
|
|
, m_xEdit(new SmEditWindow(*this, *m_xBuilder))
|
|
, aController(*m_xEdit, SID_TEXT, *pBindings_)
|
|
, bExiting(false)
|
|
, aInitialFocusTimer("SmCmdBoxWindow aInitialFocusTimer")
|
|
{
|
|
set_id("math_edit");
|
|
|
|
SetHelpId( HID_SMA_COMMAND_WIN );
|
|
SetSizePixel(LogicToPixel(Size(292 , 94), MapMode(MapUnit::MapAppFont)));
|
|
SetText(SmResId(STR_CMDBOXWINDOW));
|
|
|
|
Hide();
|
|
|
|
// Don't try to grab focus in inline edit mode
|
|
if (!SmViewShell::IsInlineEditEnabled())
|
|
{
|
|
aInitialFocusTimer.SetInvokeHandler(LINK(this, SmCmdBoxWindow, InitialFocusTimerHdl));
|
|
aInitialFocusTimer.SetTimeout(100);
|
|
}
|
|
}
|
|
|
|
Point SmCmdBoxWindow::WidgetToWindowPos(const weld::Widget& rWidget, const Point& rPos)
|
|
{
|
|
Point aRet(rPos);
|
|
int x(0), y(0), width(0), height(0);
|
|
rWidget.get_extents_relative_to(*m_xContainer, x, y, width, height);
|
|
aRet.Move(x, y);
|
|
aRet.Move(m_xBox->GetPosPixel().X(), m_xBox->GetPosPixel().Y());
|
|
return aRet;
|
|
}
|
|
|
|
void SmCmdBoxWindow::ShowContextMenu(const Point& rPos)
|
|
{
|
|
ToTop();
|
|
SmViewShell *pViewSh = GetView();
|
|
if (pViewSh)
|
|
pViewSh->GetViewFrame().GetDispatcher()->ExecutePopup("edit", this, &rPos);
|
|
}
|
|
|
|
void SmCmdBoxWindow::Command(const CommandEvent& rCEvt)
|
|
{
|
|
if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
|
|
{
|
|
ShowContextMenu(rCEvt.GetMousePosPixel());
|
|
return;
|
|
}
|
|
|
|
SfxDockingWindow::Command(rCEvt);
|
|
}
|
|
|
|
SmCmdBoxWindow::~SmCmdBoxWindow ()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void SmCmdBoxWindow::dispose()
|
|
{
|
|
aInitialFocusTimer.Stop();
|
|
bExiting = true;
|
|
aController.dispose();
|
|
m_xEdit.reset();
|
|
SfxDockingWindow::dispose();
|
|
}
|
|
|
|
SmViewShell * SmCmdBoxWindow::GetView()
|
|
{
|
|
SfxDispatcher *pDispatcher = GetBindings().GetDispatcher();
|
|
SfxViewShell *pView = pDispatcher ? pDispatcher->GetFrame()->GetViewShell() : nullptr;
|
|
return dynamic_cast<SmViewShell*>( pView);
|
|
}
|
|
|
|
Size SmCmdBoxWindow::CalcDockingSize(SfxChildAlignment eAlign)
|
|
{
|
|
switch (eAlign)
|
|
{
|
|
case SfxChildAlignment::LEFT:
|
|
case SfxChildAlignment::RIGHT:
|
|
return Size();
|
|
default:
|
|
break;
|
|
}
|
|
return SfxDockingWindow::CalcDockingSize(eAlign);
|
|
}
|
|
|
|
SfxChildAlignment SmCmdBoxWindow::CheckAlignment(SfxChildAlignment eActual,
|
|
SfxChildAlignment eWish)
|
|
{
|
|
switch (eWish)
|
|
{
|
|
case SfxChildAlignment::TOP:
|
|
case SfxChildAlignment::BOTTOM:
|
|
case SfxChildAlignment::NOALIGNMENT:
|
|
return eWish;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return eActual;
|
|
}
|
|
|
|
void SmCmdBoxWindow::StateChanged( StateChangedType nStateChange )
|
|
{
|
|
if (StateChangedType::InitShow == nStateChange)
|
|
{
|
|
Resize(); // avoid SmEditWindow not being painted correctly
|
|
|
|
// set initial position of window in floating mode
|
|
if (IsFloatingMode())
|
|
AdjustPosition(); //! don't change pos in docking-mode !
|
|
|
|
aInitialFocusTimer.Start();
|
|
}
|
|
|
|
SfxDockingWindow::StateChanged( nStateChange );
|
|
}
|
|
|
|
IMPL_LINK_NOARG( SmCmdBoxWindow, InitialFocusTimerHdl, Timer *, void )
|
|
{
|
|
// We want to have the focus in the edit window once Math has been opened
|
|
// to allow for immediate typing.
|
|
// Problem: There is no proper way to do this
|
|
// Thus: this timer based solution has been implemented (see GrabFocus below)
|
|
|
|
// Follow-up problem (#i114910): grabbing the focus may bust the help system since
|
|
// it relies on getting the current frame which conflicts with grabbing the focus.
|
|
// Thus aside from the 'GrabFocus' call everything else is to get the
|
|
// help reliably working despite using 'GrabFocus'.
|
|
|
|
try
|
|
{
|
|
uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create( comphelper::getProcessComponentContext() );
|
|
|
|
m_xEdit->GrabFocus();
|
|
|
|
SmViewShell* pView = GetView();
|
|
assert(pView);
|
|
bool bInPlace = pView->GetViewFrame().GetFrame().IsInPlace();
|
|
uno::Reference< frame::XFrame > xFrame( GetBindings().GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface());
|
|
if ( bInPlace )
|
|
{
|
|
uno::Reference<container::XChild> xModel(pView->GetDoc()->GetModel(),
|
|
uno::UNO_QUERY_THROW);
|
|
uno::Reference< frame::XModel > xParent( xModel->getParent(), uno::UNO_QUERY_THROW );
|
|
uno::Reference< frame::XController > xParentCtrler( xParent->getCurrentController() );
|
|
uno::Reference< frame::XFramesSupplier > xParentFrame( xParentCtrler->getFrame(), uno::UNO_QUERY_THROW );
|
|
xParentFrame->setActiveFrame( xFrame );
|
|
}
|
|
else
|
|
{
|
|
xDesktop->setActiveFrame( xFrame );
|
|
}
|
|
}
|
|
catch (uno::Exception &)
|
|
{
|
|
SAL_WARN( "starmath", "failed to properly set initial focus to edit window" );
|
|
}
|
|
}
|
|
|
|
void SmCmdBoxWindow::AdjustPosition()
|
|
{
|
|
const tools::Rectangle aRect( Point(), GetParent()->GetOutputSizePixel() );
|
|
Point aTopLeft( Point( aRect.Left(),
|
|
aRect.Bottom() - GetSizePixel().Height() ) );
|
|
Point aPos( GetParent()->OutputToScreenPixel( aTopLeft ) );
|
|
if (aPos.X() < 0)
|
|
aPos.setX( 0 );
|
|
if (aPos.Y() < 0)
|
|
aPos.setY( 0 );
|
|
SetPosPixel( aPos );
|
|
}
|
|
|
|
void SmCmdBoxWindow::ToggleFloatingMode()
|
|
{
|
|
SfxDockingWindow::ToggleFloatingMode();
|
|
|
|
if (GetFloatingWindow())
|
|
GetFloatingWindow()->SetMinOutputSizePixel(Size (200, 50));
|
|
}
|
|
|
|
void SmCmdBoxWindow::GetFocus()
|
|
{
|
|
if (!bExiting)
|
|
m_xEdit->GrabFocus();
|
|
}
|
|
|
|
SFX_IMPL_DOCKINGWINDOW_WITHID(SmCmdBoxWrapper, SID_CMDBOXWINDOW);
|
|
|
|
SmCmdBoxWrapper::SmCmdBoxWrapper(vcl::Window *pParentWindow, sal_uInt16 nId,
|
|
SfxBindings *pBindings,
|
|
SfxChildWinInfo *pInfo) :
|
|
SfxChildWindow(pParentWindow, nId)
|
|
{
|
|
VclPtrInstance<SmCmdBoxWindow> pDialog(pBindings, this, pParentWindow);
|
|
SetWindow(pDialog);
|
|
// make window docked to the bottom initially (after first start)
|
|
SetAlignment(SfxChildAlignment::BOTTOM);
|
|
pDialog->setDeferredProperties();
|
|
pDialog->set_border_width(CMD_BOX_PADDING);
|
|
pDialog->set_margin_top(CMD_BOX_PADDING_TOP);
|
|
pDialog->Initialize(pInfo);
|
|
}
|
|
|
|
SFX_IMPL_SUPERCLASS_INTERFACE(SmViewShell, SfxViewShell)
|
|
|
|
void SmViewShell::InitInterface_Impl()
|
|
{
|
|
GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS,
|
|
SfxVisibilityFlags::Standard | SfxVisibilityFlags::FullScreen | SfxVisibilityFlags::Server,
|
|
ToolbarId::Math_Toolbox);
|
|
//Dummy-Objectbar, to avoid quiver while activating
|
|
|
|
GetStaticInterface()->RegisterChildWindow(SmCmdBoxWrapper::GetChildWindowId());
|
|
GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
|
|
|
|
GetStaticInterface()->RegisterChildWindow(::sfx2::sidebar::SidebarChildWindow::GetChildWindowId());
|
|
}
|
|
|
|
SFX_IMPL_NAMED_VIEWFACTORY(SmViewShell, "Default")
|
|
{
|
|
SFX_VIEW_REGISTRATION(SmDocShell);
|
|
}
|
|
|
|
void SmViewShell::InnerResizePixel(const Point &rOfs, const Size &rSize, bool)
|
|
{
|
|
Size aObjSize = GetObjectShell()->GetVisArea().GetSize();
|
|
if ( !aObjSize.IsEmpty() )
|
|
{
|
|
Size aProvidedSize = GetWindow()->PixelToLogic(rSize, MapMode(SmMapUnit()));
|
|
Fraction aZoomX(aProvidedSize.Width(), aObjSize.Width());
|
|
Fraction aZoomY(aProvidedSize.Height(), aObjSize.Height());
|
|
MapMode aMap(mxGraphicWindow->GetGraphicMapMode());
|
|
aMap.SetScaleX(aZoomX);
|
|
aMap.SetScaleY(aZoomY);
|
|
mxGraphicWindow->SetGraphicMapMode(aMap);
|
|
}
|
|
|
|
SetBorderPixel( SvBorder() );
|
|
mxGraphicWindow->SetPosSizePixel(rOfs, rSize);
|
|
GetGraphicWidget().SetTotalSize();
|
|
}
|
|
|
|
void SmViewShell::OuterResizePixel(const Point &rOfs, const Size &rSize)
|
|
{
|
|
mxGraphicWindow->SetPosSizePixel(rOfs, rSize);
|
|
if (GetDoc()->IsPreview())
|
|
mxGraphicWindow->ZoomToFitInWindow();
|
|
}
|
|
|
|
void SmViewShell::QueryObjAreaPixel( tools::Rectangle& rRect ) const
|
|
{
|
|
rRect.SetSize(mxGraphicWindow->GetSizePixel());
|
|
}
|
|
|
|
void SmViewShell::SetZoomFactor( const Fraction &rX, const Fraction &rY )
|
|
{
|
|
const Fraction &rFrac = std::min(rX, rY);
|
|
mxGraphicWindow->SetZoom(sal::static_int_cast<sal_uInt16>(tools::Long(rFrac * Fraction( 100, 1 ))));
|
|
|
|
//To avoid rounding errors base class regulates crooked values too
|
|
//if necessary
|
|
SfxViewShell::SetZoomFactor( rX, rY );
|
|
}
|
|
|
|
SfxPrinter* SmViewShell::GetPrinter(bool bCreate)
|
|
{
|
|
SmDocShell* pDoc = GetDoc();
|
|
if (pDoc->HasPrinter() || bCreate)
|
|
return pDoc->GetPrinter();
|
|
return nullptr;
|
|
}
|
|
|
|
sal_uInt16 SmViewShell::SetPrinter(SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
|
|
{
|
|
SfxPrinter *pOld = GetDoc()->GetPrinter();
|
|
if ( pOld && pOld->IsPrinting() )
|
|
return SFX_PRINTERROR_BUSY;
|
|
|
|
if ((nDiffFlags & SfxPrinterChangeFlags::PRINTER) == SfxPrinterChangeFlags::PRINTER)
|
|
GetDoc()->SetPrinter( pNewPrinter );
|
|
|
|
if ((nDiffFlags & SfxPrinterChangeFlags::OPTIONS) == SfxPrinterChangeFlags::OPTIONS)
|
|
{
|
|
SmModule *pp = SM_MOD();
|
|
pp->GetConfig()->ItemSetToConfig(pNewPrinter->GetOptions());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool SmViewShell::HasPrintOptionsPage() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
std::unique_ptr<SfxTabPage> SmViewShell::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController,
|
|
const SfxItemSet &rOptions)
|
|
{
|
|
return SmPrintOptionsTabPage::Create(pPage, pController, rOptions);
|
|
}
|
|
|
|
SmEditWindow *SmViewShell::GetEditWindow()
|
|
{
|
|
SmCmdBoxWrapper* pWrapper = static_cast<SmCmdBoxWrapper*>(
|
|
GetViewFrame().GetChildWindow(SmCmdBoxWrapper::GetChildWindowId()));
|
|
|
|
if (pWrapper != nullptr)
|
|
{
|
|
SmEditWindow& rEditWin = pWrapper->GetEditWindow();
|
|
return &rEditWin;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void SmViewShell::SetStatusText(const OUString& rText)
|
|
{
|
|
maStatusText = rText;
|
|
GetViewFrame().GetBindings().Invalidate(SID_TEXTSTATUS);
|
|
}
|
|
|
|
void SmViewShell::ShowError(const SmErrorDesc* pErrorDesc)
|
|
{
|
|
assert(GetDoc());
|
|
if (pErrorDesc || nullptr != (pErrorDesc = GetDoc()->GetParser()->GetError()) )
|
|
{
|
|
SetStatusText( pErrorDesc->m_aText );
|
|
if (SmEditWindow* pEdit = GetEditWindow())
|
|
pEdit->MarkError( Point( pErrorDesc->m_pNode->GetColumn(),
|
|
pErrorDesc->m_pNode->GetRow()));
|
|
}
|
|
}
|
|
|
|
void SmViewShell::NextError()
|
|
{
|
|
assert(GetDoc());
|
|
const SmErrorDesc *pErrorDesc = GetDoc()->GetParser()->NextError();
|
|
|
|
if (pErrorDesc)
|
|
ShowError( pErrorDesc );
|
|
}
|
|
|
|
void SmViewShell::PrevError()
|
|
{
|
|
assert(GetDoc());
|
|
const SmErrorDesc *pErrorDesc = GetDoc()->GetParser()->PrevError();
|
|
|
|
if (pErrorDesc)
|
|
ShowError( pErrorDesc );
|
|
}
|
|
|
|
void SmViewShell::Insert( SfxMedium& rMedium )
|
|
{
|
|
SmDocShell *pDoc = GetDoc();
|
|
bool bRet = false;
|
|
|
|
uno::Reference <embed::XStorage> xStorage = rMedium.GetStorage();
|
|
if (xStorage.is() && xStorage->getElementNames().hasElements())
|
|
{
|
|
if (xStorage->hasByName("content.xml"))
|
|
{
|
|
// is this a fabulous math package ?
|
|
rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(pDoc->GetModel().get()));
|
|
SmXMLImportWrapper aEquation(xModel); //!! modifies the result of pDoc->GetText() !!
|
|
bRet = ERRCODE_NONE == aEquation.Import(rMedium);
|
|
}
|
|
}
|
|
|
|
if (!bRet)
|
|
return;
|
|
|
|
OUString aText = pDoc->GetText();
|
|
if (SmEditWindow *pEditWin = GetEditWindow())
|
|
pEditWin->InsertText( aText );
|
|
else
|
|
{
|
|
SAL_WARN( "starmath", "EditWindow missing" );
|
|
}
|
|
|
|
pDoc->Parse();
|
|
pDoc->SetModified();
|
|
|
|
SfxBindings &rBnd = GetViewFrame().GetBindings();
|
|
rBnd.Invalidate(SID_GRAPHIC_SM);
|
|
rBnd.Invalidate(SID_TEXT);
|
|
}
|
|
|
|
void SmViewShell::InsertFrom(SfxMedium &rMedium)
|
|
{
|
|
bool bSuccess = false;
|
|
SmDocShell* pDoc = GetDoc();
|
|
SvStream* pStream = rMedium.GetInStream();
|
|
|
|
if (pStream)
|
|
{
|
|
const OUString& rFltName = rMedium.GetFilter()->GetFilterName();
|
|
if ( rFltName == MATHML_XML )
|
|
{
|
|
rtl::Reference<SmModel> xModel(dynamic_cast<SmModel*>(pDoc->GetModel().get()));
|
|
SmXMLImportWrapper aEquation(xModel); //!! modifies the result of pDoc->GetText() !!
|
|
bSuccess = ERRCODE_NONE == aEquation.Import(rMedium);
|
|
}
|
|
}
|
|
|
|
if (!bSuccess)
|
|
return;
|
|
|
|
OUString aText = pDoc->GetText();
|
|
if (SmEditWindow *pEditWin = GetEditWindow())
|
|
pEditWin->InsertText(aText);
|
|
else
|
|
SAL_WARN( "starmath", "EditWindow missing" );
|
|
|
|
pDoc->Parse();
|
|
pDoc->SetModified();
|
|
|
|
SfxBindings& rBnd = GetViewFrame().GetBindings();
|
|
rBnd.Invalidate(SID_GRAPHIC_SM);
|
|
rBnd.Invalidate(SID_TEXT);
|
|
}
|
|
|
|
void SmViewShell::Execute(SfxRequest& rReq)
|
|
{
|
|
SmEditWindow *pWin = GetEditWindow();
|
|
|
|
switch (rReq.GetSlot())
|
|
{
|
|
case SID_FORMULACURSOR:
|
|
{
|
|
SmModule *pp = SM_MOD();
|
|
|
|
const SfxItemSet *pArgs = rReq.GetArgs();
|
|
const SfxPoolItem *pItem;
|
|
|
|
bool bVal;
|
|
if ( pArgs &&
|
|
SfxItemState::SET == pArgs->GetItemState( SID_FORMULACURSOR, false, &pItem))
|
|
bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue();
|
|
else
|
|
bVal = !pp->GetConfig()->IsShowFormulaCursor();
|
|
|
|
pp->GetConfig()->SetShowFormulaCursor(bVal);
|
|
if (!IsInlineEditEnabled())
|
|
GetGraphicWidget().ShowCursor(bVal);
|
|
break;
|
|
}
|
|
case SID_DRAW:
|
|
if (pWin)
|
|
{
|
|
GetDoc()->SetText( pWin->GetText() );
|
|
SetStatusText(OUString());
|
|
ShowError( nullptr );
|
|
GetDoc()->Repaint();
|
|
}
|
|
break;
|
|
|
|
case SID_ZOOM_OPTIMAL:
|
|
mxGraphicWindow->ZoomToFitInWindow();
|
|
break;
|
|
|
|
case SID_ZOOMIN:
|
|
mxGraphicWindow->SetZoom(mxGraphicWindow->GetZoom() + 25);
|
|
break;
|
|
|
|
case SID_ZOOMOUT:
|
|
SAL_WARN_IF( mxGraphicWindow->GetZoom() < 25, "starmath", "incorrect sal_uInt16 argument" );
|
|
mxGraphicWindow->SetZoom(mxGraphicWindow->GetZoom() - 25);
|
|
break;
|
|
|
|
case SID_COPYOBJECT:
|
|
{
|
|
//TODO/LATER: does not work because of UNO Tunneling - will be fixed later
|
|
Reference< datatransfer::XTransferable > xTrans( GetDoc()->GetModel(), uno::UNO_QUERY );
|
|
if( xTrans.is() )
|
|
{
|
|
auto pTrans = dynamic_cast<TransferableHelper*>(xTrans.get());
|
|
if (pTrans)
|
|
{
|
|
if (pWin)
|
|
pTrans->CopyToClipboard(pWin->GetClipboard());
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SID_PASTEOBJECT:
|
|
{
|
|
uno::Reference < io::XInputStream > xStrm;
|
|
if (pWin)
|
|
{
|
|
TransferableDataHelper aData(TransferableDataHelper::CreateFromClipboard(pWin->GetClipboard()));
|
|
SotClipboardFormatId nId;
|
|
if( aData.GetTransferable().is() &&
|
|
( aData.HasFormat( nId = SotClipboardFormatId::EMBEDDED_OBJ ) ||
|
|
(aData.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) &&
|
|
aData.HasFormat( nId = SotClipboardFormatId::EMBED_SOURCE ))))
|
|
xStrm = aData.GetInputStream(nId, OUString());
|
|
}
|
|
|
|
if (xStrm.is())
|
|
{
|
|
try
|
|
{
|
|
uno::Reference < embed::XStorage > xStorage =
|
|
::comphelper::OStorageHelper::GetStorageFromInputStream( xStrm, ::comphelper::getProcessComponentContext() );
|
|
SfxMedium aMedium( xStorage, OUString() );
|
|
Insert( aMedium );
|
|
GetDoc()->UpdateText();
|
|
}
|
|
catch (uno::Exception &)
|
|
{
|
|
SAL_WARN( "starmath", "SmViewShell::Execute (SID_PASTEOBJECT): failed to get storage from input stream" );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
case SID_CUT:
|
|
if (IsInlineEditEnabled())
|
|
{
|
|
GetDoc()->GetCursor().Cut(&GetGraphicWindow());
|
|
GetGraphicWidget().GrabFocus();
|
|
}
|
|
else if (pWin)
|
|
pWin->Cut();
|
|
break;
|
|
|
|
case SID_COPY:
|
|
if (IsInlineEditEnabled())
|
|
{
|
|
GetDoc()->GetCursor().Copy(&GetGraphicWindow());
|
|
GetGraphicWidget().GrabFocus();
|
|
}
|
|
else if (pWin)
|
|
{
|
|
if (pWin->IsAllSelected())
|
|
{
|
|
GetViewFrame().GetDispatcher()->ExecuteList(
|
|
SID_COPYOBJECT, SfxCallMode::RECORD,
|
|
{ new SfxVoidItem(SID_COPYOBJECT) });
|
|
}
|
|
else
|
|
pWin->Copy();
|
|
}
|
|
break;
|
|
|
|
case SID_PASTE:
|
|
{
|
|
if (IsInlineEditEnabled())
|
|
{
|
|
GetDoc()->GetCursor().Paste(&GetGraphicWindow());
|
|
GetGraphicWidget().GrabFocus();
|
|
break;
|
|
}
|
|
|
|
bool bCallExec = nullptr == pWin;
|
|
if( !bCallExec )
|
|
{
|
|
if (pWin)
|
|
{
|
|
TransferableDataHelper aDataHelper(
|
|
TransferableDataHelper::CreateFromClipboard(
|
|
pWin->GetClipboard()));
|
|
|
|
if( aDataHelper.GetTransferable().is() &&
|
|
aDataHelper.HasFormat( SotClipboardFormatId::STRING ))
|
|
pWin->Paste();
|
|
else
|
|
bCallExec = true;
|
|
}
|
|
}
|
|
if( bCallExec )
|
|
{
|
|
GetViewFrame().GetDispatcher()->ExecuteList(
|
|
SID_PASTEOBJECT, SfxCallMode::RECORD,
|
|
{ new SfxVoidItem(SID_PASTEOBJECT) });
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SID_DELETE:
|
|
if (IsInlineEditEnabled())
|
|
{
|
|
if (!GetDoc()->GetCursor().HasSelection())
|
|
{
|
|
GetDoc()->GetCursor().Move(&GetGraphicWindow().GetGraphicWidget().GetOutputDevice(), MoveRight, false);
|
|
if (!GetDoc()->GetCursor().HasComplexSelection())
|
|
GetDoc()->GetCursor().Delete();
|
|
}
|
|
else
|
|
GetDoc()->GetCursor().Delete();
|
|
GetGraphicWidget().GrabFocus();
|
|
}
|
|
else if (pWin)
|
|
pWin->Delete();
|
|
break;
|
|
|
|
case SID_SELECT:
|
|
if (pWin)
|
|
pWin->SelectAll();
|
|
break;
|
|
|
|
case SID_INSERTCOMMANDTEXT:
|
|
{
|
|
const SfxStringItem& rItem = rReq.GetArgs()->Get(SID_INSERTCOMMANDTEXT);
|
|
|
|
if (IsInlineEditEnabled())
|
|
{
|
|
GetDoc()->GetCursor().InsertCommandText(rItem.GetValue());
|
|
GetGraphicWidget().GrabFocus();
|
|
}
|
|
else if (pWin)
|
|
{
|
|
pWin->InsertText(rItem.GetValue());
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
case SID_INSERTSPECIAL:
|
|
{
|
|
const SfxStringItem& rItem = rReq.GetArgs()->Get(SID_INSERTSPECIAL);
|
|
|
|
if (IsInlineEditEnabled())
|
|
GetDoc()->GetCursor().InsertSpecial(rItem.GetValue());
|
|
else if (pWin)
|
|
pWin->InsertText(rItem.GetValue());
|
|
break;
|
|
}
|
|
|
|
case SID_IMPORT_FORMULA:
|
|
{
|
|
mpRequest.reset(new SfxRequest( rReq ));
|
|
mpDocInserter.reset(new ::sfx2::DocumentInserter(pWin ? pWin->GetFrameWeld() : nullptr,
|
|
GetDoc()->GetFactory().GetFactoryName()));
|
|
mpDocInserter->StartExecuteModal( LINK( this, SmViewShell, DialogClosedHdl ) );
|
|
break;
|
|
}
|
|
|
|
case SID_IMPORT_MATHML_CLIPBOARD:
|
|
{
|
|
if (pWin)
|
|
{
|
|
TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromClipboard(pWin->GetClipboard()));
|
|
uno::Reference < io::XInputStream > xStrm;
|
|
if ( aDataHelper.GetTransferable().is() )
|
|
{
|
|
SotClipboardFormatId nId = SotClipboardFormatId::MATHML;
|
|
if (aDataHelper.HasFormat(nId))
|
|
{
|
|
xStrm = aDataHelper.GetInputStream(nId, "");
|
|
if (xStrm.is())
|
|
{
|
|
SfxMedium aClipboardMedium;
|
|
aClipboardMedium.GetItemSet(); //generate initial itemset, not sure if necessary
|
|
std::shared_ptr<const SfxFilter> pMathFilter =
|
|
SfxFilter::GetFilterByName(MATHML_XML);
|
|
aClipboardMedium.SetFilter(pMathFilter);
|
|
aClipboardMedium.setStreamToLoadFrom(xStrm, true /*bIsReadOnly*/);
|
|
InsertFrom(aClipboardMedium);
|
|
GetDoc()->UpdateText();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
nId = SotClipboardFormatId::STRING;
|
|
if (aDataHelper.HasFormat(nId))
|
|
{
|
|
// In case of FORMAT_STRING no stream exists, need to generate one
|
|
OUString aString;
|
|
if (aDataHelper.GetString( nId, aString))
|
|
{
|
|
// tdf#117091 force xml declaration to exist
|
|
if (!aString.startsWith("<?xml"))
|
|
aString = "<?xml version=\"1.0\"?>\n" + aString;
|
|
|
|
SfxMedium aClipboardMedium;
|
|
aClipboardMedium.GetItemSet(); //generates initial itemset, not sure if necessary
|
|
std::shared_ptr<const SfxFilter> pMathFilter =
|
|
SfxFilter::GetFilterByName(MATHML_XML);
|
|
aClipboardMedium.SetFilter(pMathFilter);
|
|
|
|
SvMemoryStream aStrm( const_cast<sal_Unicode *>(aString.getStr()), aString.getLength() * sizeof(sal_Unicode), StreamMode::READ);
|
|
uno::Reference<io::XInputStream> xStrm2( new ::utl::OInputStreamWrapper(aStrm) );
|
|
aClipboardMedium.setStreamToLoadFrom(xStrm2, true /*bIsReadOnly*/);
|
|
InsertFrom(aClipboardMedium);
|
|
GetDoc()->UpdateText();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SID_NEXTERR:
|
|
NextError();
|
|
if (pWin)
|
|
pWin->GrabFocus();
|
|
break;
|
|
|
|
case SID_PREVERR:
|
|
PrevError();
|
|
if (pWin)
|
|
pWin->GrabFocus();
|
|
break;
|
|
|
|
case SID_NEXTMARK:
|
|
if (pWin)
|
|
{
|
|
pWin->SelNextMark();
|
|
pWin->GrabFocus();
|
|
}
|
|
break;
|
|
|
|
case SID_PREVMARK:
|
|
if (pWin)
|
|
{
|
|
pWin->SelPrevMark();
|
|
pWin->GrabFocus();
|
|
}
|
|
break;
|
|
|
|
case SID_TEXTSTATUS:
|
|
{
|
|
if (rReq.GetArgs() != nullptr)
|
|
{
|
|
const SfxStringItem& rItem = rReq.GetArgs()->Get(SID_TEXTSTATUS);
|
|
|
|
SetStatusText(rItem.GetValue());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SID_GETEDITTEXT:
|
|
if (pWin && !pWin->GetText().isEmpty())
|
|
GetDoc()->SetText( pWin->GetText() );
|
|
break;
|
|
|
|
case SID_ATTR_ZOOM:
|
|
{
|
|
if ( !GetViewFrame().GetFrame().IsInPlace() )
|
|
{
|
|
const SfxItemSet *pSet = rReq.GetArgs();
|
|
if ( pSet )
|
|
{
|
|
ZoomByItemSet(pSet);
|
|
}
|
|
else
|
|
{
|
|
SfxItemSetFixed<SID_ATTR_ZOOM, SID_ATTR_ZOOM> aSet( SmDocShell::GetPool() );
|
|
aSet.Put( SvxZoomItem( SvxZoomType::PERCENT, mxGraphicWindow->GetZoom()));
|
|
SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
|
|
ScopedVclPtr<AbstractSvxZoomDialog> xDlg(pFact->CreateSvxZoomDialog(GetViewFrame().GetWindow().GetFrameWeld(), aSet));
|
|
xDlg->SetLimits( MINZOOM, MAXZOOM );
|
|
if (xDlg->Execute() != RET_CANCEL)
|
|
ZoomByItemSet(xDlg->GetOutputItemSet());
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SID_ATTR_ZOOMSLIDER:
|
|
{
|
|
const SfxItemSet *pArgs = rReq.GetArgs();
|
|
const SfxPoolItem* pItem;
|
|
|
|
if ( pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_ZOOMSLIDER, true, &pItem ) )
|
|
{
|
|
const sal_uInt16 nCurrentZoom = static_cast<const SvxZoomSliderItem *>(pItem)->GetValue();
|
|
mxGraphicWindow->SetZoom(nCurrentZoom);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SID_ELEMENTSDOCKINGWINDOW:
|
|
{
|
|
// First make sure that the sidebar is visible
|
|
GetViewFrame().ShowChildWindow(SID_SIDEBAR);
|
|
|
|
sfx2::sidebar::Sidebar::TogglePanel(u"MathElementsPanel",
|
|
GetViewFrame().GetFrame().GetFrameInterface());
|
|
GetViewFrame().GetBindings().Invalidate( SID_ELEMENTSDOCKINGWINDOW );
|
|
|
|
rReq.Ignore ();
|
|
}
|
|
break;
|
|
|
|
case SID_CMDBOXWINDOW:
|
|
{
|
|
GetViewFrame().ToggleChildWindow(SID_CMDBOXWINDOW);
|
|
GetViewFrame().GetBindings().Invalidate(SID_CMDBOXWINDOW);
|
|
}
|
|
break;
|
|
|
|
case SID_UNICODE_NOTATION_TOGGLE:
|
|
{
|
|
EditEngine* pEditEngine = nullptr;
|
|
if( pWin )
|
|
pEditEngine = pWin->GetEditEngine();
|
|
|
|
EditView* pEditView = nullptr;
|
|
if( pEditEngine )
|
|
pEditView = pEditEngine->GetView();
|
|
|
|
if( pEditView )
|
|
{
|
|
const OUString sInput = pEditView->GetSurroundingText();
|
|
ESelection aSel( pWin->GetSelection() );
|
|
|
|
if ( aSel.nStartPos > aSel.nEndPos )
|
|
aSel.nEndPos = aSel.nStartPos;
|
|
|
|
//calculate a valid end-position by reading logical characters
|
|
sal_Int32 nUtf16Pos=0;
|
|
while( (nUtf16Pos < sInput.getLength()) && (nUtf16Pos < aSel.nEndPos) )
|
|
{
|
|
sInput.iterateCodePoints(&nUtf16Pos);
|
|
if( nUtf16Pos > aSel.nEndPos )
|
|
aSel.nEndPos = nUtf16Pos;
|
|
}
|
|
|
|
ToggleUnicodeCodepoint aToggle;
|
|
while( nUtf16Pos && aToggle.AllowMoreInput( sInput[nUtf16Pos-1]) )
|
|
--nUtf16Pos;
|
|
const OUString sReplacement = aToggle.ReplacementString();
|
|
if( !sReplacement.isEmpty() )
|
|
{
|
|
pEditView->SetSelection( aSel );
|
|
pEditEngine->UndoActionStart(EDITUNDO_REPLACEALL);
|
|
aSel.nStartPos = aSel.nEndPos - aToggle.StringToReplace().getLength();
|
|
pWin->SetSelection( aSel );
|
|
pEditView->InsertText( sReplacement, true );
|
|
pEditEngine->UndoActionEnd();
|
|
pWin->Flush();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SID_SYMBOLS_CATALOGUE:
|
|
{
|
|
|
|
// get device used to retrieve the FontList
|
|
SmDocShell *pDoc = GetDoc();
|
|
OutputDevice *pDev = pDoc->GetPrinter();
|
|
if (!pDev || pDev->GetFontFaceCollectionCount() == 0)
|
|
pDev = &SM_MOD()->GetDefaultVirtualDev();
|
|
SAL_WARN_IF( !pDev, "starmath", "device for font list missing" );
|
|
|
|
SmModule *pp = SM_MOD();
|
|
SmSymbolDialog aDialog(pWin ? pWin->GetFrameWeld() : nullptr, pDev, pp->GetSymbolManager(), *this);
|
|
aDialog.run();
|
|
}
|
|
break;
|
|
|
|
case SID_CHARMAP:
|
|
{
|
|
const SfxItemSet* pArgs = rReq.GetArgs();
|
|
const SfxStringItem* pItem = nullptr;
|
|
if (pArgs && SfxItemState::SET == pArgs->GetItemState(SID_CHARMAP, true, &pItem))
|
|
{
|
|
if (IsInlineEditEnabled())
|
|
GetDoc()->GetCursor().InsertText(pItem->GetValue());
|
|
else if (pWin)
|
|
pWin->InsertText(pItem->GetValue());
|
|
break;
|
|
}
|
|
|
|
SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
|
|
SfxAllItemSet aSet(GetViewFrame().GetObjectShell()->GetPool());
|
|
aSet.Put(SfxBoolItem(FN_PARAM_1, false));
|
|
aSet.Put(SfxStringItem(SID_FONT_NAME,
|
|
GetDoc()->GetFormat().GetFont(FNT_VARIABLE).GetFamilyName()));
|
|
VclPtr<SfxAbstractDialog> pDialog(
|
|
pFact->CreateCharMapDialog(pWin ? pWin->GetFrameWeld() : nullptr, aSet,
|
|
GetViewFrame().GetFrame().GetFrameInterface()));
|
|
pDialog->StartExecuteAsync(
|
|
[pDialog] (sal_Int32 /*nResult*/)->void
|
|
{
|
|
pDialog->disposeOnce();
|
|
}
|
|
);
|
|
}
|
|
break;
|
|
|
|
case SID_ATTR_PARA_LEFT_TO_RIGHT:
|
|
case SID_ATTR_PARA_RIGHT_TO_LEFT:
|
|
{
|
|
bool bRTL = rReq.GetSlot() == SID_ATTR_PARA_RIGHT_TO_LEFT;
|
|
GetDoc()->SetRightToLeft(bRTL);
|
|
GetGraphicWindow().GetGraphicWidget().GetOutputDevice().EnableRTL(bRTL);
|
|
GetViewFrame().GetBindings().Invalidate(bRTL ? SID_ATTR_PARA_LEFT_TO_RIGHT : SID_ATTR_PARA_RIGHT_TO_LEFT);
|
|
}
|
|
break;
|
|
}
|
|
rReq.Done();
|
|
}
|
|
|
|
|
|
void SmViewShell::GetState(SfxItemSet &rSet)
|
|
{
|
|
SfxWhichIter aIter(rSet);
|
|
|
|
SmEditWindow *pEditWin = GetEditWindow();
|
|
for (sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich())
|
|
{
|
|
switch (nWh)
|
|
{
|
|
case SID_CUT:
|
|
case SID_COPY:
|
|
case SID_DELETE:
|
|
if (IsInlineEditEnabled())
|
|
{
|
|
if (!GetDoc()->GetCursor().HasSelection())
|
|
rSet.DisableItem(nWh);
|
|
}
|
|
else if (! pEditWin || ! pEditWin->IsSelected())
|
|
rSet.DisableItem(nWh);
|
|
break;
|
|
|
|
case SID_PASTE:
|
|
if (pEditWin)
|
|
{
|
|
TransferableDataHelper aDataHelper(
|
|
TransferableDataHelper::CreateFromClipboard(
|
|
pEditWin->GetClipboard()) );
|
|
|
|
mbPasteState = aDataHelper.GetTransferable().is() &&
|
|
( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ||
|
|
aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ ) ||
|
|
(aDataHelper.HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR )
|
|
&& aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE )));
|
|
}
|
|
if( !mbPasteState )
|
|
rSet.DisableItem( nWh );
|
|
break;
|
|
|
|
case SID_ATTR_ZOOM:
|
|
rSet.Put(SvxZoomItem( SvxZoomType::PERCENT, mxGraphicWindow->GetZoom()));
|
|
[[fallthrough]];
|
|
case SID_ZOOMIN:
|
|
case SID_ZOOMOUT:
|
|
case SID_ZOOM_OPTIMAL:
|
|
if ( GetViewFrame().GetFrame().IsInPlace() )
|
|
rSet.DisableItem( nWh );
|
|
break;
|
|
|
|
case SID_ATTR_ZOOMSLIDER :
|
|
{
|
|
const sal_uInt16 nCurrentZoom = mxGraphicWindow->GetZoom();
|
|
SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM, MAXZOOM );
|
|
aZoomSliderItem.AddSnappingPoint( 100 );
|
|
rSet.Put( aZoomSliderItem );
|
|
}
|
|
break;
|
|
|
|
case SID_NEXTERR:
|
|
case SID_PREVERR:
|
|
case SID_NEXTMARK:
|
|
case SID_PREVMARK:
|
|
case SID_DRAW:
|
|
case SID_SELECT:
|
|
if (! pEditWin || pEditWin->IsEmpty())
|
|
rSet.DisableItem(nWh);
|
|
break;
|
|
|
|
case SID_TEXTSTATUS:
|
|
{
|
|
rSet.Put(SfxStringItem(nWh, maStatusText));
|
|
}
|
|
break;
|
|
|
|
case SID_FORMULACURSOR:
|
|
{
|
|
if (IsInlineEditEnabled())
|
|
rSet.DisableItem(nWh);
|
|
else
|
|
rSet.Put(SfxBoolItem(nWh, SM_MOD()->GetConfig()->IsShowFormulaCursor()));
|
|
}
|
|
break;
|
|
case SID_ELEMENTSDOCKINGWINDOW:
|
|
{
|
|
const bool bState = sfx2::sidebar::Sidebar::IsPanelVisible(
|
|
u"MathElementsPanel", GetViewFrame().GetFrame().GetFrameInterface());
|
|
rSet.Put(SfxBoolItem(SID_ELEMENTSDOCKINGWINDOW, bState));
|
|
}
|
|
break;
|
|
case SID_CMDBOXWINDOW:
|
|
{
|
|
bool bState = false;
|
|
auto pCmdWin = GetViewFrame().GetChildWindow(SID_CMDBOXWINDOW);
|
|
if (pCmdWin)
|
|
bState = pCmdWin->IsVisible();
|
|
rSet.Put(SfxBoolItem(SID_CMDBOXWINDOW, bState));
|
|
}
|
|
break;
|
|
case SID_ATTR_PARA_LEFT_TO_RIGHT:
|
|
rSet.Put(SfxBoolItem(nWh, !GetDoc()->GetFormat().IsRightToLeft()));
|
|
break;
|
|
|
|
case SID_ATTR_PARA_RIGHT_TO_LEFT:
|
|
rSet.Put(SfxBoolItem(nWh, GetDoc()->GetFormat().IsRightToLeft()));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace
|
|
{
|
|
css::uno::Reference<css::ui::XSidebar>
|
|
getSidebarFromModel(const css::uno::Reference<css::frame::XModel>& xModel)
|
|
{
|
|
css::uno::Reference<css::container::XChild> xChild(xModel, css::uno::UNO_QUERY);
|
|
if (!xChild.is())
|
|
return nullptr;
|
|
css::uno::Reference<css::frame::XModel> xParent(xChild->getParent(), css::uno::UNO_QUERY);
|
|
if (!xParent.is())
|
|
return nullptr;
|
|
css::uno::Reference<css::frame::XController2> xController(xParent->getCurrentController(),
|
|
css::uno::UNO_QUERY);
|
|
if (!xController.is())
|
|
return nullptr;
|
|
css::uno::Reference<css::ui::XSidebarProvider> xSidebarProvider = xController->getSidebar();
|
|
if (!xSidebarProvider.is())
|
|
return nullptr;
|
|
return xSidebarProvider->getSidebar();
|
|
}
|
|
class SmController : public SfxBaseController
|
|
{
|
|
public:
|
|
SmController(SfxViewShell& rViewShell)
|
|
: SfxBaseController(&rViewShell)
|
|
, mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
|
|
GetContextName, this, vcl::EnumContext::Context::Math))
|
|
{
|
|
rViewShell.SetContextName(GetContextName());
|
|
}
|
|
// No need to call mpSelectionChangeHandler->Disconnect() unless SmController implements XSelectionSupplier
|
|
// ~SmController() { mpSelectionChangeHandler->Disconnect(); }
|
|
|
|
// css::frame::XController
|
|
void SAL_CALL attachFrame(const css::uno::Reference<css::frame::XFrame>& xFrame) override
|
|
{
|
|
SfxBaseController::attachFrame(xFrame);
|
|
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
CopyLokViewCallbackFromFrameCreator();
|
|
// In lok mode, DocumentHolder::ShowUI is not called on OLE in-place activation,
|
|
// because respective code is skipped in OCommonEmbeddedObject::SwitchStateTo_Impl,
|
|
// so sidebar controller does not get registered properly; do it here
|
|
if (auto xSidebar = getSidebarFromModel(getModel()))
|
|
{
|
|
auto pSidebar = dynamic_cast<sfx2::sidebar::SidebarController*>(xSidebar.get());
|
|
assert(pSidebar);
|
|
pSidebar->registerSidebarForFrame(this);
|
|
pSidebar->updateModel(getModel());
|
|
}
|
|
}
|
|
|
|
// No need to call mpSelectionChangeHandler->Connect() unless SmController implements XSelectionSupplier
|
|
mpSelectionChangeHandler->selectionChanged({}); // Installs the correct context
|
|
}
|
|
|
|
virtual void SAL_CALL dispose() override
|
|
{
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
if (auto pViewShell = GetViewShell_Impl())
|
|
pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CURSOR_VISIBLE,
|
|
OString::boolean(false));
|
|
|
|
SfxBaseController::dispose();
|
|
}
|
|
|
|
private:
|
|
static OUString GetContextName() { return "Math"; } // Static constant for now
|
|
|
|
rtl::Reference<svx::sidebar::SelectionChangeHandler> mpSelectionChangeHandler;
|
|
};
|
|
}
|
|
|
|
SmViewShell::SmViewShell(SfxViewFrame& rFrame_, SfxViewShell *)
|
|
: SfxViewShell(rFrame_, SfxViewShellFlags::HAS_PRINTOPTIONS)
|
|
, mxGraphicWindow(VclPtr<SmGraphicWindow>::Create(*this))
|
|
, maGraphicController(mxGraphicWindow->GetGraphicWidget(), SID_GRAPHIC_SM, rFrame_.GetBindings())
|
|
, mbPasteState(false)
|
|
{
|
|
SetStatusText(OUString());
|
|
SetWindow(mxGraphicWindow.get());
|
|
SfxShell::SetName("SmView");
|
|
SfxShell::SetUndoManager( &GetDoc()->GetEditEngine().GetUndoManager() );
|
|
SetController(new SmController(*this));
|
|
}
|
|
|
|
SmViewShell::~SmViewShell()
|
|
{
|
|
//!! this view shell is not active anymore !!
|
|
// Thus 'SmGetActiveView' will give a 0 pointer.
|
|
// Thus we need to supply this view as argument
|
|
if (SmEditWindow *pEditWin = GetEditWindow())
|
|
pEditWin->DeleteEditView();
|
|
mxGraphicWindow.disposeAndClear();
|
|
}
|
|
|
|
void SmViewShell::Deactivate( bool bIsMDIActivate )
|
|
{
|
|
if (SmEditWindow *pEdit = GetEditWindow())
|
|
pEdit->Flush();
|
|
|
|
SfxViewShell::Deactivate( bIsMDIActivate );
|
|
}
|
|
|
|
void SmViewShell::Activate( bool bIsMDIActivate )
|
|
{
|
|
SfxViewShell::Activate( bIsMDIActivate );
|
|
|
|
if (IsInlineEditEnabled())
|
|
{
|
|
// In LOK, activate in-place editing
|
|
GetGraphicWidget().GrabFocus();
|
|
}
|
|
else if (SmEditWindow *pEdit = GetEditWindow())
|
|
{
|
|
//! Since there is no way to be informed if a "drag and drop"
|
|
//! event has taken place, we call SetText here in order to
|
|
//! synchronize the GraphicWindow display with the text in the
|
|
//! EditEngine.
|
|
SmDocShell *pDoc = GetDoc();
|
|
pDoc->SetText( pDoc->GetEditEngine().GetText() );
|
|
|
|
if ( bIsMDIActivate )
|
|
pEdit->GrabFocus();
|
|
}
|
|
}
|
|
|
|
IMPL_LINK( SmViewShell, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
|
|
{
|
|
assert(_pFileDlg && "SmViewShell::DialogClosedHdl(): no file dialog");
|
|
assert(mpDocInserter && "ScDocShell::DialogClosedHdl(): no document inserter");
|
|
|
|
if ( ERRCODE_NONE == _pFileDlg->GetError() )
|
|
{
|
|
std::unique_ptr<SfxMedium> pMedium = mpDocInserter->CreateMedium();
|
|
|
|
if ( pMedium )
|
|
{
|
|
if ( pMedium->IsStorage() )
|
|
Insert( *pMedium );
|
|
else
|
|
InsertFrom( *pMedium );
|
|
pMedium.reset();
|
|
|
|
SmDocShell* pDoc = GetDoc();
|
|
pDoc->UpdateText();
|
|
pDoc->ArrangeFormula();
|
|
pDoc->Repaint();
|
|
// adjust window, repaint, increment ModifyCount,...
|
|
GetViewFrame().GetBindings().Invalidate(SID_GRAPHIC_SM);
|
|
}
|
|
}
|
|
|
|
mpRequest->SetReturnValue( SfxBoolItem( mpRequest->GetSlot(), true ) );
|
|
mpRequest->Done();
|
|
}
|
|
|
|
void SmViewShell::Notify( SfxBroadcaster& , const SfxHint& rHint )
|
|
{
|
|
switch( rHint.GetId() )
|
|
{
|
|
case SfxHintId::ModeChanged:
|
|
case SfxHintId::DocChanged:
|
|
GetViewFrame().GetBindings().InvalidateAll(false);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool SmViewShell::IsInlineEditEnabled()
|
|
{
|
|
return comphelper::LibreOfficeKit::isActive()
|
|
|| SM_MOD()->GetConfig()->IsInlineEditEnable();
|
|
}
|
|
|
|
void SmViewShell::StartMainHelp()
|
|
{
|
|
Help* pHelp = Application::GetHelp();
|
|
if (pHelp)
|
|
pHelp->Start(HID_SMA_MAIN_HELP, GetViewFrame().GetFrameWeld());
|
|
}
|
|
|
|
void SmViewShell::ZoomByItemSet(const SfxItemSet *pSet)
|
|
{
|
|
assert(pSet);
|
|
const SvxZoomItem &rZoom = pSet->Get(SID_ATTR_ZOOM);
|
|
switch( rZoom.GetType() )
|
|
{
|
|
case SvxZoomType::PERCENT:
|
|
mxGraphicWindow->SetZoom(sal::static_int_cast<sal_uInt16>(rZoom.GetValue ()));
|
|
break;
|
|
|
|
case SvxZoomType::OPTIMAL:
|
|
mxGraphicWindow->ZoomToFitInWindow();
|
|
break;
|
|
|
|
case SvxZoomType::PAGEWIDTH:
|
|
case SvxZoomType::WHOLEPAGE:
|
|
{
|
|
const MapMode aMap( SmMapUnit() );
|
|
SfxPrinter *pPrinter = GetPrinter( true );
|
|
tools::Rectangle OutputRect(Point(), pPrinter->GetOutputSize());
|
|
Size OutputSize(pPrinter->LogicToPixel(Size(OutputRect.GetWidth(),
|
|
OutputRect.GetHeight()), aMap));
|
|
Size GraphicSize(pPrinter->LogicToPixel(GetDoc()->GetSize(), aMap));
|
|
if (GraphicSize.Width() <= 0 || GraphicSize.Height() <= 0)
|
|
break;
|
|
sal_uInt16 nZ = std::min(o3tl::convert(OutputSize.Width(), 100, GraphicSize.Width()),
|
|
o3tl::convert(OutputSize.Height(), 100, GraphicSize.Height()));
|
|
mxGraphicWindow->SetZoom(nZ);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::optional<OString> SmViewShell::getLOKPayload(int nType, int nViewId) const
|
|
{
|
|
switch (nType)
|
|
{
|
|
case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
|
|
{
|
|
OString sRectangle;
|
|
if (const SmGraphicWidget& widget = GetGraphicWidget(); widget.IsCursorVisible())
|
|
{
|
|
SmCursor& rCursor = GetDoc()->GetCursor();
|
|
OutputDevice& rOutDev = const_cast<SmGraphicWidget&>(widget).GetOutputDevice();
|
|
tools::Rectangle aCaret = rCursor.GetCaretRectangle(rOutDev);
|
|
Point aFormulaDrawPos = widget.GetFormulaDrawPos();
|
|
aCaret.Move(aFormulaDrawPos.X(), aFormulaDrawPos.Y());
|
|
LokStarMathHelper helper(SfxViewShell::Current());
|
|
tools::Rectangle aBounds = helper.GetBoundingBox();
|
|
aCaret.Move(aBounds.Left(), aBounds.Top());
|
|
sRectangle = aCaret.toString();
|
|
}
|
|
return SfxLokHelper::makeVisCursorInvalidation(nViewId, sRectangle, false, {});
|
|
}
|
|
case LOK_CALLBACK_TEXT_SELECTION:
|
|
{
|
|
OString sRectangle;
|
|
if (const SmGraphicWidget& widget = GetGraphicWidget(); widget.IsCursorVisible())
|
|
{
|
|
SmCursor& rCursor = GetDoc()->GetCursor();
|
|
OutputDevice& rOutDev = const_cast<SmGraphicWidget&>(widget).GetOutputDevice();
|
|
tools::Rectangle aSelection = rCursor.GetSelectionRectangle(rOutDev);
|
|
if (!aSelection.IsEmpty())
|
|
{
|
|
Point aFormulaDrawPos = widget.GetFormulaDrawPos();
|
|
aSelection.Move(aFormulaDrawPos.X(), aFormulaDrawPos.Y());
|
|
LokStarMathHelper helper(SfxViewShell::Current());
|
|
tools::Rectangle aBounds = helper.GetBoundingBox();
|
|
|
|
aSelection.Move(aBounds.Left(), aBounds.Top());
|
|
sRectangle = aSelection.toString();
|
|
}
|
|
}
|
|
return sRectangle;
|
|
}
|
|
case LOK_CALLBACK_TEXT_SELECTION_START:
|
|
case LOK_CALLBACK_TEXT_SELECTION_END:
|
|
case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
|
|
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
|
|
return {};
|
|
}
|
|
return SfxViewShell::getLOKPayload(nType, nViewId); // aborts
|
|
}
|
|
|
|
void SmViewShell::SendCaretToLOK() const
|
|
{
|
|
const int nViewId = sal_Int32(GetViewShellId());
|
|
if (const auto& payload = getLOKPayload(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR, nViewId))
|
|
{
|
|
libreOfficeKitViewCallbackWithViewId(LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR,
|
|
*payload, nViewId);
|
|
}
|
|
if (const auto& payload = getLOKPayload(LOK_CALLBACK_TEXT_SELECTION, nViewId))
|
|
{
|
|
libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, *payload);
|
|
}
|
|
}
|
|
|
|
void SmViewShell::InvalidateSlots()
|
|
{
|
|
auto& rBind = GetViewFrame().GetBindings();
|
|
rBind.Invalidate(SID_COPY);
|
|
rBind.Invalidate(SID_CUT);
|
|
rBind.Invalidate(SID_DELETE);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|