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

Quelle  baside2b.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 <cassert>
#include <string_view>

#include <helpids.h>
#include <iderid.hxx>
#include <strings.hrc>
#include <bitmaps.hlst>

#include "baside2.hxx"
#include "brkdlg.hxx"
#include <basidesh.hxx>
#include <basobj.hxx>
#include <iderdll.hxx>

#include <basic/sbmeth.hxx>
#include <basic/sbuno.hxx>
#include <com/sun/star/beans/XMultiPropertySet.hpp>
#include <com/sun/star/beans/XPropertiesChangeListener.hpp>
#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
#include <com/sun/star/script/XLibraryContainer2.hpp>
#include <comphelper/string.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <o3tl/string_view.hxx>
#include <officecfg/Office/Common.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/progress.hxx>
#include <sfx2/viewfrm.hxx>
#include <tools/debug.hxx>
#include <utility>
#include <vcl/image.hxx>
#include <vcl/weld.hxx>
#include <vcl/weldutils.hxx>
#include <svl/urihelper.hxx>
#include <svx/svxids.hrc>
#include <toolkit/awt/vclxwindow.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/xtextedt.hxx>
#include <vcl/textview.hxx>
#include <vcl/txtattr.hxx>
#include <vcl/settings.hxx>
#include <vcl/ptrstyle.hxx>
#include <vcl/event.hxx>
#include <vcl/svapp.hxx>
#include <vcl/taskpanelist.hxx>
#include <vcl/help.hxx>
#include <cppuhelper/implbase.hxx>
#include <vector>
#include <com/sun/star/reflection/theCoreReflection.hpp>
#include <unotools/charclass.hxx>
#include "textwindowaccessibility.hxx"
#include "uiobject.hxx"
#include <basegfx/utils/zoomtools.hxx>
#include <svl/itemset.hxx>
#include <BasicColorConfig.hxx>

namespace basctl
{

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;

namespace
{

sal_uInt16 const NoMarker = 0xFFFF;
tools::Long const nBasePad = 2;
tools::Long const nCursorPad = 5;

tools::Long nVirtToolBoxHeight;    // inited in WatchWindow, used in Stackwindow

// Returns pBase converted to SbxVariable if valid and is not an SbxMethod.
SbxVariable* IsSbxVariable (SbxBase* pBase)
{
    if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pBase))
        if (!dynamic_cast<SbxMethod*>(pVar))
            return pVar;
    return nullptr;
}

Image GetImage(const OUString& rId)
{
    return Image(StockImage::Yes, rId);
}

int const nScrollLine = 12;
int const nScrollPage = 60;
int const DWBORDER = 3;

std::u16string_view const cSuffixes = u"%&!#@$";

// namespace


/**
 * Helper functions to get/set text in TextEngine using
 * the stream interface.
 *
 * get/setText() only supports tools Strings limited to 64K).
 */

OUString getTextEngineText (ExtTextEngine& rEngine)
{
    SvMemoryStream aMemStream;
    aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
    aMemStream.SetLineDelimiter( LINEEND_LF );
    rEngine.Write( aMemStream );
    std::size_t nSize = aMemStream.Tell();
    OUString aText( static_cast<const char*>(aMemStream.GetData()),
        nSize, RTL_TEXTENCODING_UTF8 );
    return aText;
}

void setTextEngineText (ExtTextEngine& rEngine, std::u16string_view aStr)
{
    rEngine.SetText(OUString());
    OString aUTF8Str = OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 );
    SvMemoryStream aMemStream( const_cast<char *>(aUTF8Str.getStr()), aUTF8Str.getLength(),
        StreamMode::READ );
    aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
    aMemStream.SetLineDelimiter( LINEEND_LF );
    rEngine.Read(aMemStream);
}

namespace
{

void lcl_DrawIDEWindowFrame(DockingWindow const * pWin, vcl::RenderContext& rRenderContext)
{
    if (pWin->IsFloatingMode())
        return;

    Size aSz(pWin->GetOutputSizePixel());
    const Color aOldLineColor(rRenderContext.GetLineColor());
    rRenderContext.SetLineColor(COL_WHITE);
    // White line on top
    rRenderContext.DrawLine(Point(0, 0), Point(aSz.Width(), 0));
    // Black line at bottom
    rRenderContext.SetLineColor(COL_BLACK);
    rRenderContext.DrawLine(Point(0, aSz.Height() - 1),
                            Point(aSz.Width(), aSz.Height() - 1));
    rRenderContext.SetLineColor(aOldLineColor);
}

void lcl_SeparateNameAndIndex( const OUString& rVName, OUString& rVar, OUString&&nbsp;rIndex )
{
    rVar = rVName;
    rIndex.clear();
    sal_Int32 nIndexStart = rVar.indexOf( '(' );
    if ( nIndexStart != -1 )
    {
        sal_Int32 nIndexEnd = rVar.indexOf( ')', nIndexStart );
        if (nIndexEnd != -1)
        {
            rIndex = rVar.copy(nIndexStart + 1, nIndexEnd - nIndexStart - 1);
            rVar = rVar.copy(0, nIndexStart);
            rVar = comphelper::string::stripEnd(rVar, ' ');
            rIndex = comphelper::string::strip(rIndex, ' ');
        }
    }

    if ( !rVar.isEmpty() )
    {
        sal_uInt16 nLastChar = rVar.getLength()-1;
        if ( cSuffixes.find(rVar[ nLastChar ] ) != std::u16string_view::npos )
            rVar = rVar.replaceAt( nLastChar, 1, u"" );
    }
    if ( !rIndex.isEmpty() )
    {
        sal_uInt16 nLastChar = rIndex.getLength()-1;
        if ( cSuffixes.find(rIndex[ nLastChar ] ) != std::u16string_view::npos )
            rIndex = rIndex.replaceAt( nLastChar, 1, u"" );
    }
}

// namespace


// EditorWindow


class EditorWindow::ChangesListener:
    public cppu::WeakImplHelper< beans::XPropertiesChangeListener >
{
public:
    explicit ChangesListener(EditorWindow & editor): editor_(editor) {}

private:
    virtual ~ChangesListener() override {}

    virtual void SAL_CALL disposing(lang::EventObject const &) override
    {
        std::unique_lock g(editor_.mutex_);
        editor_.notifier_.clear();
    }

    virtual void SAL_CALL propertiesChange(
        Sequence< beans::PropertyChangeEvent > const &) override
    {
        SolarMutexGuard g;
        editor_.ImplSetFont();
    }

    EditorWindow & editor_;
};

class EditorWindow::ProgressInfo : public SfxProgress
{
public:
    ProgressInfo (SfxObjectShell* pObjSh, OUString const& rText, sal_uInt32 nRange) :
        SfxProgress(pObjSh, rText, nRange),
        nCurState(0)
    { }

    void StepProgress ()
    {
        SetState(++nCurState);
    }

private:
    sal_uInt32 nCurState;
};

EditorWindow::EditorWindow (vcl::Window* pParent, ModulWindow* pModulWindow) :
    Window(pParent, WB_BORDER),
    rModulWindow(*pModulWindow),
    nCurTextWidth(0),
    m_nSetSourceInBasicId(nullptr),
    aHighlighter(HighlighterLanguage::Basic),
    aSyntaxIdle( "basctl EditorWindow aSyntaxIdle" ),
    bHighlighting(false),
    bDoSyntaxHighlight(true),
    bDelayHighlight(true),
    m_nLastHighlightPara(0),
    pCodeCompleteWnd(VclPtr<CodeCompleteWindow>::Create(this))
{
    set_id(u"EditorWindow"_ustr);
    const Wallpaper aBackground(rModulWindow.GetLayout().GetSyntaxBackgroundColor());
    SetBackground(aBackground);
    GetWindow(GetWindowType::Border)->SetBackground(aBackground);
    SetLineHighlightColor(GetShell()->GetColorConfig()->GetCurrentColorScheme().m_aLineHighlightColor);
    SetPointer( PointerStyle::Text );
    SetHelpId( HID_BASICIDE_EDITORWINDOW );

    listener_ = new ChangesListener(*this);
    Reference< beans::XMultiPropertySet > n(
        officecfg::Office::Common::Font::SourceViewFont::get(),
        UNO_QUERY_THROW);
    {
        std::unique_lock g(mutex_);
        notifier_ = n;
    }

    // The zoom level applied to the editor window is the zoom slider value in the shell
    nCurrentZoomLevel = GetShell()->GetCurrentZoomSliderValue();

    const Sequence<OUString> aPropertyNames{u"FontHeight"_ustr, u"FontName"_ustr};
    n->addPropertiesChangeListener(aPropertyNames, listener_);
}


EditorWindow::~EditorWindow()
{
    disposeOnce();
}

void EditorWindow::dispose()
{
    if (m_nSetSourceInBasicId)
    {
        Application::RemoveUserEvent(m_nSetSourceInBasicId);
        m_nSetSourceInBasicId = nullptr;
    }

    Reference< beans::XMultiPropertySet > n;
    {
        std::unique_lock g(mutex_);
        n = notifier_;
    }
    if (n.is()) {
        n->removePropertiesChangeListener(listener_);
    }

    aSyntaxIdle.Stop();

    if ( pEditEngine )
    {
        EndListening( *pEditEngine );
        pEditEngine->RemoveView(pEditView.get());
    }
    pCodeCompleteWnd.disposeAndClear();
    vcl::Window::dispose();
}

OUString EditorWindow::GetWordAtCursor()
{
    OUString aWord;

    if ( pEditView )
    {
        TextEngine* pTextEngine = pEditView->GetTextEngine();
        if ( pTextEngine )
        {
            // check first, if the cursor is at a help URL
            const TextSelection& rSelection = pEditView->GetSelection();
            const TextPaM& rSelStart = rSelection.GetStart();
            const TextPaM& rSelEnd = rSelection.GetEnd();
            OUString aText = pTextEngine->GetText( rSelEnd.GetPara() );
            CharClass aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() );
            sal_Int32 nSelStart = rSelStart.GetIndex();
            sal_Int32 nSelEnd = rSelEnd.GetIndex();
            sal_Int32 nLength = aText.getLength();
            sal_Int32 nStart = 0;
            sal_Int32 nEnd = nLength;
            while ( nStart < nLength )
            {
                OUString aURL( URIHelper::FindFirstURLInText( aText, nStart, nEnd, aClass ) );
                INetURLObject aURLObj( aURL );
                if ( aURLObj.GetProtocol() == INetProtocol::VndSunStarHelp
                     && nSelStart >= nStart && nSelStart <= nEnd && nSelEnd >= nStart && nSelEnd <= nEnd )
                {
                    aWord = aURL;
                    break;
                }
                nStart = nEnd;
                nEnd = nLength;
            }

            // Not the selected range, but at the CursorPosition,
            // if a word is partially selected.
            if ( aWord.isEmpty() )
                aWord = pTextEngine->GetWord( rSelEnd );

            // Can be empty when full word selected, as Cursor behind it
            if ( aWord.isEmpty() && pEditView->HasSelection() )
                aWord = pTextEngine->GetWord( rSelStart );
        }
    }

    return aWord;
}

void EditorWindow::RequestHelp( const HelpEvent& rHEvt )
{
    bool bDone = false;

    // Should have been activated at some point
    if ( pEditEngine )
    {
        if ( rHEvt.GetMode() & HelpEventMode::CONTEXT )
        {
            OUString aKeyword = GetWordAtCursor();
            Application::GetHelp()->SearchKeyword( aKeyword );
            bDone = true;
        }
        else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
        {
            OUString aHelpText;
            tools::Rectangle aHelpRect;
            if ( StarBASIC::IsRunning() )
            {
                Point aWindowPos = rHEvt.GetMousePosPixel();
                aWindowPos = ScreenToOutputPixel( aWindowPos );
                Point aDocPos = GetEditView()->GetDocPos( aWindowPos );
                TextPaM aCursor = GetEditView()->GetTextEngine()->GetPaM(aDocPos);
                TextPaM aStartOfWord;
                OUString aWord = GetEditView()->GetTextEngine()->GetWord( aCursor, &aStartOfWord );
                if ( !aWord.isEmpty() && !comphelper::string::isdigitAsciiString(aWord) )
                {
                    sal_uInt16 nLastChar = aWord.getLength() - 1;
                    if ( cSuffixes.find(aWord[ nLastChar ] ) != std::u16string_view::npos )
                        aWord = aWord.replaceAt( nLastChar, 1, u"" );
                    SbxBase* pSBX = StarBASIC::FindSBXInCurrentScope( aWord );
                    if (SbxVariable const* pVar = IsSbxVariable(pSBX))
                    {
                        SbxDataType eType = pVar->GetType();
                        if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) )
                            // might cause a crash e. g. at the selections-object
                            // Type == Object does not mean pVar == Object!
                            ; // aHelpText = ((SbxObject*)pVar)->GetClassName();
                        else if ( eType & SbxARRAY )
                            ; // aHelpText = "{...}";
                        else if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxEMPTY) )
                        {
                            aHelpText = pVar->GetName();
                            if ( aHelpText.isEmpty() )     // name is not copied with the passed parameters
                                aHelpText = aWord;
                            aHelpText += "=" + pVar->GetOUString();
                        }
                    }
                    if ( !aHelpText.isEmpty() )
                    {
                        tools::Rectangle aStartWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aStartOfWord));
                        TextPaM aEndOfWord(aStartOfWord.GetPara(), aStartOfWord.GetIndex() + aWord.getLength());
                        tools::Rectangle aEndWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aEndOfWord));
                        aHelpRect = aStartWordRect.GetUnion(aEndWordRect);

                        Point aTopLeft = GetEditView()->GetWindowPos(aHelpRect.TopLeft());
                        aTopLeft = GetEditView()->GetWindow()->OutputToScreenPixel(aTopLeft);

                        aHelpRect.SetPos(aTopLeft);
                    }
                }
            }
            Help::ShowQuickHelp( this, aHelpRect, aHelpText, QuickHelpFlags::NONE);
            bDone = true;
        }
    }

    if ( !bDone )
        Window::RequestHelp( rHEvt );
}


void EditorWindow::Resize()
{
    // ScrollBars, etc. happens in Adjust...
    if ( !pEditView )
        return;

    tools::Long nVisY = pEditView->GetStartDocPos().Y();

    pEditView->ShowCursor();
    Size aOutSz( GetOutputSizePixel() );
    tools::Long nMaxVisAreaStart = pEditView->GetTextEngine()->GetTextHeight() - aOutSz.Height();
    if ( nMaxVisAreaStart < 0 )
        nMaxVisAreaStart = 0;
    if ( pEditView->GetStartDocPos().Y() > nMaxVisAreaStart )
    {
        Point aStartDocPos( pEditView->GetStartDocPos() );
        aStartDocPos.setY( nMaxVisAreaStart );
        pEditView->SetStartDocPos( aStartDocPos );
        pEditView->ShowCursor();
        rModulWindow.GetBreakPointWindow().GetCurYOffset() = aStartDocPos.Y();
        rModulWindow.GetLineNumberWindow().GetCurYOffset() = aStartDocPos.Y();
    }
    InitScrollBars();
    if ( nVisY != pEditView->GetStartDocPos().Y() )
        Invalidate();
}


void EditorWindow::MouseMove( const MouseEvent &rEvt )
{
    if ( pEditView )
        pEditView->MouseMove( rEvt );
}


void EditorWindow::MouseButtonUp( const MouseEvent &rEvt )
{
    if ( pEditView )
    {
        pEditView->MouseButtonUp( rEvt );
        if (SfxBindings* pBindings = GetBindingsPtr())
        {
            pBindings->Invalidate( SID_BASICIDE_STAT_POS );
            pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
        }
    }
}

void EditorWindow::MouseButtonDown( const MouseEvent &rEvt )
{
    GrabFocus();
    if (!pEditView)
        return;
    pEditView->MouseButtonDown(rEvt);
    if( pCodeCompleteWnd->IsVisible() )
    {
        if (pEditView->GetSelection() != pCodeCompleteWnd->GetTextSelection())
        {
            //selection changed, code complete window should be hidden
            pCodeCompleteWnd->HideAndRestoreFocus();
        }
    }
}

void EditorWindow::Command( const CommandEvent& rCEvt )
{
    if ( !pEditView )
        return;

    pEditView->Command( rCEvt );
    if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) ||
         ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) ||
         ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) )
    {
        const CommandWheelData* pData = rCEvt.GetWheelData();

        // Check if it is a Ctrl+Wheel zoom command
        if (pData && pData->IsMod1())
        {
            const sal_uInt16 nOldZoom = GetCurrentZoom();
            sal_uInt16 nNewZoom;
            if( pData->GetDelta() < 0 )
                nNewZoom = std::max<sal_uInt16>(basctl::Shell::GetMinZoom(),
                                                basegfx::zoomtools::zoomOut(nOldZoom));
            else
                nNewZoom = std::min<sal_uInt16>(basctl::Shell::GetMaxZoom(),
                                                basegfx::zoomtools::zoomIn(nOldZoom));
            GetShell()->SetGlobalEditorZoomLevel(nNewZoom);
        }
        else
            HandleScrollCommand(rCEvt, &rModulWindow.GetEditHScrollBar(), &rModulWindow.GetEditVScrollBar());
    }
    else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) {
        SfxDispatcher* pDispatcher = GetDispatcher();
        if ( pDispatcher )
        {
            SfxDispatcher::ExecutePopup();
        }
        if( pCodeCompleteWnd->IsVisible() ) // hide the code complete window
            pCodeCompleteWnd->ClearAndHide();
    }
}

bool EditorWindow::ImpCanModify()
{
    bool bCanModify = true;
    if ( StarBASIC::IsRunning() && rModulWindow.GetBasicStatus().bIsRunning )
    {
        // If in Trace-mode, abort the trace or refuse input
        // Remove markers in the modules in Notify at Basic::Stopped
        std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
                                                       VclMessageType::Question, VclButtonsType::OkCancel,
                                                       IDEResId(RID_STR_WILLSTOPPRG)));
        if (xQueryBox->run() == RET_OK)
        {
            rModulWindow.GetBasicStatus().bIsRunning = false;
            StopBasic();
        }
        else
            bCanModify = false;
    }
    return bCanModify;
}

void EditorWindow::KeyInput( const KeyEvent& rKEvt )
{
    if ( !pEditView )   // Happens in Win95
        return;

    bool const bWasModified = pEditEngine->IsModified();
    // see if there is an accelerator to be processed first
    SfxViewShell *pVS( SfxViewShell::Current());
    bool bDone = pVS && pVS->KeyInput( rKEvt );

    if (pCodeCompleteWnd->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn())
    {
        pCodeCompleteWnd->HandleKeyInput(rKEvt);
        if( rKEvt.GetKeyCode().GetCode() == KEY_UP
            || rKEvt.GetKeyCode().GetCode() == KEY_DOWN
            || rKEvt.GetKeyCode().GetCode() == KEY_TAB
            || rKEvt.GetKeyCode().GetCode() == KEY_POINT)
            return;
    }

    if( (rKEvt.GetKeyCode().GetCode() == KEY_SPACE ||
        rKEvt.GetKeyCode().GetCode() == KEY_TAB ||
        rKEvt.GetKeyCode().GetCode() == KEY_RETURN ) && CodeCompleteOptions::IsAutoCorrectOn() )
    {
        HandleAutoCorrect();
    }

    if( rKEvt.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() )
    {//autoclose double quotes
        HandleAutoCloseDoubleQuotes();
    }

    if( rKEvt.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() )
    {//autoclose parenthesis
        HandleAutoCloseParen();
    }

    if( rKEvt.GetKeyCode().GetCode() == KEY_RETURN && CodeCompleteOptions::IsProcedureAutoCompleteOn() )
    {//autoclose implementation
       HandleProcedureCompletion();
    }

    if( rKEvt.GetKeyCode().GetCode() == KEY_POINT && CodeCompleteOptions::IsCodeCompleteOn() )
    {
        HandleCodeCompletion();
    }
    if ( !bDone && ( !TextEngine::DoesKeyChangeText( rKEvt ) || ImpCanModify()  ) )
    {
        if ( ( rKEvt.GetKeyCode().GetCode() == KEY_TAB ) && !rKEvt.GetKeyCode().IsMod1() &&
              !rKEvt.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() )
        {
            TextSelection aSel( pEditView->GetSelection() );
            if ( aSel.GetStart().GetPara() != aSel.GetEnd().GetPara() )
            {
                bDelayHighlight = false;
                if ( !rKEvt.GetKeyCode().IsShift() )
                    pEditView->IndentBlock();
                else
                    pEditView->UnindentBlock();
                bDelayHighlight = true;
                bDone = true;
            }
        }
        if ( !bDone )
            bDone = pEditView->KeyInput( rKEvt );
    }
    if ( !bDone )
    {
            Window::KeyInput( rKEvt );
    }
    else
    {
        if (SfxBindings* pBindings = GetBindingsPtr())
        {
            pBindings->Invalidate( SID_BASICIDE_STAT_POS );
            pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
            if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR )
            {
                pBindings->Update( SID_BASICIDE_STAT_POS );
                pBindings->Update( SID_BASICIDE_STAT_TITLE );
            }
            if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_ALPHA ||
                 rKEvt.GetKeyCode().GetGroup() == KEYGROUP_NUM )
            {
                // If the module is read-only, warn that it can't be edited
                if ( rModulWindow.IsReadOnly() )
                    rModulWindow.ShowReadOnlyInfoBar();
            }
            if ( !bWasModified && pEditEngine->IsModified() )
            {
                pBindings->Invalidate( SID_SAVEDOC );
                pBindings->Invalidate( SID_DOC_MODIFIED );
                pBindings->Invalidate( SID_UNDO );
            }
            if ( rKEvt.GetKeyCode().GetCode() == KEY_INSERT )
                pBindings->Invalidate( SID_ATTR_INSERT );
        }
    }
}

void EditorWindow::HandleAutoCorrect()
{
    TextSelection aSel = GetEditView()->GetSelection();
    const sal_uInt32 nLine =  aSel.GetStart().GetPara();
    const sal_Int32 nIndex =  aSel.GetStart().GetIndex();
    OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
    const OUString sActSubName = GetActualSubName( nLine ); // the actual procedure

    std::vector<HighlightPortion> aPortions;
    aHighlighter.getHighlightPortions( aLine, aPortions );

    if( aPortions.empty() )
        return;

    HighlightPortion& r = aPortions.back();
    ifstatic_cast<size_t>(nIndex) != aPortions.size()-1 )
    {//cursor is not standing at the end of the line
        for (auto const& portion : aPortions)
        {
            if( portion.nEnd == nIndex )
            {
                r = portion;
                break;
            }
        }
    }

    OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin );
    //if WS or empty string: stop, nothing to do
    if( ( r.tokenType == TokenType::Whitespace ) || sStr.isEmpty() )
        return;
    //create the appropriate TextSelection, and update the cache
    TextPaM aStart( nLine, r.nBegin );
    TextPaM aEnd( nLine, r.nBegin + sStr.getLength() );
    TextSelection sTextSelection( aStart, aEnd );
    rModulWindow.UpdateModule();
    rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache );
    // correct the last entered keyword
    if( r.tokenType == TokenType::Keywords )
    {
        sStr = sStr.toAsciiLowerCase();
        if( !SbModule::GetKeywordCase(sStr).isEmpty() )
        // if it is a keyword, get its correct case
            sStr = SbModule::GetKeywordCase(sStr);
        else
        // else capitalize first letter/select the correct one, and replace
            sStr = sStr.replaceAt( 0, 1, OUString(sStr[0]).toAsciiUpperCase() );

        pEditEngine->ReplaceText( sTextSelection, sStr );
        pEditView->SetSelection( aSel );
    }
    if( r.tokenType != TokenType::Identifier )
        return;

// correct variables
    if( !aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ).isEmpty() )
    {
        sStr = aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName );
        pEditEngine->ReplaceText( sTextSelection, sStr );
        pEditView->SetSelection( aSel );
    }
    else
    {
        //autocorrect procedures
        SbxArray* pArr = rModulWindow.GetSbModule()->GetMethods().get();
        for (sal_uInt32 i = 0; i < pArr->Count(); ++i)
        {
            if (pArr->Get(i)->GetName().equalsIgnoreAsciiCase(sStr))
            {
                sStr = pArr->Get(i)->GetName(); //if found, get the correct case
                pEditEngine->ReplaceText( sTextSelection, sStr );
                pEditView->SetSelection( aSel );
                return;
            }
        }
    }
}

void EditorWindow::SetLineHighlightColor(Color aColor)
{
    m_aLineHighlightColor = aColor;
}

TextSelection EditorWindow::GetLastHighlightPortionTextSelection() const
{//creates a text selection from the highlight portion on the cursor
    const sal_uInt32 nLine = GetEditView()->GetSelection().GetStart().GetPara();
    const sal_Int32 nIndex = GetEditView()->GetSelection().GetStart().GetIndex();
    OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
    std::vector<HighlightPortion> aPortions;
    aHighlighter.getHighlightPortions( aLine, aPortions );

    assert(!aPortions.empty());
    HighlightPortion& r = aPortions.back();
    ifstatic_cast<size_t>(nIndex) != aPortions.size()-1 )
    {//cursor is not standing at the end of the line
        for (auto const& portion : aPortions)
        {
            if( portion.nEnd == nIndex )
            {
                r = portion;
                break;
            }
        }
    }

    if( aPortions.empty() )
        return TextSelection();

    std::u16string_view sStr = aLine.subView( r.nBegin, r.nEnd - r.nBegin );
    TextPaM aStart( nLine, r.nBegin );
    TextPaM aEnd( nLine, r.nBegin + sStr.size() );
    return TextSelection( aStart, aEnd );
}

void EditorWindow::HandleAutoCloseParen()
{
    TextSelection aSel = GetEditView()->GetSelection();
    const sal_uInt32 nLine =  aSel.GetStart().GetPara();
    OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified

    if( aLine.getLength() > 0 && aLine[aSel.GetEnd().GetIndex()-1] != '(' )
    {
        GetEditView()->InsertText(u")"_ustr);
        //leave the cursor on its place: inside the parenthesis
        TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
        GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
    }
}

void EditorWindow::HandleAutoCloseDoubleQuotes()
{
    TextSelection aSel = GetEditView()->GetSelection();
    const sal_uInt32 nLine =  aSel.GetStart().GetPara();
    OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified

    std::vector<HighlightPortion> aPortions;
    aHighlighter.getHighlightPortions( aLine, aPortions );

    if( aPortions.empty() )
        return;

    if( aLine.getLength() > 0 && !aLine.endsWith("\"") && (aPortions.back().tokenType != TokenType::String) )
    {
        GetEditView()->InsertText(u"\""_ustr);
        //leave the cursor on its place: inside the two double quotes
        TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
        GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
    }
}

void EditorWindow::HandleProcedureCompletion()
{

    TextSelection aSel = GetEditView()->GetSelection();
    const sal_uInt32 nLine = aSel.GetStart().GetPara();
    OUString aLine( pEditEngine->GetText( nLine ) );

    OUString sProcType;
    OUString sProcName;
    bool bFoundName = GetProcedureName(aLine, sProcType, sProcName);
    if (!bFoundName)
      return;

    OUString sText(u"\nEnd "_ustr);
    aSel = GetEditView()->GetSelection();
    if( sProcType.equalsIgnoreAsciiCase("function") )
        sText += "Function\n";
    if( sProcType.equalsIgnoreAsciiCase("sub") )
        sText += "Sub\n";

    if( nLine+1 == pEditEngine->GetParagraphCount() )
    {
        pEditView->InsertText( sText );//append to the end
        GetEditView()->SetSelection(aSel);
    }
    else
    {
        for( sal_uInt32 i = nLine+1; i < pEditEngine->GetParagraphCount(); ++i )
        {//searching forward for end token, or another sub/function definition
            OUString aCurrLine = pEditEngine->GetText( i );
            std::vector<HighlightPortion> aCurrPortions;
            aHighlighter.getHighlightPortions( aCurrLine, aCurrPortions );

            if( aCurrPortions.size() >= 3 )
            {//at least 3 tokens: (sub|function) whitespace identifier...
                HighlightPortion& r = aCurrPortions.front();
                std::u16string_view sStr = aCurrLine.subView(r.nBegin, r.nEnd - r.nBegin);

                if( r.tokenType == TokenType::Keywords )
                {
                    if( o3tl::equalsIgnoreAsciiCase(sStr, u"sub") || o3tl::equalsIgnoreAsciiCase(sStr, u"function") )
                    {
                        pEditView->InsertText( sText );//append to the end
                        GetEditView()->SetSelection(aSel);
                        break;
                    }
                    if( o3tl::equalsIgnoreAsciiCase(sStr, u"end") )
                        break;
                }
            }
        }
    }
}

bool EditorWindow::GetProcedureName(std::u16string_view rLine, OUString& rProcType, OUString& rProcName) const
{
    std::vector<HighlightPortion> aPortions;
    aHighlighter.getHighlightPortions(rLine, aPortions);

    if( aPortions.empty() )
        return false;

    bool bFoundType = false;
    bool bFoundName = false;

    for (auto const& portion : aPortions)
    {
        std::u16string_view sTokStr = rLine.substr(portion.nBegin, portion.nEnd - portion.nBegin);

        if( portion.tokenType == TokenType::Keywords && ( o3tl::equalsIgnoreAsciiCase(sTokStr, u"sub")
            || o3tl::equalsIgnoreAsciiCase(sTokStr, u"function")) )
        {
            rProcType = sTokStr;
            bFoundType = true;
        }
        if( portion.tokenType == TokenType::Identifier && bFoundType )
        {
            rProcName = sTokStr;
            bFoundName = true;
            break;
        }
    }

    if( !bFoundType || !bFoundName )
        return false;// no sub/function keyword or there is no identifier

    return true;

}

void EditorWindow::HandleCodeCompletion()
{
    rModulWindow.UpdateModule();
    rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache);
    TextSelection aSel = GetEditView()->GetSelection();
    const sal_uInt32 nLine =  aSel.GetStart().GetPara();
    OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
    std::vector< OUString > aVect; //vector to hold the base variable+methods for the nested reflection

    std::vector<HighlightPortion> aPortions;
    aLine = aLine.copy(0, aSel.GetEnd().GetIndex());
    aHighlighter.getHighlightPortions( aLine, aPortions );
    if( aPortions.empty() )
        return;

    //use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod ..
    for( std::vector<HighlightPortion>::reverse_iterator i(
             aPortions.rbegin());
         i != aPortions.rend(); ++i)
    {
        if( i->tokenType == TokenType::Whitespace ) // a whitespace: stop; if there is no ws, it goes to the beginning of the line
            break;
        if( i->tokenType == TokenType::Identifier || i->tokenType == TokenType::Keywords ) // extract the identifiers(methods, base variable)
        /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue
         * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!)
         * */

            aVect.insert( aVect.begin(), aLine.copy(i->nBegin, i->nEnd - i->nBegin) );
    }

    if( aVect.empty() )//nothing to do
        return;

    OUString sBaseName = aVect[aVect.size()-1];//variable name
    OUString sVarType = aCodeCompleteCache.GetVarType( sBaseName );

    if( !sVarType.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() )
    {//correct variable name, if autocorrection on
        const OUString sStr = aCodeCompleteCache.GetCorrectCaseVarName( sBaseName, GetActualSubName(nLine) );
        if( !sStr.isEmpty() )
        {
            TextPaM aStart(nLine, aSel.GetStart().GetIndex() - sStr.getLength() );
            TextSelection sTextSelection(aStart, TextPaM(nLine, aSel.GetStart().GetIndex()));
            pEditEngine->ReplaceText( sTextSelection, sStr );
            pEditView->SetSelection( aSel );
        }
    }

    UnoTypeCodeCompletetor aTypeCompletor( aVect, sVarType );

    if( !aTypeCompletor.CanCodeComplete() )
        return;

    std::vector< OUString > aEntryVect;//entries to be inserted into the list
    std::vector< OUString > aFieldVect = aTypeCompletor.GetXIdlClassFields();//fields
    aEntryVect.insert(aEntryVect.end(), aFieldVect.begin(), aFieldVect.end() );
    if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
    {// if extended types on, reflect classes, else just the structs (XIdlClass without methods)
        std::vector< OUString > aMethVect = aTypeCompletor.GetXIdlClassMethods();//methods
        aEntryVect.insert(aEntryVect.end(), aMethVect.begin(), aMethVect.end() );
    }
    if( !aEntryVect.empty() )
        SetupAndShowCodeCompleteWnd( aEntryVect, aSel );
}

void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector< OUString >& aEntryVect, TextSelection aSel )
{
    // clear the listbox
    pCodeCompleteWnd->ClearListBox();
    // fill the listbox
    for(const auto & l : aEntryVect)
    {
        pCodeCompleteWnd->InsertEntry( l );
    }
    // show it
    pCodeCompleteWnd->Show();
    pCodeCompleteWnd->ResizeAndPositionListBox();
    pCodeCompleteWnd->SelectFirstEntry();
    // correct text selection, and set it
    ++aSel.GetStart().GetIndex();
    ++aSel.GetEnd().GetIndex();
    pCodeCompleteWnd->SetTextSelection( aSel );
    //give the focus to the EditView
    pEditView->GetWindow()->GrabFocus();
}

void EditorWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
{
    if (!pEditEngine)     // We need it now at latest
        CreateEditEngine();

    HighlightCurrentLine(rRenderContext);

    pEditView->Paint(rRenderContext, rRect);
}

void EditorWindow::HighlightCurrentLine(vcl::RenderContext& rRenderContext)
{
    // If the cursor is in a single line and nothing is selected, then a highlight color
    // is applied to the background of the current line
    TextPaM aStartPaM = pEditView->GetSelection().GetStart();
    TextPaM aEndPaM = pEditView->GetSelection().GetEnd();
    if (aStartPaM == aEndPaM)
    {
        Size aWinSize(GetOutputSizePixel());
        sal_Int16 nDocPosY = pEditView->GetStartDocPos().Y();
        sal_Int16 nY1 = pEditEngine->PaMtoEditCursor(aStartPaM).TopLeft().Y();
        sal_Int16 nY2 = pEditEngine->PaMtoEditCursor(aStartPaM).BottomRight().Y();
        // Only draw if the cursor is in a visible position
        if ((nY1 >= nDocPosY && nY1 <= nDocPosY + aWinSize.Height())
            || (nY2 >= nDocPosY && nY2 <= nDocPosY + aWinSize.Height()))
        {
            tools::Rectangle aRect(Point(0, nY1 - nDocPosY), Point(aWinSize.Width(), nY2 - nDocPosY));
            rRenderContext.SetFillColor(m_aLineHighlightColor);
            rRenderContext.DrawRect(aRect);
        }
    }
}

void EditorWindow::LoseFocus()
{
    // tdf#114258 wait until the next event loop cycle to do this so it doesn't
    // happen during a mouse down/up selection in the treeview whose contents
    // this may update
    if (!m_nSetSourceInBasicId)
        m_nSetSourceInBasicId = Application::PostUserEvent(LINK(this, EditorWindow, SetSourceInBasicHdl));
    Window::LoseFocus();
}

IMPL_LINK_NOARG(EditorWindow, SetSourceInBasicHdl, void*, void)
{
    m_nSetSourceInBasicId = nullptr;
    SetSourceInBasic();
}

void EditorWindow::SetSourceInBasic()
{
    if ( pEditEngine && pEditEngine->IsModified()
        && !GetEditView()->IsReadOnly() )   // Added for #i60626, otherwise
            // any read only bug in the text engine could lead to a crash later
    {
        if ( !StarBASIC::IsRunning() ) // Not at runtime!
        {
            rModulWindow.UpdateModule();
        }
    }
}

// Returns the position of the last character of any of the following
// EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found
sal_Int32 searchEOL( std::u16string_view rStr, sal_Int32 fromIndex )
{
    size_t iLF = rStr.find( LINE_SEP, fromIndex );
    if( iLF != std::u16string_view::npos )
        return iLF;

    size_t iCR = rStr.find( LINE_SEP_CR, fromIndex );
    return iCR == std::u16string_view::npos ? -1 : iCR;
}

void EditorWindow::CreateEditEngine()
{
    if (pEditEngine)
        return;

    pEditEngine.reset(new ExtTextEngine);
    pEditView.reset(new TextView(pEditEngine.get(), this));
    pEditView->SetAutoIndentMode(true);
    pEditEngine->SetUpdateMode(false);
    pEditEngine->InsertView(pEditView.get());

    ImplSetFont();

    aSyntaxIdle.SetInvokeHandler( LINK( this, EditorWindow, SyntaxTimerHdl ) );

    bool bWasDoSyntaxHighlight = bDoSyntaxHighlight;
    bDoSyntaxHighlight = false// too slow for large texts...
    OUString aOUSource(rModulWindow.GetModule());
    sal_Int32 nLines = 0;
    sal_Int32 nIndex = -1;
    do
    {
        nLines++;
        nIndex = searchEOL( aOUSource, nIndex+1 );
    }
    while (nIndex >= 0);

    // nLines*4: SetText+Formatting+DoHighlight+Formatting
    // it could be cut down on one formatting but you would wait even longer
    // for the text then if the source code is long...
    pProgress.reset(new ProgressInfo(GetShell()->GetViewFrame().GetObjectShell(),
                                     IDEResId(RID_STR_GENERATESOURCE),
                                     nLines * 4));
    setTextEngineText(*pEditEngine, aOUSource);

    pEditView->SetStartDocPos(Point(0, 0));
    pEditView->SetSelection(TextSelection());
    rModulWindow.GetBreakPointWindow().GetCurYOffset() = 0;
    rModulWindow.GetLineNumberWindow().GetCurYOffset() = 0;
    pEditEngine->SetUpdateMode(true);
    rModulWindow.PaintImmediately();   // has only been invalidated at UpdateMode = true

    pEditView->ShowCursor();

    StartListening(*pEditEngine);

    aSyntaxIdle.Stop();
    bDoSyntaxHighlight = bWasDoSyntaxHighlight;

    for (sal_Int32 nLine = 0; nLine < nLines; nLine++)
        aSyntaxLineTable.insert(nLine);
    ForceSyntaxTimeout();

    pProgress.reset();

    pEditEngine->SetModified( false );
    pEditEngine->EnableUndo( true );

    InitScrollBars();

    if (SfxBindings* pBindings = GetBindingsPtr())
    {
        pBindings->Invalidate(SID_BASICIDE_STAT_POS);
        pBindings->Invalidate(SID_BASICIDE_STAT_TITLE);
    }

    DBG_ASSERT(rModulWindow.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?");

    // set readonly mode for readonly libraries
    ScriptDocument aDocument(rModulWindow.GetDocument());
    OUString aOULibName(rModulWindow.GetLibName());
    Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) );
    if (xModLibContainer.is()
     && xModLibContainer->hasByName(aOULibName)
     && xModLibContainer->isLibraryReadOnly(aOULibName))
    {
        rModulWindow.SetReadOnly(true);
    }

    if (aDocument.isDocument() && aDocument.isReadOnly())
        rModulWindow.SetReadOnly(true);
}

void EditorWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
{
    if( rHint.GetId() == SfxHintId::TextViewScrolled )
    {
        rModulWindow.GetEditVScrollBar().SetThumbPos( pEditView->GetStartDocPos().Y() );
        rModulWindow.GetEditHScrollBar().SetThumbPos( pEditView->GetStartDocPos().X() );
        rModulWindow.GetBreakPointWindow().DoScroll
            ( rModulWindow.GetBreakPointWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
        rModulWindow.GetLineNumberWindow().DoScroll
            ( rModulWindow.GetLineNumberWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
    }
    else if( rHint.GetId() == SfxHintId::TextHeightChanged )
    {
        if ( pEditView->GetStartDocPos().Y() )
        {
            tools::Long nOutHeight = GetOutputSizePixel().Height();
            tools::Long nTextHeight = pEditEngine->GetTextHeight();
            if ( nTextHeight < nOutHeight )
                pEditView->Scroll( 0, pEditView->GetStartDocPos().Y() );

            rModulWindow.GetLineNumberWindow().Invalidate();
        }

        SetScrollBarRanges();
    }
    else if( rHint.GetId() == SfxHintId::TextFormatted )
    {

        const tools::Long nWidth = pEditEngine->CalcTextWidth();
        if ( nWidth != nCurTextWidth )
        {
            nCurTextWidth = nWidth;
            rModulWindow.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth-1) );
            rModulWindow.GetEditHScrollBar().SetThumbPos( pEditView->GetStartDocPos().X() );
        }
        tools::Long nPrevTextWidth = nCurTextWidth;
        nCurTextWidth = pEditEngine->CalcTextWidth();
        if ( nCurTextWidth != nPrevTextWidth )
            SetScrollBarRanges();
    }
    else if( rHint.GetId() == SfxHintId::TextParaInserted )
    {
        TextHint const & rTextHint = static_cast<TextHint const&>(rHint);
        ParagraphInsertedDeleted( rTextHint.GetValue(), true );
        DoDelayedSyntaxHighlight( rTextHint.GetValue() );
    }
    else if( rHint.GetId() == SfxHintId::TextParaRemoved )
    {
        TextHint const & rTextHint = static_cast<TextHint const&>(rHint);
        ParagraphInsertedDeleted( rTextHint.GetValue(), false );
    }
    else if( rHint.GetId() == SfxHintId::TextParaContentChanged )
    {
        TextHint const & rTextHint = static_cast<TextHint const&>(rHint);
        DoDelayedSyntaxHighlight( rTextHint.GetValue() );
    }
    else if( rHint.GetId() == SfxHintId::TextViewSelectionChanged )
    {
        if (SfxBindings* pBindings = GetBindingsPtr())
        {
            pBindings->Invalidate( SID_CUT );
            pBindings->Invalidate( SID_COPY );
        }
    }
    else if( rHint.GetId() == SfxHintId::TextViewCaretChanged )
    {
        // Check whether the line number where the caret is has changed and the
        // highlight needs to be redrawn
        sal_uInt32 nStartPara = pEditView->GetSelection().GetStart().GetPara();
        sal_uInt32 nEndPara = pEditView->GetSelection().GetEnd().GetPara();
        if (nStartPara == nEndPara && nStartPara != m_nLastHighlightPara)
        {
            m_nLastHighlightPara = nStartPara;
            Invalidate();
            rModulWindow.GetLineNumberWindow().Invalidate();
        }
        else if (nStartPara != nEndPara)
        {
            // If multiple lines are selected, then update the line number window
            rModulWindow.GetLineNumberWindow().Invalidate();
        }
    }
}

OUString EditorWindow::GetActualSubName( sal_uInt32 nLine )
{
    SbxArrayRef pMethods = rModulWindow.GetSbModule()->GetMethods();
    for (sal_uInt32 i = 0; i < pMethods->Count(); i++)
    {
        SbMethod* pMeth = dynamic_cast<SbMethod*>(pMethods->Get(i));
        if( pMeth )
        {
            sal_uInt16 l1,l2;
            pMeth->GetLineRange(l1,l2);
            if( (l1 <= nLine+1) && (nLine+1 <= l2) )
            {
                return pMeth->GetName();
            }
        }
    }
    return OUString();
}

void EditorWindow::SetScrollBarRanges()
{
    // extra method, not InitScrollBars, because for EditEngine events too
    if ( !pEditEngine )
        return;

    rModulWindow.GetEditVScrollBar().SetRange( Range( 0, pEditEngine->GetTextHeight()-1 ) );
    rModulWindow.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth-1 ) );
}

void EditorWindow::InitScrollBars()
{
    if (!pEditEngine)
        return;

    SetScrollBarRanges();
    Size aOutSz(GetOutputSizePixel());
    rModulWindow.GetEditVScrollBar().SetVisibleSize(aOutSz.Height());
    rModulWindow.GetEditVScrollBar().SetPageSize(aOutSz.Height() * 8 / 10);
    rModulWindow.GetEditVScrollBar().SetLineSize(GetTextHeight());
    rModulWindow.GetEditVScrollBar().SetThumbPos(pEditView->GetStartDocPos().Y());
    rModulWindow.GetEditVScrollBar().Show();

    rModulWindow.GetEditHScrollBar().SetVisibleSize(aOutSz.Width());
    rModulWindow.GetEditHScrollBar().SetPageSize(aOutSz.Width() * 8 / 10);
    rModulWindow.GetEditHScrollBar().SetLineSize(GetTextWidth( u"x"_ustr ));
    rModulWindow.GetEditHScrollBar().SetThumbPos(pEditView->GetStartDocPos().X());
    rModulWindow.GetEditHScrollBar().Show();
}

void EditorWindow::ImpDoHighlight( sal_uInt32 nLine )
{
    if ( !bDoSyntaxHighlight )
        return;

    OUString aLine( pEditEngine->GetText( nLine ) );
    bool const bWasModified = pEditEngine->IsModified();
    pEditEngine->RemoveAttribs( nLine );
    std::vector<HighlightPortion> aPortions;
    aHighlighter.getHighlightPortions( aLine, aPortions );

    for (auto const& portion : aPortions)
    {
        Color const aColor = rModulWindow.GetLayout().GetSyntaxColor(portion.tokenType);
        pEditEngine->SetAttrib(TextAttribFontColor(aColor), nLine, portion.nBegin, portion.nEnd);
    }

    pEditEngine->SetModified(bWasModified);
}

void EditorWindow::ChangeFontColor( Color aColor )
{
    if (pEditEngine)
    {
        vcl::Font aFont(pEditEngine->GetFont());
        aFont.SetColor(aColor);
        pEditEngine->SetFont(aFont);
    }
}

void EditorWindow::UpdateSyntaxHighlighting ()
{
    if (pEditEngine)
    {
        const sal_uInt32 nCount = pEditEngine->GetParagraphCount();
        for (sal_uInt32 i = 0; i < nCount; ++i)
            DoDelayedSyntaxHighlight(i);
    }
}

void EditorWindow::ImplSetFont()
{
    // Get default font name and height defined in the Options dialog
    OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString()));
    if (sFontName.isEmpty())
    {
        vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED,
                                                        Application::GetSettings().GetUILanguageTag().getLanguageType(),
                                                        GetDefaultFontFlags::NONE, GetOutDev()));
        sFontName = aTmpFont.GetFamilyName();
    }
    sal_uInt16 nDefaultFontHeight = officecfg::Office::Common::Font::SourceViewFont::FontHeight::get();

    // Calculate font size considering zoom level
    sal_uInt16 nNewFontHeight = nDefaultFontHeight * (static_cast<float>(nCurrentZoomLevel) / 100);
    Size aFontSize(0, nNewFontHeight);

    vcl::Font aFont(sFontName, aFontSize);
    aFont.SetColor(rModulWindow.GetLayout().GetFontColor());
    SetPointFont(*GetOutDev(), aFont); // FIXME RenderContext
    aFont = GetFont();

    rModulWindow.GetBreakPointWindow().SetFont(aFont);
    rModulWindow.GetLineNumberWindow().SetFont(aFont);
    rModulWindow.Invalidate();

    if (pEditEngine)
    {
        bool const bModified = pEditEngine->IsModified();
        pEditEngine->SetFont(aFont);
        pEditEngine->SetModified(bModified);
    }

    // Update controls
    if (SfxBindings* pBindings = GetBindingsPtr())
    {
        pBindings->Invalidate( SID_BASICIDE_CURRENT_ZOOM );
        pBindings->Invalidate( SID_ATTR_ZOOMSLIDER );
    }
}

void EditorWindow::SetEditorZoomLevel(sal_uInt16 nNewZoomLevel)
{
    if (nCurrentZoomLevel == nNewZoomLevel)
        return;

    if (nNewZoomLevel < MIN_ZOOM_LEVEL || nNewZoomLevel > MAX_ZOOM_LEVEL)
        return;

    nCurrentZoomLevel = nNewZoomLevel;
    ImplSetFont();
}

void EditorWindow::DoSyntaxHighlight( sal_uInt32 nPara )
{
    // because of the DelayedSyntaxHighlight it's possible
    // that this line does not exist anymore!
    if ( nPara < pEditEngine->GetParagraphCount() )
    {
        // unfortunately I'm not sure that exactly this line does Modified()...
        if ( pProgress )
            pProgress->StepProgress();
        ImpDoHighlight( nPara );
    }
}

void EditorWindow::DoDelayedSyntaxHighlight( sal_uInt32 nPara )
{
    // line is only added to list, processed in TimerHdl
    // => don't manipulate breaks while EditEngine is formatting
    if ( pProgress )
        pProgress->StepProgress();

    if ( !bHighlighting && bDoSyntaxHighlight )
    {
        if ( bDelayHighlight )
        {
            aSyntaxLineTable.insert( nPara );
            aSyntaxIdle.Start();
        }
        else
            DoSyntaxHighlight( nPara );
    }
}

IMPL_LINK_NOARG(EditorWindow, SyntaxTimerHdl, Timer *, void)
{
    DBG_ASSERT( pEditView, "Not yet a View, but Syntax-Highlight?!" );

    bool const bWasModified = pEditEngine->IsModified();
    //pEditEngine->SetUpdateMode(false);

    bHighlighting = true;
    for (auto const& syntaxLine : aSyntaxLineTable)
    {
        DoSyntaxHighlight(syntaxLine);
    }

    // #i45572#
    if ( pEditView )
        pEditView->ShowCursor( false );

    pEditEngine->SetModified( bWasModified );

    aSyntaxLineTable.clear();
    bHighlighting = false;
}

void EditorWindow::ParagraphInsertedDeleted( sal_uInt32 nPara, bool bInserted )
{
    if ( pProgress )
        pProgress->StepProgress();

    if ( !bInserted && ( nPara == TEXT_PARA_ALL ) )
    {
        rModulWindow.GetBreakPoints().reset();
        rModulWindow.GetBreakPointWindow().Invalidate();
        rModulWindow.GetLineNumberWindow().Invalidate();
    }
    else
    {
        rModulWindow.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16>(nPara)+1, bInserted );

        tools::Long nLineHeight = GetTextHeight();
        Size aSz = rModulWindow.GetBreakPointWindow().GetOutDev()->GetOutputSize();
        tools::Rectangle aInvRect( Point( 0, 0 ), aSz );
        tools::Long nY = nPara*nLineHeight - rModulWindow.GetBreakPointWindow().GetCurYOffset();
        aInvRect.SetTop( nY );
        rModulWindow.GetBreakPointWindow().Invalidate( aInvRect );

        Size aLnSz(rModulWindow.GetLineNumberWindow().GetWidth(),
                   GetOutputSizePixel().Height() - 2 * DWBORDER);
        rModulWindow.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER + 19, DWBORDER), aLnSz);
        rModulWindow.GetLineNumberWindow().Invalidate();
    }
}

void EditorWindow::CreateProgress( const OUString& rText, sal_uInt32 nRange )
{
    DBG_ASSERT( !pProgress, "ProgressInfo exists already" );
    pProgress.reset(new ProgressInfo(
        GetShell()->GetViewFrame().GetObjectShell(),
        rText,
        nRange
    ));
}

void EditorWindow::DestroyProgress()
{
    pProgress.reset();
}

void EditorWindow::ForceSyntaxTimeout()
{
    aSyntaxIdle.Stop();
    aSyntaxIdle.Invoke();
}

FactoryFunction EditorWindow::GetUITestFactory() const
{
    return EditorWindowUIObject::create;
}


// BreakPointWindow

BreakPointWindow::BreakPointWindow (vcl::Window* pParent, ModulWindow* pModulWindow)
    : Window(pParent, WB_BORDER)
    , rModulWindow(*pModulWindow)
    , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine
    , nMarkerPos(NoMarker)
    , bErrorMarker(false)
{
    setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor());
    SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW);
}

void BreakPointWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    SyncYOffset(); // Don't return even if invalidated, to avoid flicker

    Size const aOutSz = rRenderContext.GetOutputSize();
    tools::Long const nLineHeight = rRenderContext.GetTextHeight();

    Image const aBrk[2] =
    {
        GetImage(RID_BMP_BRKDISABLED),
        GetImage(RID_BMP_BRKENABLED)
    };

    Size const aBmpSz = rRenderContext.PixelToLogic(aBrk[1].GetSizePixel());
    Point const aBmpOff((aOutSz.Width() - aBmpSz.Width()) / 2,
                        (nLineHeight - aBmpSz.Height()) / 2);

    for (size_t i = 0, n = GetBreakPoints().size(); i < n; ++i)
    {
        BreakPoint& rBrk = GetBreakPoints().at(i);
        sal_uInt16 const nLine = rBrk.nLine - 1;
        size_t const nY = nLine*nLineHeight - nCurYOffset;
        rRenderContext.DrawImage(Point(0, nY) + aBmpOff, aBrk[rBrk.bEnabled]);
    }

    ShowMarker(rRenderContext);
}

void BreakPointWindow::ShowMarker(vcl::RenderContext& rRenderContext)
{
    if (nMarkerPos == NoMarker)
        return;

    Size const aOutSz = GetOutDev()->GetOutputSize();
    tools::Long const nLineHeight = GetTextHeight();

    Image aMarker = GetImage(bErrorMarker ? RID_BMP_ERRORMARKER : RID_BMP_STEPMARKER);

    Size aMarkerSz(aMarker.GetSizePixel());
    aMarkerSz = rRenderContext.PixelToLogic(aMarkerSz);
    Point aMarkerOff(0, 0);
    aMarkerOff.setX( (aOutSz.Width() - aMarkerSz.Width()) / 2 );
    aMarkerOff.setY( (nLineHeight - aMarkerSz.Height()) / 2 );

    tools::Long nY = nMarkerPos * nLineHeight - nCurYOffset;
    Point aPos(0, nY);
    aPos += aMarkerOff;

    rRenderContext.DrawImage(aPos, aMarker);
}

void BreakPointWindow::DoScroll( tools::Long nVertScroll )
{
    nCurYOffset -= nVertScroll;
    Window::Scroll(0, nVertScroll, ScrollFlags::Update);
}

void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine, bool bError )
{
    bool bPaintImmediately = SyncYOffset();

    nMarkerPos = nLine;
    bErrorMarker = bError;
    Invalidate();
    if (bPaintImmediately)
        PaintImmediately();
}

void BreakPointWindow::SetNoMarker ()
{
    SetMarkerPos(NoMarker);
}

BreakPoint* BreakPointWindow::FindBreakPoint( const Point& rMousePos )
{
    size_t nLineHeight = GetTextHeight();
    nLineHeight = nLineHeight > 0 ? nLineHeight : 1;
    size_t nYPos = rMousePos.Y() + nCurYOffset;

    for ( size_t i = 0, n = GetBreakPoints().size(); i < n ; ++i )
    {
        BreakPoint& rBrk = GetBreakPoints().at( i );
        sal_uInt16 nLine = rBrk.nLine-1;
        size_t nY = nLine*nLineHeight;
        if ( ( nYPos > nY ) && ( nYPos < ( nY + nLineHeight ) ) )
            return &rBrk;
    }
    return nullptr;
}

void BreakPointWindow::MouseButtonDown( const MouseEvent& rMEvt )
{
    if ( rMEvt.GetClicks() == 2 )
    {
        Point aMousePos( PixelToLogic( rMEvt.GetPosPixel() ) );
        tools::Long nLineHeight = GetTextHeight();
        if(nLineHeight)
        {
            tools::Long nYPos = aMousePos.Y() + nCurYOffset;
            tools::Long nLine = nYPos / nLineHeight + 1;
            rModulWindow.ToggleBreakPoint( static_cast<sal_uInt16>(nLine) );
            Invalidate();
        }
    }
}

void BreakPointWindow::Command( const CommandEvent& rCEvt )
{
    if ( rCEvt.GetCommand() != CommandEventId::ContextMenu )
        return;

    Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) );
    tools::Rectangle aRect(aPos, Size(1, 1));
    weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);

    std::unique_ptr<weld::Builder> xUIBuilder(Application::CreateBuilder(pPopupParent, u"modules/BasicIDE/ui/breakpointmenus.ui"_ustr));

    Point aEventPos( PixelToLogic( aPos ) );
    BreakPoint* pBrk = rCEvt.IsMouseEvent() ? FindBreakPoint( aEventPos ) : nullptr;
    if ( pBrk )
    {
        // test if break point is enabled...
        std::unique_ptr<weld::Menu> xBrkPropMenu = xUIBuilder->weld_menu(u"breakmenu"_ustr);
        xBrkPropMenu->set_active(u"active"_ustr, pBrk->bEnabled);
        OUString sCommand = xBrkPropMenu->popup_at_rect(pPopupParent, aRect);
        if (sCommand == "active")
        {
            pBrk->bEnabled = !pBrk->bEnabled;
            rModulWindow.UpdateBreakPoint( *pBrk );
            Invalidate();
        }
        else if (sCommand == "properties")
        {
            BreakPointDialog aBrkDlg(pPopupParent, GetBreakPoints());
            aBrkDlg.SetCurrentBreakPoint( *pBrk );
            aBrkDlg.run();
            Invalidate();
        }
    }
    else
    {
        std::unique_ptr<weld::Menu> xBrkListMenu = xUIBuilder->weld_menu(u"breaklistmenu"_ustr);
        OUString sCommand = xBrkListMenu->popup_at_rect(pPopupParent, aRect);
        if (sCommand == "manage")
        {
            BreakPointDialog aBrkDlg(pPopupParent, GetBreakPoints());
            aBrkDlg.run();
            Invalidate();
        }
    }
}

bool BreakPointWindow::SyncYOffset()
{
    TextView* pView = rModulWindow.GetEditView();
    if ( pView )
    {
        tools::Long nViewYOffset = pView->GetStartDocPos().Y();
        if ( nCurYOffset != nViewYOffset )
        {
            nCurYOffset = nViewYOffset;
            Invalidate();
            return true;
        }
    }
    return false;
}

// virtual
void BreakPointWindow::DataChanged(DataChangedEvent const & rDCEvt)
{
    Window::DataChanged(rDCEvt);
    if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
        && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
    {
        Color aColor(GetSettings().GetStyleSettings().GetFieldColor());
        const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
        if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor())
        {
            setBackgroundColor(aColor);
            Invalidate();
        }
    }
}

void BreakPointWindow::setBackgroundColor(Color aColor)
{
    SetBackground(Wallpaper(aColor));
}

namespace {

struct WatchItem
{
    OUString        maName;
    OUString        maDisplayName;
    SbxObjectRef    mpObject;
    std::vector<OUString> maMemberList;

    SbxDimArrayRef  mpArray;
    int             nDimLevel;  // 0 = Root
    int             nDimCount;
    std::vector<sal_Int32> vIndices;

    WatchItem*      mpArrayParentItem;

    explicit WatchItem (OUString aName):
        maName(std::move(aName)),
        nDimLevel(0),
        nDimCount(0),
        mpArrayParentItem(nullptr)
    { }

    void clearWatchItem ()
    {
        maMemberList.clear();
    }

    WatchItem* GetRootItem();
    SbxDimArray* GetRootArray();
};

}

