office-gobmx/basctl/source/basicide/baside2.cxx
Caolán McNamara 8a83a62410 cid#1555167 COPY_INSTEAD_OF_MOVE
and

cid#1555172 COPY_INSTEAD_OF_MOVE
cid#1555184 COPY_INSTEAD_OF_MOVE
cid#1555188 COPY_INSTEAD_OF_MOVE
cid#1555197 COPY_INSTEAD_OF_MOVE
cid#1555209 COPY_INSTEAD_OF_MOVE
cid#1555211 COPY_INSTEAD_OF_MOVE
cid#1555215 COPY_INSTEAD_OF_MOVE
cid#1555216 COPY_INSTEAD_OF_MOVE
cid#1555217 COPY_INSTEAD_OF_MOVE
cid#1555218 COPY_INSTEAD_OF_MOVE
cid#1555222 COPY_INSTEAD_OF_MOVE
cid#1556674 COPY_INSTEAD_OF_MOVE
cid#1555229 COPY_INSTEAD_OF_MOVE
cid#1555233 COPY_INSTEAD_OF_MOVE
cid#1555234 COPY_INSTEAD_OF_MOVE
cid#1555242 COPY_INSTEAD_OF_MOVE
cid#1555250 COPY_INSTEAD_OF_MOVE
cid#1555251 COPY_INSTEAD_OF_MOVE
cid#1555254 COPY_INSTEAD_OF_MOVE
cid#1555304 COPY_INSTEAD_OF_MOVE
cid#1555307 COPY_INSTEAD_OF_MOVE
cid#1555317 COPY_INSTEAD_OF_MOVE
cid#1555329 COPY_INSTEAD_OF_MOVE
cid#1555340 COPY_INSTEAD_OF_MOVE
cid#1555347 COPY_INSTEAD_OF_MOVE
cid#1555352 COPY_INSTEAD_OF_MOVE
cid#1555358 COPY_INSTEAD_OF_MOVE
cid#1555363 COPY_INSTEAD_OF_MOVE
cid#1555365 COPY_INSTEAD_OF_MOVE
cid#1555367 COPY_INSTEAD_OF_MOVE
cid#1555374 COPY_INSTEAD_OF_MOVE
cid#1555380 COPY_INSTEAD_OF_MOVE

Change-Id: I343194c10749488a1143e2517ee0638ab19da218
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170888
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
2024-07-23 21:58:02 +02:00

1691 lines
50 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "baside2.hxx"
#include <baside3.hxx>
#include <basobj.hxx>
#include <basidesh.hxx>
#include "brkdlg.hxx"
#include <iderdll.hxx>
#include <iderid.hxx>
#include "moduldlg.hxx"
#include <sfx2/dispatch.hxx>
#include <docsignature.hxx>
#include <colorscheme.hxx>
#include <officecfg/Office/BasicIDE.hxx>
#include <helpids.h>
#include <strings.hrc>
#include <basic/basmgr.hxx>
#include <basic/basrdll.hxx>
#include <basic/sbmeth.hxx>
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
#include <com/sun/star/script/ModuleType.hpp>
#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
#include <comphelper/SetFlagContextHelper.hxx>
#include <comphelper/string.hxx>
#include <svl/srchdefs.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/filedlghelper.hxx>
#include <sfx2/request.hxx>
#include <sfx2/viewfrm.hxx>
#include <sot/exchange.hxx>
#include <svl/eitem.hxx>
#include <svl/srchitem.hxx>
#include <svl/stritem.hxx>
#include <svl/visitem.hxx>
#include <svl/whiter.hxx>
#include <svx/svxids.hrc>
#include <tools/debug.hxx>
#include <utility>
#include <vcl/locktoplevels.hxx>
#include <vcl/errinf.hxx>
#include <vcl/event.hxx>
#include <vcl/print.hxx>
#include <vcl/svapp.hxx>
#include <vcl/textview.hxx>
#include <vcl/weld.hxx>
#include <vcl/xtextedt.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <cassert>
#include <osl/diagnose.h>
#include <officecfg/Office/Common.hxx>
#include <BasicColorConfig.hxx>
namespace basctl
{
namespace
{
namespace Print
{
tools::Long const nLeftMargin = 1700;
tools::Long const nRightMargin = 900;
tools::Long const nTopMargin = 2000;
tools::Long const nBottomMargin = 1000;
tools::Long const nBorder = 300;
}
short const ValidWindow = 0x1234;
// What (who) are OW and MTF? Compare to baside3.cxx where an
// identically named variable, used in the same way, has the value
// "*.*" on Windows, "*" otherwise. Is that what should be done here,
// too?
#if defined(OW) || defined(MTF)
char const FilterMask_All[] = "*";
#else
constexpr OUString FilterMask_All = u"*.*"_ustr;
#endif
} // end anonymous namespace
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::ui::dialogs;
using namespace utl;
using namespace comphelper;
namespace
{
void lcl_PrintHeader( Printer* pPrinter, sal_uInt16 nPages, sal_uInt16 nCurPage, const OUString& rTitle, bool bOutput )
{
Size const aSz = pPrinter->GetOutputSize();
const Color aOldLineColor( pPrinter->GetLineColor() );
const Color aOldFillColor( pPrinter->GetFillColor() );
const vcl::Font aOldFont( pPrinter->GetFont() );
pPrinter->SetLineColor( COL_BLACK );
pPrinter->SetFillColor();
vcl::Font aFont( aOldFont );
aFont.SetWeight( WEIGHT_BOLD );
aFont.SetAlignment( ALIGN_BOTTOM );
pPrinter->SetFont( aFont );
tools::Long nFontHeight = pPrinter->GetTextHeight();
// 1st Border => line, 2+3 Border = free space
tools::Long nYTop = Print::nTopMargin - 3*Print::nBorder - nFontHeight;
tools::Long nXLeft = Print::nLeftMargin - Print::nBorder;
tools::Long nXRight = aSz.Width() - Print::nRightMargin + Print::nBorder;
if( bOutput )
pPrinter->DrawRect(tools::Rectangle(
Point(nXLeft, nYTop),
Size(nXRight - nXLeft, aSz.Height() - nYTop - Print::nBottomMargin + Print::nBorder)
));
tools::Long nY = Print::nTopMargin - 2*Print::nBorder;
Point aPos(Print::nLeftMargin, nY);
if( bOutput )
pPrinter->DrawText( aPos, rTitle );
if ( nPages != 1 )
{
aFont.SetWeight( WEIGHT_NORMAL );
pPrinter->SetFont( aFont );
aPos.AdjustX(pPrinter->GetTextWidth( rTitle ) );
if( bOutput )
{
OUString aPageStr = " [" + IDEResId(RID_STR_PAGE) + " " + OUString::number( nCurPage ) + "]";
pPrinter->DrawText( aPos, aPageStr );
}
}
nY = Print::nTopMargin - Print::nBorder;
if( bOutput )
pPrinter->DrawLine( Point( nXLeft, nY ), Point( nXRight, nY ) );
pPrinter->SetFont( aOldFont );
pPrinter->SetFillColor( aOldFillColor );
pPrinter->SetLineColor( aOldLineColor );
}
void lcl_ConvertTabsToSpaces( OUString& rLine )
{
if ( rLine.isEmpty() )
return;
OUStringBuffer aResult( rLine );
sal_Int32 nPos = 0;
sal_Int32 nMax = aResult.getLength();
while ( nPos < nMax )
{
if ( aResult[nPos] == '\t' )
{
// not 4 Blanks, but at 4 TabPos:
OUStringBuffer aBlanker;
string::padToLength(aBlanker, ( 4 - ( nPos % 4 ) ), ' ');
aResult.remove( nPos, 1 );
aResult.insert( nPos, aBlanker );
nMax = aResult.getLength();
}
++nPos;
}
rLine = aResult.makeStringAndClear();
}
} // namespace
ModulWindow::ModulWindow (ModulWindowLayout* pParent, ScriptDocument const& rDocument,
const OUString& aLibName, const OUString& aName, OUString aModule)
: BaseWindow(pParent, rDocument, aLibName, aName)
, m_rLayout(*pParent)
, m_nValid(ValidWindow)
, m_aXEditorWindow(VclPtr<ComplexEditorWindow>::Create(this))
, m_aModule(std::move(aModule))
{
// Active editor color scheme
m_sWinColorScheme = GetShell()->GetColorConfig()->GetCurrentColorSchemeName();
m_aXEditorWindow->Show();
SetBackground();
}
SbModuleRef const & ModulWindow::XModule()
{
// ModuleWindows can now be created as a result of the
// modules getting created via the api. This is a result of an
// elementInserted event from the BasicLibrary container.
// However the SbModule is also created from a different listener to
// the same event ( in basmgr ) Therefore it is possible when we look
// for m_xModule it may not yet be available, here we keep trying to access
// the module until such time as it exists
if ( !m_xModule.is() )
{
BasicManager* pBasMgr = GetDocument().getBasicManager();
if ( pBasMgr )
{
StarBASIC* pBasic = pBasMgr->GetLib( GetLibName() );
if ( pBasic )
{
m_xBasic = pBasic;
m_xModule = pBasic->FindModule( GetName() );
}
}
}
return m_xModule;
}
ModulWindow::~ModulWindow()
{
disposeOnce();
}
void ModulWindow::dispose()
{
m_nValid = 0;
StarBASIC::Stop();
m_aXEditorWindow.disposeAndClear();
BaseWindow::dispose();
}
void ModulWindow::GetFocus()
{
if (m_nValid != ValidWindow)
return;
m_aXEditorWindow->GetEdtWindow().GrabFocus();
// don't call basic calls because focus is somewhere else...
}
void ModulWindow::DoInit()
{
GetEditorWindow().InitScrollBars();
}
void ModulWindow::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle&)
{
}
void ModulWindow::Resize()
{
m_aXEditorWindow->SetPosSizePixel( Point( 0, 0 ), GetOutputSizePixel() );
}
void ModulWindow::CheckCompileBasic()
{
if ( !XModule().is() )
return;
// never compile while running!
bool const bRunning = StarBASIC::IsRunning();
bool const bModified = ( !m_xModule->IsCompiled() ||
( GetEditEngine() && GetEditEngine()->IsModified() ) );
if ( bRunning || !bModified )
return;
bool bDone = false;
GetShell()->GetViewFrame().GetWindow().EnterWait();
AssertValidEditEngine();
GetEditorWindow().SetSourceInBasic();
bool bWasModified = GetBasic()->IsModified();
{
// tdf#106529: only use strict compilation mode when compiling from the IDE
css::uno::ContextLayer layer(comphelper::NewFlagContext(u"BasicStrict"_ustr));
bDone = m_xModule->Compile();
}
if ( !bWasModified )
GetBasic()->SetModified(false);
if ( bDone )
{
GetBreakPoints().SetBreakPointsInBasic( m_xModule.get() );
}
GetShell()->GetViewFrame().GetWindow().LeaveWait();
m_aStatus.bError = !bDone;
m_aStatus.bIsRunning = false;
}
void ModulWindow::BasicExecute()
{
// #116444# check security settings before macro execution
ScriptDocument aDocument( GetDocument() );
bool bMacrosDisabled = officecfg::Office::Common::Security::Scripting::DisableMacrosExecution::get();
if (bMacrosDisabled || (aDocument.isDocument() && !aDocument.allowMacros()))
{
std::unique_ptr<weld::MessageDialog> xBox(
Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Warning,
VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO)));
xBox->run();
return;
}
CheckCompileBasic();
if ( !XModule().is() || !m_xModule->IsCompiled() || m_aStatus.bError )
return;
if ( GetBreakPoints().size() )
m_aStatus.nBasicFlags = m_aStatus.nBasicFlags | BasicDebugFlags::Break;
if ( !m_aStatus.bIsRunning )
{
DBG_ASSERT( m_xModule.is(), "No Module!" );
AddStatus( BASWIN_RUNNINGBASIC );
sal_uInt16 nStart, nEnd;
TextSelection aSel = GetEditView()->GetSelection();
// Init cursor to top
const sal_uInt32 nCurMethodStart = aSel.GetStart().GetPara() + 1;
SbMethod* pMethod = nullptr;
// first Macro, else blind "Main" (ExtSearch?)
for (sal_uInt32 nMacro = 0; nMacro < m_xModule->GetMethods()->Count(); nMacro++)
{
SbMethod* pM = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMacro));
assert(pM && "Method?");
pM->GetLineRange( nStart, nEnd );
if ( nCurMethodStart >= nStart && nCurMethodStart <= nEnd )
{
// matched a method to the cursor position
pMethod = pM;
break;
}
}
if ( !pMethod )
{
// If not in a method then prompt the user
ChooseMacro(GetFrameWeld(), uno::Reference<frame::XModel>());
return;
}
pMethod->SetDebugFlags(m_aStatus.nBasicFlags);
BasicDLL::SetDebugMode(true);
RunMethod(pMethod);
BasicDLL::SetDebugMode(false);
// if cancelled during Interactive=false
BasicDLL::EnableBreak(true);
ClearStatus( BASWIN_RUNNINGBASIC );
}
else
m_aStatus.bIsRunning = false; // cancel of Reschedule()
}
void ModulWindow::CompileBasic()
{
CheckCompileBasic();
XModule().is() && m_xModule->IsCompiled();
}
void ModulWindow::BasicRun()
{
m_aStatus.nBasicFlags = BasicDebugFlags::NONE;
BasicExecute();
}
void ModulWindow::BasicStepOver()
{
m_aStatus.nBasicFlags = BasicDebugFlags::StepInto | BasicDebugFlags::StepOver;
BasicExecute();
}
void ModulWindow::BasicStepInto()
{
m_aStatus.nBasicFlags = BasicDebugFlags::StepInto;
BasicExecute();
}
void ModulWindow::BasicStepOut()
{
m_aStatus.nBasicFlags = BasicDebugFlags::StepOut;
BasicExecute();
}
void ModulWindow::BasicStop()
{
StarBASIC::Stop();
m_aStatus.bIsRunning = false;
}
void ModulWindow::LoadBasic()
{
sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
FileDialogFlags::NONE, this->GetFrameWeld());
aDlg.SetContext(sfx2::FileDialogHelper::BasicImportSource);
Reference<XFilePicker3> xFP = aDlg.GetFilePicker();
xFP->appendFilter( u"BASIC"_ustr , u"*.bas"_ustr );
xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All );
xFP->setCurrentFilter( u"BASIC"_ustr );
if( aDlg.Execute() != ERRCODE_NONE )
return;
Sequence< OUString > aPaths = xFP->getSelectedFiles();
SfxMedium aMedium( aPaths[0], StreamMode::READ | StreamMode::SHARE_DENYWRITE | StreamMode::NOCREATE );
SvStream* pStream = aMedium.GetInStream();
if ( pStream )
{
AssertValidEditEngine();
sal_uInt32 nLines = CalcLineCount( *pStream );
// nLines*4: ReadText/Formatting/Highlighting/Formatting
GetEditorWindow().CreateProgress( IDEResId(RID_STR_GENERATESOURCE), nLines*4 );
GetEditEngine()->SetUpdateMode( false );
// tdf#139196 - import macros using either default or utf-8 text encoding
pStream->StartReadingUnicodeText(RTL_TEXTENCODING_UTF8);
if (pStream->Tell() == 3)
pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8);
GetEditView()->Read( *pStream );
GetEditEngine()->SetUpdateMode( true );
GetEditorWindow().PaintImmediately();
GetEditorWindow().ForceSyntaxTimeout();
GetEditorWindow().DestroyProgress();
ErrCodeMsg nError = aMedium.GetErrorIgnoreWarning();
if ( nError )
ErrorHandler::HandleError( nError );
}
else
{
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTREAD)));
xBox->run();
}
}
void ModulWindow::SaveBasicSource()
{
sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION,
FileDialogFlags::NONE, this->GetFrameWeld());
aDlg.SetContext(sfx2::FileDialogHelper::BasicExportSource);
const Reference<XFilePicker3>& xFP = aDlg.GetFilePicker();
xFP.queryThrow<XFilePickerControlAccess>()->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, Any(true));
xFP->appendFilter( u"BASIC"_ustr, u"*.bas"_ustr );
xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All );
xFP->setCurrentFilter( u"BASIC"_ustr );
if( aDlg.Execute() != ERRCODE_NONE )
return;
Sequence< OUString > aPaths = xFP->getSelectedFiles();
SfxMedium aMedium( aPaths[0], StreamMode::WRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC );
SvStream* pStream = aMedium.GetOutStream();
if ( pStream )
{
EnterWait();
AssertValidEditEngine();
// tdf#139196 - export macros using utf-8 including BOM
pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8);
pStream->WriteUChar(0xEF).WriteUChar(0xBB).WriteUChar(0xBF);
GetEditEngine()->Write( *pStream );
aMedium.Commit();
LeaveWait();
ErrCodeMsg nError = aMedium.GetErrorIgnoreWarning();
if ( nError )
ErrorHandler::HandleError( nError );
}
else
{
std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(GetFrameWeld(),
VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTWRITE)));
xErrorBox->run();
}
}
void ModulWindow::ImportDialog()
{
const ScriptDocument& rDocument = GetDocument();
OUString aLibName = GetLibName();
implImportDialog(GetFrameWeld(), rDocument, aLibName);
}
void ModulWindow::ToggleBreakPoint( sal_uInt16 nLine )
{
DBG_ASSERT( XModule().is(), "No Module!" );
if ( !XModule().is() )
return;
CheckCompileBasic();
if ( m_aStatus.bError )
{
return;
}
BreakPoint* pBrk = GetBreakPoints().FindBreakPoint( nLine );
if ( pBrk ) // remove
{
m_xModule->ClearBP( nLine );
GetBreakPoints().remove( pBrk );
}
else // create one
{
if ( m_xModule->SetBP( nLine ))
{
GetBreakPoints().InsertSorted( BreakPoint( nLine ) );
if ( StarBASIC::IsRunning() )
{
for (sal_uInt32 nMethod = 0; nMethod < m_xModule->GetMethods()->Count(); nMethod++)
{
SbMethod* pMethod
= static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMethod));
assert(pMethod && "Method not found! (NULL)");
pMethod->SetDebugFlags( pMethod->GetDebugFlags() | BasicDebugFlags::Break );
}
}
}
}
}
void ModulWindow::UpdateBreakPoint( const BreakPoint& rBrk )
{
DBG_ASSERT( XModule().is(), "No Module!" );
if ( XModule().is() )
{
CheckCompileBasic();
if ( rBrk.bEnabled )
m_xModule->SetBP( rBrk.nLine );
else
m_xModule->ClearBP( rBrk.nLine );
}
}
void ModulWindow::BasicToggleBreakPoint()
{
AssertValidEditEngine();
TextSelection aSel = GetEditView()->GetSelection();
aSel.GetStart().GetPara()++; // Basic lines start at 1!
aSel.GetEnd().GetPara()++;
for ( sal_uInt32 nLine = aSel.GetStart().GetPara(); nLine <= aSel.GetEnd().GetPara(); ++nLine )
{
ToggleBreakPoint( nLine );
}
m_aXEditorWindow->GetBrkWindow().Invalidate();
}
void ModulWindow::BasicToggleBreakPointEnabled()
{
AssertValidEditEngine();
TextView* pView = GetEditView();
if ( !pView )
return;
TextSelection aSel = pView->GetSelection();
BreakPointList& rList = GetBreakPoints();
for ( sal_uInt32 nLine = ++aSel.GetStart().GetPara(), nEnd = ++aSel.GetEnd().GetPara(); nLine <= nEnd; ++nLine )
{
BreakPoint* pBrk = rList.FindBreakPoint( nLine );
if ( pBrk )
{
pBrk->bEnabled = !pBrk->bEnabled;
UpdateBreakPoint( *pBrk );
}
}
GetBreakPointWindow().Invalidate();
}
void ModulWindow::ManageBreakPoints()
{
BreakPointWindow& rBrkWin = GetBreakPointWindow();
BreakPointDialog aBrkDlg(rBrkWin.GetFrameWeld(), GetBreakPoints());
aBrkDlg.run();
rBrkWin.Invalidate();
}
void ModulWindow::BasicErrorHdl( StarBASIC const * pBasic )
{
GetShell()->GetViewFrame().ToTop();
// Return value: BOOL
// FALSE: cancel
// TRUE: go on...
sal_uInt16 nErrorLine = StarBASIC::GetLine() - 1;
sal_uInt16 nErrCol1 = StarBASIC::GetCol1();
sal_uInt16 nErrCol2 = StarBASIC::GetCol2();
if ( nErrCol2 != 0xFFFF )
nErrCol2++;
AssertValidEditEngine();
GetEditView()->SetSelection( TextSelection( TextPaM( nErrorLine, nErrCol1 ), TextPaM( nErrorLine, nErrCol2 ) ) );
// if other basic, the IDE should try to display the correct module
bool const bMarkError = pBasic == GetBasic();
if ( bMarkError )
m_aXEditorWindow->GetBrkWindow().SetMarkerPos(nErrorLine, true);
// #i47002#
Reference< awt::XWindow > xWindow = VCLUnoHelper::GetInterface( this );
// tdf#118572 make a currently running dialog, regardless of what its modal
// to, insensitive to user input until after this error dialog goes away.
TopLevelWindowLocker aBusy;
aBusy.incBusy(nullptr);
ErrorHandler::HandleError(StarBASIC::GetErrorCode(), GetFrameWeld());
aBusy.decBusy();
// #i47002#
VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
if ( !pWindow )
return;
if ( bMarkError )
m_aXEditorWindow->GetBrkWindow().SetNoMarker();
return;
}
BasicDebugFlags ModulWindow::BasicBreakHdl()
{
// Return value: sal_uInt16 => see SB-Debug-Flags
sal_uInt16 nErrorLine = StarBASIC::GetLine();
BreakPoint* pBrk = GetBreakPoints().FindBreakPoint( nErrorLine );
if ( pBrk )
{
pBrk->nHitCount++;
if ( pBrk->nHitCount <= pBrk->nStopAfter && GetBasic()->IsBreak() )
return m_aStatus.nBasicFlags; // go on...
}
nErrorLine--; // EditEngine starts at 0, Basic at 1
AssertValidEditEngine();
GetEditView()->SetSelection( TextSelection( TextPaM( nErrorLine, 0 ), TextPaM( nErrorLine, 0 ) ) );
m_aXEditorWindow->GetBrkWindow().SetMarkerPos( nErrorLine );
m_rLayout.UpdateDebug(false);
m_aStatus.bIsInReschedule = true;
m_aStatus.bIsRunning = true;
AddStatus( BASWIN_INRESCHEDULE );
InvalidateDebuggerSlots();
while( m_aStatus.bIsRunning && !Application::IsQuit())
Application::Yield();
m_aStatus.bIsInReschedule = false;
m_aXEditorWindow->GetBrkWindow().SetNoMarker();
ClearStatus( BASWIN_INRESCHEDULE );
return m_aStatus.nBasicFlags;
}
void ModulWindow::BasicAddWatch()
{
AssertValidEditEngine();
bool bAdd = true;
if ( !GetEditView()->HasSelection() )
{
// tdf#57307 - expand selection to include connector punctuations
TextSelection aSel;
OUString aWord = GetEditEngine()->GetWord( GetEditView()->GetSelection().GetEnd(), &aSel.GetStart(), &aSel.GetEnd() );
if ( !aWord.isEmpty() )
GetEditView()->SetSelection( aSel );
else
bAdd = false;
}
if ( bAdd )
{
TextSelection aSel = GetEditView()->GetSelection();
if ( aSel.GetStart().GetPara() == aSel.GetEnd().GetPara() ) // single line selection
m_rLayout.BasicAddWatch(GetEditView()->GetSelected());
}
}
void ModulWindow::EditMacro( const OUString& rMacroName )
{
DBG_ASSERT( XModule().is(), "No Module!" );
if ( !XModule().is() )
return;
CheckCompileBasic();
if ( m_aStatus.bError )
return;
sal_uInt16 nStart, nEnd;
SbMethod* pMethod = static_cast<SbMethod*>(m_xModule->Find( rMacroName, SbxClassType::Method ));
if ( !pMethod )
return;
pMethod->GetLineRange( nStart, nEnd );
if ( nStart )
{
nStart--;
nEnd--;
}
TextSelection aSel( TextPaM( nStart, 0 ), TextPaM( nStart, 0 ) );
AssertValidEditEngine();
TextView * pView = GetEditView();
// scroll if applicable so that first line is at the top
tools::Long nVisHeight = GetOutputSizePixel().Height();
if ( pView->GetTextEngine()->GetTextHeight() > nVisHeight )
{
tools::Long nMaxY = pView->GetTextEngine()->GetTextHeight() - nVisHeight;
tools::Long nOldStartY = pView->GetStartDocPos().Y();
tools::Long nNewStartY = static_cast<tools::Long>(nStart) * pView->GetTextEngine()->GetCharHeight();
nNewStartY = std::min( nNewStartY, nMaxY );
pView->Scroll( 0, -(nNewStartY-nOldStartY) );
pView->ShowCursor( false );
GetEditVScrollBar().SetThumbPos( pView->GetStartDocPos().Y() );
}
pView->SetSelection( aSel );
pView->ShowCursor();
pView->GetWindow()->GrabFocus();
}
void ModulWindow::StoreData()
{
// StoreData is called when the BasicManager is destroyed or
// this window is closed.
// => interrupts undesired!
GetEditorWindow().SetSourceInBasic();
}
bool ModulWindow::AllowUndo()
{
return GetEditorWindow().CanModify();
}
void ModulWindow::UpdateData()
{
DBG_ASSERT( XModule().is(), "No Module!" );
// UpdateData is called when the source has changed from outside
// => interrupts undesired!
if ( !XModule().is() )
return;
SetModule( m_xModule->GetSource32() );
if ( GetEditView() )
{
TextSelection aSel = GetEditView()->GetSelection();
setTextEngineText(*GetEditEngine(), m_xModule->GetSource32());
GetEditView()->SetSelection( aSel );
GetEditEngine()->SetModified( false );
MarkDocumentModified( GetDocument() );
}
}
sal_Int32 ModulWindow::countPages( Printer* pPrinter )
{
return FormatAndPrint( pPrinter, -1 );
}
void ModulWindow::printPage( sal_Int32 nPage, Printer* pPrinter )
{
FormatAndPrint( pPrinter, nPage );
}
/* implementation note: this is totally inefficient for the XRenderable interface
usage since the whole "document" will be format for every page. Should this ever
become a problem we should
- format only once for every new printer
- keep an index list for each page which is the starting paragraph
*/
sal_Int32 ModulWindow::FormatAndPrint( Printer* pPrinter, sal_Int32 nPrintPage )
{
AssertValidEditEngine();
MapMode eOldMapMode( pPrinter->GetMapMode() );
vcl::Font aOldFont( pPrinter->GetFont() );
vcl::Font aFont( GetEditEngine()->GetFont() );
aFont.SetAlignment( ALIGN_BOTTOM );
aFont.SetTransparent( true );
aFont.SetFontSize( Size( 0, 360 ) );
pPrinter->SetFont( aFont );
pPrinter->SetMapMode(MapMode(MapUnit::Map100thMM));
OUString aTitle( CreateQualifiedName() );
sal_Int32 nLineHeight = pPrinter->GetTextHeight();
if(nLineHeight == 0)
{
nLineHeight = 1;
}
Size aPaperSz = pPrinter->GetOutputSize();
aPaperSz.AdjustWidth( -(Print::nLeftMargin + Print::nRightMargin) );
aPaperSz.AdjustHeight( -(Print::nTopMargin + Print::nBottomMargin) );
// nLinepPage is not correct if there's a line break
sal_Int32 nLinespPage = aPaperSz.Height()/nLineHeight;
tools::Long nXTextWidth = pPrinter->approximate_digit_width();
sal_Int32 nCharspLine = aPaperSz.Width() / std::max<tools::Long>(nXTextWidth, 1);
const sal_uInt32 nParas = GetEditEngine()->GetParagraphCount();
sal_Int32 nPages = nParas/nLinespPage+1;
sal_Int32 nCurPage = 1;
lcl_PrintHeader( pPrinter, nPages, nCurPage, aTitle, nPrintPage == 0 );
Point aPos( Print::nLeftMargin, Print::nTopMargin );
for ( sal_uInt32 nPara = 0; nPara < nParas; ++nPara )
{
OUString aLine( GetEditEngine()->GetText( nPara ) );
lcl_ConvertTabsToSpaces( aLine );
sal_Int32 nLines = aLine.getLength()/nCharspLine+1;
for (sal_Int32 nLine = 0; nLine < nLines; ++nLine)
{
sal_Int32 nBeginIndex = nLine*nCharspLine;
sal_Int32 nCopyCount = std::min<sal_Int32>(nCharspLine, aLine.getLength()-nBeginIndex);
OUString aTmpLine = aLine.copy(nBeginIndex, nCopyCount);
aPos.AdjustY(nLineHeight );
if ( aPos.Y() > ( aPaperSz.Height() + Print::nTopMargin ) )
{
nCurPage++;
lcl_PrintHeader( pPrinter, nPages, nCurPage, aTitle, nCurPage-1 == nPrintPage );
aPos = Point(Print::nLeftMargin, Print::nTopMargin + nLineHeight);
}
if( nCurPage-1 == nPrintPage )
pPrinter->DrawText( aPos, aTmpLine );
}
aPos.AdjustY(10 ); // nParaSpace
}
pPrinter->SetFont( aOldFont );
pPrinter->SetMapMode( eOldMapMode );
return nCurPage;
}
void ModulWindow::ExecuteCommand (SfxRequest& rReq)
{
AssertValidEditEngine();
switch (rReq.GetSlot())
{
case SID_DELETE:
{
if (!IsReadOnly())
{
KeyEvent aFakeDelete(0, KEY_DELETE);
(void)GetEditView()->KeyInput(aFakeDelete);
}
break;
}
case SID_SELECTALL:
{
TextSelection aSel( TextPaM( 0, 0 ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) );
TextView * pView = GetEditView();
pView->SetSelection( aSel );
pView->GetWindow()->GrabFocus();
break;
}
case SID_BASICRUN:
{
BasicRun();
}
break;
case SID_BASICCOMPILE:
{
CompileBasic();
}
break;
case SID_BASICSTEPOVER:
{
BasicStepOver();
}
break;
case SID_BASICSTEPINTO:
{
BasicStepInto();
}
break;
case SID_BASICSTEPOUT:
{
BasicStepOut();
}
break;
case SID_BASICLOAD:
{
LoadBasic();
}
break;
case SID_BASICSAVEAS:
{
SaveBasicSource();
}
break;
case SID_IMPORT_DIALOG:
{
ImportDialog();
}
break;
case SID_BASICIDE_MATCHGROUP:
{
GetEditView()->MatchGroup();
}
break;
case SID_BASICIDE_TOGGLEBRKPNT:
{
BasicToggleBreakPoint();
}
break;
case SID_BASICIDE_MANAGEBRKPNTS:
{
ManageBreakPoints();
}
break;
case SID_BASICIDE_TOGGLEBRKPNTENABLED:
{
BasicToggleBreakPointEnabled();
}
break;
case SID_BASICIDE_ADDWATCH:
{
BasicAddWatch();
}
break;
case SID_BASICIDE_REMOVEWATCH:
{
m_rLayout.BasicRemoveWatch();
}
break;
case SID_CUT:
{
if ( !IsReadOnly() )
{
GetEditView()->Cut();
if (SfxBindings* pBindings = GetBindingsPtr())
pBindings->Invalidate( SID_DOC_MODIFIED );
}
}
break;
case SID_COPY:
{
GetEditView()->Copy();
}
break;
case SID_PASTE:
{
if ( !IsReadOnly() )
{
GetEditView()->Paste();
if (SfxBindings* pBindings = GetBindingsPtr())
pBindings->Invalidate( SID_DOC_MODIFIED );
}
}
break;
case SID_BASICIDE_BRKPNTSCHANGED:
{
GetBreakPointWindow().Invalidate();
}
break;
case SID_SHOWLINES:
{
const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(rReq.GetSlot());
bool bLineNumbers = pItem && pItem->GetValue();
m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers);
std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
officecfg::Office::BasicIDE::EditorSettings::LineNumbering::set(bLineNumbers, batch);
batch->commit();
}
break;
case SID_BASICIDE_DELETECURRENT:
{
if (QueryDelModule(m_aName, GetFrameWeld()))
{
// tdf#134551 don't delete the window if last module is removed until this block
// is complete
VclPtr<ModulWindow> xKeepRef(this);
if (m_aDocument.removeModule(m_aLibName, m_aName))
MarkDocumentModified(m_aDocument);
}
}
break;
case FID_SEARCH_OFF:
GrabFocus();
break;
case SID_GOTOLINE:
{
sal_uInt32 nCurLine = GetEditView()->GetSelection().GetStart().GetPara() + 1;
sal_uInt32 nLineCount = GetEditEngine()->GetParagraphCount();
GotoLineDialog aGotoDlg(GetFrameWeld(), nCurLine, nLineCount);
if (aGotoDlg.run() == RET_OK)
{
if (sal_Int32 const nLine = aGotoDlg.GetLineNumber())
{
TextSelection const aSel(TextPaM(nLine - 1, 0), TextPaM(nLine - 1, 0));
GrabFocus();
GetEditView()->SetSelection(aSel);
}
}
break;
}
}
}
void ModulWindow::ExecuteGlobal (SfxRequest& rReq)
{
switch (rReq.GetSlot())
{
case SID_SIGNATURE:
{
DocumentSignature aSignature(m_aDocument);
if (aSignature.supportsSignatures())
{
aSignature.signScriptingContent(rReq.GetFrameWeld());
if (SfxBindings* pBindings = GetBindingsPtr())
pBindings->Invalidate(SID_SIGNATURE);
}
}
break;
case SID_BASICIDE_STAT_POS:
{
GetDispatcher()->Execute(SID_GOTOLINE);
}
break;
case SID_TOGGLE_COMMENT:
{
GetEditView()->ToggleComment();
}
break;
}
}
void ModulWindow::GetState( SfxItemSet &rSet )
{
SfxWhichIter aIter(rSet);
for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich() )
{
switch ( nWh )
{
case SID_CUT:
{
if ( !GetEditView() || !GetEditView()->HasSelection() )
rSet.DisableItem( nWh );
if ( IsReadOnly() )
rSet.DisableItem( nWh );
}
break;
case SID_COPY:
{
if ( !GetEditView() || !GetEditView()->HasSelection() )
rSet.DisableItem( nWh );
}
break;
case SID_PASTE:
{
if ( !IsPasteAllowed() )
rSet.DisableItem( nWh );
if ( IsReadOnly() )
rSet.DisableItem( nWh );
}
break;
case SID_BASICIDE_STAT_POS:
{
TextView* pView = GetEditView();
if ( pView )
{
TextSelection aSel = pView->GetSelection();
OUString aPos = IDEResId( RID_STR_LINE ) +
" " +
OUString::number(aSel.GetEnd().GetPara()+1) +
", " +
IDEResId( RID_STR_COLUMN ) +
" " +
OUString::number(aSel.GetEnd().GetIndex()+1);
SfxStringItem aItem( SID_BASICIDE_STAT_POS, aPos );
rSet.Put( aItem );
}
}
break;
case SID_BASICIDE_STAT_TITLE:
{
// search for current procedure name (Sub or Function)
TextView* pView = GetEditView();
if ( pView )
{
OUString sProcName;
TextSelection aSel = pView->GetSelection();
sal_uInt32 i = aSel.GetStart().GetPara();
do
{
OUString aCurrLine = GetEditEngine()->GetText( i );
OUString sProcType;
if (GetEditorWindow().GetProcedureName(aCurrLine, sProcType, sProcName))
break;
} while (i--);
OUString aTitle = CreateQualifiedName();
if (!sProcName.isEmpty())
aTitle += "." + sProcName;
if (IsReadOnly())
aTitle += " (" + IDEResId(RID_STR_READONLY) + ")";
SfxStringItem aTitleItem( SID_BASICIDE_STAT_TITLE, aTitle );
rSet.Put( aTitleItem );
}
}
break;
case SID_ATTR_INSERT:
{
TextView* pView = GetEditView();
if ( pView )
{
SfxBoolItem aItem( SID_ATTR_INSERT, pView->IsInsertMode() );
rSet.Put( aItem );
}
}
break;
case SID_SHOWLINES:
{
bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get();
rSet.Put(SfxBoolItem(nWh, bLineNumbers));
break;
}
case SID_SELECTALL:
{
if ( !GetEditView() )
rSet.DisableItem( nWh );
}
break;
}
}
}
void ModulWindow::DoScroll( Scrollable* pCurScrollBar )
{
if ( ( pCurScrollBar == GetHScrollBar() ) && GetEditView() )
{
// don't scroll with the value but rather use the Thumb-Pos for the VisArea:
tools::Long nDiff = GetEditView()->GetStartDocPos().X() - pCurScrollBar->GetThumbPos();
GetEditView()->Scroll( nDiff, 0 );
GetEditView()->ShowCursor( false );
pCurScrollBar->SetThumbPos( GetEditView()->GetStartDocPos().X() );
}
}
bool ModulWindow::IsModified()
{
return GetEditEngine() && GetEditEngine()->IsModified();
}
OUString ModulWindow::GetSbModuleName()
{
OUString aModuleName;
if ( XModule().is() )
aModuleName = m_xModule->GetName();
return aModuleName;
}
OUString ModulWindow::GetTitle()
{
return GetSbModuleName();
}
void ModulWindow::ShowCursor( bool bOn )
{
if ( GetEditEngine() )
{
TextView* pView = GetEditEngine()->GetActiveView();
if ( pView )
{
if ( bOn )
pView->ShowCursor();
else
pView->HideCursor();
}
}
}
void ModulWindow::AssertValidEditEngine()
{
if ( !GetEditEngine() )
GetEditorWindow().CreateEditEngine();
}
void ModulWindow::Activating ()
{
bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get();
m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers);
Show();
}
void ModulWindow::Deactivating()
{
Hide();
}
sal_uInt16 ModulWindow::StartSearchAndReplace( const SvxSearchItem& rSearchItem, bool bFromStart )
{
if (IsSuspended())
return 0;
// one could also relinquish syntaxhighlighting/formatting instead of the stupid replace-everything...
AssertValidEditEngine();
TextView* pView = GetEditView();
TextSelection aSel;
if ( bFromStart )
{
aSel = pView->GetSelection();
if ( !rSearchItem.GetBackward() )
pView->SetSelection( TextSelection() );
else
pView->SetSelection( TextSelection( TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) );
}
bool const bForward = !rSearchItem.GetBackward();
sal_uInt16 nFound = 0;
if ( ( rSearchItem.GetCommand() == SvxSearchCmd::FIND ) ||
( rSearchItem.GetCommand() == SvxSearchCmd::FIND_ALL ) )
{
nFound = pView->Search( rSearchItem.GetSearchOptions() , bForward ) ? 1 : 0;
}
else if ( ( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE ) ||
( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE_ALL ) )
{
if ( !IsReadOnly() )
{
bool const bAll = rSearchItem.GetCommand() == SvxSearchCmd::REPLACE_ALL;
nFound = pView->Replace( rSearchItem.GetSearchOptions() , bAll , bForward );
}
}
if ( bFromStart && !nFound )
pView->SetSelection( aSel );
return nFound;
}
SfxUndoManager* ModulWindow::GetUndoManager()
{
if ( GetEditEngine() )
return &GetEditEngine()->GetUndoManager();
return nullptr;
}
SearchOptionFlags ModulWindow::GetSearchOptions()
{
SearchOptionFlags nOptions = SearchOptionFlags::SEARCH |
SearchOptionFlags::WHOLE_WORDS |
SearchOptionFlags::BACKWARDS |
SearchOptionFlags::REG_EXP |
SearchOptionFlags::EXACT |
SearchOptionFlags::SELECTION |
SearchOptionFlags::SIMILARITY;
if ( !IsReadOnly() )
{
nOptions |= SearchOptionFlags::REPLACE;
nOptions |= SearchOptionFlags::REPLACE_ALL;
}
return nOptions;
}
void ModulWindow::BasicStarted()
{
if ( !XModule().is() )
return;
m_aStatus.bIsRunning = true;
BreakPointList& rList = GetBreakPoints();
if ( rList.size() )
{
rList.ResetHitCount();
rList.SetBreakPointsInBasic( m_xModule.get() );
for (sal_uInt32 nMethod = 0; nMethod < m_xModule->GetMethods()->Count(); nMethod++)
{
SbMethod* pMethod = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMethod));
assert(pMethod && "Method not found! (NULL)");
pMethod->SetDebugFlags( pMethod->GetDebugFlags() | BasicDebugFlags::Break );
}
}
}
void ModulWindow::BasicStopped()
{
m_aStatus.bIsRunning = false;
GetBreakPointWindow().SetNoMarker();
}
EntryDescriptor ModulWindow::CreateEntryDescriptor()
{
ScriptDocument aDocument( GetDocument() );
OUString aLibName( GetLibName() );
LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName );
OUString aModName( GetName() );
OUString aLibSubName;
if( m_xBasic.is() && aDocument.isInVBAMode() && XModule().is() )
{
switch( m_xModule->GetModuleType() )
{
case script::ModuleType::DOCUMENT:
{
aLibSubName = IDEResId( RID_STR_DOCUMENT_OBJECTS );
uno::Reference< container::XNameContainer > xLib = aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName );
if( xLib.is() )
{
OUString sObjName;
ModuleInfoHelper::getObjectName( xLib, aModName, sObjName );
if( !sObjName.isEmpty() )
{
aModName += " (" + sObjName + ")";
}
}
break;
}
case script::ModuleType::FORM:
aLibSubName = IDEResId( RID_STR_USERFORMS );
break;
case script::ModuleType::NORMAL:
aLibSubName = IDEResId( RID_STR_NORMAL_MODULES );
break;
case script::ModuleType::CLASS:
aLibSubName = IDEResId( RID_STR_CLASS_MODULES );
break;
}
}
return EntryDescriptor( std::move(aDocument), eLocation, aLibName, aLibSubName, aModName, OBJ_TYPE_MODULE );
}
void ModulWindow::SetReadOnly (bool b)
{
if ( GetEditView() )
GetEditView()->SetReadOnly( b );
}
bool ModulWindow::IsReadOnly()
{
return GetEditView() && GetEditView()->IsReadOnly();
}
bool ModulWindow::IsPasteAllowed()
{
bool bPaste = false;
// get clipboard
Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
if ( xClipboard.is() )
{
Reference< datatransfer::XTransferable > xTransf = xClipboard->getContents();
if ( xTransf.is() )
{
datatransfer::DataFlavor aFlavor;
SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
if ( xTransf->isDataFlavorSupported( aFlavor ) )
bPaste = true;
}
}
return bPaste;
}
void ModulWindow::OnNewDocument ()
{
bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get();
m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers);
}
OUString ModulWindow::GetHid () const
{
return HID_BASICIDE_MODULWINDOW;
}
SbxItemType ModulWindow::GetSbxType () const
{
return SBX_TYPE_MODULE;
}
bool ModulWindow::HasActiveEditor () const
{
return !IsSuspended();
}
void ModulWindow::UpdateModule ()
{
OUString const aModule = getTextEngineText(*GetEditEngine());
// update module in basic
assert(m_xModule.is());
// update module in module window
SetModule(aModule);
// update module in library
OSL_VERIFY(m_aDocument.updateModule(m_aLibName, m_aName, aModule));
GetEditEngine()->SetModified(false);
MarkDocumentModified(m_aDocument);
}
void ModulWindow::SetEditorColorScheme(const OUString& rColorScheme)
{
m_sWinColorScheme = rColorScheme;
EditorWindow& rEditWindow = GetEditorWindow();
Wallpaper aBackgroundColor(GetLayout().GetSyntaxBackgroundColor());
rEditWindow.SetBackground(aBackgroundColor);
rEditWindow.GetWindow(GetWindowType::Border)->SetBackground(aBackgroundColor);
rEditWindow.SetLineHighlightColor(GetShell()->GetColorConfig()->GetColorScheme(rColorScheme).m_aLineHighlightColor);
// The EditEngine is created only when the module is actually opened for the first time,
// therefore we need to check if it actually exists before updating its syntax highlighting
ExtTextEngine* pEditEngine = GetEditEngine();
if (pEditEngine)
rEditWindow.UpdateSyntaxHighlighting();
}
ModulWindowLayout::ModulWindowLayout (vcl::Window* pParent, ObjectCatalog& rObjectCatalog_) :
Layout(pParent),
pChild(nullptr),
aWatchWindow(VclPtr<WatchWindow>::Create(this)),
aStackWindow(VclPtr<StackWindow>::Create(this)),
rObjectCatalog(rObjectCatalog_)
{
// Get active color scheme from the registry
m_sColorSchemeId = GetShell()->GetColorConfig()->GetCurrentColorSchemeName();
aSyntaxColors.ApplyColorScheme(m_sColorSchemeId, true);
// Initialize the visibility of the Stack Window
bool bStackVisible = ::officecfg::Office::BasicIDE::EditorSettings::StackWindow::get();
if (!bStackVisible)
aStackWindow->Show(bStackVisible);
// Initialize the visibility of the Watched Expressions window
bool bWatchVisible = ::officecfg::Office::BasicIDE::EditorSettings::WatchWindow::get();
if (!bWatchVisible)
aWatchWindow->Show(bWatchVisible);
}
ModulWindowLayout::~ModulWindowLayout()
{
disposeOnce();
}
void ModulWindowLayout::dispose()
{
aWatchWindow.disposeAndClear();
aStackWindow.disposeAndClear();
pChild.clear();
Layout::dispose();
}
void ModulWindowLayout::UpdateDebug (bool bBasicStopped)
{
aWatchWindow->UpdateWatches(bBasicStopped);
aStackWindow->UpdateCalls();
}
void ModulWindowLayout::Paint (vcl::RenderContext& rRenderContext, tools::Rectangle const&)
{
rRenderContext.DrawText(Point(), IDEResId(RID_STR_NOMODULE));
}
void ModulWindowLayout::Activating (BaseWindow& rChild)
{
assert(dynamic_cast<ModulWindow*>(&rChild));
pChild = &static_cast<ModulWindow&>(rChild);
aWatchWindow->Show();
aStackWindow->Show();
rObjectCatalog.Show();
rObjectCatalog.SetLayoutWindow(this);
rObjectCatalog.UpdateEntries();
Layout::Activating(rChild);
aSyntaxColors.SetActiveEditor(&pChild->GetEditorWindow());
aSyntaxColors.SetActiveColorSchemeId(m_sColorSchemeId);
}
void ModulWindowLayout::Deactivating ()
{
aSyntaxColors.SetActiveEditor(nullptr);
Layout::Deactivating();
aWatchWindow->Hide();
aStackWindow->Hide();
rObjectCatalog.Hide();
pChild = nullptr;
}
void ModulWindowLayout::GetState (SfxItemSet &rSet, unsigned nWhich)
{
switch (nWhich)
{
case SID_SHOW_PROPERTYBROWSER:
rSet.Put(SfxVisibilityItem(nWhich, false));
break;
case SID_BASICIDE_CHOOSEMACRO:
rSet.Put(SfxVisibilityItem(nWhich, true));
break;
}
}
void ModulWindowLayout::BasicAddWatch (OUString const& rWatchStr)
{
aWatchWindow->AddWatch(rWatchStr);
}
void ModulWindowLayout::BasicRemoveWatch ()
{
aWatchWindow->RemoveSelectedWatch();
}
void ModulWindowLayout::ShowWatchWindow(bool bVisible)
{
aWatchWindow->Show(bVisible);
ArrangeWindows();
}
void ModulWindowLayout::ShowStackWindow(bool bVisible)
{
aStackWindow->Show(bVisible);
ArrangeWindows();
}
void ModulWindowLayout::OnFirstSize (tools::Long const nWidth, tools::Long const nHeight)
{
AddToLeft(&rObjectCatalog, Size(nWidth * 0.20, nHeight * 0.75));
AddToBottom(aWatchWindow.get(), Size(nWidth * 0.67, nHeight * 0.25));
AddToBottom(aStackWindow.get(), Size(nWidth * 0.33, nHeight * 0.25));
}
// Applies the color scheme to the current window and updates color definitions;
// note that other ModulWindow instances are not affected by calling this method
void ModulWindowLayout::ApplyColorSchemeToCurrentWindow(const OUString& rSchemeId)
{
// Apply new color scheme to the UI
m_sColorSchemeId = rSchemeId;
aSyntaxColors.ApplyColorScheme(m_sColorSchemeId, false);
}
ModulWindowLayout::SyntaxColors::SyntaxColors ()
: pEditor(nullptr)
{
aConfig.AddListener(this);
}
ModulWindowLayout::SyntaxColors::~SyntaxColors ()
{
aConfig.RemoveListener(this);
}
// virtual
void ModulWindowLayout::SyntaxColors::ConfigurationChanged (utl::ConfigurationBroadcaster*, ConfigurationHints)
{
// The color scheme only needs to be applied when configuration changed if the "default" color
// scheme (based on Application Colors) is being used
if (m_sActiveSchemeId == DEFAULT_SCHEME)
ApplyColorScheme(DEFAULT_SCHEME, false);
}
// Applies an entire new color scheme; when bFirst is true, then the checks to see if the color scheme
// has changed are ignored to make sure the color scheme is applied
void ModulWindowLayout::SyntaxColors::ApplyColorScheme(OUString aSchemeId, bool bFirst)
{
const TokenType vTokenTypes[] =
{
TokenType::Unknown,
TokenType::Identifier,
TokenType::Whitespace,
TokenType::Number,
TokenType::String,
TokenType::EOL,
TokenType::Comment,
TokenType::Error,
TokenType::Operator,
TokenType::Keywords
};
m_sActiveSchemeId = aSchemeId;
ColorScheme aColorScheme = GetShell()->GetColorConfig()->GetColorScheme(aSchemeId);
Color aFontColor = aColorScheme.m_aGenericFontColor;
m_aFontColor = aFontColor;
Color aDocColor = aColorScheme.m_aBackgroundColor;
m_aBackgroundColor = aDocColor;
if (!bFirst && pEditor)
{
pEditor->ChangeFontColor(aFontColor);
pEditor->SetBackground(Wallpaper(aDocColor));
pEditor->SetLineHighlightColor(aColorScheme.m_aLineHighlightColor);
pEditor->Invalidate();
}
for (const auto& aToken: vTokenTypes)
{
// Retrieves the new color to be set from the color scheme
Color aNewColor;
switch (aToken)
{
case TokenType::EOL:
case TokenType::Whitespace:
case TokenType::Unknown:
aNewColor = aColorScheme.m_aGenericFontColor;
break;
case TokenType::Identifier:
aNewColor = aColorScheme.m_aIdentifierColor;
break;
case TokenType::Number:
aNewColor = aColorScheme.m_aNumberColor;
break;
case TokenType::String:
aNewColor = aColorScheme.m_aStringColor;
break;
case TokenType::Comment:
aNewColor = aColorScheme.m_aCommentColor;
break;
case TokenType::Error:
aNewColor = aColorScheme.m_aErrorColor;
break;
case TokenType::Operator:
aNewColor = aColorScheme.m_aOperatorColor;
break;
case TokenType::Keywords:
aNewColor = aColorScheme.m_aKeywordColor;
break;
default:
SAL_WARN("basctl.basicide", "Unexpected token type for color scheme");
aNewColor = aColorScheme.m_aGenericFontColor;
}
Color& rCurrentColor = aColors[aToken];
rCurrentColor = aNewColor;
}
// This check is needed because the EditEngine will only exist in the EditorWindow when the
// module is actually opened
if (!bFirst && pEditor)
pEditor->UpdateSyntaxHighlighting();
}
} // namespace basctl
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */