8a83a62410
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>
1691 lines
50 KiB
C++
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: */
|