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.24 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.