Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/starmath/source/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 75 kB image not shown  

Quelle  view.cxx   Sprache: 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 <svl/hint.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;

static OUString GetScrollUIName(const SmViewShell& rShell)
{
    const SmDocShell* pShell = rShell.GetDoc();
    if (pShell && pShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED)
    {
        // This one has no border on the scrolledwindow, to maximize the space
        // available when in embedded mode and minimize the difference from
        // the ole preview to give a more seamless embedded editing experience.
        return "modules/smath/ui/embedwindow.ui";
    }
    return "modules/smath/ui/mathwindow.ui";
}

SmGraphicWindow::SmGraphicWindow(SmViewShell& rShell)
    : InterimItemWindow(&rShell.GetViewFrame().GetWindow(), GetScrollUIName(rShell), u"MathWindow"_ustr)
    , 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(u"scrolledwindow"_ustr, true))
    , mxGraphic(new SmGraphicWidget(rShell, *this))
    , mxGraphicWin(new weld::CustomWeld(*m_xBuilder, u"mathview"_ustr, *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(
        SmModule::get()->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->dispose();
    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;

    if (IsCursorVisible())
        ShowCursor(false);      // clean up remainings of old cursor
    aCursorRect = rRect;
    if (SmModule::get()->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);

            if (pFound && SmModule::get()->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;
            }

            defaultbreak;
        }
    }

    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, u"EditWindow"_ustr, u"modules/smath/ui/editwindow.ui"_ustr)
    , m_xEdit(new SmEditWindow(*this, *m_xBuilder))
    , aController(*m_xEdit, SID_TEXT, *pBindings_)
    , bExiting(false)
    , aInitialFocusTimer("SmCmdBoxWindow aInitialFocusTimer")
{
    set_id(u"math_edit"_ustr);

    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&&nbsp;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(u"edit"_ustr, 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::get()->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(u"content.xml"_ustr))
        {
            // 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:
        {
            auto* config = SmModule::get()->GetConfig();

            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 = !config->IsShowFormulaCursor();

            config->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;
                }

                if( pWin )
                {
                    TransferableDataHelper aDataHelper(
                        TransferableDataHelper::CreateFromClipboard(
                                                    pWin->GetClipboard()));

                    if( aDataHelper.GetTransferable().is() &&
                        aDataHelper.HasFormat( SotClipboardFormatId::STRING ))
                        pWin->Paste();
                    else
                    {
                        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, u""_ustr);
                        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("))
                                    aString = "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.start.nIndex > aSel.end.nIndex)
                    aSel.end.nIndex = aSel.start.nIndex;

                //calculate a valid end-position by reading logical characters
                sal_Int32 nUtf16Pos=0;
                while ((nUtf16Pos < sInput.getLength()) && (nUtf16Pos < aSel.end.nIndex))
                {
                    sInput.iterateCodePoints(&nUtf16Pos);
                    if (nUtf16Pos > aSel.end.nIndex)
                        aSel.end.nIndex = 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.start.nIndex = aSel.end.nIndex - aToggle.StringToReplace().getLength();
                    pWin->SetSelection( aSel );
                    pEditView->InsertText( sReplacement, true );
                    pEditEngine->UndoActionEnd();
                    pWin->Flush();
                }
            }
        }
        break;

        case SID_SYMBOLS_CATALOGUE:
        {
            SmModule* pp = SmModule::get();

            // get device used to retrieve the FontList
            SmDocShell *pDoc = GetDoc();
            OutputDevice *pDev = pDoc->GetPrinter();
            if (!pDev || pDev->GetFontFaceCollectionCount() == 0)
                pDev = &pp->GetDefaultVirtualDev();
            SAL_WARN_IF( !pDev, "starmath""device for font list missing" );

            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;
        case SID_SAVE_FORMULA:
        {
            OUString aName = "My Formula 1";
            OUString aDesc(SmResId(STR_USER_DEFINED_FORMULA));
            SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
            ScopedVclPtr<AbstractSvxNameDialog> pDlg(
                pFact->CreateSvxNameDialog(GetFrameWeld(), aName, aDesc));

            if (pDlg->Execute() == RET_OK)
            {
                aName = pDlg->GetName();
                if (SmModule::get()->GetConfig()->HasUserDefinedFormula(aName))
                {
                    std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(
                        GetFrameWeld(), VclMessageType::Question, VclButtonsType::YesNo,
                        SmResId(STR_USER_DEFINED_FORMULA_EXISTS).replaceAll("%1", aName)));
                    if (xQuery->run() == RET_NO)
                        break;
                }
                if (SmEditWindow* pEditWin = GetEditWindow())
                    SmModule::get()->GetConfig()->SaveUserDefinedFormula(aName, pEditWin->GetText());

                // Show the Elements sidebar with the "User-defined" entry selected
                GetViewFrame().ShowChildWindow(SID_SIDEBAR);
                sfx2::sidebar::Sidebar::ShowPanel(u"MathElementsPanel",
                                                  GetViewFrame().GetFrame().GetFrameInterface());
                GetViewFrame().GetBindings().Invalidate( SID_ELEMENTSDOCKINGWINDOW );
                Broadcast(SfxHint(SfxHintId::SmNewUserFormula));
                rReq.Ignore ();
            }
            pDlg.disposeAndClear();
        }
        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, SmModule::get()->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();
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=97 G=95

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.