WatchWindow::WatchWindow(Layout* pParent)
    : DockingWindow(pParent, u"modules/BasicIDE/ui/dockingwatch.ui"_ustr, u"DockingWatch"_ustr)
    , m_nUpdateWatchesId(nullptr)
{
    m_xTitleArea = m_xBuilder->weld_container(u"titlearea"_ustr);

    nVirtToolBoxHeight = m_xTitleArea->get_preferred_size().Height();

    m_xTitle = m_xBuilder->weld_label(u"title"_ustr);
    m_xTitle->set_label(IDEResId(RID_STR_REMOVEWATCH));

    m_xEdit = m_xBuilder->weld_entry(u"edit"_ustr);
    m_xRemoveWatchButton = m_xBuilder->weld_button(u"remove"_ustr);
    m_xTreeListBox = m_xBuilder->weld_tree_view(u"treeview"_ustr);

    m_xEdit->set_accessible_name(IDEResId(RID_STR_WATCHNAME));
    m_xEdit->set_help_id(HID_BASICIDE_WATCHWINDOW_EDIT);
    m_xEdit->set_size_request(LogicToPixel(Size(80, 0), MapMode(MapUnit::MapAppFont)).Width(), -1);
    m_xEdit->connect_activate(LINK( this, WatchWindow, ActivateHdl));
    m_xEdit->connect_key_press(LINK( this, WatchWindow, KeyInputHdl));
    m_xTreeListBox->set_accessible_name(IDEResId(RID_STR_WATCHNAME));

    m_xRemoveWatchButton->set_sensitive(false);
    m_xRemoveWatchButton->connect_clicked(LINK( this, WatchWindow, ButtonHdl));
    m_xRemoveWatchButton->set_help_id(HID_BASICIDE_REMOVEWATCH);
    m_xRemoveWatchButton->set_tooltip_text(IDEResId(RID_STR_REMOVEWATCHTIP));

    m_xTreeListBox->set_help_id(HID_BASICIDE_WATCHWINDOW_LIST);
    m_xTreeListBox->connect_editing(LINK(this, WatchWindow, EditingEntryHdl),
                                    LINK(this, WatchWindow, EditedEntryHdl));
    m_xTreeListBox->connect_selection_changed(LINK(this, WatchWindow, TreeListHdl));
    m_xTreeListBox->connect_expanding(LINK(this, WatchWindow, RequestingChildrenHdl));

    // VarTabWidth, ValueTabWidth, TypeTabWidth
    std::vector<int> aWidths { 220, 100, 1250 };
    std::vector<bool> aEditables { falsetruefalse };
    m_xTreeListBox->set_column_fixed_widths(aWidths);
    m_xTreeListBox->set_column_editables(aEditables);

    SetText(IDEResId(RID_STR_WATCHNAME));

    SetHelpId( HID_BASICIDE_WATCHWINDOW );

    // make watch window keyboard accessible
    GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
}

WatchWindow::~WatchWindow()
{
    disposeOnce();
}

void WatchWindow::dispose()
{
    if (m_nUpdateWatchesId)
    {
        Application::RemoveUserEvent(m_nUpdateWatchesId);
        m_nUpdateWatchesId = nullptr;
    }

    // Destroy user data
    m_xTreeListBox->all_foreach([this](weld::TreeIter& rEntry){
        WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rEntry));
        delete pItem;
        return false;
    });

    m_xTitle.reset();
    m_xEdit.reset();
    m_xRemoveWatchButton.reset();
    m_xTitleArea.reset();
    m_xTreeListBox.reset();
    GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
    DockingWindow::dispose();
}

void WatchWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    lcl_DrawIDEWindowFrame(this, rRenderContext);
}

void WatchWindow::Resize()
{
    Size aSz = GetOutputSizePixel();
    Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - 2*DWBORDER);

    if ( aBoxSz.Width() < 4 )
        aBoxSz.setWidth( 0 );
    if ( aBoxSz.Height() < 4 )
        aBoxSz.setHeight( 0 );

    m_xBox->SetPosSizePixel(Point(DWBORDER, DWBORDER), aBoxSz);

    Invalidate();
}

WatchItem* WatchItem::GetRootItem()
{
    WatchItem* pItem = mpArrayParentItem;
    while( pItem )
    {
        if( pItem->mpArray.is() )
            break;
        pItem = pItem->mpArrayParentItem;
    }
    return pItem;
}

SbxDimArray* WatchItem::GetRootArray()
{
    WatchItem* pRootItem = GetRootItem();
    SbxDimArray* pRet = nullptr;
    if( pRootItem )
        pRet = pRootItem->mpArray.get();
    return pRet;
}

void WatchWindow::AddWatch( const OUString& rVName )
{
    OUString aVar, aIndex;
    lcl_SeparateNameAndIndex( rVName, aVar, aIndex );
    WatchItem* pWatchItem = new WatchItem(aVar);

    OUString sId(weld::toId(pWatchItem));
    std::unique_ptr<weld::TreeIter> xRet = m_xTreeListBox->make_iterator();
    m_xTreeListBox->insert(nullptr, -1, &aVar, &sId, nullptr, nullptr, false, xRet.get());
    m_xTreeListBox->set_text(*xRet, u""_ustr, 1);
    m_xTreeListBox->set_text(*xRet, u""_ustr, 2);

    m_xTreeListBox->set_cursor(*xRet);
    m_xTreeListBox->select(*xRet);
    m_xTreeListBox->scroll_to_row(*xRet);
    m_xRemoveWatchButton->set_sensitive(true);

    UpdateWatches(false);
}

void WatchWindow::RemoveSelectedWatch()
{
    std::unique_ptr<weld::TreeIter> xEntry = m_xTreeListBox->make_iterator();
    bool bEntry = m_xTreeListBox->get_cursor(xEntry.get());
    if (bEntry)
    {
        m_xTreeListBox->remove(*xEntry);
        bEntry = m_xTreeListBox->get_cursor(xEntry.get());
        if (bEntry)
            m_xEdit->set_text(weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xEntry))->maName);
        else
            m_xEdit->set_text(OUString());
        if ( !m_xTreeListBox->n_children() )
            m_xRemoveWatchButton->set_sensitive(false);
    }
}

IMPL_STATIC_LINK_NOARG(WatchWindow, ButtonHdl, weld::Button&, void)
{
    if (SfxDispatcher* pDispatcher = GetDispatcher())
        pDispatcher->Execute(SID_BASICIDE_REMOVEWATCH);
}

IMPL_LINK_NOARG(WatchWindow, TreeListHdl, weld::TreeView&, void)
{
    std::unique_ptr<weld::TreeIter> xCurEntry = m_xTreeListBox->make_iterator();
    bool bCurEntry = m_xTreeListBox->get_cursor(xCurEntry.get());
    if (!bCurEntry)
        return;
    WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xCurEntry));
    if (!pItem)
        return;
    m_xEdit->set_text(pItem->maName);
}

IMPL_LINK_NOARG(WatchWindow, ActivateHdl, weld::Entry&, bool)
{
    OUString aCurText(m_xEdit->get_text());
    if (!aCurText.isEmpty())
    {
        AddWatch(aCurText);
        m_xEdit->select_region(0, -1);
    }
    return true;
}

IMPL_LINK(WatchWindow, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{
    bool bHandled = false;

    sal_uInt16 nKeyCode = rKEvt.GetKeyCode().GetCode();
    if (nKeyCode == KEY_ESCAPE)
    {
        m_xEdit->set_text(OUString());
        bHandled = true;
    }

    return bHandled;
}

// StackWindow
StackWindow::StackWindow(Layout* pParent)
    : DockingWindow(pParent, u"modules/BasicIDE/ui/dockingstack.ui"_ustr, u"DockingStack"_ustr)
{
    m_xTitle = m_xBuilder->weld_label(u"title"_ustr);
    m_xTitle->set_label(IDEResId(RID_STR_STACK));

    m_xTitle->set_size_request(-1, nVirtToolBoxHeight); // so the two title areas are the same height

    m_xTreeListBox = m_xBuilder->weld_tree_view(u"stack"_ustr);

    m_xTreeListBox->set_help_id(HID_BASICIDE_STACKWINDOW_LIST);
    m_xTreeListBox->set_accessible_name(IDEResId(RID_STR_STACKNAME));
    m_xTreeListBox->set_selection_mode(SelectionMode::NONE);
    m_xTreeListBox->append_text(OUString());

    SetText(IDEResId(RID_STR_STACKNAME));

    SetHelpId( HID_BASICIDE_STACKWINDOW );

    // make stack window keyboard accessible
    GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
}

StackWindow::~StackWindow()
{
    disposeOnce();
}

void StackWindow::dispose()
{
    GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
    m_xTitle.reset();
    m_xTreeListBox.reset();
    DockingWindow::dispose();
}

void StackWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
{
    lcl_DrawIDEWindowFrame(this, rRenderContext);
}

void StackWindow::Resize()
{
    Size aSz = GetOutputSizePixel();
    Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - 2*DWBORDER);

    if ( aBoxSz.Width() < 4 )
        aBoxSz.setWidth( 0 );
    if ( aBoxSz.Height() < 4 )
        aBoxSz.setHeight( 0 );

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

--> maximum size reached

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

Messung V0.5
C=91 H=95 G=92

¤ Dauer der Verarbeitung: 0.33 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Versionsinformation zu Columbo

Bemerkung:

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Anfrage:

Dauer der Verarbeitung:

Sekunden

sprechenden Kalenders