1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
23 #include <string_view>
27 #include <strings.hrc>
28 #include <bitmaps.hlst>
30 #include "baside2.hxx"
32 #include <basidesh.hxx>
34 #include <iderdll.hxx>
36 #include <basic/sbmeth.hxx>
37 #include <basic/sbuno.hxx>
38 #include <com/sun/star/beans/XMultiPropertySet.hpp>
39 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
40 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
41 #include <com/sun/star/script/XLibraryContainer2.hpp>
42 #include <comphelper/string.hxx>
43 #include <comphelper/diagnose_ex.hxx>
44 #include <o3tl/string_view.hxx>
45 #include <officecfg/Office/Common.hxx>
46 #include <sfx2/dispatch.hxx>
47 #include <sfx2/progress.hxx>
48 #include <sfx2/viewfrm.hxx>
49 #include <tools/debug.hxx>
51 #include <vcl/image.hxx>
52 #include <vcl/weld.hxx>
53 #include <vcl/weldutils.hxx>
54 #include <svl/urihelper.hxx>
55 #include <svx/svxids.hrc>
56 #include <vcl/commandevent.hxx>
57 #include <vcl/xtextedt.hxx>
58 #include <vcl/textview.hxx>
59 #include <vcl/txtattr.hxx>
60 #include <vcl/settings.hxx>
61 #include <vcl/ptrstyle.hxx>
62 #include <vcl/event.hxx>
63 #include <vcl/svapp.hxx>
64 #include <vcl/taskpanelist.hxx>
65 #include <vcl/help.hxx>
66 #include <cppuhelper/implbase.hxx>
68 #include <com/sun/star/reflection/theCoreReflection.hpp>
69 #include <unotools/charclass.hxx>
70 #include "textwindowpeer.hxx"
71 #include "uiobject.hxx"
72 #include <basegfx/utils/zoomtools.hxx>
73 #include <svl/itemset.hxx>
74 #include <BasicColorConfig.hxx>
79 using namespace ::com::sun::star
;
80 using namespace ::com::sun::star::uno
;
85 sal_uInt16
const NoMarker
= 0xFFFF;
86 tools::Long
const nBasePad
= 2;
87 tools::Long
const nCursorPad
= 5;
89 tools::Long nVirtToolBoxHeight
; // inited in WatchWindow, used in Stackwindow
91 // Returns pBase converted to SbxVariable if valid and is not an SbxMethod.
92 SbxVariable
* IsSbxVariable (SbxBase
* pBase
)
94 if (SbxVariable
* pVar
= dynamic_cast<SbxVariable
*>(pBase
))
95 if (!dynamic_cast<SbxMethod
*>(pVar
))
100 Image
GetImage(const OUString
& rId
)
102 return Image(StockImage::Yes
, rId
);
105 int const nScrollLine
= 12;
106 int const nScrollPage
= 60;
107 int const DWBORDER
= 3;
109 std::u16string_view
const cSuffixes
= u
"%&!#@$";
115 * Helper functions to get/set text in TextEngine using
116 * the stream interface.
118 * get/setText() only supports tools Strings limited to 64K).
120 OUString
getTextEngineText (ExtTextEngine
& rEngine
)
122 SvMemoryStream aMemStream
;
123 aMemStream
.SetStreamCharSet( RTL_TEXTENCODING_UTF8
);
124 aMemStream
.SetLineDelimiter( LINEEND_LF
);
125 rEngine
.Write( aMemStream
);
126 std::size_t nSize
= aMemStream
.Tell();
127 OUString
aText( static_cast<const char*>(aMemStream
.GetData()),
128 nSize
, RTL_TEXTENCODING_UTF8
);
132 void setTextEngineText (ExtTextEngine
& rEngine
, std::u16string_view aStr
)
134 rEngine
.SetText(OUString());
135 OString aUTF8Str
= OUStringToOString( aStr
, RTL_TEXTENCODING_UTF8
);
136 SvMemoryStream
aMemStream( const_cast<char *>(aUTF8Str
.getStr()), aUTF8Str
.getLength(),
138 aMemStream
.SetStreamCharSet( RTL_TEXTENCODING_UTF8
);
139 aMemStream
.SetLineDelimiter( LINEEND_LF
);
140 rEngine
.Read(aMemStream
);
146 void lcl_DrawIDEWindowFrame(DockingWindow
const * pWin
, vcl::RenderContext
& rRenderContext
)
148 if (pWin
->IsFloatingMode())
151 Size
aSz(pWin
->GetOutputSizePixel());
152 const Color
aOldLineColor(rRenderContext
.GetLineColor());
153 rRenderContext
.SetLineColor(COL_WHITE
);
155 rRenderContext
.DrawLine(Point(0, 0), Point(aSz
.Width(), 0));
156 // Black line at bottom
157 rRenderContext
.SetLineColor(COL_BLACK
);
158 rRenderContext
.DrawLine(Point(0, aSz
.Height() - 1),
159 Point(aSz
.Width(), aSz
.Height() - 1));
160 rRenderContext
.SetLineColor(aOldLineColor
);
163 void lcl_SeparateNameAndIndex( const OUString
& rVName
, OUString
& rVar
, OUString
& rIndex
)
167 sal_Int32 nIndexStart
= rVar
.indexOf( '(' );
168 if ( nIndexStart
!= -1 )
170 sal_Int32 nIndexEnd
= rVar
.indexOf( ')', nIndexStart
);
173 rIndex
= rVar
.copy(nIndexStart
+ 1, nIndexEnd
- nIndexStart
- 1);
174 rVar
= rVar
.copy(0, nIndexStart
);
175 rVar
= comphelper::string::stripEnd(rVar
, ' ');
176 rIndex
= comphelper::string::strip(rIndex
, ' ');
180 if ( !rVar
.isEmpty() )
182 sal_uInt16 nLastChar
= rVar
.getLength()-1;
183 if ( cSuffixes
.find(rVar
[ nLastChar
] ) != std::u16string_view::npos
)
184 rVar
= rVar
.replaceAt( nLastChar
, 1, u
"" );
186 if ( !rIndex
.isEmpty() )
188 sal_uInt16 nLastChar
= rIndex
.getLength()-1;
189 if ( cSuffixes
.find(rIndex
[ nLastChar
] ) != std::u16string_view::npos
)
190 rIndex
= rIndex
.replaceAt( nLastChar
, 1, u
"" );
200 class EditorWindow::ChangesListener
:
201 public cppu::WeakImplHelper
< beans::XPropertiesChangeListener
>
204 explicit ChangesListener(EditorWindow
& editor
): editor_(editor
) {}
207 virtual ~ChangesListener() override
{}
209 virtual void SAL_CALL
disposing(lang::EventObject
const &) override
211 std::unique_lock
g(editor_
.mutex_
);
212 editor_
.notifier_
.clear();
215 virtual void SAL_CALL
propertiesChange(
216 Sequence
< beans::PropertyChangeEvent
> const &) override
219 editor_
.ImplSetFont();
222 EditorWindow
& editor_
;
225 class EditorWindow::ProgressInfo
: public SfxProgress
228 ProgressInfo (SfxObjectShell
* pObjSh
, OUString
const& rText
, sal_uInt32 nRange
) :
229 SfxProgress(pObjSh
, rText
, nRange
),
235 SetState(++nCurState
);
239 sal_uInt32 nCurState
;
242 EditorWindow::EditorWindow (vcl::Window
* pParent
, ModulWindow
* pModulWindow
) :
243 Window(pParent
, WB_BORDER
),
244 rModulWindow(*pModulWindow
),
246 m_nSetSourceInBasicId(nullptr),
247 aHighlighter(HighlighterLanguage::Basic
),
248 aSyntaxIdle( "basctl EditorWindow aSyntaxIdle" ),
249 bHighlighting(false),
250 bDoSyntaxHighlight(true),
251 bDelayHighlight(true),
252 m_nLastHighlightPara(0),
253 pCodeCompleteWnd(VclPtr
<CodeCompleteWindow
>::Create(this))
255 set_id(u
"EditorWindow"_ustr
);
256 const Wallpaper
aBackground(rModulWindow
.GetLayout().GetSyntaxBackgroundColor());
257 SetBackground(aBackground
);
258 GetWindow(GetWindowType::Border
)->SetBackground(aBackground
);
259 SetLineHighlightColor(GetShell()->GetColorConfig()->GetCurrentColorScheme().m_aLineHighlightColor
);
260 SetPointer( PointerStyle::Text
);
261 SetHelpId( HID_BASICIDE_EDITORWINDOW
);
263 listener_
= new ChangesListener(*this);
264 Reference
< beans::XMultiPropertySet
> n(
265 officecfg::Office::Common::Font::SourceViewFont::get(),
268 std::unique_lock
g(mutex_
);
272 // The zoom level applied to the editor window is the zoom slider value in the shell
273 nCurrentZoomLevel
= GetShell()->GetCurrentZoomSliderValue();
275 const Sequence
<OUString
> aPropertyNames
{u
"FontHeight"_ustr
, u
"FontName"_ustr
};
276 n
->addPropertiesChangeListener(aPropertyNames
, listener_
);
280 EditorWindow::~EditorWindow()
285 void EditorWindow::dispose()
287 if (m_nSetSourceInBasicId
)
289 Application::RemoveUserEvent(m_nSetSourceInBasicId
);
290 m_nSetSourceInBasicId
= nullptr;
293 Reference
< beans::XMultiPropertySet
> n
;
295 std::unique_lock
g(mutex_
);
299 n
->removePropertiesChangeListener(listener_
);
306 EndListening( *pEditEngine
);
307 pEditEngine
->RemoveView(pEditView
.get());
309 pCodeCompleteWnd
.disposeAndClear();
310 vcl::Window::dispose();
313 OUString
EditorWindow::GetWordAtCursor()
319 TextEngine
* pTextEngine
= pEditView
->GetTextEngine();
322 // check first, if the cursor is at a help URL
323 const TextSelection
& rSelection
= pEditView
->GetSelection();
324 const TextPaM
& rSelStart
= rSelection
.GetStart();
325 const TextPaM
& rSelEnd
= rSelection
.GetEnd();
326 OUString aText
= pTextEngine
->GetText( rSelEnd
.GetPara() );
327 CharClass
aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() );
328 sal_Int32 nSelStart
= rSelStart
.GetIndex();
329 sal_Int32 nSelEnd
= rSelEnd
.GetIndex();
330 sal_Int32 nLength
= aText
.getLength();
331 sal_Int32 nStart
= 0;
332 sal_Int32 nEnd
= nLength
;
333 while ( nStart
< nLength
)
335 OUString
aURL( URIHelper::FindFirstURLInText( aText
, nStart
, nEnd
, aClass
) );
336 INetURLObject
aURLObj( aURL
);
337 if ( aURLObj
.GetProtocol() == INetProtocol::VndSunStarHelp
338 && nSelStart
>= nStart
&& nSelStart
<= nEnd
&& nSelEnd
>= nStart
&& nSelEnd
<= nEnd
)
347 // Not the selected range, but at the CursorPosition,
348 // if a word is partially selected.
349 if ( aWord
.isEmpty() )
350 aWord
= pTextEngine
->GetWord( rSelEnd
);
352 // Can be empty when full word selected, as Cursor behind it
353 if ( aWord
.isEmpty() && pEditView
->HasSelection() )
354 aWord
= pTextEngine
->GetWord( rSelStart
);
361 void EditorWindow::RequestHelp( const HelpEvent
& rHEvt
)
365 // Should have been activated at some point
368 if ( rHEvt
.GetMode() & HelpEventMode::CONTEXT
)
370 OUString aKeyword
= GetWordAtCursor();
371 Application::GetHelp()->SearchKeyword( aKeyword
);
374 else if ( rHEvt
.GetMode() & HelpEventMode::QUICK
)
377 tools::Rectangle aHelpRect
;
378 if ( StarBASIC::IsRunning() )
380 Point aWindowPos
= rHEvt
.GetMousePosPixel();
381 aWindowPos
= ScreenToOutputPixel( aWindowPos
);
382 Point aDocPos
= GetEditView()->GetDocPos( aWindowPos
);
383 TextPaM aCursor
= GetEditView()->GetTextEngine()->GetPaM(aDocPos
);
384 TextPaM aStartOfWord
;
385 OUString aWord
= GetEditView()->GetTextEngine()->GetWord( aCursor
, &aStartOfWord
);
386 if ( !aWord
.isEmpty() && !comphelper::string::isdigitAsciiString(aWord
) )
388 sal_uInt16 nLastChar
= aWord
.getLength() - 1;
389 if ( cSuffixes
.find(aWord
[ nLastChar
] ) != std::u16string_view::npos
)
390 aWord
= aWord
.replaceAt( nLastChar
, 1, u
"" );
391 SbxBase
* pSBX
= StarBASIC::FindSBXInCurrentScope( aWord
);
392 if (SbxVariable
const* pVar
= IsSbxVariable(pSBX
))
394 SbxDataType eType
= pVar
->GetType();
395 if ( static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxOBJECT
) )
396 // might cause a crash e. g. at the selections-object
397 // Type == Object does not mean pVar == Object!
398 ; // aHelpText = ((SbxObject*)pVar)->GetClassName();
399 else if ( eType
& SbxARRAY
)
400 ; // aHelpText = "{...}";
401 else if ( static_cast<sal_uInt8
>(eType
) != sal_uInt8(SbxEMPTY
) )
403 aHelpText
= pVar
->GetName();
404 if ( aHelpText
.isEmpty() ) // name is not copied with the passed parameters
406 aHelpText
+= "=" + pVar
->GetOUString();
409 if ( !aHelpText
.isEmpty() )
411 tools::Rectangle
aStartWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aStartOfWord
));
412 TextPaM
aEndOfWord(aStartOfWord
.GetPara(), aStartOfWord
.GetIndex() + aWord
.getLength());
413 tools::Rectangle
aEndWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aEndOfWord
));
414 aHelpRect
= aStartWordRect
.GetUnion(aEndWordRect
);
416 Point aTopLeft
= GetEditView()->GetWindowPos(aHelpRect
.TopLeft());
417 aTopLeft
= GetEditView()->GetWindow()->OutputToScreenPixel(aTopLeft
);
419 aHelpRect
.SetPos(aTopLeft
);
423 Help::ShowQuickHelp( this, aHelpRect
, aHelpText
, QuickHelpFlags::NONE
);
429 Window::RequestHelp( rHEvt
);
433 void EditorWindow::Resize()
435 // ScrollBars, etc. happens in Adjust...
439 tools::Long nVisY
= pEditView
->GetStartDocPos().Y();
441 pEditView
->ShowCursor();
442 Size
aOutSz( GetOutputSizePixel() );
443 tools::Long nMaxVisAreaStart
= pEditView
->GetTextEngine()->GetTextHeight() - aOutSz
.Height();
444 if ( nMaxVisAreaStart
< 0 )
445 nMaxVisAreaStart
= 0;
446 if ( pEditView
->GetStartDocPos().Y() > nMaxVisAreaStart
)
448 Point
aStartDocPos( pEditView
->GetStartDocPos() );
449 aStartDocPos
.setY( nMaxVisAreaStart
);
450 pEditView
->SetStartDocPos( aStartDocPos
);
451 pEditView
->ShowCursor();
452 rModulWindow
.GetBreakPointWindow().GetCurYOffset() = aStartDocPos
.Y();
453 rModulWindow
.GetLineNumberWindow().GetCurYOffset() = aStartDocPos
.Y();
456 if ( nVisY
!= pEditView
->GetStartDocPos().Y() )
461 void EditorWindow::MouseMove( const MouseEvent
&rEvt
)
464 pEditView
->MouseMove( rEvt
);
468 void EditorWindow::MouseButtonUp( const MouseEvent
&rEvt
)
472 pEditView
->MouseButtonUp( rEvt
);
473 if (SfxBindings
* pBindings
= GetBindingsPtr())
475 pBindings
->Invalidate( SID_BASICIDE_STAT_POS
);
476 pBindings
->Invalidate( SID_BASICIDE_STAT_TITLE
);
481 void EditorWindow::MouseButtonDown( const MouseEvent
&rEvt
)
486 pEditView
->MouseButtonDown(rEvt
);
487 if( pCodeCompleteWnd
->IsVisible() )
489 if (pEditView
->GetSelection() != pCodeCompleteWnd
->GetTextSelection())
491 //selection changed, code complete window should be hidden
492 pCodeCompleteWnd
->HideAndRestoreFocus();
497 void EditorWindow::Command( const CommandEvent
& rCEvt
)
502 pEditView
->Command( rCEvt
);
503 if ( ( rCEvt
.GetCommand() == CommandEventId::Wheel
) ||
504 ( rCEvt
.GetCommand() == CommandEventId::StartAutoScroll
) ||
505 ( rCEvt
.GetCommand() == CommandEventId::AutoScroll
) )
507 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
509 // Check if it is a Ctrl+Wheel zoom command
510 if (pData
&& pData
->IsMod1())
512 const sal_uInt16 nOldZoom
= GetCurrentZoom();
514 if( pData
->GetDelta() < 0 )
515 nNewZoom
= std::max
<sal_uInt16
>(basctl::Shell::GetMinZoom(),
516 basegfx::zoomtools::zoomOut(nOldZoom
));
518 nNewZoom
= std::min
<sal_uInt16
>(basctl::Shell::GetMaxZoom(),
519 basegfx::zoomtools::zoomIn(nOldZoom
));
520 GetShell()->SetGlobalEditorZoomLevel(nNewZoom
);
523 HandleScrollCommand(rCEvt
, &rModulWindow
.GetEditHScrollBar(), &rModulWindow
.GetEditVScrollBar());
525 else if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
) {
526 SfxDispatcher
* pDispatcher
= GetDispatcher();
529 SfxDispatcher::ExecutePopup();
531 if( pCodeCompleteWnd
->IsVisible() ) // hide the code complete window
532 pCodeCompleteWnd
->ClearAndHide();
536 bool EditorWindow::ImpCanModify()
538 bool bCanModify
= true;
539 if ( StarBASIC::IsRunning() && rModulWindow
.GetBasicStatus().bIsRunning
)
541 // If in Trace-mode, abort the trace or refuse input
542 // Remove markers in the modules in Notify at Basic::Stopped
543 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(nullptr,
544 VclMessageType::Question
, VclButtonsType::OkCancel
,
545 IDEResId(RID_STR_WILLSTOPPRG
)));
546 if (xQueryBox
->run() == RET_OK
)
548 rModulWindow
.GetBasicStatus().bIsRunning
= false;
557 void EditorWindow::KeyInput( const KeyEvent
& rKEvt
)
559 if ( !pEditView
) // Happens in Win95
562 bool const bWasModified
= pEditEngine
->IsModified();
563 // see if there is an accelerator to be processed first
564 SfxViewShell
*pVS( SfxViewShell::Current());
565 bool bDone
= pVS
&& pVS
->KeyInput( rKEvt
);
567 if (pCodeCompleteWnd
->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn())
569 pCodeCompleteWnd
->HandleKeyInput(rKEvt
);
570 if( rKEvt
.GetKeyCode().GetCode() == KEY_UP
571 || rKEvt
.GetKeyCode().GetCode() == KEY_DOWN
572 || rKEvt
.GetKeyCode().GetCode() == KEY_TAB
573 || rKEvt
.GetKeyCode().GetCode() == KEY_POINT
)
577 if( (rKEvt
.GetKeyCode().GetCode() == KEY_SPACE
||
578 rKEvt
.GetKeyCode().GetCode() == KEY_TAB
||
579 rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
) && CodeCompleteOptions::IsAutoCorrectOn() )
584 if( rKEvt
.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() )
585 {//autoclose double quotes
586 HandleAutoCloseDoubleQuotes();
589 if( rKEvt
.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() )
590 {//autoclose parenthesis
591 HandleAutoCloseParen();
594 if( rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
&& CodeCompleteOptions::IsProcedureAutoCompleteOn() )
595 {//autoclose implementation
596 HandleProcedureCompletion();
599 if( rKEvt
.GetKeyCode().GetCode() == KEY_POINT
&& CodeCompleteOptions::IsCodeCompleteOn() )
601 HandleCodeCompletion();
603 if ( !bDone
&& ( !TextEngine::DoesKeyChangeText( rKEvt
) || ImpCanModify() ) )
605 if ( ( rKEvt
.GetKeyCode().GetCode() == KEY_TAB
) && !rKEvt
.GetKeyCode().IsMod1() &&
606 !rKEvt
.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() )
608 TextSelection
aSel( pEditView
->GetSelection() );
609 if ( aSel
.GetStart().GetPara() != aSel
.GetEnd().GetPara() )
611 bDelayHighlight
= false;
612 if ( !rKEvt
.GetKeyCode().IsShift() )
613 pEditView
->IndentBlock();
615 pEditView
->UnindentBlock();
616 bDelayHighlight
= true;
621 bDone
= pEditView
->KeyInput( rKEvt
);
625 Window::KeyInput( rKEvt
);
629 if (SfxBindings
* pBindings
= GetBindingsPtr())
631 pBindings
->Invalidate( SID_BASICIDE_STAT_POS
);
632 pBindings
->Invalidate( SID_BASICIDE_STAT_TITLE
);
633 if ( rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_CURSOR
)
635 pBindings
->Update( SID_BASICIDE_STAT_POS
);
636 pBindings
->Update( SID_BASICIDE_STAT_TITLE
);
638 if ( rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_ALPHA
||
639 rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_NUM
)
641 // If the module is read-only, warn that it can't be edited
642 if ( rModulWindow
.IsReadOnly() )
643 rModulWindow
.ShowReadOnlyInfoBar();
645 if ( !bWasModified
&& pEditEngine
->IsModified() )
647 pBindings
->Invalidate( SID_SAVEDOC
);
648 pBindings
->Invalidate( SID_DOC_MODIFIED
);
649 pBindings
->Invalidate( SID_UNDO
);
651 if ( rKEvt
.GetKeyCode().GetCode() == KEY_INSERT
)
652 pBindings
->Invalidate( SID_ATTR_INSERT
);
657 void EditorWindow::HandleAutoCorrect()
659 TextSelection aSel
= GetEditView()->GetSelection();
660 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
661 const sal_Int32 nIndex
= aSel
.GetStart().GetIndex();
662 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
663 const OUString sActSubName
= GetActualSubName( nLine
); // the actual procedure
665 std::vector
<HighlightPortion
> aPortions
;
666 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
668 if( aPortions
.empty() )
671 HighlightPortion
& r
= aPortions
.back();
672 if( static_cast<size_t>(nIndex
) != aPortions
.size()-1 )
673 {//cursor is not standing at the end of the line
674 for (auto const& portion
: aPortions
)
676 if( portion
.nEnd
== nIndex
)
684 OUString sStr
= aLine
.copy( r
.nBegin
, r
.nEnd
- r
.nBegin
);
685 //if WS or empty string: stop, nothing to do
686 if( ( r
.tokenType
== TokenType::Whitespace
) || sStr
.isEmpty() )
688 //create the appropriate TextSelection, and update the cache
689 TextPaM
aStart( nLine
, r
.nBegin
);
690 TextPaM
aEnd( nLine
, r
.nBegin
+ sStr
.getLength() );
691 TextSelection
sTextSelection( aStart
, aEnd
);
692 rModulWindow
.UpdateModule();
693 rModulWindow
.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache
);
694 // correct the last entered keyword
695 if( r
.tokenType
== TokenType::Keywords
)
697 sStr
= sStr
.toAsciiLowerCase();
698 if( !SbModule::GetKeywordCase(sStr
).isEmpty() )
699 // if it is a keyword, get its correct case
700 sStr
= SbModule::GetKeywordCase(sStr
);
702 // else capitalize first letter/select the correct one, and replace
703 sStr
= sStr
.replaceAt( 0, 1, OUString(sStr
[0]).toAsciiUpperCase() );
705 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
706 pEditView
->SetSelection( aSel
);
708 if( r
.tokenType
!= TokenType::Identifier
)
712 if( !aCodeCompleteCache
.GetCorrectCaseVarName( sStr
, sActSubName
).isEmpty() )
714 sStr
= aCodeCompleteCache
.GetCorrectCaseVarName( sStr
, sActSubName
);
715 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
716 pEditView
->SetSelection( aSel
);
720 //autocorrect procedures
721 SbxArray
* pArr
= rModulWindow
.GetSbModule()->GetMethods().get();
722 for (sal_uInt32 i
= 0; i
< pArr
->Count(); ++i
)
724 if (pArr
->Get(i
)->GetName().equalsIgnoreAsciiCase(sStr
))
726 sStr
= pArr
->Get(i
)->GetName(); //if found, get the correct case
727 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
728 pEditView
->SetSelection( aSel
);
735 void EditorWindow::SetLineHighlightColor(Color aColor
)
737 m_aLineHighlightColor
= aColor
;
740 TextSelection
EditorWindow::GetLastHighlightPortionTextSelection() const
741 {//creates a text selection from the highlight portion on the cursor
742 const sal_uInt32 nLine
= GetEditView()->GetSelection().GetStart().GetPara();
743 const sal_Int32 nIndex
= GetEditView()->GetSelection().GetStart().GetIndex();
744 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
745 std::vector
<HighlightPortion
> aPortions
;
746 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
748 assert(!aPortions
.empty());
749 HighlightPortion
& r
= aPortions
.back();
750 if( static_cast<size_t>(nIndex
) != aPortions
.size()-1 )
751 {//cursor is not standing at the end of the line
752 for (auto const& portion
: aPortions
)
754 if( portion
.nEnd
== nIndex
)
762 if( aPortions
.empty() )
763 return TextSelection();
765 std::u16string_view sStr
= aLine
.subView( r
.nBegin
, r
.nEnd
- r
.nBegin
);
766 TextPaM
aStart( nLine
, r
.nBegin
);
767 TextPaM
aEnd( nLine
, r
.nBegin
+ sStr
.size() );
768 return TextSelection( aStart
, aEnd
);
771 void EditorWindow::HandleAutoCloseParen()
773 TextSelection aSel
= GetEditView()->GetSelection();
774 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
775 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
777 if( aLine
.getLength() > 0 && aLine
[aSel
.GetEnd().GetIndex()-1] != '(' )
779 GetEditView()->InsertText(u
")"_ustr
);
780 //leave the cursor on its place: inside the parenthesis
781 TextPaM
aEnd(nLine
, aSel
.GetEnd().GetIndex());
782 GetEditView()->SetSelection( TextSelection( aEnd
, aEnd
) );
786 void EditorWindow::HandleAutoCloseDoubleQuotes()
788 TextSelection aSel
= GetEditView()->GetSelection();
789 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
790 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
792 std::vector
<HighlightPortion
> aPortions
;
793 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
795 if( aPortions
.empty() )
798 if( aLine
.getLength() > 0 && !aLine
.endsWith("\"") && (aPortions
.back().tokenType
!= TokenType::String
) )
800 GetEditView()->InsertText(u
"\""_ustr
);
801 //leave the cursor on its place: inside the two double quotes
802 TextPaM
aEnd(nLine
, aSel
.GetEnd().GetIndex());
803 GetEditView()->SetSelection( TextSelection( aEnd
, aEnd
) );
807 void EditorWindow::HandleProcedureCompletion()
810 TextSelection aSel
= GetEditView()->GetSelection();
811 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
812 OUString
aLine( pEditEngine
->GetText( nLine
) );
816 bool bFoundName
= GetProcedureName(aLine
, sProcType
, sProcName
);
820 OUString
sText(u
"\nEnd "_ustr
);
821 aSel
= GetEditView()->GetSelection();
822 if( sProcType
.equalsIgnoreAsciiCase("function") )
823 sText
+= "Function\n";
824 if( sProcType
.equalsIgnoreAsciiCase("sub") )
827 if( nLine
+1 == pEditEngine
->GetParagraphCount() )
829 pEditView
->InsertText( sText
);//append to the end
830 GetEditView()->SetSelection(aSel
);
834 for( sal_uInt32 i
= nLine
+1; i
< pEditEngine
->GetParagraphCount(); ++i
)
835 {//searching forward for end token, or another sub/function definition
836 OUString aCurrLine
= pEditEngine
->GetText( i
);
837 std::vector
<HighlightPortion
> aCurrPortions
;
838 aHighlighter
.getHighlightPortions( aCurrLine
, aCurrPortions
);
840 if( aCurrPortions
.size() >= 3 )
841 {//at least 3 tokens: (sub|function) whitespace identifier...
842 HighlightPortion
& r
= aCurrPortions
.front();
843 std::u16string_view sStr
= aCurrLine
.subView(r
.nBegin
, r
.nEnd
- r
.nBegin
);
845 if( r
.tokenType
== TokenType::Keywords
)
847 if( o3tl::equalsIgnoreAsciiCase(sStr
, u
"sub") || o3tl::equalsIgnoreAsciiCase(sStr
, u
"function") )
849 pEditView
->InsertText( sText
);//append to the end
850 GetEditView()->SetSelection(aSel
);
853 if( o3tl::equalsIgnoreAsciiCase(sStr
, u
"end") )
861 bool EditorWindow::GetProcedureName(std::u16string_view rLine
, OUString
& rProcType
, OUString
& rProcName
) const
863 std::vector
<HighlightPortion
> aPortions
;
864 aHighlighter
.getHighlightPortions(rLine
, aPortions
);
866 if( aPortions
.empty() )
869 bool bFoundType
= false;
870 bool bFoundName
= false;
872 for (auto const& portion
: aPortions
)
874 std::u16string_view sTokStr
= rLine
.substr(portion
.nBegin
, portion
.nEnd
- portion
.nBegin
);
876 if( portion
.tokenType
== TokenType::Keywords
&& ( o3tl::equalsIgnoreAsciiCase(sTokStr
, u
"sub")
877 || o3tl::equalsIgnoreAsciiCase(sTokStr
, u
"function")) )
882 if( portion
.tokenType
== TokenType::Identifier
&& bFoundType
)
890 if( !bFoundType
|| !bFoundName
)
891 return false;// no sub/function keyword or there is no identifier
897 void EditorWindow::HandleCodeCompletion()
899 rModulWindow
.UpdateModule();
900 rModulWindow
.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache
);
901 TextSelection aSel
= GetEditView()->GetSelection();
902 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
903 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
904 std::vector
< OUString
> aVect
; //vector to hold the base variable+methods for the nested reflection
906 std::vector
<HighlightPortion
> aPortions
;
907 aLine
= aLine
.copy(0, aSel
.GetEnd().GetIndex());
908 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
909 if( aPortions
.empty() )
912 //use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod ..
913 for( std::vector
<HighlightPortion
>::reverse_iterator
i(
915 i
!= aPortions
.rend(); ++i
)
917 if( i
->tokenType
== TokenType::Whitespace
) // a whitespace: stop; if there is no ws, it goes to the beginning of the line
919 if( i
->tokenType
== TokenType::Identifier
|| i
->tokenType
== TokenType::Keywords
) // extract the identifiers(methods, base variable)
920 /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue
921 * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!)
923 aVect
.insert( aVect
.begin(), aLine
.copy(i
->nBegin
, i
->nEnd
- i
->nBegin
) );
926 if( aVect
.empty() )//nothing to do
929 OUString sBaseName
= aVect
[aVect
.size()-1];//variable name
930 OUString sVarType
= aCodeCompleteCache
.GetVarType( sBaseName
);
932 if( !sVarType
.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() )
933 {//correct variable name, if autocorrection on
934 const OUString sStr
= aCodeCompleteCache
.GetCorrectCaseVarName( sBaseName
, GetActualSubName(nLine
) );
935 if( !sStr
.isEmpty() )
937 TextPaM
aStart(nLine
, aSel
.GetStart().GetIndex() - sStr
.getLength() );
938 TextSelection
sTextSelection(aStart
, TextPaM(nLine
, aSel
.GetStart().GetIndex()));
939 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
940 pEditView
->SetSelection( aSel
);
944 UnoTypeCodeCompletetor
aTypeCompletor( aVect
, sVarType
);
946 if( !aTypeCompletor
.CanCodeComplete() )
949 std::vector
< OUString
> aEntryVect
;//entries to be inserted into the list
950 std::vector
< OUString
> aFieldVect
= aTypeCompletor
.GetXIdlClassFields();//fields
951 aEntryVect
.insert(aEntryVect
.end(), aFieldVect
.begin(), aFieldVect
.end() );
952 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
953 {// if extended types on, reflect classes, else just the structs (XIdlClass without methods)
954 std::vector
< OUString
> aMethVect
= aTypeCompletor
.GetXIdlClassMethods();//methods
955 aEntryVect
.insert(aEntryVect
.end(), aMethVect
.begin(), aMethVect
.end() );
957 if( !aEntryVect
.empty() )
958 SetupAndShowCodeCompleteWnd( aEntryVect
, aSel
);
961 void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector
< OUString
>& aEntryVect
, TextSelection aSel
)
964 pCodeCompleteWnd
->ClearListBox();
966 for(const auto & l
: aEntryVect
)
968 pCodeCompleteWnd
->InsertEntry( l
);
971 pCodeCompleteWnd
->Show();
972 pCodeCompleteWnd
->ResizeAndPositionListBox();
973 pCodeCompleteWnd
->SelectFirstEntry();
974 // correct text selection, and set it
975 ++aSel
.GetStart().GetIndex();
976 ++aSel
.GetEnd().GetIndex();
977 pCodeCompleteWnd
->SetTextSelection( aSel
);
978 //give the focus to the EditView
979 pEditView
->GetWindow()->GrabFocus();
982 void EditorWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
984 if (!pEditEngine
) // We need it now at latest
987 HighlightCurrentLine(rRenderContext
);
989 pEditView
->Paint(rRenderContext
, rRect
);
992 void EditorWindow::HighlightCurrentLine(vcl::RenderContext
& rRenderContext
)
994 // If the cursor is in a single line and nothing is selected, then a highlight color
995 // is applied to the background of the current line
996 TextPaM aStartPaM
= pEditView
->GetSelection().GetStart();
997 TextPaM aEndPaM
= pEditView
->GetSelection().GetEnd();
998 if (aStartPaM
== aEndPaM
)
1000 Size
aWinSize(GetOutputSizePixel());
1001 sal_Int16 nDocPosY
= pEditView
->GetStartDocPos().Y();
1002 sal_Int16 nY1
= pEditEngine
->PaMtoEditCursor(aStartPaM
).TopLeft().Y();
1003 sal_Int16 nY2
= pEditEngine
->PaMtoEditCursor(aStartPaM
).BottomRight().Y();
1004 // Only draw if the cursor is in a visible position
1005 if ((nY1
>= nDocPosY
&& nY1
<= nDocPosY
+ aWinSize
.Height())
1006 || (nY2
>= nDocPosY
&& nY2
<= nDocPosY
+ aWinSize
.Height()))
1008 tools::Rectangle
aRect(Point(0, nY1
- nDocPosY
), Point(aWinSize
.Width(), nY2
- nDocPosY
));
1009 rRenderContext
.SetFillColor(m_aLineHighlightColor
);
1010 rRenderContext
.DrawRect(aRect
);
1015 void EditorWindow::LoseFocus()
1017 // tdf#114258 wait until the next event loop cycle to do this so it doesn't
1018 // happen during a mouse down/up selection in the treeview whose contents
1020 if (!m_nSetSourceInBasicId
)
1021 m_nSetSourceInBasicId
= Application::PostUserEvent(LINK(this, EditorWindow
, SetSourceInBasicHdl
));
1022 Window::LoseFocus();
1025 IMPL_LINK_NOARG(EditorWindow
, SetSourceInBasicHdl
, void*, void)
1027 m_nSetSourceInBasicId
= nullptr;
1031 void EditorWindow::SetSourceInBasic()
1033 if ( pEditEngine
&& pEditEngine
->IsModified()
1034 && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise
1035 // any read only bug in the text engine could lead to a crash later
1037 if ( !StarBASIC::IsRunning() ) // Not at runtime!
1039 rModulWindow
.UpdateModule();
1044 // Returns the position of the last character of any of the following
1045 // EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found
1046 sal_Int32
searchEOL( std::u16string_view rStr
, sal_Int32 fromIndex
)
1048 size_t iLF
= rStr
.find( LINE_SEP
, fromIndex
);
1049 if( iLF
!= std::u16string_view::npos
)
1052 size_t iCR
= rStr
.find( LINE_SEP_CR
, fromIndex
);
1053 return iCR
== std::u16string_view::npos
? -1 : iCR
;
1056 void EditorWindow::CreateEditEngine()
1061 pEditEngine
.reset(new ExtTextEngine
);
1062 pEditView
.reset(new TextView(pEditEngine
.get(), this));
1063 pEditView
->SetAutoIndentMode(true);
1064 pEditEngine
->SetUpdateMode(false);
1065 pEditEngine
->InsertView(pEditView
.get());
1069 aSyntaxIdle
.SetInvokeHandler( LINK( this, EditorWindow
, SyntaxTimerHdl
) );
1071 bool bWasDoSyntaxHighlight
= bDoSyntaxHighlight
;
1072 bDoSyntaxHighlight
= false; // too slow for large texts...
1073 OUString
aOUSource(rModulWindow
.GetModule());
1074 sal_Int32 nLines
= 0;
1075 sal_Int32 nIndex
= -1;
1079 nIndex
= searchEOL( aOUSource
, nIndex
+1 );
1081 while (nIndex
>= 0);
1083 // nLines*4: SetText+Formatting+DoHighlight+Formatting
1084 // it could be cut down on one formatting but you would wait even longer
1085 // for the text then if the source code is long...
1086 pProgress
.reset(new ProgressInfo(GetShell()->GetViewFrame().GetObjectShell(),
1087 IDEResId(RID_STR_GENERATESOURCE
),
1089 setTextEngineText(*pEditEngine
, aOUSource
);
1091 pEditView
->SetStartDocPos(Point(0, 0));
1092 pEditView
->SetSelection(TextSelection());
1093 rModulWindow
.GetBreakPointWindow().GetCurYOffset() = 0;
1094 rModulWindow
.GetLineNumberWindow().GetCurYOffset() = 0;
1095 pEditEngine
->SetUpdateMode(true);
1096 rModulWindow
.PaintImmediately(); // has only been invalidated at UpdateMode = true
1098 pEditView
->ShowCursor();
1100 StartListening(*pEditEngine
);
1103 bDoSyntaxHighlight
= bWasDoSyntaxHighlight
;
1105 for (sal_Int32 nLine
= 0; nLine
< nLines
; nLine
++)
1106 aSyntaxLineTable
.insert(nLine
);
1107 ForceSyntaxTimeout();
1111 pEditEngine
->SetModified( false );
1112 pEditEngine
->EnableUndo( true );
1116 if (SfxBindings
* pBindings
= GetBindingsPtr())
1118 pBindings
->Invalidate(SID_BASICIDE_STAT_POS
);
1119 pBindings
->Invalidate(SID_BASICIDE_STAT_TITLE
);
1122 DBG_ASSERT(rModulWindow
.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?");
1124 // set readonly mode for readonly libraries
1125 ScriptDocument
aDocument(rModulWindow
.GetDocument());
1126 OUString
aOULibName(rModulWindow
.GetLibName());
1127 Reference
< script::XLibraryContainer2
> xModLibContainer( aDocument
.getLibraryContainer( E_SCRIPTS
), UNO_QUERY
);
1128 if (xModLibContainer
.is()
1129 && xModLibContainer
->hasByName(aOULibName
)
1130 && xModLibContainer
->isLibraryReadOnly(aOULibName
))
1132 rModulWindow
.SetReadOnly(true);
1135 if (aDocument
.isDocument() && aDocument
.isReadOnly())
1136 rModulWindow
.SetReadOnly(true);
1139 void EditorWindow::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1141 if( rHint
.GetId() == SfxHintId::TextViewScrolled
)
1143 rModulWindow
.GetEditVScrollBar().SetThumbPos( pEditView
->GetStartDocPos().Y() );
1144 rModulWindow
.GetEditHScrollBar().SetThumbPos( pEditView
->GetStartDocPos().X() );
1145 rModulWindow
.GetBreakPointWindow().DoScroll
1146 ( rModulWindow
.GetBreakPointWindow().GetCurYOffset() - pEditView
->GetStartDocPos().Y() );
1147 rModulWindow
.GetLineNumberWindow().DoScroll
1148 ( rModulWindow
.GetLineNumberWindow().GetCurYOffset() - pEditView
->GetStartDocPos().Y() );
1150 else if( rHint
.GetId() == SfxHintId::TextHeightChanged
)
1152 if ( pEditView
->GetStartDocPos().Y() )
1154 tools::Long nOutHeight
= GetOutputSizePixel().Height();
1155 tools::Long nTextHeight
= pEditEngine
->GetTextHeight();
1156 if ( nTextHeight
< nOutHeight
)
1157 pEditView
->Scroll( 0, pEditView
->GetStartDocPos().Y() );
1159 rModulWindow
.GetLineNumberWindow().Invalidate();
1162 SetScrollBarRanges();
1164 else if( rHint
.GetId() == SfxHintId::TextFormatted
)
1167 const tools::Long nWidth
= pEditEngine
->CalcTextWidth();
1168 if ( nWidth
!= nCurTextWidth
)
1170 nCurTextWidth
= nWidth
;
1171 rModulWindow
.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth
-1) );
1172 rModulWindow
.GetEditHScrollBar().SetThumbPos( pEditView
->GetStartDocPos().X() );
1174 tools::Long nPrevTextWidth
= nCurTextWidth
;
1175 nCurTextWidth
= pEditEngine
->CalcTextWidth();
1176 if ( nCurTextWidth
!= nPrevTextWidth
)
1177 SetScrollBarRanges();
1179 else if( rHint
.GetId() == SfxHintId::TextParaInserted
)
1181 TextHint
const & rTextHint
= static_cast<TextHint
const&>(rHint
);
1182 ParagraphInsertedDeleted( rTextHint
.GetValue(), true );
1183 DoDelayedSyntaxHighlight( rTextHint
.GetValue() );
1185 else if( rHint
.GetId() == SfxHintId::TextParaRemoved
)
1187 TextHint
const & rTextHint
= static_cast<TextHint
const&>(rHint
);
1188 ParagraphInsertedDeleted( rTextHint
.GetValue(), false );
1190 else if( rHint
.GetId() == SfxHintId::TextParaContentChanged
)
1192 TextHint
const & rTextHint
= static_cast<TextHint
const&>(rHint
);
1193 DoDelayedSyntaxHighlight( rTextHint
.GetValue() );
1195 else if( rHint
.GetId() == SfxHintId::TextViewSelectionChanged
)
1197 if (SfxBindings
* pBindings
= GetBindingsPtr())
1199 pBindings
->Invalidate( SID_CUT
);
1200 pBindings
->Invalidate( SID_COPY
);
1203 else if( rHint
.GetId() == SfxHintId::TextViewCaretChanged
)
1205 // Check whether the line number where the caret is has changed and the
1206 // highlight needs to be redrawn
1207 sal_uInt32 nStartPara
= pEditView
->GetSelection().GetStart().GetPara();
1208 sal_uInt32 nEndPara
= pEditView
->GetSelection().GetEnd().GetPara();
1209 if (nStartPara
== nEndPara
&& nStartPara
!= m_nLastHighlightPara
)
1211 m_nLastHighlightPara
= nStartPara
;
1213 rModulWindow
.GetLineNumberWindow().Invalidate();
1215 else if (nStartPara
!= nEndPara
)
1217 // If multiple lines are selected, then update the line number window
1218 rModulWindow
.GetLineNumberWindow().Invalidate();
1223 OUString
EditorWindow::GetActualSubName( sal_uInt32 nLine
)
1225 SbxArrayRef pMethods
= rModulWindow
.GetSbModule()->GetMethods();
1226 for (sal_uInt32 i
= 0; i
< pMethods
->Count(); i
++)
1228 SbMethod
* pMeth
= dynamic_cast<SbMethod
*>(pMethods
->Get(i
));
1232 pMeth
->GetLineRange(l1
,l2
);
1233 if( (l1
<= nLine
+1) && (nLine
+1 <= l2
) )
1235 return pMeth
->GetName();
1242 void EditorWindow::SetScrollBarRanges()
1244 // extra method, not InitScrollBars, because for EditEngine events too
1248 rModulWindow
.GetEditVScrollBar().SetRange( Range( 0, pEditEngine
->GetTextHeight()-1 ) );
1249 rModulWindow
.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth
-1 ) );
1252 void EditorWindow::InitScrollBars()
1257 SetScrollBarRanges();
1258 Size
aOutSz(GetOutputSizePixel());
1259 rModulWindow
.GetEditVScrollBar().SetVisibleSize(aOutSz
.Height());
1260 rModulWindow
.GetEditVScrollBar().SetPageSize(aOutSz
.Height() * 8 / 10);
1261 rModulWindow
.GetEditVScrollBar().SetLineSize(GetTextHeight());
1262 rModulWindow
.GetEditVScrollBar().SetThumbPos(pEditView
->GetStartDocPos().Y());
1263 rModulWindow
.GetEditVScrollBar().Show();
1265 rModulWindow
.GetEditHScrollBar().SetVisibleSize(aOutSz
.Width());
1266 rModulWindow
.GetEditHScrollBar().SetPageSize(aOutSz
.Width() * 8 / 10);
1267 rModulWindow
.GetEditHScrollBar().SetLineSize(GetTextWidth( u
"x"_ustr
));
1268 rModulWindow
.GetEditHScrollBar().SetThumbPos(pEditView
->GetStartDocPos().X());
1269 rModulWindow
.GetEditHScrollBar().Show();
1272 void EditorWindow::ImpDoHighlight( sal_uInt32 nLine
)
1274 if ( !bDoSyntaxHighlight
)
1277 OUString
aLine( pEditEngine
->GetText( nLine
) );
1278 bool const bWasModified
= pEditEngine
->IsModified();
1279 pEditEngine
->RemoveAttribs( nLine
);
1280 std::vector
<HighlightPortion
> aPortions
;
1281 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
1283 for (auto const& portion
: aPortions
)
1285 Color
const aColor
= rModulWindow
.GetLayout().GetSyntaxColor(portion
.tokenType
);
1286 pEditEngine
->SetAttrib(TextAttribFontColor(aColor
), nLine
, portion
.nBegin
, portion
.nEnd
);
1289 pEditEngine
->SetModified(bWasModified
);
1292 void EditorWindow::ChangeFontColor( Color aColor
)
1296 vcl::Font
aFont(pEditEngine
->GetFont());
1297 aFont
.SetColor(aColor
);
1298 pEditEngine
->SetFont(aFont
);
1302 void EditorWindow::UpdateSyntaxHighlighting ()
1306 const sal_uInt32 nCount
= pEditEngine
->GetParagraphCount();
1307 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
1308 DoDelayedSyntaxHighlight(i
);
1312 void EditorWindow::ImplSetFont()
1314 // Get default font name and height defined in the Options dialog
1315 OUString
sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString()));
1316 if (sFontName
.isEmpty())
1318 vcl::Font
aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED
,
1319 Application::GetSettings().GetUILanguageTag().getLanguageType(),
1320 GetDefaultFontFlags::NONE
, GetOutDev()));
1321 sFontName
= aTmpFont
.GetFamilyName();
1323 sal_uInt16 nDefaultFontHeight
= officecfg::Office::Common::Font::SourceViewFont::FontHeight::get();
1325 // Calculate font size considering zoom level
1326 sal_uInt16 nNewFontHeight
= nDefaultFontHeight
* (static_cast<float>(nCurrentZoomLevel
) / 100);
1327 Size
aFontSize(0, nNewFontHeight
);
1329 vcl::Font
aFont(sFontName
, aFontSize
);
1330 aFont
.SetColor(rModulWindow
.GetLayout().GetFontColor());
1331 SetPointFont(*GetOutDev(), aFont
); // FIXME RenderContext
1334 rModulWindow
.GetBreakPointWindow().SetFont(aFont
);
1335 rModulWindow
.GetLineNumberWindow().SetFont(aFont
);
1336 rModulWindow
.Invalidate();
1340 bool const bModified
= pEditEngine
->IsModified();
1341 pEditEngine
->SetFont(aFont
);
1342 pEditEngine
->SetModified(bModified
);
1346 if (SfxBindings
* pBindings
= GetBindingsPtr())
1348 pBindings
->Invalidate( SID_BASICIDE_CURRENT_ZOOM
);
1349 pBindings
->Invalidate( SID_ATTR_ZOOMSLIDER
);
1353 void EditorWindow::SetEditorZoomLevel(sal_uInt16 nNewZoomLevel
)
1355 if (nCurrentZoomLevel
== nNewZoomLevel
)
1358 if (nNewZoomLevel
< MIN_ZOOM_LEVEL
|| nNewZoomLevel
> MAX_ZOOM_LEVEL
)
1361 nCurrentZoomLevel
= nNewZoomLevel
;
1365 void EditorWindow::DoSyntaxHighlight( sal_uInt32 nPara
)
1367 // because of the DelayedSyntaxHighlight it's possible
1368 // that this line does not exist anymore!
1369 if ( nPara
< pEditEngine
->GetParagraphCount() )
1371 // unfortunately I'm not sure that exactly this line does Modified()...
1373 pProgress
->StepProgress();
1374 ImpDoHighlight( nPara
);
1378 void EditorWindow::DoDelayedSyntaxHighlight( sal_uInt32 nPara
)
1380 // line is only added to list, processed in TimerHdl
1381 // => don't manipulate breaks while EditEngine is formatting
1383 pProgress
->StepProgress();
1385 if ( !bHighlighting
&& bDoSyntaxHighlight
)
1387 if ( bDelayHighlight
)
1389 aSyntaxLineTable
.insert( nPara
);
1390 aSyntaxIdle
.Start();
1393 DoSyntaxHighlight( nPara
);
1397 IMPL_LINK_NOARG(EditorWindow
, SyntaxTimerHdl
, Timer
*, void)
1399 DBG_ASSERT( pEditView
, "Not yet a View, but Syntax-Highlight?!" );
1401 bool const bWasModified
= pEditEngine
->IsModified();
1402 //pEditEngine->SetUpdateMode(false);
1404 bHighlighting
= true;
1405 for (auto const& syntaxLine
: aSyntaxLineTable
)
1407 DoSyntaxHighlight(syntaxLine
);
1412 pEditView
->ShowCursor( false );
1414 pEditEngine
->SetModified( bWasModified
);
1416 aSyntaxLineTable
.clear();
1417 bHighlighting
= false;
1420 void EditorWindow::ParagraphInsertedDeleted( sal_uInt32 nPara
, bool bInserted
)
1423 pProgress
->StepProgress();
1425 if ( !bInserted
&& ( nPara
== TEXT_PARA_ALL
) )
1427 rModulWindow
.GetBreakPoints().reset();
1428 rModulWindow
.GetBreakPointWindow().Invalidate();
1429 rModulWindow
.GetLineNumberWindow().Invalidate();
1433 rModulWindow
.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16
>(nPara
)+1, bInserted
);
1435 tools::Long nLineHeight
= GetTextHeight();
1436 Size aSz
= rModulWindow
.GetBreakPointWindow().GetOutDev()->GetOutputSize();
1437 tools::Rectangle
aInvRect( Point( 0, 0 ), aSz
);
1438 tools::Long nY
= nPara
*nLineHeight
- rModulWindow
.GetBreakPointWindow().GetCurYOffset();
1439 aInvRect
.SetTop( nY
);
1440 rModulWindow
.GetBreakPointWindow().Invalidate( aInvRect
);
1442 Size
aLnSz(rModulWindow
.GetLineNumberWindow().GetWidth(),
1443 GetOutputSizePixel().Height() - 2 * DWBORDER
);
1444 rModulWindow
.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER
+ 19, DWBORDER
), aLnSz
);
1445 rModulWindow
.GetLineNumberWindow().Invalidate();
1449 void EditorWindow::CreateProgress( const OUString
& rText
, sal_uInt32 nRange
)
1451 DBG_ASSERT( !pProgress
, "ProgressInfo exists already" );
1452 pProgress
.reset(new ProgressInfo(
1453 GetShell()->GetViewFrame().GetObjectShell(),
1459 void EditorWindow::DestroyProgress()
1464 void EditorWindow::ForceSyntaxTimeout()
1467 aSyntaxIdle
.Invoke();
1470 FactoryFunction
EditorWindow::GetUITestFactory() const
1472 return EditorWindowUIObject::create
;
1478 BreakPointWindow::BreakPointWindow (vcl::Window
* pParent
, ModulWindow
* pModulWindow
)
1479 : Window(pParent
, WB_BORDER
)
1480 , rModulWindow(*pModulWindow
)
1481 , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine
1482 , nMarkerPos(NoMarker
)
1483 , bErrorMarker(false)
1485 setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor());
1486 SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW
);
1489 void BreakPointWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1494 Size
const aOutSz
= rRenderContext
.GetOutputSize();
1495 tools::Long
const nLineHeight
= rRenderContext
.GetTextHeight();
1497 Image
const aBrk
[2] =
1499 GetImage(RID_BMP_BRKDISABLED
),
1500 GetImage(RID_BMP_BRKENABLED
)
1503 Size
const aBmpSz
= rRenderContext
.PixelToLogic(aBrk
[1].GetSizePixel());
1504 Point
const aBmpOff((aOutSz
.Width() - aBmpSz
.Width()) / 2,
1505 (nLineHeight
- aBmpSz
.Height()) / 2);
1507 for (size_t i
= 0, n
= GetBreakPoints().size(); i
< n
; ++i
)
1509 BreakPoint
& rBrk
= GetBreakPoints().at(i
);
1510 sal_uInt16
const nLine
= rBrk
.nLine
- 1;
1511 size_t const nY
= nLine
*nLineHeight
- nCurYOffset
;
1512 rRenderContext
.DrawImage(Point(0, nY
) + aBmpOff
, aBrk
[rBrk
.bEnabled
]);
1515 ShowMarker(rRenderContext
);
1518 void BreakPointWindow::ShowMarker(vcl::RenderContext
& rRenderContext
)
1520 if (nMarkerPos
== NoMarker
)
1523 Size
const aOutSz
= GetOutDev()->GetOutputSize();
1524 tools::Long
const nLineHeight
= GetTextHeight();
1526 Image aMarker
= GetImage(bErrorMarker
? RID_BMP_ERRORMARKER
: RID_BMP_STEPMARKER
);
1528 Size
aMarkerSz(aMarker
.GetSizePixel());
1529 aMarkerSz
= rRenderContext
.PixelToLogic(aMarkerSz
);
1530 Point
aMarkerOff(0, 0);
1531 aMarkerOff
.setX( (aOutSz
.Width() - aMarkerSz
.Width()) / 2 );
1532 aMarkerOff
.setY( (nLineHeight
- aMarkerSz
.Height()) / 2 );
1534 tools::Long nY
= nMarkerPos
* nLineHeight
- nCurYOffset
;
1538 rRenderContext
.DrawImage(aPos
, aMarker
);
1541 void BreakPointWindow::DoScroll( tools::Long nVertScroll
)
1543 nCurYOffset
-= nVertScroll
;
1544 Window::Scroll( 0, nVertScroll
);
1547 void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine
, bool bError
)
1549 if ( SyncYOffset() )
1553 bErrorMarker
= bError
;
1557 void BreakPointWindow::SetNoMarker ()
1559 SetMarkerPos(NoMarker
);
1562 BreakPoint
* BreakPointWindow::FindBreakPoint( const Point
& rMousePos
)
1564 size_t nLineHeight
= GetTextHeight();
1565 nLineHeight
= nLineHeight
> 0 ? nLineHeight
: 1;
1566 size_t nYPos
= rMousePos
.Y() + nCurYOffset
;
1568 for ( size_t i
= 0, n
= GetBreakPoints().size(); i
< n
; ++i
)
1570 BreakPoint
& rBrk
= GetBreakPoints().at( i
);
1571 sal_uInt16 nLine
= rBrk
.nLine
-1;
1572 size_t nY
= nLine
*nLineHeight
;
1573 if ( ( nYPos
> nY
) && ( nYPos
< ( nY
+ nLineHeight
) ) )
1579 void BreakPointWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
1581 if ( rMEvt
.GetClicks() == 2 )
1583 Point
aMousePos( PixelToLogic( rMEvt
.GetPosPixel() ) );
1584 tools::Long nLineHeight
= GetTextHeight();
1587 tools::Long nYPos
= aMousePos
.Y() + nCurYOffset
;
1588 tools::Long nLine
= nYPos
/ nLineHeight
+ 1;
1589 rModulWindow
.ToggleBreakPoint( static_cast<sal_uInt16
>(nLine
) );
1595 void BreakPointWindow::Command( const CommandEvent
& rCEvt
)
1597 if ( rCEvt
.GetCommand() != CommandEventId::ContextMenu
)
1600 Point
aPos( rCEvt
.IsMouseEvent() ? rCEvt
.GetMousePosPixel() : Point(1,1) );
1601 tools::Rectangle
aRect(aPos
, Size(1, 1));
1602 weld::Window
* pPopupParent
= weld::GetPopupParent(*this, aRect
);
1604 std::unique_ptr
<weld::Builder
> xUIBuilder(Application::CreateBuilder(pPopupParent
, u
"modules/BasicIDE/ui/breakpointmenus.ui"_ustr
));
1606 Point
aEventPos( PixelToLogic( aPos
) );
1607 BreakPoint
* pBrk
= rCEvt
.IsMouseEvent() ? FindBreakPoint( aEventPos
) : nullptr;
1610 // test if break point is enabled...
1611 std::unique_ptr
<weld::Menu
> xBrkPropMenu
= xUIBuilder
->weld_menu(u
"breakmenu"_ustr
);
1612 xBrkPropMenu
->set_active(u
"active"_ustr
, pBrk
->bEnabled
);
1613 OUString sCommand
= xBrkPropMenu
->popup_at_rect(pPopupParent
, aRect
);
1614 if (sCommand
== "active")
1616 pBrk
->bEnabled
= !pBrk
->bEnabled
;
1617 rModulWindow
.UpdateBreakPoint( *pBrk
);
1620 else if (sCommand
== "properties")
1622 BreakPointDialog
aBrkDlg(pPopupParent
, GetBreakPoints());
1623 aBrkDlg
.SetCurrentBreakPoint( *pBrk
);
1630 std::unique_ptr
<weld::Menu
> xBrkListMenu
= xUIBuilder
->weld_menu(u
"breaklistmenu"_ustr
);
1631 OUString sCommand
= xBrkListMenu
->popup_at_rect(pPopupParent
, aRect
);
1632 if (sCommand
== "manage")
1634 BreakPointDialog
aBrkDlg(pPopupParent
, GetBreakPoints());
1641 bool BreakPointWindow::SyncYOffset()
1643 TextView
* pView
= rModulWindow
.GetEditView();
1646 tools::Long nViewYOffset
= pView
->GetStartDocPos().Y();
1647 if ( nCurYOffset
!= nViewYOffset
)
1649 nCurYOffset
= nViewYOffset
;
1658 void BreakPointWindow::DataChanged(DataChangedEvent
const & rDCEvt
)
1660 Window::DataChanged(rDCEvt
);
1661 if (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
1662 && (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
1664 Color
aColor(GetSettings().GetStyleSettings().GetFieldColor());
1665 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
1666 if (!pOldSettings
|| aColor
!= pOldSettings
->GetStyleSettings().GetFieldColor())
1668 setBackgroundColor(aColor
);
1674 void BreakPointWindow::setBackgroundColor(Color aColor
)
1676 SetBackground(Wallpaper(aColor
));
1684 OUString maDisplayName
;
1685 SbxObjectRef mpObject
;
1686 std::vector
<OUString
> maMemberList
;
1688 SbxDimArrayRef mpArray
;
1689 int nDimLevel
; // 0 = Root
1691 std::vector
<sal_Int32
> vIndices
;
1693 WatchItem
* mpArrayParentItem
;
1695 explicit WatchItem (OUString aName
):
1696 maName(std::move(aName
)),
1699 mpArrayParentItem(nullptr)
1702 void clearWatchItem ()
1704 maMemberList
.clear();
1707 WatchItem
* GetRootItem();
1708 SbxDimArray
* GetRootArray();
1713 WatchWindow::WatchWindow(Layout
* pParent
)
1714 : DockingWindow(pParent
, u
"modules/BasicIDE/ui/dockingwatch.ui"_ustr
, u
"DockingWatch"_ustr
)
1715 , m_nUpdateWatchesId(nullptr)
1717 m_xTitleArea
= m_xBuilder
->weld_container(u
"titlearea"_ustr
);
1719 nVirtToolBoxHeight
= m_xTitleArea
->get_preferred_size().Height();
1721 m_xTitle
= m_xBuilder
->weld_label(u
"title"_ustr
);
1722 m_xTitle
->set_label(IDEResId(RID_STR_REMOVEWATCH
));
1724 m_xEdit
= m_xBuilder
->weld_entry(u
"edit"_ustr
);
1725 m_xRemoveWatchButton
= m_xBuilder
->weld_button(u
"remove"_ustr
);
1726 m_xTreeListBox
= m_xBuilder
->weld_tree_view(u
"treeview"_ustr
);
1728 m_xEdit
->set_accessible_name(IDEResId(RID_STR_WATCHNAME
));
1729 m_xEdit
->set_help_id(HID_BASICIDE_WATCHWINDOW_EDIT
);
1730 m_xEdit
->set_size_request(LogicToPixel(Size(80, 0), MapMode(MapUnit::MapAppFont
)).Width(), -1);
1731 m_xEdit
->connect_activate(LINK( this, WatchWindow
, ActivateHdl
));
1732 m_xEdit
->connect_key_press(LINK( this, WatchWindow
, KeyInputHdl
));
1733 m_xTreeListBox
->set_accessible_name(IDEResId(RID_STR_WATCHNAME
));
1735 m_xRemoveWatchButton
->set_sensitive(false);
1736 m_xRemoveWatchButton
->connect_clicked(LINK( this, WatchWindow
, ButtonHdl
));
1737 m_xRemoveWatchButton
->set_help_id(HID_BASICIDE_REMOVEWATCH
);
1738 m_xRemoveWatchButton
->set_tooltip_text(IDEResId(RID_STR_REMOVEWATCHTIP
));
1740 m_xTreeListBox
->set_help_id(HID_BASICIDE_WATCHWINDOW_LIST
);
1741 m_xTreeListBox
->connect_editing(LINK(this, WatchWindow
, EditingEntryHdl
),
1742 LINK(this, WatchWindow
, EditedEntryHdl
));
1743 m_xTreeListBox
->connect_selection_changed(LINK(this, WatchWindow
, TreeListHdl
));
1744 m_xTreeListBox
->connect_expanding(LINK(this, WatchWindow
, RequestingChildrenHdl
));
1746 // VarTabWidth, ValueTabWidth, TypeTabWidth
1747 std::vector
<int> aWidths
{ 220, 100, 1250 };
1748 std::vector
<bool> aEditables
{ false, true, false };
1749 m_xTreeListBox
->set_column_fixed_widths(aWidths
);
1750 m_xTreeListBox
->set_column_editables(aEditables
);
1752 SetText(IDEResId(RID_STR_WATCHNAME
));
1754 SetHelpId( HID_BASICIDE_WATCHWINDOW
);
1756 // make watch window keyboard accessible
1757 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1760 WatchWindow::~WatchWindow()
1765 void WatchWindow::dispose()
1767 if (m_nUpdateWatchesId
)
1769 Application::RemoveUserEvent(m_nUpdateWatchesId
);
1770 m_nUpdateWatchesId
= nullptr;
1773 // Destroy user data
1774 m_xTreeListBox
->all_foreach([this](weld::TreeIter
& rEntry
){
1775 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
1782 m_xRemoveWatchButton
.reset();
1783 m_xTitleArea
.reset();
1784 m_xTreeListBox
.reset();
1785 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1786 DockingWindow::dispose();
1789 void WatchWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1791 lcl_DrawIDEWindowFrame(this, rRenderContext
);
1794 void WatchWindow::Resize()
1796 Size aSz
= GetOutputSizePixel();
1797 Size
aBoxSz(aSz
.Width() - 2*DWBORDER
, aSz
.Height() - 2*DWBORDER
);
1799 if ( aBoxSz
.Width() < 4 )
1800 aBoxSz
.setWidth( 0 );
1801 if ( aBoxSz
.Height() < 4 )
1802 aBoxSz
.setHeight( 0 );
1804 m_xBox
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBoxSz
);
1809 WatchItem
* WatchItem::GetRootItem()
1811 WatchItem
* pItem
= mpArrayParentItem
;
1814 if( pItem
->mpArray
.is() )
1816 pItem
= pItem
->mpArrayParentItem
;
1821 SbxDimArray
* WatchItem::GetRootArray()
1823 WatchItem
* pRootItem
= GetRootItem();
1824 SbxDimArray
* pRet
= nullptr;
1826 pRet
= pRootItem
->mpArray
.get();
1830 void WatchWindow::AddWatch( const OUString
& rVName
)
1832 OUString aVar
, aIndex
;
1833 lcl_SeparateNameAndIndex( rVName
, aVar
, aIndex
);
1834 WatchItem
* pWatchItem
= new WatchItem(aVar
);
1836 OUString
sId(weld::toId(pWatchItem
));
1837 std::unique_ptr
<weld::TreeIter
> xRet
= m_xTreeListBox
->make_iterator();
1838 m_xTreeListBox
->insert(nullptr, -1, &aVar
, &sId
, nullptr, nullptr, false, xRet
.get());
1839 m_xTreeListBox
->set_text(*xRet
, u
""_ustr
, 1);
1840 m_xTreeListBox
->set_text(*xRet
, u
""_ustr
, 2);
1842 m_xTreeListBox
->set_cursor(*xRet
);
1843 m_xTreeListBox
->select(*xRet
);
1844 m_xTreeListBox
->scroll_to_row(*xRet
);
1845 m_xRemoveWatchButton
->set_sensitive(true);
1847 UpdateWatches(false);
1850 void WatchWindow::RemoveSelectedWatch()
1852 std::unique_ptr
<weld::TreeIter
> xEntry
= m_xTreeListBox
->make_iterator();
1853 bool bEntry
= m_xTreeListBox
->get_cursor(xEntry
.get());
1856 m_xTreeListBox
->remove(*xEntry
);
1857 bEntry
= m_xTreeListBox
->get_cursor(xEntry
.get());
1859 m_xEdit
->set_text(weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xEntry
))->maName
);
1861 m_xEdit
->set_text(OUString());
1862 if ( !m_xTreeListBox
->n_children() )
1863 m_xRemoveWatchButton
->set_sensitive(false);
1867 IMPL_STATIC_LINK_NOARG(WatchWindow
, ButtonHdl
, weld::Button
&, void)
1869 if (SfxDispatcher
* pDispatcher
= GetDispatcher())
1870 pDispatcher
->Execute(SID_BASICIDE_REMOVEWATCH
);
1873 IMPL_LINK_NOARG(WatchWindow
, TreeListHdl
, weld::TreeView
&, void)
1875 std::unique_ptr
<weld::TreeIter
> xCurEntry
= m_xTreeListBox
->make_iterator();
1876 bool bCurEntry
= m_xTreeListBox
->get_cursor(xCurEntry
.get());
1879 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xCurEntry
));
1882 m_xEdit
->set_text(pItem
->maName
);
1885 IMPL_LINK_NOARG(WatchWindow
, ActivateHdl
, weld::Entry
&, bool)
1887 OUString
aCurText(m_xEdit
->get_text());
1888 if (!aCurText
.isEmpty())
1891 m_xEdit
->select_region(0, -1);
1896 IMPL_LINK(WatchWindow
, KeyInputHdl
, const KeyEvent
&, rKEvt
, bool)
1898 bool bHandled
= false;
1900 sal_uInt16 nKeyCode
= rKEvt
.GetKeyCode().GetCode();
1901 if (nKeyCode
== KEY_ESCAPE
)
1903 m_xEdit
->set_text(OUString());
1911 StackWindow::StackWindow(Layout
* pParent
)
1912 : DockingWindow(pParent
, u
"modules/BasicIDE/ui/dockingstack.ui"_ustr
, u
"DockingStack"_ustr
)
1914 m_xTitle
= m_xBuilder
->weld_label(u
"title"_ustr
);
1915 m_xTitle
->set_label(IDEResId(RID_STR_STACK
));
1917 m_xTitle
->set_size_request(-1, nVirtToolBoxHeight
); // so the two title areas are the same height
1919 m_xTreeListBox
= m_xBuilder
->weld_tree_view(u
"stack"_ustr
);
1921 m_xTreeListBox
->set_help_id(HID_BASICIDE_STACKWINDOW_LIST
);
1922 m_xTreeListBox
->set_accessible_name(IDEResId(RID_STR_STACKNAME
));
1923 m_xTreeListBox
->set_selection_mode(SelectionMode::NONE
);
1924 m_xTreeListBox
->append_text(OUString());
1926 SetText(IDEResId(RID_STR_STACKNAME
));
1928 SetHelpId( HID_BASICIDE_STACKWINDOW
);
1930 // make stack window keyboard accessible
1931 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1934 StackWindow::~StackWindow()
1939 void StackWindow::dispose()
1941 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1943 m_xTreeListBox
.reset();
1944 DockingWindow::dispose();
1947 void StackWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1949 lcl_DrawIDEWindowFrame(this, rRenderContext
);
1952 void StackWindow::Resize()
1954 Size aSz
= GetOutputSizePixel();
1955 Size
aBoxSz(aSz
.Width() - 2*DWBORDER
, aSz
.Height() - 2*DWBORDER
);
1957 if ( aBoxSz
.Width() < 4 )
1958 aBoxSz
.setWidth( 0 );
1959 if ( aBoxSz
.Height() < 4 )
1960 aBoxSz
.setHeight( 0 );
1962 m_xBox
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBoxSz
);
1967 void StackWindow::UpdateCalls()
1969 m_xTreeListBox
->freeze();
1970 m_xTreeListBox
->clear();
1972 if (StarBASIC::IsRunning())
1974 ErrCode eOld
= SbxBase::GetError();
1975 m_xTreeListBox
->set_selection_mode(SelectionMode::Single
);
1977 sal_Int32 nScope
= 0;
1978 SbMethod
* pMethod
= StarBASIC::GetActiveMethod( nScope
);
1981 OUStringBuffer
aEntry( OUString::number(nScope
));
1982 if ( aEntry
.getLength() < 2 )
1983 aEntry
.insert(0, " ");
1984 aEntry
.append(": " + pMethod
->GetName());
1985 SbxArray
* pParams
= pMethod
->GetParameters();
1986 SbxInfo
* pInfo
= pMethod
->GetInfo();
1990 // 0 is the sub's name...
1991 for (sal_uInt32 nParam
= 1; nParam
< pParams
->Count(); nParam
++)
1993 SbxVariable
* pVar
= pParams
->Get(nParam
);
1994 assert(pVar
&& "Parameter?!");
1995 if ( !pVar
->GetName().isEmpty() )
1997 aEntry
.append(pVar
->GetName());
2001 assert(nParam
<= std::numeric_limits
<sal_uInt16
>::max());
2002 const SbxParamInfo
* pParam
= pInfo
->GetParam( sal::static_int_cast
<sal_uInt16
>(nParam
) );
2005 aEntry
.append(pParam
->aName
);
2009 SbxDataType eType
= pVar
->GetType();
2010 if( eType
& SbxARRAY
)
2012 aEntry
.append("...");
2014 else if( eType
!= SbxOBJECT
)
2016 aEntry
.append(pVar
->GetOUString());
2018 if (nParam
< (pParams
->Count() - 1))
2020 aEntry
.append(", ");
2025 m_xTreeListBox
->append_text(aEntry
.makeStringAndClear());
2027 pMethod
= StarBASIC::GetActiveMethod( nScope
);
2030 SbxBase::ResetError();
2031 if( eOld
!= ERRCODE_NONE
)
2032 SbxBase::SetError( eOld
);
2036 m_xTreeListBox
->set_selection_mode(SelectionMode::NONE
);
2037 m_xTreeListBox
->append_text(OUString());
2040 m_xTreeListBox
->thaw();
2043 ComplexEditorWindow::ComplexEditorWindow( ModulWindow
* pParent
) :
2044 Window( pParent
, WB_3DLOOK
| WB_CLIPCHILDREN
),
2045 aBrkWindow(VclPtr
<BreakPointWindow
>::Create(this, pParent
)),
2046 aLineNumberWindow(VclPtr
<LineNumberWindow
>::Create(this, pParent
)),
2047 aEdtWindow(VclPtr
<EditorWindow
>::Create(this, pParent
)),
2048 aEWVScrollBar(VclPtr
<ScrollAdaptor
>::Create(this, false)),
2049 aEWHScrollBar(VclPtr
<ScrollAdaptor
>::Create(this, true))
2051 // tdf#153853 The line numbering and breakpoint windows should appear on
2052 // the left, even on RTL locales
2058 aEWVScrollBar
->SetLineSize(nScrollLine
);
2059 aEWVScrollBar
->SetPageSize(nScrollPage
);
2060 aEWVScrollBar
->SetScrollHdl( LINK( this, ComplexEditorWindow
, ScrollHdl
) );
2061 aEWVScrollBar
->Show();
2063 aEWHScrollBar
->SetLineSize(nScrollLine
);
2064 aEWHScrollBar
->SetPageSize(nScrollPage
);
2065 aEWHScrollBar
->SetScrollHdl( LINK( this, ComplexEditorWindow
, ScrollHdl
) );
2066 aEWHScrollBar
->Show();
2069 ComplexEditorWindow::~ComplexEditorWindow()
2074 void ComplexEditorWindow::dispose()
2076 aBrkWindow
.disposeAndClear();
2077 aLineNumberWindow
.disposeAndClear();
2078 aEdtWindow
.disposeAndClear();
2079 aEWVScrollBar
.disposeAndClear();
2080 aEWHScrollBar
.disposeAndClear();
2081 vcl::Window::dispose();
2084 void ComplexEditorWindow::Resize()
2086 Size aOutSz
= GetOutputSizePixel();
2088 aSz
.AdjustWidth( -(2*DWBORDER
) );
2089 aSz
.AdjustHeight( -(2*DWBORDER
) );
2090 tools::Long nBrkWidth
= 20;
2091 tools::Long nSBWidth
= aEWVScrollBar
->GetSizePixel().Width();
2092 tools::Long nSBHeight
= aEWHScrollBar
->GetSizePixel().Height();
2094 Size
aBrkSz(nBrkWidth
, aSz
.Height() - nSBHeight
);
2096 if (aLineNumberWindow
->IsVisible())
2098 Size
aLnSz(aLineNumberWindow
->GetWidth(), aSz
.Height() - nSBHeight
);
2099 Size
aEWSz(aSz
.Width() - nBrkWidth
- aLineNumberWindow
->GetWidth() - nSBWidth
, aSz
.Height() - nSBHeight
);
2100 aBrkWindow
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBrkSz
);
2101 aLineNumberWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
, DWBORDER
), aLnSz
);
2102 aEdtWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
+ aLnSz
.Width(), DWBORDER
), aEWSz
);
2106 Size
aEWSz(aSz
.Width() - nBrkWidth
- nSBWidth
, aSz
.Height() - nSBHeight
);
2107 aBrkWindow
->SetPosSizePixel( Point( DWBORDER
, DWBORDER
), aBrkSz
);
2108 aEdtWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
, DWBORDER
), aEWSz
);
2111 aEWVScrollBar
->SetPosSizePixel(Point(aOutSz
.Width() - DWBORDER
- nSBWidth
, DWBORDER
),
2112 Size(nSBWidth
, aSz
.Height() - nSBHeight
));
2113 aEWHScrollBar
->SetPosSizePixel(Point(DWBORDER
, aOutSz
.Height() - DWBORDER
- nSBHeight
),
2114 Size(aSz
.Width() - nSBWidth
, nSBHeight
));
2117 IMPL_LINK_NOARG(ComplexEditorWindow
, ScrollHdl
, weld::Scrollbar
&, void)
2119 if (aEdtWindow
->GetEditView())
2121 tools::Long nXDiff
= aEdtWindow
->GetEditView()->GetStartDocPos().X() - aEWHScrollBar
->GetThumbPos();
2122 tools::Long nYDiff
= aEdtWindow
->GetEditView()->GetStartDocPos().Y() - aEWVScrollBar
->GetThumbPos();
2123 aEdtWindow
->GetEditView()->Scroll(nXDiff
, nYDiff
);
2124 aBrkWindow
->DoScroll( nYDiff
);
2125 aLineNumberWindow
->DoScroll( nYDiff
);
2126 aEdtWindow
->GetEditView()->ShowCursor(false);
2127 aEWVScrollBar
->SetThumbPos( aEdtWindow
->GetEditView()->GetStartDocPos().Y() );
2131 void ComplexEditorWindow::DataChanged(DataChangedEvent
const & rDCEvt
)
2133 Window::DataChanged(rDCEvt
);
2134 if (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
2135 && (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
2137 Color
aColor(GetSettings().GetStyleSettings().GetFaceColor());
2138 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
2139 if (!pOldSettings
|| aColor
!= pOldSettings
->GetStyleSettings().GetFaceColor())
2141 SetBackground(Wallpaper(aColor
));
2147 void ComplexEditorWindow::SetLineNumberDisplay(bool b
)
2149 aLineNumberWindow
->Show(b
);
2153 uno::Reference
< awt::XVclWindowPeer
>
2154 EditorWindow::GetComponentInterface(bool bCreate
)
2156 uno::Reference
< awt::XVclWindowPeer
> xPeer(
2157 Window::GetComponentInterface(false));
2158 if (!xPeer
.is() && bCreate
)
2160 // Make sure edit engine and view are available:
2164 xPeer
= createTextWindowPeer(*GetEditView());
2165 SetComponentInterface(xPeer
);
2170 static sal_uInt32
getCorrectedPropCount(SbxArray
* p
)
2172 sal_uInt32 nPropCount
= p
->Count();
2173 if (nPropCount
>= 3 && p
->Get(nPropCount
- 1)->GetName().equalsIgnoreAsciiCase("Dbg_Methods")
2174 && p
->Get(nPropCount
- 2)->GetName().equalsIgnoreAsciiCase("Dbg_Properties")
2175 && p
->Get(nPropCount
- 3)->GetName().equalsIgnoreAsciiCase("Dbg_SupportedInterfaces"))
2182 IMPL_LINK(WatchWindow
, RequestingChildrenHdl
, const weld::TreeIter
&, rParent
, bool)
2184 if( !StarBASIC::IsRunning() )
2187 if (m_xTreeListBox
->iter_has_child(rParent
))
2190 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rParent
));
2191 std::unique_ptr
<weld::TreeIter
> xRet
= m_xTreeListBox
->make_iterator();
2193 SbxDimArray
* pArray
= pItem
->mpArray
.get();
2194 SbxDimArray
* pRootArray
= pItem
->GetRootArray();
2195 bool bArrayIsRootArray
= false;
2196 if( !pArray
&& pRootArray
)
2198 pArray
= pRootArray
;
2199 bArrayIsRootArray
= true;
2202 SbxObject
* pObj
= pItem
->mpObject
.get();
2205 createAllObjectProperties( pObj
);
2206 SbxArray
* pProps
= pObj
->GetProperties();
2207 const sal_uInt32 nPropCount
= getCorrectedPropCount(pProps
);
2208 pItem
->maMemberList
.reserve(nPropCount
);
2210 for( sal_uInt32 i
= 0 ; i
< nPropCount
; ++i
)
2212 SbxVariable
* pVar
= pProps
->Get(i
);
2214 pItem
->maMemberList
.push_back(pVar
->GetName());
2215 OUString
const& rName
= pItem
->maMemberList
.back();
2217 WatchItem
* pWatchItem
= new WatchItem(rName
);
2218 OUString
sId(weld::toId(pWatchItem
));
2220 m_xTreeListBox
->insert(&rParent
, -1, &rName
, &sId
, nullptr, nullptr, false, xRet
.get());
2221 m_xTreeListBox
->set_text(*xRet
, u
""_ustr
, 1);
2222 m_xTreeListBox
->set_text(*xRet
, u
""_ustr
, 2);
2225 if (nPropCount
> 0 && !m_nUpdateWatchesId
)
2227 m_nUpdateWatchesId
= Application::PostUserEvent(LINK(this, WatchWindow
, ExecuteUpdateWatches
));
2232 sal_uInt16 nElementCount
= 0;
2234 // Loop through indices of current level
2235 int nParentLevel
= bArrayIsRootArray
? pItem
->nDimLevel
: 0;
2236 int nThisLevel
= nParentLevel
+ 1;
2237 sal_Int32 nMin
, nMax
;
2238 if (pArray
->GetDim(nThisLevel
, nMin
, nMax
))
2240 for (sal_Int32 i
= nMin
; i
<= nMax
; i
++)
2242 WatchItem
* pChildItem
= new WatchItem(pItem
->maName
);
2244 // Copy data and create name
2246 OUStringBuffer aIndexStr
= "(";
2247 pChildItem
->mpArrayParentItem
= pItem
;
2248 pChildItem
->nDimLevel
= nThisLevel
;
2249 pChildItem
->nDimCount
= pItem
->nDimCount
;
2250 pChildItem
->vIndices
.resize(pChildItem
->nDimCount
);
2252 for (j
= 0; j
< nParentLevel
; j
++)
2254 sal_Int32 n
= pChildItem
->vIndices
[j
] = pItem
->vIndices
[j
];
2255 aIndexStr
.append( OUString::number(n
) + "," );
2257 pChildItem
->vIndices
[nParentLevel
] = i
;
2258 aIndexStr
.append( OUString::number(i
) + ")" );
2260 OUString aDisplayName
;
2261 WatchItem
* pArrayRootItem
= pChildItem
->GetRootItem();
2262 if (pArrayRootItem
&& pArrayRootItem
->mpArrayParentItem
)
2263 aDisplayName
= pItem
->maDisplayName
;
2265 aDisplayName
= pItem
->maName
;
2266 aDisplayName
+= aIndexStr
;
2267 pChildItem
->maDisplayName
= aDisplayName
;
2269 OUString
sId(weld::toId(pChildItem
));
2271 m_xTreeListBox
->insert(&rParent
, -1, &aDisplayName
, &sId
, nullptr, nullptr, false,
2273 m_xTreeListBox
->set_text(*xRet
, u
""_ustr
, 1);
2274 m_xTreeListBox
->set_text(*xRet
, u
""_ustr
, 2);
2279 if (nElementCount
> 0 && !m_nUpdateWatchesId
)
2281 m_nUpdateWatchesId
= Application::PostUserEvent(LINK(this, WatchWindow
, ExecuteUpdateWatches
));
2288 IMPL_LINK_NOARG(WatchWindow
, ExecuteUpdateWatches
, void*, void)
2290 m_nUpdateWatchesId
= nullptr;
2294 SbxBase
* WatchWindow::ImplGetSBXForEntry(const weld::TreeIter
& rEntry
, bool& rbArrayElement
)
2296 SbxBase
* pSBX
= nullptr;
2297 rbArrayElement
= false;
2299 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
2300 OUString
aVName( pItem
->maName
);
2302 std::unique_ptr
<weld::TreeIter
> xParentEntry
= m_xTreeListBox
->make_iterator(&rEntry
);
2303 bool bParentEntry
= m_xTreeListBox
->iter_parent(*xParentEntry
);
2304 WatchItem
* pParentItem
= bParentEntry
? weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xParentEntry
)) : nullptr;
2307 SbxObject
* pObj
= pParentItem
->mpObject
.get();
2308 SbxDimArray
* pArray
;
2311 pSBX
= pObj
->Find( aVName
, SbxClassType::DontCare
);
2312 if (SbxVariable
const* pVar
= IsSbxVariable(pSBX
))
2314 // Force getting value
2316 aRes
.eType
= SbxVOID
;
2317 if (!isVeryLargeUnoProperty(pVar
))
2321 aRes
.eType
= SbxSTRING
;
2322 aRes
.pOUString
= new OUString("<" + IDEResId(RID_VARIABLE_TOO_LARGE_TO_DISPLAY
) + ">");
2327 else if( (pArray
= pItem
->GetRootArray()) != nullptr )
2329 rbArrayElement
= true;
2330 if( pParentItem
->nDimLevel
+ 1 == pParentItem
->nDimCount
)
2331 pSBX
= pArray
->Get(pItem
->vIndices
.empty() ? nullptr : &*pItem
->vIndices
.begin());
2336 pSBX
= StarBASIC::FindSBXInCurrentScope( aVName
);
2341 IMPL_LINK(WatchWindow
, EditingEntryHdl
, const weld::TreeIter
&, rIter
, bool)
2343 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rIter
));
2346 if (StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError())
2348 // No out of scope entries
2350 SbxBase
* pSbx
= ImplGetSBXForEntry(rIter
, bArrayElement
);
2351 if (IsSbxVariable(pSbx
) || bArrayElement
)
2353 // Accept no objects and only end nodes of arrays for editing
2354 if( !pItem
->mpObject
.is() && ( !pItem
->mpArray
.is() || pItem
->nDimLevel
== pItem
->nDimCount
) )
2356 aEditingRes
= m_xTreeListBox
->get_text(rIter
, 1);
2357 aEditingRes
= comphelper::string::strip(aEditingRes
, ' ');
2366 IMPL_LINK(WatchWindow
, EditedEntryHdl
, const IterString
&, rIterString
, bool)
2368 const weld::TreeIter
& rIter
= rIterString
.first
;
2369 OUString aResult
= comphelper::string::strip(rIterString
.second
, ' ');
2371 sal_uInt16 nResultLen
= aResult
.getLength();
2372 sal_Unicode cFirst
= aResult
[0];
2373 sal_Unicode cLast
= aResult
[ nResultLen
- 1 ];
2374 if( cFirst
== '\"' && cLast
== '\"' )
2375 aResult
= aResult
.copy( 1, nResultLen
- 2 );
2377 if (aResult
== aEditingRes
)
2381 SbxBase
* pSBX
= ImplGetSBXForEntry(rIter
, bArrayElement
);
2383 if (SbxVariable
* pVar
= IsSbxVariable(pSBX
))
2385 SbxDataType eType
= pVar
->GetType();
2386 if ( static_cast<sal_uInt8
>(eType
) != sal_uInt8(SbxOBJECT
)
2387 && ( eType
& SbxARRAY
) == 0 )
2389 // If the type is variable, the conversion of the SBX does not matter,
2390 // else the string is converted.
2391 pVar
->PutStringExt( aResult
);
2395 if ( SbxBase::IsError() )
2397 SbxBase::ResetError();
2402 // The text should never be taken/copied 1:1,
2403 // as the UpdateWatches will be lost
2410 void implCollapseModifiedObjectEntry(const weld::TreeIter
& rParent
, weld::TreeView
& rTree
)
2412 rTree
.collapse_row(rParent
);
2414 std::unique_ptr
<weld::TreeIter
> xDeleteEntry
= rTree
.make_iterator(&rParent
);
2416 while (rTree
.iter_children(*xDeleteEntry
))
2418 implCollapseModifiedObjectEntry(*xDeleteEntry
, rTree
);
2420 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(rTree
.get_id(*xDeleteEntry
));
2422 rTree
.remove(*xDeleteEntry
);
2423 rTree
.copy_iterator(rParent
, *xDeleteEntry
);
2427 OUString
implCreateTypeStringForDimArray( WatchItem
* pItem
, SbxDataType eType
)
2429 OUString aRetStr
= getBasicTypeName( eType
);
2431 SbxDimArray
* pArray
= pItem
->mpArray
.get();
2433 pArray
= pItem
->GetRootArray();
2436 int nDimLevel
= pItem
->nDimLevel
;
2437 int nDims
= pItem
->nDimCount
;
2438 if( nDimLevel
< nDims
)
2441 for( int i
= nDimLevel
; i
< nDims
; i
++ )
2443 sal_Int32 nMin
, nMax
;
2444 pArray
->GetDim(sal::static_int_cast
<sal_Int32
>(i
+ 1), nMin
, nMax
);
2445 aRetStr
+= OUString::number(nMin
) + " to " + OUString::number(nMax
);
2457 void WatchWindow::implEnableChildren(const weld::TreeIter
& rEntry
, bool bEnable
)
2461 if (!m_xTreeListBox
->get_row_expanded(rEntry
))
2462 m_xTreeListBox
->set_children_on_demand(rEntry
, true);
2466 assert(!m_xTreeListBox
->get_row_expanded(rEntry
));
2467 m_xTreeListBox
->set_children_on_demand(rEntry
, false);
2471 void WatchWindow::UpdateWatches(bool bBasicStopped
)
2473 SbMethod
* pCurMethod
= StarBASIC::GetActiveMethod();
2475 ErrCode eOld
= SbxBase::GetError();
2476 setBasicWatchMode( true );
2478 m_xTreeListBox
->all_foreach([this, pCurMethod
, bBasicStopped
](weld::TreeIter
& rEntry
){
2479 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
2480 DBG_ASSERT( !pItem
->maName
.isEmpty(), "Var? - Must not be empty!" );
2485 bool bCollapse
= false;
2486 TriState eEnableChildren
= TRISTATE_INDET
;
2489 SbxBase
* pSBX
= ImplGetSBXForEntry(rEntry
, bArrayElement
);
2491 // Array? If no end node create type string
2492 if( bArrayElement
&& pItem
->nDimLevel
< pItem
->nDimCount
)
2494 SbxDimArray
* pRootArray
= pItem
->GetRootArray();
2495 SbxDataType eType
= pRootArray
->GetType();
2496 aTypeStr
= implCreateTypeStringForDimArray( pItem
, eType
);
2497 eEnableChildren
= TRISTATE_TRUE
;
2500 if (SbxVariable
* pVar
= dynamic_cast<SbxVariable
*>(pSBX
))
2502 // extra treatment of arrays
2503 SbxDataType eType
= pVar
->GetType();
2504 if (isVeryLargeUnoProperty(pVar
))
2506 aWatchStr
+= "<" + IDEResId(RID_VARIABLE_TOO_LARGE_TO_DISPLAY
) + ">";
2508 else if ( eType
& SbxARRAY
)
2510 // consider multidimensional arrays!
2511 if (SbxDimArray
* pNewArray
= dynamic_cast<SbxDimArray
*>(pVar
->GetObject()))
2513 SbxDimArray
* pOldArray
= pItem
->mpArray
.get();
2515 bool bArrayChanged
= false;
2516 if (pOldArray
!= nullptr)
2518 // Compare Array dimensions to see if array has changed
2519 // Can be a copy, so comparing pointers does not work
2520 sal_Int32 nOldDims
= pOldArray
->GetDims();
2521 sal_Int32 nNewDims
= pNewArray
->GetDims();
2522 if( nOldDims
!= nNewDims
)
2524 bArrayChanged
= true;
2528 for( sal_Int32 i
= 0 ; i
< nOldDims
; i
++ )
2530 sal_Int32 nOldMin
, nOldMax
;
2531 sal_Int32 nNewMin
, nNewMax
;
2533 pOldArray
->GetDim(i
+ 1, nOldMin
, nOldMax
);
2534 pNewArray
->GetDim(i
+ 1, nNewMin
, nNewMax
);
2535 if( nOldMin
!= nNewMin
|| nOldMax
!= nNewMax
)
2537 bArrayChanged
= true;
2545 bArrayChanged
= true;
2547 eEnableChildren
= TRISTATE_TRUE
;
2548 // #i37227 Clear always and replace array
2549 if( pNewArray
!= pOldArray
)
2551 pItem
->clearWatchItem();
2553 pItem
->mpArray
= pNewArray
;
2554 sal_Int32 nDims
= pNewArray
->GetDims();
2555 pItem
->nDimLevel
= 0;
2556 pItem
->nDimCount
= nDims
;
2558 if( bArrayChanged
&& pOldArray
!= nullptr )
2562 aTypeStr
= implCreateTypeStringForDimArray( pItem
, eType
);
2569 else if ( static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxOBJECT
) )
2571 if (SbxObject
* pObj
= dynamic_cast<SbxObject
*>(pVar
->GetObject()))
2573 if ( pItem
->mpObject
.is() && !pItem
->maMemberList
.empty() )
2575 createAllObjectProperties(pObj
);
2576 SbxArray
* pProps
= pObj
->GetProperties();
2577 const sal_uInt32 nPropCount
= getCorrectedPropCount(pProps
);
2578 // Check if member list has changed
2579 bCollapse
= pItem
->maMemberList
.size() != nPropCount
;
2580 for( sal_uInt32 i
= 0 ; !bCollapse
&& i
< nPropCount
; i
++ )
2582 SbxVariable
* pVar_
= pProps
->Get(i
);
2583 if( pItem
->maMemberList
[i
] != pVar_
->GetName() )
2588 pItem
->mpObject
= pObj
;
2589 eEnableChildren
= TRISTATE_TRUE
;
2590 aTypeStr
= getBasicObjectTypeName( pObj
);
2595 if( pItem
->mpObject
.is() )
2598 eEnableChildren
= TRISTATE_FALSE
;
2604 if( pItem
->mpObject
.is() )
2607 eEnableChildren
= TRISTATE_FALSE
;
2610 bool bString
= (static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxSTRING
));
2611 OUString
aStrStr( u
"\""_ustr
);
2614 aWatchStr
+= aStrStr
;
2616 // tdf#57308 - avoid a second call to retrieve the data
2617 const SbxFlagBits nFlags
= pVar
->GetFlags();
2618 pVar
->SetFlag(SbxFlagBits::NoBroadcast
);
2619 aWatchStr
+= pVar
->GetOUString();
2620 pVar
->SetFlags(nFlags
);
2623 aWatchStr
+= aStrStr
;
2626 if( aTypeStr
.isEmpty() )
2628 if( !pVar
->IsFixed() )
2630 aTypeStr
= "Variant/";
2632 aTypeStr
+= getBasicTypeName( pVar
->GetType() );
2635 else if( !bArrayElement
)
2637 aWatchStr
+= "<Out of Scope>";
2642 implCollapseModifiedObjectEntry(rEntry
, *m_xTreeListBox
);
2643 pItem
->clearWatchItem();
2646 if (eEnableChildren
!= TRISTATE_INDET
)
2647 implEnableChildren(rEntry
, eEnableChildren
== TRISTATE_TRUE
);
2649 else if( bBasicStopped
)
2651 if( pItem
->mpObject
.is() || pItem
->mpArray
.is() )
2653 implCollapseModifiedObjectEntry(rEntry
, *m_xTreeListBox
);
2654 pItem
->mpObject
.clear();
2655 pItem
->mpArray
.clear();
2657 pItem
->clearWatchItem();
2660 m_xTreeListBox
->set_text(rEntry
, aWatchStr
, 1);
2661 m_xTreeListBox
->set_text(rEntry
, aTypeStr
, 2);
2666 SbxBase::ResetError();
2667 if( eOld
!= ERRCODE_NONE
)
2668 SbxBase::SetError( eOld
);
2669 setBasicWatchMode( false );
2672 IMPL_LINK_NOARG(CodeCompleteWindow
, ImplDoubleClickHdl
, weld::TreeView
&, bool)
2674 InsertSelectedEntry();
2678 IMPL_LINK_NOARG(CodeCompleteWindow
, ImplSelectHdl
, weld::TreeView
&, void)
2680 //give back the focus to the parent
2681 pParent
->GrabFocus();
2684 TextView
* CodeCompleteWindow::GetParentEditView()
2686 return pParent
->GetEditView();
2689 void CodeCompleteWindow::InsertSelectedEntry()
2691 OUString sSelectedEntry
= m_xListBox
->get_selected_text();
2693 if( !aFuncBuffer
.isEmpty() )
2695 // if the user typed in something: remove, and insert
2696 GetParentEditView()->SetSelection(pParent
->GetLastHighlightPortionTextSelection());
2697 GetParentEditView()->DeleteSelected();
2699 if (!sSelectedEntry
.isEmpty())
2701 // if the user selected something
2702 GetParentEditView()->InsertText(sSelectedEntry
);
2707 if (!sSelectedEntry
.isEmpty())
2709 // if the user selected something
2710 GetParentEditView()->InsertText(sSelectedEntry
);
2713 HideAndRestoreFocus();
2716 void CodeCompleteWindow::SetMatchingEntries()
2718 for (sal_Int32 i
= 0, nEntryCount
= m_xListBox
->n_children(); i
< nEntryCount
; ++i
)
2720 OUString sEntry
= m_xListBox
->get_text(i
);
2721 if (sEntry
.startsWithIgnoreAsciiCase(aFuncBuffer
))
2723 m_xListBox
->select(i
);
2729 IMPL_LINK(CodeCompleteWindow
, KeyInputHdl
, const KeyEvent
&, rKEvt
, bool)
2731 return HandleKeyInput(rKEvt
);
2734 bool CodeCompleteWindow::HandleKeyInput( const KeyEvent
& rKeyEvt
)
2736 bool bHandled
= true;
2738 sal_Unicode aChar
= rKeyEvt
.GetKeyCode().GetCode();
2739 if( (( aChar
>= KEY_A
) && ( aChar
<= KEY_Z
))
2740 || ((aChar
>= KEY_0
) && (aChar
<= KEY_9
)) )
2742 aFuncBuffer
.append(rKeyEvt
.GetCharCode());
2743 SetMatchingEntries();
2751 case KEY_ESCAPE
: // hide, do nothing
2753 HideAndRestoreFocus();
2757 TextSelection
aTextSelection( GetParentEditView()->GetSelection() );
2758 if( aTextSelection
.GetEnd().GetPara() != GetTextSelection().GetEnd().GetPara()-1 )
2760 HideAndRestoreFocus();
2766 TextSelection
aTextSelection( GetParentEditView()->GetSelection() );
2767 if( aTextSelection
.GetStart().GetIndex()-1 < GetTextSelection().GetStart().GetIndex() )
2768 {//leave the cursor where it is
2769 HideAndRestoreFocus();
2775 TextSelection aTextSelection
= pParent
->GetLastHighlightPortionTextSelection();
2776 OUString sTypedText
= pParent
->GetEditEngine()->GetText(aTextSelection
);
2777 if( !aFuncBuffer
.isEmpty() )
2779 sal_Int32 nInd
= m_xListBox
->get_selected_index();
2782 int nEntryCount
= m_xListBox
->n_children();
2783 //if there is something selected
2784 bool bFound
= false;
2785 for (sal_Int32 i
= nInd
; i
!= nEntryCount
; ++i
)
2787 OUString sEntry
= m_xListBox
->get_text(i
);
2788 if( sEntry
.startsWithIgnoreAsciiCase( aFuncBuffer
)
2789 && (std::u16string_view(aFuncBuffer
) != sTypedText
) && (i
!= nInd
) )
2791 m_xListBox
->select(i
);
2797 SetMatchingEntries();
2799 GetParentEditView()->SetSelection( aTextSelection
);
2800 GetParentEditView()->DeleteSelected();
2801 GetParentEditView()->InsertText(m_xListBox
->get_selected_text());
2806 case KEY_BACKSPACE
: case KEY_DELETE
:
2807 if( !aFuncBuffer
.isEmpty() )
2809 //if there was something inserted by tab: add it to aFuncBuffer
2810 TextSelection
aSel( GetParentEditView()->GetSelection() );
2811 TextPaM
aEnd( GetParentEditView()->CursorEndOfLine(GetTextSelection().GetEnd()) );
2812 GetParentEditView()->SetSelection(TextSelection(GetTextSelection().GetStart(), aEnd
) );
2813 OUString
aTabInsertedStr( GetParentEditView()->GetSelected() );
2814 GetParentEditView()->SetSelection( aSel
);
2816 if( !aTabInsertedStr
.isEmpty() && aTabInsertedStr
!= std::u16string_view(aFuncBuffer
) )
2818 aFuncBuffer
= aTabInsertedStr
;
2820 aFuncBuffer
.remove(aFuncBuffer
.getLength()-1, 1);
2821 SetMatchingEntries();
2830 InsertSelectedEntry();
2834 int nInd
= m_xListBox
->get_selected_index();
2836 m_xListBox
->select(nInd
- 1);
2841 int nInd
= m_xListBox
->get_selected_index();
2842 if (nInd
+ 1 < m_xListBox
->n_children())
2843 m_xListBox
->select(nInd
+ 1);
2855 void CodeCompleteWindow::HideAndRestoreFocus()
2858 pParent
->GrabFocus();
2861 CodeCompleteWindow::CodeCompleteWindow(EditorWindow
* pPar
)
2862 : InterimItemWindow(pPar
, u
"modules/BasicIDE/ui/codecomplete.ui"_ustr
, u
"CodeComplete"_ustr
)
2864 , m_xListBox(m_xBuilder
->weld_tree_view(u
"treeview"_ustr
))
2866 m_xListBox
->connect_row_activated(LINK(this, CodeCompleteWindow
, ImplDoubleClickHdl
));
2867 m_xListBox
->connect_selection_changed(LINK(this, CodeCompleteWindow
, ImplSelectHdl
));
2868 m_xListBox
->connect_key_press(LINK(this, CodeCompleteWindow
, KeyInputHdl
));
2869 m_xListBox
->make_sorted();
2870 m_xListBox
->set_direction(false);
2872 m_xListBox
->set_size_request(150, 150); // default, this will adopt the line length
2873 SetSizePixel(m_xContainer
->get_preferred_size());
2876 CodeCompleteWindow::~CodeCompleteWindow()
2881 void CodeCompleteWindow::dispose()
2885 InterimItemWindow::dispose();
2888 void CodeCompleteWindow::InsertEntry( const OUString
& aStr
)
2890 m_xListBox
->append_text(aStr
);
2893 void CodeCompleteWindow::ClearListBox()
2895 m_xListBox
->clear();
2896 aFuncBuffer
.setLength(0);
2899 void CodeCompleteWindow::SetTextSelection( const TextSelection
& aSel
)
2901 m_aTextSelection
= aSel
;
2904 void CodeCompleteWindow::ResizeAndPositionListBox()
2906 if (m_xListBox
->n_children() < 1)
2909 // if there is at least one element inside
2910 // calculate basic position: under the current line
2911 tools::Rectangle aRect
= static_cast<TextEngine
*>(pParent
->GetEditEngine())->PaMtoEditCursor( pParent
->GetEditView()->GetSelection().GetEnd() );
2912 tools::Long nViewYOffset
= pParent
->GetEditView()->GetStartDocPos().Y();
2913 Point aPos
= aRect
.BottomRight();// this variable will be used later (if needed)
2914 aPos
.setY( (aPos
.Y() - nViewYOffset
) + nBasePad
);
2917 const sal_uInt16 nLines
= static_cast<sal_uInt16
>(std::min(6, m_xListBox
->n_children()));
2919 m_xListBox
->set_size_request(-1, m_xListBox
->get_height_rows(nLines
));
2921 Size aSize
= m_xContainer
->get_preferred_size();
2923 SetSizePixel( aSize
);
2925 //calculate position
2926 const tools::Rectangle
aVisArea( pParent
->GetEditView()->GetStartDocPos(), pParent
->GetOutputSizePixel() ); //the visible area
2927 const Point aBottomPoint
= aVisArea
.BottomRight();
2929 if( aVisArea
.TopRight().getY() + aPos
.getY() + aSize
.getHeight() > aBottomPoint
.getY() )
2930 {//clipped at the bottom: move it up
2931 const tools::Long nParentFontHeight
= pParent
->GetEditEngine()->GetFont().GetFontHeight(); //parent's font (in the IDE): needed for height
2932 aPos
.AdjustY( -(aSize
.getHeight() + nParentFontHeight
+ nCursorPad
) );
2935 if( aVisArea
.TopLeft().getX() + aPos
.getX() + aSize
.getWidth() > aBottomPoint
.getX() )
2936 {//clipped at the right side, move it a bit left
2937 aPos
.AdjustX( -(aSize
.getWidth() + aVisArea
.TopLeft().getX()) );
2940 SetPosPixel( aPos
);
2943 void CodeCompleteWindow::SelectFirstEntry()
2945 if (m_xListBox
->n_children() > 0)
2946 m_xListBox
->select(0);
2949 void CodeCompleteWindow::ClearAndHide()
2952 HideAndRestoreFocus();
2955 UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector
< OUString
>& aVect
, const OUString
& sVarType
)
2956 : bCanComplete( true )
2958 if( aVect
.empty() || sVarType
.isEmpty() )
2960 bCanComplete
= false;//invalid parameters, nothing to code complete
2966 // Get the base class for reflection:
2967 xClass
= css::reflection::theCoreReflection::get(
2968 comphelper::getProcessComponentContext())->forName(sVarType
);
2970 catch( const Exception
& )
2972 bCanComplete
= false;
2976 //start from aVect[1]: aVect[0] is the variable name
2977 bCanComplete
= std::none_of(aVect
.begin() + 1, aVect
.end(), [this](const OUString
& rMethName
) {
2978 return (!CodeCompleteOptions::IsExtendedTypeDeclaration() || !CheckMethod(rMethName
)) && !CheckField(rMethName
); });
2981 std::vector
< OUString
> UnoTypeCodeCompletetor::GetXIdlClassMethods() const
2983 std::vector
< OUString
> aRetVect
;
2984 if( bCanComplete
&& ( xClass
!= nullptr ) )
2986 const Sequence
< Reference
< reflection::XIdlMethod
> > aMethods
= xClass
->getMethods();
2987 for(Reference
< reflection::XIdlMethod
> const & rMethod
: aMethods
)
2989 aRetVect
.push_back( rMethod
->getName() );
2992 return aRetVect
;//this is empty when cannot code complete
2995 std::vector
< OUString
> UnoTypeCodeCompletetor::GetXIdlClassFields() const
2997 std::vector
< OUString
> aRetVect
;
2998 if( bCanComplete
&& ( xClass
!= nullptr ) )
3000 const Sequence
< Reference
< reflection::XIdlField
> > aFields
= xClass
->getFields();
3001 for(Reference
< reflection::XIdlField
> const & rxField
: aFields
)
3003 aRetVect
.push_back( rxField
->getName() );
3006 return aRetVect
;//this is empty when cannot code complete
3010 bool UnoTypeCodeCompletetor::CheckField( const OUString
& sFieldName
)
3011 {// modifies xClass!!!
3013 if ( xClass
== nullptr )
3016 Reference
< reflection::XIdlField
> xField
= xClass
->getField( sFieldName
);
3017 if( xField
!= nullptr )
3019 xClass
= xField
->getType();
3020 if( xClass
!= nullptr )
3028 bool UnoTypeCodeCompletetor::CheckMethod( const OUString
& sMethName
)
3029 {// modifies xClass!!!
3032 if ( xClass
== nullptr )
3035 Reference
< reflection::XIdlMethod
> xMethod
= xClass
->getMethod( sMethName
);
3036 if( xMethod
!= nullptr ) //method OK, check return type
3038 xClass
= xMethod
->getReturnType();
3039 if( xClass
!= nullptr )
3047 } // namespace basctl
3049 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */