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>
78 using namespace ::com::sun::star
;
79 using namespace ::com::sun::star::uno
;
84 sal_uInt16
const NoMarker
= 0xFFFF;
85 tools::Long
const nBasePad
= 2;
86 tools::Long
const nCursorPad
= 5;
88 tools::Long nVirtToolBoxHeight
; // inited in WatchWindow, used in Stackwindow
90 // Returns pBase converted to SbxVariable if valid and is not an SbxMethod.
91 SbxVariable
* IsSbxVariable (SbxBase
* pBase
)
93 if (SbxVariable
* pVar
= dynamic_cast<SbxVariable
*>(pBase
))
94 if (!dynamic_cast<SbxMethod
*>(pVar
))
99 Image
GetImage(const OUString
& rId
)
101 return Image(StockImage::Yes
, rId
);
104 int const nScrollLine
= 12;
105 int const nScrollPage
= 60;
106 int const DWBORDER
= 3;
108 std::u16string_view
const cSuffixes
= u
"%&!#@$";
114 * Helper functions to get/set text in TextEngine using
115 * the stream interface.
117 * get/setText() only supports tools Strings limited to 64K).
119 OUString
getTextEngineText (ExtTextEngine
& rEngine
)
121 SvMemoryStream aMemStream
;
122 aMemStream
.SetStreamCharSet( RTL_TEXTENCODING_UTF8
);
123 aMemStream
.SetLineDelimiter( LINEEND_LF
);
124 rEngine
.Write( aMemStream
);
125 std::size_t nSize
= aMemStream
.Tell();
126 OUString
aText( static_cast<const char*>(aMemStream
.GetData()),
127 nSize
, RTL_TEXTENCODING_UTF8
);
131 void setTextEngineText (ExtTextEngine
& rEngine
, std::u16string_view aStr
)
133 rEngine
.SetText(OUString());
134 OString aUTF8Str
= OUStringToOString( aStr
, RTL_TEXTENCODING_UTF8
);
135 SvMemoryStream
aMemStream( const_cast<char *>(aUTF8Str
.getStr()), aUTF8Str
.getLength(),
137 aMemStream
.SetStreamCharSet( RTL_TEXTENCODING_UTF8
);
138 aMemStream
.SetLineDelimiter( LINEEND_LF
);
139 rEngine
.Read(aMemStream
);
145 void lcl_DrawIDEWindowFrame(DockingWindow
const * pWin
, vcl::RenderContext
& rRenderContext
)
147 if (pWin
->IsFloatingMode())
150 Size
aSz(pWin
->GetOutputSizePixel());
151 const Color
aOldLineColor(rRenderContext
.GetLineColor());
152 rRenderContext
.SetLineColor(COL_WHITE
);
154 rRenderContext
.DrawLine(Point(0, 0), Point(aSz
.Width(), 0));
155 // Black line at bottom
156 rRenderContext
.SetLineColor(COL_BLACK
);
157 rRenderContext
.DrawLine(Point(0, aSz
.Height() - 1),
158 Point(aSz
.Width(), aSz
.Height() - 1));
159 rRenderContext
.SetLineColor(aOldLineColor
);
162 void lcl_SeparateNameAndIndex( const OUString
& rVName
, OUString
& rVar
, OUString
& rIndex
)
166 sal_Int32 nIndexStart
= rVar
.indexOf( '(' );
167 if ( nIndexStart
!= -1 )
169 sal_Int32 nIndexEnd
= rVar
.indexOf( ')', nIndexStart
);
172 rIndex
= rVar
.copy(nIndexStart
+ 1, nIndexEnd
- nIndexStart
- 1);
173 rVar
= rVar
.copy(0, nIndexStart
);
174 rVar
= comphelper::string::stripEnd(rVar
, ' ');
175 rIndex
= comphelper::string::strip(rIndex
, ' ');
179 if ( !rVar
.isEmpty() )
181 sal_uInt16 nLastChar
= rVar
.getLength()-1;
182 if ( cSuffixes
.find(rVar
[ nLastChar
] ) != std::u16string_view::npos
)
183 rVar
= rVar
.replaceAt( nLastChar
, 1, u
"" );
185 if ( !rIndex
.isEmpty() )
187 sal_uInt16 nLastChar
= rIndex
.getLength()-1;
188 if ( cSuffixes
.find(rIndex
[ nLastChar
] ) != std::u16string_view::npos
)
189 rIndex
= rIndex
.replaceAt( nLastChar
, 1, u
"" );
199 class EditorWindow::ChangesListener
:
200 public cppu::WeakImplHelper
< beans::XPropertiesChangeListener
>
203 explicit ChangesListener(EditorWindow
& editor
): editor_(editor
) {}
206 virtual ~ChangesListener() override
{}
208 virtual void SAL_CALL
disposing(lang::EventObject
const &) override
210 std::unique_lock
g(editor_
.mutex_
);
211 editor_
.notifier_
.clear();
214 virtual void SAL_CALL
propertiesChange(
215 Sequence
< beans::PropertyChangeEvent
> const &) override
218 editor_
.ImplSetFont();
221 EditorWindow
& editor_
;
224 class EditorWindow::ProgressInfo
: public SfxProgress
227 ProgressInfo (SfxObjectShell
* pObjSh
, OUString
const& rText
, sal_uInt32 nRange
) :
228 SfxProgress(pObjSh
, rText
, nRange
),
234 SetState(++nCurState
);
238 sal_uInt32 nCurState
;
241 EditorWindow::EditorWindow (vcl::Window
* pParent
, ModulWindow
* pModulWindow
) :
242 Window(pParent
, WB_BORDER
),
243 rModulWindow(*pModulWindow
),
245 m_nSetSourceInBasicId(nullptr),
246 aHighlighter(HighlighterLanguage::Basic
),
247 aSyntaxIdle( "basctl EditorWindow aSyntaxIdle" ),
248 bHighlighting(false),
249 bDoSyntaxHighlight(true),
250 bDelayHighlight(true),
251 pCodeCompleteWnd(VclPtr
<CodeCompleteWindow
>::Create(this))
253 set_id("EditorWindow");
254 const Wallpaper
aBackground(rModulWindow
.GetLayout().GetSyntaxBackgroundColor());
255 SetBackground(aBackground
);
256 GetWindow(GetWindowType::Border
)->SetBackground(aBackground
);
257 SetPointer( PointerStyle::Text
);
258 SetHelpId( HID_BASICIDE_EDITORWINDOW
);
260 listener_
= new ChangesListener(*this);
261 Reference
< beans::XMultiPropertySet
> n(
262 officecfg::Office::Common::Font::SourceViewFont::get(),
265 std::unique_lock
g(mutex_
);
269 // The zoom level applied to the editor window is the zoom slider value in the shell
270 nCurrentZoomLevel
= GetShell()->GetCurrentZoomSliderValue();
272 const Sequence
<OUString
> aPropertyNames
{"FontHeight", "FontName"};
273 n
->addPropertiesChangeListener(aPropertyNames
, listener_
);
277 EditorWindow::~EditorWindow()
282 void EditorWindow::dispose()
284 if (m_nSetSourceInBasicId
)
286 Application::RemoveUserEvent(m_nSetSourceInBasicId
);
287 m_nSetSourceInBasicId
= nullptr;
290 Reference
< beans::XMultiPropertySet
> n
;
292 std::unique_lock
g(mutex_
);
296 n
->removePropertiesChangeListener(listener_
);
303 EndListening( *pEditEngine
);
304 pEditEngine
->RemoveView(pEditView
.get());
306 pCodeCompleteWnd
.disposeAndClear();
307 vcl::Window::dispose();
310 OUString
EditorWindow::GetWordAtCursor()
316 TextEngine
* pTextEngine
= pEditView
->GetTextEngine();
319 // check first, if the cursor is at a help URL
320 const TextSelection
& rSelection
= pEditView
->GetSelection();
321 const TextPaM
& rSelStart
= rSelection
.GetStart();
322 const TextPaM
& rSelEnd
= rSelection
.GetEnd();
323 OUString aText
= pTextEngine
->GetText( rSelEnd
.GetPara() );
324 CharClass
aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() );
325 sal_Int32 nSelStart
= rSelStart
.GetIndex();
326 sal_Int32 nSelEnd
= rSelEnd
.GetIndex();
327 sal_Int32 nLength
= aText
.getLength();
328 sal_Int32 nStart
= 0;
329 sal_Int32 nEnd
= nLength
;
330 while ( nStart
< nLength
)
332 OUString
aURL( URIHelper::FindFirstURLInText( aText
, nStart
, nEnd
, aClass
) );
333 INetURLObject
aURLObj( aURL
);
334 if ( aURLObj
.GetProtocol() == INetProtocol::VndSunStarHelp
335 && nSelStart
>= nStart
&& nSelStart
<= nEnd
&& nSelEnd
>= nStart
&& nSelEnd
<= nEnd
)
344 // Not the selected range, but at the CursorPosition,
345 // if a word is partially selected.
346 if ( aWord
.isEmpty() )
347 aWord
= pTextEngine
->GetWord( rSelEnd
);
349 // Can be empty when full word selected, as Cursor behind it
350 if ( aWord
.isEmpty() && pEditView
->HasSelection() )
351 aWord
= pTextEngine
->GetWord( rSelStart
);
358 void EditorWindow::RequestHelp( const HelpEvent
& rHEvt
)
362 // Should have been activated at some point
365 if ( rHEvt
.GetMode() & HelpEventMode::CONTEXT
)
367 OUString aKeyword
= GetWordAtCursor();
368 Application::GetHelp()->SearchKeyword( aKeyword
);
371 else if ( rHEvt
.GetMode() & HelpEventMode::QUICK
)
374 tools::Rectangle aHelpRect
;
375 if ( StarBASIC::IsRunning() )
377 Point aWindowPos
= rHEvt
.GetMousePosPixel();
378 aWindowPos
= ScreenToOutputPixel( aWindowPos
);
379 Point aDocPos
= GetEditView()->GetDocPos( aWindowPos
);
380 TextPaM aCursor
= GetEditView()->GetTextEngine()->GetPaM(aDocPos
);
381 TextPaM aStartOfWord
;
382 OUString aWord
= GetEditView()->GetTextEngine()->GetWord( aCursor
, &aStartOfWord
);
383 if ( !aWord
.isEmpty() && !comphelper::string::isdigitAsciiString(aWord
) )
385 sal_uInt16 nLastChar
= aWord
.getLength() - 1;
386 if ( cSuffixes
.find(aWord
[ nLastChar
] ) != std::u16string_view::npos
)
387 aWord
= aWord
.replaceAt( nLastChar
, 1, u
"" );
388 SbxBase
* pSBX
= StarBASIC::FindSBXInCurrentScope( aWord
);
389 if (SbxVariable
const* pVar
= IsSbxVariable(pSBX
))
391 SbxDataType eType
= pVar
->GetType();
392 if ( static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxOBJECT
) )
393 // might cause a crash e. g. at the selections-object
394 // Type == Object does not mean pVar == Object!
395 ; // aHelpText = ((SbxObject*)pVar)->GetClassName();
396 else if ( eType
& SbxARRAY
)
397 ; // aHelpText = "{...}";
398 else if ( static_cast<sal_uInt8
>(eType
) != sal_uInt8(SbxEMPTY
) )
400 aHelpText
= pVar
->GetName();
401 if ( aHelpText
.isEmpty() ) // name is not copied with the passed parameters
403 aHelpText
+= "=" + pVar
->GetOUString();
406 if ( !aHelpText
.isEmpty() )
408 tools::Rectangle
aStartWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aStartOfWord
));
409 TextPaM
aEndOfWord(aStartOfWord
.GetPara(), aStartOfWord
.GetIndex() + aWord
.getLength());
410 tools::Rectangle
aEndWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aEndOfWord
));
411 aHelpRect
= aStartWordRect
.GetUnion(aEndWordRect
);
413 Point aTopLeft
= GetEditView()->GetWindowPos(aHelpRect
.TopLeft());
414 aTopLeft
= GetEditView()->GetWindow()->OutputToScreenPixel(aTopLeft
);
416 aHelpRect
.SetPos(aTopLeft
);
420 Help::ShowQuickHelp( this, aHelpRect
, aHelpText
, QuickHelpFlags::NONE
);
426 Window::RequestHelp( rHEvt
);
430 void EditorWindow::Resize()
432 // ScrollBars, etc. happens in Adjust...
436 tools::Long nVisY
= pEditView
->GetStartDocPos().Y();
438 pEditView
->ShowCursor();
439 Size
aOutSz( GetOutputSizePixel() );
440 tools::Long nMaxVisAreaStart
= pEditView
->GetTextEngine()->GetTextHeight() - aOutSz
.Height();
441 if ( nMaxVisAreaStart
< 0 )
442 nMaxVisAreaStart
= 0;
443 if ( pEditView
->GetStartDocPos().Y() > nMaxVisAreaStart
)
445 Point
aStartDocPos( pEditView
->GetStartDocPos() );
446 aStartDocPos
.setY( nMaxVisAreaStart
);
447 pEditView
->SetStartDocPos( aStartDocPos
);
448 pEditView
->ShowCursor();
449 rModulWindow
.GetBreakPointWindow().GetCurYOffset() = aStartDocPos
.Y();
450 rModulWindow
.GetLineNumberWindow().GetCurYOffset() = aStartDocPos
.Y();
453 if ( nVisY
!= pEditView
->GetStartDocPos().Y() )
458 void EditorWindow::MouseMove( const MouseEvent
&rEvt
)
461 pEditView
->MouseMove( rEvt
);
465 void EditorWindow::MouseButtonUp( const MouseEvent
&rEvt
)
469 pEditView
->MouseButtonUp( rEvt
);
470 if (SfxBindings
* pBindings
= GetBindingsPtr())
472 pBindings
->Invalidate( SID_BASICIDE_STAT_POS
);
473 pBindings
->Invalidate( SID_BASICIDE_STAT_TITLE
);
478 void EditorWindow::MouseButtonDown( const MouseEvent
&rEvt
)
483 pEditView
->MouseButtonDown(rEvt
);
484 if( pCodeCompleteWnd
->IsVisible() )
486 if (pEditView
->GetSelection() != pCodeCompleteWnd
->GetTextSelection())
488 //selection changed, code complete window should be hidden
489 pCodeCompleteWnd
->HideAndRestoreFocus();
494 void EditorWindow::Command( const CommandEvent
& rCEvt
)
499 pEditView
->Command( rCEvt
);
500 if ( ( rCEvt
.GetCommand() == CommandEventId::Wheel
) ||
501 ( rCEvt
.GetCommand() == CommandEventId::StartAutoScroll
) ||
502 ( rCEvt
.GetCommand() == CommandEventId::AutoScroll
) )
504 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
506 // Check if it is a Ctrl+Wheel zoom command
507 if (pData
&& pData
->IsMod1())
509 const sal_uInt16 nOldZoom
= GetCurrentZoom();
511 if( pData
->GetDelta() < 0 )
512 nNewZoom
= std::max
<sal_uInt16
>(basctl::Shell::GetMinZoom(),
513 basegfx::zoomtools::zoomOut(nOldZoom
));
515 nNewZoom
= std::min
<sal_uInt16
>(basctl::Shell::GetMaxZoom(),
516 basegfx::zoomtools::zoomIn(nOldZoom
));
517 GetShell()->SetGlobalEditorZoomLevel(nNewZoom
);
520 HandleScrollCommand(rCEvt
, &rModulWindow
.GetEditHScrollBar(), &rModulWindow
.GetEditVScrollBar());
522 else if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
) {
523 SfxDispatcher
* pDispatcher
= GetDispatcher();
526 SfxDispatcher::ExecutePopup();
528 if( pCodeCompleteWnd
->IsVisible() ) // hide the code complete window
529 pCodeCompleteWnd
->ClearAndHide();
533 bool EditorWindow::ImpCanModify()
535 bool bCanModify
= true;
536 if ( StarBASIC::IsRunning() && rModulWindow
.GetBasicStatus().bIsRunning
)
538 // If in Trace-mode, abort the trace or refuse input
539 // Remove markers in the modules in Notify at Basic::Stopped
540 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(nullptr,
541 VclMessageType::Question
, VclButtonsType::OkCancel
,
542 IDEResId(RID_STR_WILLSTOPPRG
)));
543 if (xQueryBox
->run() == RET_OK
)
545 rModulWindow
.GetBasicStatus().bIsRunning
= false;
554 void EditorWindow::KeyInput( const KeyEvent
& rKEvt
)
556 if ( !pEditView
) // Happens in Win95
559 bool const bWasModified
= pEditEngine
->IsModified();
560 // see if there is an accelerator to be processed first
561 SfxViewShell
*pVS( SfxViewShell::Current());
562 bool bDone
= pVS
&& pVS
->KeyInput( rKEvt
);
564 if (pCodeCompleteWnd
->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn())
566 pCodeCompleteWnd
->HandleKeyInput(rKEvt
);
567 if( rKEvt
.GetKeyCode().GetCode() == KEY_UP
568 || rKEvt
.GetKeyCode().GetCode() == KEY_DOWN
569 || rKEvt
.GetKeyCode().GetCode() == KEY_TAB
570 || rKEvt
.GetKeyCode().GetCode() == KEY_POINT
)
574 if( (rKEvt
.GetKeyCode().GetCode() == KEY_SPACE
||
575 rKEvt
.GetKeyCode().GetCode() == KEY_TAB
||
576 rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
) && CodeCompleteOptions::IsAutoCorrectOn() )
581 if( rKEvt
.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() )
582 {//autoclose double quotes
583 HandleAutoCloseDoubleQuotes();
586 if( rKEvt
.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() )
587 {//autoclose parenthesis
588 HandleAutoCloseParen();
591 if( rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
&& CodeCompleteOptions::IsProcedureAutoCompleteOn() )
592 {//autoclose implementation
593 HandleProcedureCompletion();
596 if( rKEvt
.GetKeyCode().GetCode() == KEY_POINT
&& CodeCompleteOptions::IsCodeCompleteOn() )
598 HandleCodeCompletion();
600 if ( !bDone
&& ( !TextEngine::DoesKeyChangeText( rKEvt
) || ImpCanModify() ) )
602 if ( ( rKEvt
.GetKeyCode().GetCode() == KEY_TAB
) && !rKEvt
.GetKeyCode().IsMod1() &&
603 !rKEvt
.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() )
605 TextSelection
aSel( pEditView
->GetSelection() );
606 if ( aSel
.GetStart().GetPara() != aSel
.GetEnd().GetPara() )
608 bDelayHighlight
= false;
609 if ( !rKEvt
.GetKeyCode().IsShift() )
610 pEditView
->IndentBlock();
612 pEditView
->UnindentBlock();
613 bDelayHighlight
= true;
618 bDone
= pEditView
->KeyInput( rKEvt
);
622 Window::KeyInput( rKEvt
);
626 if (SfxBindings
* pBindings
= GetBindingsPtr())
628 pBindings
->Invalidate( SID_BASICIDE_STAT_POS
);
629 pBindings
->Invalidate( SID_BASICIDE_STAT_TITLE
);
630 if ( rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_CURSOR
)
632 pBindings
->Update( SID_BASICIDE_STAT_POS
);
633 pBindings
->Update( SID_BASICIDE_STAT_TITLE
);
635 if ( rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_ALPHA
||
636 rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_NUM
)
638 // If the module is read-only, warn that it can't be edited
639 if ( rModulWindow
.IsReadOnly() )
640 rModulWindow
.ShowReadOnlyInfoBar();
642 if ( !bWasModified
&& pEditEngine
->IsModified() )
644 pBindings
->Invalidate( SID_SAVEDOC
);
645 pBindings
->Invalidate( SID_DOC_MODIFIED
);
646 pBindings
->Invalidate( SID_UNDO
);
648 if ( rKEvt
.GetKeyCode().GetCode() == KEY_INSERT
)
649 pBindings
->Invalidate( SID_ATTR_INSERT
);
654 void EditorWindow::HandleAutoCorrect()
656 TextSelection aSel
= GetEditView()->GetSelection();
657 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
658 const sal_Int32 nIndex
= aSel
.GetStart().GetIndex();
659 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
660 const OUString
& sActSubName
= GetActualSubName( nLine
); // the actual procedure
662 std::vector
<HighlightPortion
> aPortions
;
663 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
665 if( aPortions
.empty() )
668 HighlightPortion
& r
= aPortions
.back();
669 if( static_cast<size_t>(nIndex
) != aPortions
.size()-1 )
670 {//cursor is not standing at the end of the line
671 for (auto const& portion
: aPortions
)
673 if( portion
.nEnd
== nIndex
)
681 OUString sStr
= aLine
.copy( r
.nBegin
, r
.nEnd
- r
.nBegin
);
682 //if WS or empty string: stop, nothing to do
683 if( ( r
.tokenType
== TokenType::Whitespace
) || sStr
.isEmpty() )
685 //create the appropriate TextSelection, and update the cache
686 TextPaM
aStart( nLine
, r
.nBegin
);
687 TextPaM
aEnd( nLine
, r
.nBegin
+ sStr
.getLength() );
688 TextSelection
sTextSelection( aStart
, aEnd
);
689 rModulWindow
.UpdateModule();
690 rModulWindow
.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache
);
691 // correct the last entered keyword
692 if( r
.tokenType
== TokenType::Keywords
)
694 sStr
= sStr
.toAsciiLowerCase();
695 if( !SbModule::GetKeywordCase(sStr
).isEmpty() )
696 // if it is a keyword, get its correct case
697 sStr
= SbModule::GetKeywordCase(sStr
);
699 // else capitalize first letter/select the correct one, and replace
700 sStr
= sStr
.replaceAt( 0, 1, OUString(sStr
[0]).toAsciiUpperCase() );
702 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
703 pEditView
->SetSelection( aSel
);
705 if( r
.tokenType
!= TokenType::Identifier
)
709 if( !aCodeCompleteCache
.GetCorrectCaseVarName( sStr
, sActSubName
).isEmpty() )
711 sStr
= aCodeCompleteCache
.GetCorrectCaseVarName( sStr
, sActSubName
);
712 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
713 pEditView
->SetSelection( aSel
);
717 //autocorrect procedures
718 SbxArray
* pArr
= rModulWindow
.GetSbModule()->GetMethods().get();
719 for (sal_uInt32 i
= 0; i
< pArr
->Count(); ++i
)
721 if (pArr
->Get(i
)->GetName().equalsIgnoreAsciiCase(sStr
))
723 sStr
= pArr
->Get(i
)->GetName(); //if found, get the correct case
724 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
725 pEditView
->SetSelection( aSel
);
732 TextSelection
EditorWindow::GetLastHighlightPortionTextSelection() const
733 {//creates a text selection from the highlight portion on the cursor
734 const sal_uInt32 nLine
= GetEditView()->GetSelection().GetStart().GetPara();
735 const sal_Int32 nIndex
= GetEditView()->GetSelection().GetStart().GetIndex();
736 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
737 std::vector
<HighlightPortion
> aPortions
;
738 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
740 assert(!aPortions
.empty());
741 HighlightPortion
& r
= aPortions
.back();
742 if( static_cast<size_t>(nIndex
) != aPortions
.size()-1 )
743 {//cursor is not standing at the end of the line
744 for (auto const& portion
: aPortions
)
746 if( portion
.nEnd
== nIndex
)
754 if( aPortions
.empty() )
755 return TextSelection();
757 std::u16string_view sStr
= aLine
.subView( r
.nBegin
, r
.nEnd
- r
.nBegin
);
758 TextPaM
aStart( nLine
, r
.nBegin
);
759 TextPaM
aEnd( nLine
, r
.nBegin
+ sStr
.size() );
760 return TextSelection( aStart
, aEnd
);
763 void EditorWindow::HandleAutoCloseParen()
765 TextSelection aSel
= GetEditView()->GetSelection();
766 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
767 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
769 if( aLine
.getLength() > 0 && aLine
[aSel
.GetEnd().GetIndex()-1] != '(' )
771 GetEditView()->InsertText(")");
772 //leave the cursor on its place: inside the parenthesis
773 TextPaM
aEnd(nLine
, aSel
.GetEnd().GetIndex());
774 GetEditView()->SetSelection( TextSelection( aEnd
, aEnd
) );
778 void EditorWindow::HandleAutoCloseDoubleQuotes()
780 TextSelection aSel
= GetEditView()->GetSelection();
781 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
782 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
784 std::vector
<HighlightPortion
> aPortions
;
785 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
787 if( aPortions
.empty() )
790 if( aLine
.getLength() > 0 && !aLine
.endsWith("\"") && (aPortions
.back().tokenType
!= TokenType::String
) )
792 GetEditView()->InsertText("\"");
793 //leave the cursor on its place: inside the two double quotes
794 TextPaM
aEnd(nLine
, aSel
.GetEnd().GetIndex());
795 GetEditView()->SetSelection( TextSelection( aEnd
, aEnd
) );
799 void EditorWindow::HandleProcedureCompletion()
802 TextSelection aSel
= GetEditView()->GetSelection();
803 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
804 OUString
aLine( pEditEngine
->GetText( nLine
) );
808 bool bFoundName
= GetProcedureName(aLine
, sProcType
, sProcName
);
812 OUString
sText("\nEnd ");
813 aSel
= GetEditView()->GetSelection();
814 if( sProcType
.equalsIgnoreAsciiCase("function") )
815 sText
+= "Function\n";
816 if( sProcType
.equalsIgnoreAsciiCase("sub") )
819 if( nLine
+1 == pEditEngine
->GetParagraphCount() )
821 pEditView
->InsertText( sText
);//append to the end
822 GetEditView()->SetSelection(aSel
);
826 for( sal_uInt32 i
= nLine
+1; i
< pEditEngine
->GetParagraphCount(); ++i
)
827 {//searching forward for end token, or another sub/function definition
828 OUString aCurrLine
= pEditEngine
->GetText( i
);
829 std::vector
<HighlightPortion
> aCurrPortions
;
830 aHighlighter
.getHighlightPortions( aCurrLine
, aCurrPortions
);
832 if( aCurrPortions
.size() >= 3 )
833 {//at least 3 tokens: (sub|function) whitespace identifier...
834 HighlightPortion
& r
= aCurrPortions
.front();
835 std::u16string_view sStr
= aCurrLine
.subView(r
.nBegin
, r
.nEnd
- r
.nBegin
);
837 if( r
.tokenType
== TokenType::Keywords
)
839 if( o3tl::equalsIgnoreAsciiCase(sStr
, u
"sub") || o3tl::equalsIgnoreAsciiCase(sStr
, u
"function") )
841 pEditView
->InsertText( sText
);//append to the end
842 GetEditView()->SetSelection(aSel
);
845 if( o3tl::equalsIgnoreAsciiCase(sStr
, u
"end") )
853 bool EditorWindow::GetProcedureName(std::u16string_view rLine
, OUString
& rProcType
, OUString
& rProcName
) const
855 std::vector
<HighlightPortion
> aPortions
;
856 aHighlighter
.getHighlightPortions(rLine
, aPortions
);
858 if( aPortions
.empty() )
861 bool bFoundType
= false;
862 bool bFoundName
= false;
864 for (auto const& portion
: aPortions
)
866 std::u16string_view sTokStr
= rLine
.substr(portion
.nBegin
, portion
.nEnd
- portion
.nBegin
);
868 if( portion
.tokenType
== TokenType::Keywords
&& ( o3tl::equalsIgnoreAsciiCase(sTokStr
, u
"sub")
869 || o3tl::equalsIgnoreAsciiCase(sTokStr
, u
"function")) )
874 if( portion
.tokenType
== TokenType::Identifier
&& bFoundType
)
882 if( !bFoundType
|| !bFoundName
)
883 return false;// no sub/function keyword or there is no identifier
889 void EditorWindow::HandleCodeCompletion()
891 rModulWindow
.UpdateModule();
892 rModulWindow
.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache
);
893 TextSelection aSel
= GetEditView()->GetSelection();
894 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
895 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
896 std::vector
< OUString
> aVect
; //vector to hold the base variable+methods for the nested reflection
898 std::vector
<HighlightPortion
> aPortions
;
899 aLine
= aLine
.copy(0, aSel
.GetEnd().GetIndex());
900 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
901 if( aPortions
.empty() )
904 //use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod ..
905 for( std::vector
<HighlightPortion
>::reverse_iterator
i(
907 i
!= aPortions
.rend(); ++i
)
909 if( i
->tokenType
== TokenType::Whitespace
) // a whitespace: stop; if there is no ws, it goes to the beginning of the line
911 if( i
->tokenType
== TokenType::Identifier
|| i
->tokenType
== TokenType::Keywords
) // extract the identifiers(methods, base variable)
912 /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue
913 * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!)
915 aVect
.insert( aVect
.begin(), aLine
.copy(i
->nBegin
, i
->nEnd
- i
->nBegin
) );
918 if( aVect
.empty() )//nothing to do
921 OUString sBaseName
= aVect
[aVect
.size()-1];//variable name
922 OUString sVarType
= aCodeCompleteCache
.GetVarType( sBaseName
);
924 if( !sVarType
.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() )
925 {//correct variable name, if autocorrection on
926 const OUString
& sStr
= aCodeCompleteCache
.GetCorrectCaseVarName( sBaseName
, GetActualSubName(nLine
) );
927 if( !sStr
.isEmpty() )
929 TextPaM
aStart(nLine
, aSel
.GetStart().GetIndex() - sStr
.getLength() );
930 TextSelection
sTextSelection(aStart
, TextPaM(nLine
, aSel
.GetStart().GetIndex()));
931 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
932 pEditView
->SetSelection( aSel
);
936 UnoTypeCodeCompletetor
aTypeCompletor( aVect
, sVarType
);
938 if( !aTypeCompletor
.CanCodeComplete() )
941 std::vector
< OUString
> aEntryVect
;//entries to be inserted into the list
942 std::vector
< OUString
> aFieldVect
= aTypeCompletor
.GetXIdlClassFields();//fields
943 aEntryVect
.insert(aEntryVect
.end(), aFieldVect
.begin(), aFieldVect
.end() );
944 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
945 {// if extended types on, reflect classes, else just the structs (XIdlClass without methods)
946 std::vector
< OUString
> aMethVect
= aTypeCompletor
.GetXIdlClassMethods();//methods
947 aEntryVect
.insert(aEntryVect
.end(), aMethVect
.begin(), aMethVect
.end() );
949 if( !aEntryVect
.empty() )
950 SetupAndShowCodeCompleteWnd( aEntryVect
, aSel
);
953 void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector
< OUString
>& aEntryVect
, TextSelection aSel
)
956 pCodeCompleteWnd
->ClearListBox();
958 for(const auto & l
: aEntryVect
)
960 pCodeCompleteWnd
->InsertEntry( l
);
963 pCodeCompleteWnd
->Show();
964 pCodeCompleteWnd
->ResizeAndPositionListBox();
965 pCodeCompleteWnd
->SelectFirstEntry();
966 // correct text selection, and set it
967 ++aSel
.GetStart().GetIndex();
968 ++aSel
.GetEnd().GetIndex();
969 pCodeCompleteWnd
->SetTextSelection( aSel
);
970 //give the focus to the EditView
971 pEditView
->GetWindow()->GrabFocus();
974 void EditorWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
976 if (!pEditEngine
) // We need it now at latest
979 pEditView
->Paint(rRenderContext
, rRect
);
982 void EditorWindow::LoseFocus()
984 // tdf#114258 wait until the next event loop cycle to do this so it doesn't
985 // happen during a mouse down/up selection in the treeview whose contents
987 if (!m_nSetSourceInBasicId
)
988 m_nSetSourceInBasicId
= Application::PostUserEvent(LINK(this, EditorWindow
, SetSourceInBasicHdl
));
992 IMPL_LINK_NOARG(EditorWindow
, SetSourceInBasicHdl
, void*, void)
994 m_nSetSourceInBasicId
= nullptr;
998 void EditorWindow::SetSourceInBasic()
1000 if ( pEditEngine
&& pEditEngine
->IsModified()
1001 && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise
1002 // any read only bug in the text engine could lead to a crash later
1004 if ( !StarBASIC::IsRunning() ) // Not at runtime!
1006 rModulWindow
.UpdateModule();
1011 // Returns the position of the last character of any of the following
1012 // EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found
1013 sal_Int32
searchEOL( std::u16string_view rStr
, sal_Int32 fromIndex
)
1015 size_t iLF
= rStr
.find( LINE_SEP
, fromIndex
);
1016 if( iLF
!= std::u16string_view::npos
)
1019 size_t iCR
= rStr
.find( LINE_SEP_CR
, fromIndex
);
1020 return iCR
== std::u16string_view::npos
? -1 : iCR
;
1023 void EditorWindow::CreateEditEngine()
1028 pEditEngine
.reset(new ExtTextEngine
);
1029 pEditView
.reset(new TextView(pEditEngine
.get(), this));
1030 pEditView
->SetAutoIndentMode(true);
1031 pEditEngine
->SetUpdateMode(false);
1032 pEditEngine
->InsertView(pEditView
.get());
1036 aSyntaxIdle
.SetInvokeHandler( LINK( this, EditorWindow
, SyntaxTimerHdl
) );
1038 bool bWasDoSyntaxHighlight
= bDoSyntaxHighlight
;
1039 bDoSyntaxHighlight
= false; // too slow for large texts...
1040 OUString
aOUSource(rModulWindow
.GetModule());
1041 sal_Int32 nLines
= 0;
1042 sal_Int32 nIndex
= -1;
1046 nIndex
= searchEOL( aOUSource
, nIndex
+1 );
1048 while (nIndex
>= 0);
1050 // nLines*4: SetText+Formatting+DoHighlight+Formatting
1051 // it could be cut down on one formatting but you would wait even longer
1052 // for the text then if the source code is long...
1053 pProgress
.reset(new ProgressInfo(GetShell()->GetViewFrame().GetObjectShell(),
1054 IDEResId(RID_STR_GENERATESOURCE
),
1056 setTextEngineText(*pEditEngine
, aOUSource
);
1058 pEditView
->SetStartDocPos(Point(0, 0));
1059 pEditView
->SetSelection(TextSelection());
1060 rModulWindow
.GetBreakPointWindow().GetCurYOffset() = 0;
1061 rModulWindow
.GetLineNumberWindow().GetCurYOffset() = 0;
1062 pEditEngine
->SetUpdateMode(true);
1063 rModulWindow
.PaintImmediately(); // has only been invalidated at UpdateMode = true
1065 pEditView
->ShowCursor();
1067 StartListening(*pEditEngine
);
1070 bDoSyntaxHighlight
= bWasDoSyntaxHighlight
;
1072 for (sal_Int32 nLine
= 0; nLine
< nLines
; nLine
++)
1073 aSyntaxLineTable
.insert(nLine
);
1074 ForceSyntaxTimeout();
1078 pEditEngine
->SetModified( false );
1079 pEditEngine
->EnableUndo( true );
1083 if (SfxBindings
* pBindings
= GetBindingsPtr())
1085 pBindings
->Invalidate(SID_BASICIDE_STAT_POS
);
1086 pBindings
->Invalidate(SID_BASICIDE_STAT_TITLE
);
1089 DBG_ASSERT(rModulWindow
.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?");
1091 // set readonly mode for readonly libraries
1092 ScriptDocument
aDocument(rModulWindow
.GetDocument());
1093 OUString
aOULibName(rModulWindow
.GetLibName());
1094 Reference
< script::XLibraryContainer2
> xModLibContainer( aDocument
.getLibraryContainer( E_SCRIPTS
), UNO_QUERY
);
1095 if (xModLibContainer
.is()
1096 && xModLibContainer
->hasByName(aOULibName
)
1097 && xModLibContainer
->isLibraryReadOnly(aOULibName
))
1099 rModulWindow
.SetReadOnly(true);
1102 if (aDocument
.isDocument() && aDocument
.isReadOnly())
1103 rModulWindow
.SetReadOnly(true);
1106 void EditorWindow::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1108 TextHint
const* pTextHint
= dynamic_cast<TextHint
const*>(&rHint
);
1112 TextHint
const& rTextHint
= *pTextHint
;
1113 if( rTextHint
.GetId() == SfxHintId::TextViewScrolled
)
1115 rModulWindow
.GetEditVScrollBar().SetThumbPos( pEditView
->GetStartDocPos().Y() );
1116 rModulWindow
.GetEditHScrollBar().SetThumbPos( pEditView
->GetStartDocPos().X() );
1117 rModulWindow
.GetBreakPointWindow().DoScroll
1118 ( rModulWindow
.GetBreakPointWindow().GetCurYOffset() - pEditView
->GetStartDocPos().Y() );
1119 rModulWindow
.GetLineNumberWindow().DoScroll
1120 ( rModulWindow
.GetLineNumberWindow().GetCurYOffset() - pEditView
->GetStartDocPos().Y() );
1122 else if( rTextHint
.GetId() == SfxHintId::TextHeightChanged
)
1124 if ( pEditView
->GetStartDocPos().Y() )
1126 tools::Long nOutHeight
= GetOutputSizePixel().Height();
1127 tools::Long nTextHeight
= pEditEngine
->GetTextHeight();
1128 if ( nTextHeight
< nOutHeight
)
1129 pEditView
->Scroll( 0, pEditView
->GetStartDocPos().Y() );
1131 rModulWindow
.GetLineNumberWindow().Invalidate();
1134 SetScrollBarRanges();
1136 else if( rTextHint
.GetId() == SfxHintId::TextFormatted
)
1139 const tools::Long nWidth
= pEditEngine
->CalcTextWidth();
1140 if ( nWidth
!= nCurTextWidth
)
1142 nCurTextWidth
= nWidth
;
1143 rModulWindow
.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth
-1) );
1144 rModulWindow
.GetEditHScrollBar().SetThumbPos( pEditView
->GetStartDocPos().X() );
1146 tools::Long nPrevTextWidth
= nCurTextWidth
;
1147 nCurTextWidth
= pEditEngine
->CalcTextWidth();
1148 if ( nCurTextWidth
!= nPrevTextWidth
)
1149 SetScrollBarRanges();
1151 else if( rTextHint
.GetId() == SfxHintId::TextParaInserted
)
1153 ParagraphInsertedDeleted( rTextHint
.GetValue(), true );
1154 DoDelayedSyntaxHighlight( rTextHint
.GetValue() );
1156 else if( rTextHint
.GetId() == SfxHintId::TextParaRemoved
)
1158 ParagraphInsertedDeleted( rTextHint
.GetValue(), false );
1160 else if( rTextHint
.GetId() == SfxHintId::TextParaContentChanged
)
1162 DoDelayedSyntaxHighlight( rTextHint
.GetValue() );
1164 else if( rTextHint
.GetId() == SfxHintId::TextViewSelectionChanged
)
1166 if (SfxBindings
* pBindings
= GetBindingsPtr())
1168 pBindings
->Invalidate( SID_CUT
);
1169 pBindings
->Invalidate( SID_COPY
);
1174 OUString
EditorWindow::GetActualSubName( sal_uInt32 nLine
)
1176 SbxArrayRef pMethods
= rModulWindow
.GetSbModule()->GetMethods();
1177 for (sal_uInt32 i
= 0; i
< pMethods
->Count(); i
++)
1179 SbMethod
* pMeth
= dynamic_cast<SbMethod
*>(pMethods
->Get(i
));
1183 pMeth
->GetLineRange(l1
,l2
);
1184 if( (l1
<= nLine
+1) && (nLine
+1 <= l2
) )
1186 return pMeth
->GetName();
1193 void EditorWindow::SetScrollBarRanges()
1195 // extra method, not InitScrollBars, because for EditEngine events too
1199 rModulWindow
.GetEditVScrollBar().SetRange( Range( 0, pEditEngine
->GetTextHeight()-1 ) );
1200 rModulWindow
.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth
-1 ) );
1203 void EditorWindow::InitScrollBars()
1208 SetScrollBarRanges();
1209 Size
aOutSz(GetOutputSizePixel());
1210 rModulWindow
.GetEditVScrollBar().SetVisibleSize(aOutSz
.Height());
1211 rModulWindow
.GetEditVScrollBar().SetPageSize(aOutSz
.Height() * 8 / 10);
1212 rModulWindow
.GetEditVScrollBar().SetLineSize(GetTextHeight());
1213 rModulWindow
.GetEditVScrollBar().SetThumbPos(pEditView
->GetStartDocPos().Y());
1214 rModulWindow
.GetEditVScrollBar().Show();
1216 rModulWindow
.GetEditHScrollBar().SetVisibleSize(aOutSz
.Width());
1217 rModulWindow
.GetEditHScrollBar().SetPageSize(aOutSz
.Width() * 8 / 10);
1218 rModulWindow
.GetEditHScrollBar().SetLineSize(GetTextWidth( "x" ));
1219 rModulWindow
.GetEditHScrollBar().SetThumbPos(pEditView
->GetStartDocPos().X());
1220 rModulWindow
.GetEditHScrollBar().Show();
1223 void EditorWindow::ImpDoHighlight( sal_uInt32 nLine
)
1225 if ( !bDoSyntaxHighlight
)
1228 OUString
aLine( pEditEngine
->GetText( nLine
) );
1229 bool const bWasModified
= pEditEngine
->IsModified();
1230 pEditEngine
->RemoveAttribs( nLine
);
1231 std::vector
<HighlightPortion
> aPortions
;
1232 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
1234 for (auto const& portion
: aPortions
)
1236 Color
const aColor
= rModulWindow
.GetLayout().GetSyntaxColor(portion
.tokenType
);
1237 pEditEngine
->SetAttrib(TextAttribFontColor(aColor
), nLine
, portion
.nBegin
, portion
.nEnd
);
1240 pEditEngine
->SetModified(bWasModified
);
1243 void EditorWindow::ChangeFontColor( Color aColor
)
1247 vcl::Font
aFont(pEditEngine
->GetFont());
1248 aFont
.SetColor(aColor
);
1249 pEditEngine
->SetFont(aFont
);
1253 void EditorWindow::UpdateSyntaxHighlighting ()
1257 const sal_uInt32 nCount
= pEditEngine
->GetParagraphCount();
1258 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
1259 DoDelayedSyntaxHighlight(i
);
1263 void EditorWindow::ImplSetFont()
1265 // Get default font name and height defined in the Options dialog
1266 OUString
sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString()));
1267 if (sFontName
.isEmpty())
1269 vcl::Font
aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED
,
1270 Application::GetSettings().GetUILanguageTag().getLanguageType(),
1271 GetDefaultFontFlags::NONE
, GetOutDev()));
1272 sFontName
= aTmpFont
.GetFamilyName();
1274 sal_uInt16 nDefaultFontHeight
= officecfg::Office::Common::Font::SourceViewFont::FontHeight::get();
1276 // Calculate font size considering zoom level
1277 sal_uInt16 nNewFontHeight
= nDefaultFontHeight
* (static_cast<float>(nCurrentZoomLevel
) / 100);
1278 Size
aFontSize(0, nNewFontHeight
);
1280 vcl::Font
aFont(sFontName
, aFontSize
);
1281 aFont
.SetColor(rModulWindow
.GetLayout().GetFontColor());
1282 SetPointFont(*GetOutDev(), aFont
); // FIXME RenderContext
1285 rModulWindow
.GetBreakPointWindow().SetFont(aFont
);
1286 rModulWindow
.GetLineNumberWindow().SetFont(aFont
);
1287 rModulWindow
.Invalidate();
1291 bool const bModified
= pEditEngine
->IsModified();
1292 pEditEngine
->SetFont(aFont
);
1293 pEditEngine
->SetModified(bModified
);
1297 if (SfxBindings
* pBindings
= GetBindingsPtr())
1299 pBindings
->Invalidate( SID_BASICIDE_CURRENT_ZOOM
);
1300 pBindings
->Invalidate( SID_ATTR_ZOOMSLIDER
);
1304 void EditorWindow::SetEditorZoomLevel(sal_uInt16 nNewZoomLevel
)
1306 if (nCurrentZoomLevel
== nNewZoomLevel
)
1309 if (nNewZoomLevel
< MIN_ZOOM_LEVEL
|| nNewZoomLevel
> MAX_ZOOM_LEVEL
)
1312 nCurrentZoomLevel
= nNewZoomLevel
;
1316 void EditorWindow::DoSyntaxHighlight( sal_uInt32 nPara
)
1318 // because of the DelayedSyntaxHighlight it's possible
1319 // that this line does not exist anymore!
1320 if ( nPara
< pEditEngine
->GetParagraphCount() )
1322 // unfortunately I'm not sure that exactly this line does Modified()...
1324 pProgress
->StepProgress();
1325 ImpDoHighlight( nPara
);
1329 void EditorWindow::DoDelayedSyntaxHighlight( sal_uInt32 nPara
)
1331 // line is only added to list, processed in TimerHdl
1332 // => don't manipulate breaks while EditEngine is formatting
1334 pProgress
->StepProgress();
1336 if ( !bHighlighting
&& bDoSyntaxHighlight
)
1338 if ( bDelayHighlight
)
1340 aSyntaxLineTable
.insert( nPara
);
1341 aSyntaxIdle
.Start();
1344 DoSyntaxHighlight( nPara
);
1348 IMPL_LINK_NOARG(EditorWindow
, SyntaxTimerHdl
, Timer
*, void)
1350 DBG_ASSERT( pEditView
, "Not yet a View, but Syntax-Highlight?!" );
1352 bool const bWasModified
= pEditEngine
->IsModified();
1353 //pEditEngine->SetUpdateMode(false);
1355 bHighlighting
= true;
1356 for (auto const& syntaxLine
: aSyntaxLineTable
)
1358 DoSyntaxHighlight(syntaxLine
);
1363 pEditView
->ShowCursor( false );
1365 pEditEngine
->SetModified( bWasModified
);
1367 aSyntaxLineTable
.clear();
1368 bHighlighting
= false;
1371 void EditorWindow::ParagraphInsertedDeleted( sal_uInt32 nPara
, bool bInserted
)
1374 pProgress
->StepProgress();
1376 if ( !bInserted
&& ( nPara
== TEXT_PARA_ALL
) )
1378 rModulWindow
.GetBreakPoints().reset();
1379 rModulWindow
.GetBreakPointWindow().Invalidate();
1380 rModulWindow
.GetLineNumberWindow().Invalidate();
1384 rModulWindow
.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16
>(nPara
)+1, bInserted
);
1386 tools::Long nLineHeight
= GetTextHeight();
1387 Size aSz
= rModulWindow
.GetBreakPointWindow().GetOutDev()->GetOutputSize();
1388 tools::Rectangle
aInvRect( Point( 0, 0 ), aSz
);
1389 tools::Long nY
= nPara
*nLineHeight
- rModulWindow
.GetBreakPointWindow().GetCurYOffset();
1390 aInvRect
.SetTop( nY
);
1391 rModulWindow
.GetBreakPointWindow().Invalidate( aInvRect
);
1393 Size
aLnSz(rModulWindow
.GetLineNumberWindow().GetWidth(),
1394 GetOutputSizePixel().Height() - 2 * DWBORDER
);
1395 rModulWindow
.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER
+ 19, DWBORDER
), aLnSz
);
1396 rModulWindow
.GetLineNumberWindow().Invalidate();
1400 void EditorWindow::CreateProgress( const OUString
& rText
, sal_uInt32 nRange
)
1402 DBG_ASSERT( !pProgress
, "ProgressInfo exists already" );
1403 pProgress
.reset(new ProgressInfo(
1404 GetShell()->GetViewFrame().GetObjectShell(),
1410 void EditorWindow::DestroyProgress()
1415 void EditorWindow::ForceSyntaxTimeout()
1418 aSyntaxIdle
.Invoke();
1421 FactoryFunction
EditorWindow::GetUITestFactory() const
1423 return EditorWindowUIObject::create
;
1429 BreakPointWindow::BreakPointWindow (vcl::Window
* pParent
, ModulWindow
* pModulWindow
)
1430 : Window(pParent
, WB_BORDER
)
1431 , rModulWindow(*pModulWindow
)
1432 , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine
1433 , nMarkerPos(NoMarker
)
1434 , bErrorMarker(false)
1436 setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor());
1437 SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW
);
1440 void BreakPointWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1445 Size
const aOutSz
= rRenderContext
.GetOutputSize();
1446 tools::Long
const nLineHeight
= rRenderContext
.GetTextHeight();
1448 Image
const aBrk
[2] =
1450 GetImage(RID_BMP_BRKDISABLED
),
1451 GetImage(RID_BMP_BRKENABLED
)
1454 Size
const aBmpSz
= rRenderContext
.PixelToLogic(aBrk
[1].GetSizePixel());
1455 Point
const aBmpOff((aOutSz
.Width() - aBmpSz
.Width()) / 2,
1456 (nLineHeight
- aBmpSz
.Height()) / 2);
1458 for (size_t i
= 0, n
= GetBreakPoints().size(); i
< n
; ++i
)
1460 BreakPoint
& rBrk
= GetBreakPoints().at(i
);
1461 sal_uInt16
const nLine
= rBrk
.nLine
- 1;
1462 size_t const nY
= nLine
*nLineHeight
- nCurYOffset
;
1463 rRenderContext
.DrawImage(Point(0, nY
) + aBmpOff
, aBrk
[rBrk
.bEnabled
]);
1466 ShowMarker(rRenderContext
);
1469 void BreakPointWindow::ShowMarker(vcl::RenderContext
& rRenderContext
)
1471 if (nMarkerPos
== NoMarker
)
1474 Size
const aOutSz
= GetOutDev()->GetOutputSize();
1475 tools::Long
const nLineHeight
= GetTextHeight();
1477 Image aMarker
= GetImage(bErrorMarker
? RID_BMP_ERRORMARKER
: RID_BMP_STEPMARKER
);
1479 Size
aMarkerSz(aMarker
.GetSizePixel());
1480 aMarkerSz
= rRenderContext
.PixelToLogic(aMarkerSz
);
1481 Point
aMarkerOff(0, 0);
1482 aMarkerOff
.setX( (aOutSz
.Width() - aMarkerSz
.Width()) / 2 );
1483 aMarkerOff
.setY( (nLineHeight
- aMarkerSz
.Height()) / 2 );
1485 tools::Long nY
= nMarkerPos
* nLineHeight
- nCurYOffset
;
1489 rRenderContext
.DrawImage(aPos
, aMarker
);
1492 void BreakPointWindow::DoScroll( tools::Long nVertScroll
)
1494 nCurYOffset
-= nVertScroll
;
1495 Window::Scroll( 0, nVertScroll
);
1498 void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine
, bool bError
)
1500 if ( SyncYOffset() )
1504 bErrorMarker
= bError
;
1508 void BreakPointWindow::SetNoMarker ()
1510 SetMarkerPos(NoMarker
);
1513 BreakPoint
* BreakPointWindow::FindBreakPoint( const Point
& rMousePos
)
1515 size_t nLineHeight
= GetTextHeight();
1516 nLineHeight
= nLineHeight
> 0 ? nLineHeight
: 1;
1517 size_t nYPos
= rMousePos
.Y() + nCurYOffset
;
1519 for ( size_t i
= 0, n
= GetBreakPoints().size(); i
< n
; ++i
)
1521 BreakPoint
& rBrk
= GetBreakPoints().at( i
);
1522 sal_uInt16 nLine
= rBrk
.nLine
-1;
1523 size_t nY
= nLine
*nLineHeight
;
1524 if ( ( nYPos
> nY
) && ( nYPos
< ( nY
+ nLineHeight
) ) )
1530 void BreakPointWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
1532 if ( rMEvt
.GetClicks() == 2 )
1534 Point
aMousePos( PixelToLogic( rMEvt
.GetPosPixel() ) );
1535 tools::Long nLineHeight
= GetTextHeight();
1538 tools::Long nYPos
= aMousePos
.Y() + nCurYOffset
;
1539 tools::Long nLine
= nYPos
/ nLineHeight
+ 1;
1540 rModulWindow
.ToggleBreakPoint( static_cast<sal_uInt16
>(nLine
) );
1546 void BreakPointWindow::Command( const CommandEvent
& rCEvt
)
1548 if ( rCEvt
.GetCommand() != CommandEventId::ContextMenu
)
1551 Point
aPos( rCEvt
.IsMouseEvent() ? rCEvt
.GetMousePosPixel() : Point(1,1) );
1552 tools::Rectangle
aRect(aPos
, Size(1, 1));
1553 weld::Window
* pPopupParent
= weld::GetPopupParent(*this, aRect
);
1555 std::unique_ptr
<weld::Builder
> xUIBuilder(Application::CreateBuilder(pPopupParent
, "modules/BasicIDE/ui/breakpointmenus.ui"));
1557 Point
aEventPos( PixelToLogic( aPos
) );
1558 BreakPoint
* pBrk
= rCEvt
.IsMouseEvent() ? FindBreakPoint( aEventPos
) : nullptr;
1561 // test if break point is enabled...
1562 std::unique_ptr
<weld::Menu
> xBrkPropMenu
= xUIBuilder
->weld_menu("breakmenu");
1563 xBrkPropMenu
->set_active("active", pBrk
->bEnabled
);
1564 OUString sCommand
= xBrkPropMenu
->popup_at_rect(pPopupParent
, aRect
);
1565 if (sCommand
== "active")
1567 pBrk
->bEnabled
= !pBrk
->bEnabled
;
1568 rModulWindow
.UpdateBreakPoint( *pBrk
);
1571 else if (sCommand
== "properties")
1573 BreakPointDialog
aBrkDlg(pPopupParent
, GetBreakPoints());
1574 aBrkDlg
.SetCurrentBreakPoint( *pBrk
);
1581 std::unique_ptr
<weld::Menu
> xBrkListMenu
= xUIBuilder
->weld_menu("breaklistmenu");
1582 OUString sCommand
= xBrkListMenu
->popup_at_rect(pPopupParent
, aRect
);
1583 if (sCommand
== "manage")
1585 BreakPointDialog
aBrkDlg(pPopupParent
, GetBreakPoints());
1592 bool BreakPointWindow::SyncYOffset()
1594 TextView
* pView
= rModulWindow
.GetEditView();
1597 tools::Long nViewYOffset
= pView
->GetStartDocPos().Y();
1598 if ( nCurYOffset
!= nViewYOffset
)
1600 nCurYOffset
= nViewYOffset
;
1609 void BreakPointWindow::DataChanged(DataChangedEvent
const & rDCEvt
)
1611 Window::DataChanged(rDCEvt
);
1612 if (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
1613 && (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
1615 Color
aColor(GetSettings().GetStyleSettings().GetFieldColor());
1616 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
1617 if (!pOldSettings
|| aColor
!= pOldSettings
->GetStyleSettings().GetFieldColor())
1619 setBackgroundColor(aColor
);
1625 void BreakPointWindow::setBackgroundColor(Color aColor
)
1627 SetBackground(Wallpaper(aColor
));
1635 OUString maDisplayName
;
1636 SbxObjectRef mpObject
;
1637 std::vector
<OUString
> maMemberList
;
1639 SbxDimArrayRef mpArray
;
1640 int nDimLevel
; // 0 = Root
1642 std::vector
<sal_Int32
> vIndices
;
1644 WatchItem
* mpArrayParentItem
;
1646 explicit WatchItem (OUString aName
):
1647 maName(std::move(aName
)),
1650 mpArrayParentItem(nullptr)
1653 void clearWatchItem ()
1655 maMemberList
.clear();
1658 WatchItem
* GetRootItem();
1659 SbxDimArray
* GetRootArray();
1664 WatchWindow::WatchWindow(Layout
* pParent
)
1665 : DockingWindow(pParent
, "modules/BasicIDE/ui/dockingwatch.ui", "DockingWatch")
1666 , m_nUpdateWatchesId(nullptr)
1668 m_xTitleArea
= m_xBuilder
->weld_container("titlearea");
1670 nVirtToolBoxHeight
= m_xTitleArea
->get_preferred_size().Height();
1672 m_xTitle
= m_xBuilder
->weld_label("title");
1673 m_xTitle
->set_label(IDEResId(RID_STR_REMOVEWATCH
));
1675 m_xEdit
= m_xBuilder
->weld_entry("edit");
1676 m_xRemoveWatchButton
= m_xBuilder
->weld_button("remove");
1677 m_xTreeListBox
= m_xBuilder
->weld_tree_view("treeview");
1679 m_xEdit
->set_accessible_name(IDEResId(RID_STR_WATCHNAME
));
1680 m_xEdit
->set_help_id(HID_BASICIDE_WATCHWINDOW_EDIT
);
1681 m_xEdit
->set_size_request(LogicToPixel(Size(80, 0), MapMode(MapUnit::MapAppFont
)).Width(), -1);
1682 m_xEdit
->connect_activate(LINK( this, WatchWindow
, ActivateHdl
));
1683 m_xEdit
->connect_key_press(LINK( this, WatchWindow
, KeyInputHdl
));
1684 m_xTreeListBox
->set_accessible_name(IDEResId(RID_STR_WATCHNAME
));
1686 m_xRemoveWatchButton
->set_sensitive(false);
1687 m_xRemoveWatchButton
->connect_clicked(LINK( this, WatchWindow
, ButtonHdl
));
1688 m_xRemoveWatchButton
->set_help_id(HID_BASICIDE_REMOVEWATCH
);
1689 m_xRemoveWatchButton
->set_tooltip_text(IDEResId(RID_STR_REMOVEWATCHTIP
));
1691 m_xTreeListBox
->set_help_id(HID_BASICIDE_WATCHWINDOW_LIST
);
1692 m_xTreeListBox
->connect_editing(LINK(this, WatchWindow
, EditingEntryHdl
),
1693 LINK(this, WatchWindow
, EditedEntryHdl
));
1694 m_xTreeListBox
->connect_changed( LINK( this, WatchWindow
, TreeListHdl
) );
1695 m_xTreeListBox
->connect_expanding(LINK(this, WatchWindow
, RequestingChildrenHdl
));
1697 // VarTabWidth, ValueTabWidth, TypeTabWidth
1698 std::vector
<int> aWidths
{ 220, 100, 1250 };
1699 std::vector
<bool> aEditables
{ false, true, false };
1700 m_xTreeListBox
->set_column_fixed_widths(aWidths
);
1701 m_xTreeListBox
->set_column_editables(aEditables
);
1703 SetText(IDEResId(RID_STR_WATCHNAME
));
1705 SetHelpId( HID_BASICIDE_WATCHWINDOW
);
1707 // make watch window keyboard accessible
1708 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1711 WatchWindow::~WatchWindow()
1716 void WatchWindow::dispose()
1718 if (m_nUpdateWatchesId
)
1720 Application::RemoveUserEvent(m_nUpdateWatchesId
);
1721 m_nUpdateWatchesId
= nullptr;
1724 // Destroy user data
1725 m_xTreeListBox
->all_foreach([this](weld::TreeIter
& rEntry
){
1726 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
1733 m_xRemoveWatchButton
.reset();
1734 m_xTitleArea
.reset();
1735 m_xTreeListBox
.reset();
1736 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1737 DockingWindow::dispose();
1740 void WatchWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1742 lcl_DrawIDEWindowFrame(this, rRenderContext
);
1745 void WatchWindow::Resize()
1747 Size aSz
= GetOutputSizePixel();
1748 Size
aBoxSz(aSz
.Width() - 2*DWBORDER
, aSz
.Height() - 2*DWBORDER
);
1750 if ( aBoxSz
.Width() < 4 )
1751 aBoxSz
.setWidth( 0 );
1752 if ( aBoxSz
.Height() < 4 )
1753 aBoxSz
.setHeight( 0 );
1755 m_xBox
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBoxSz
);
1760 WatchItem
* WatchItem::GetRootItem()
1762 WatchItem
* pItem
= mpArrayParentItem
;
1765 if( pItem
->mpArray
.is() )
1767 pItem
= pItem
->mpArrayParentItem
;
1772 SbxDimArray
* WatchItem::GetRootArray()
1774 WatchItem
* pRootItem
= GetRootItem();
1775 SbxDimArray
* pRet
= nullptr;
1777 pRet
= pRootItem
->mpArray
.get();
1781 void WatchWindow::AddWatch( const OUString
& rVName
)
1783 OUString aVar
, aIndex
;
1784 lcl_SeparateNameAndIndex( rVName
, aVar
, aIndex
);
1785 WatchItem
* pWatchItem
= new WatchItem(aVar
);
1787 OUString
sId(weld::toId(pWatchItem
));
1788 std::unique_ptr
<weld::TreeIter
> xRet
= m_xTreeListBox
->make_iterator();
1789 m_xTreeListBox
->insert(nullptr, -1, &aVar
, &sId
, nullptr, nullptr, false, xRet
.get());
1790 m_xTreeListBox
->set_text(*xRet
, "", 1);
1791 m_xTreeListBox
->set_text(*xRet
, "", 2);
1793 m_xTreeListBox
->set_cursor(*xRet
);
1794 m_xTreeListBox
->select(*xRet
);
1795 m_xTreeListBox
->scroll_to_row(*xRet
);
1796 m_xRemoveWatchButton
->set_sensitive(true);
1798 UpdateWatches(false);
1801 void WatchWindow::RemoveSelectedWatch()
1803 std::unique_ptr
<weld::TreeIter
> xEntry
= m_xTreeListBox
->make_iterator();
1804 bool bEntry
= m_xTreeListBox
->get_cursor(xEntry
.get());
1807 m_xTreeListBox
->remove(*xEntry
);
1808 bEntry
= m_xTreeListBox
->get_cursor(xEntry
.get());
1810 m_xEdit
->set_text(weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xEntry
))->maName
);
1812 m_xEdit
->set_text(OUString());
1813 if ( !m_xTreeListBox
->n_children() )
1814 m_xRemoveWatchButton
->set_sensitive(false);
1818 IMPL_STATIC_LINK_NOARG(WatchWindow
, ButtonHdl
, weld::Button
&, void)
1820 if (SfxDispatcher
* pDispatcher
= GetDispatcher())
1821 pDispatcher
->Execute(SID_BASICIDE_REMOVEWATCH
);
1824 IMPL_LINK_NOARG(WatchWindow
, TreeListHdl
, weld::TreeView
&, void)
1826 std::unique_ptr
<weld::TreeIter
> xCurEntry
= m_xTreeListBox
->make_iterator();
1827 bool bCurEntry
= m_xTreeListBox
->get_cursor(xCurEntry
.get());
1830 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xCurEntry
));
1833 m_xEdit
->set_text(pItem
->maName
);
1836 IMPL_LINK_NOARG(WatchWindow
, ActivateHdl
, weld::Entry
&, bool)
1838 OUString
aCurText(m_xEdit
->get_text());
1839 if (!aCurText
.isEmpty())
1842 m_xEdit
->select_region(0, -1);
1847 IMPL_LINK(WatchWindow
, KeyInputHdl
, const KeyEvent
&, rKEvt
, bool)
1849 bool bHandled
= false;
1851 sal_uInt16 nKeyCode
= rKEvt
.GetKeyCode().GetCode();
1852 if (nKeyCode
== KEY_ESCAPE
)
1854 m_xEdit
->set_text(OUString());
1862 StackWindow::StackWindow(Layout
* pParent
)
1863 : DockingWindow(pParent
, "modules/BasicIDE/ui/dockingstack.ui", "DockingStack")
1865 m_xTitle
= m_xBuilder
->weld_label("title");
1866 m_xTitle
->set_label(IDEResId(RID_STR_STACK
));
1868 m_xTitle
->set_size_request(-1, nVirtToolBoxHeight
); // so the two title areas are the same height
1870 m_xTreeListBox
= m_xBuilder
->weld_tree_view("stack");
1872 m_xTreeListBox
->set_help_id(HID_BASICIDE_STACKWINDOW_LIST
);
1873 m_xTreeListBox
->set_accessible_name(IDEResId(RID_STR_STACKNAME
));
1874 m_xTreeListBox
->set_selection_mode(SelectionMode::NONE
);
1875 m_xTreeListBox
->append_text(OUString());
1877 SetText(IDEResId(RID_STR_STACKNAME
));
1879 SetHelpId( HID_BASICIDE_STACKWINDOW
);
1881 // make stack window keyboard accessible
1882 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1885 StackWindow::~StackWindow()
1890 void StackWindow::dispose()
1892 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1894 m_xTreeListBox
.reset();
1895 DockingWindow::dispose();
1898 void StackWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1900 lcl_DrawIDEWindowFrame(this, rRenderContext
);
1903 void StackWindow::Resize()
1905 Size aSz
= GetOutputSizePixel();
1906 Size
aBoxSz(aSz
.Width() - 2*DWBORDER
, aSz
.Height() - 2*DWBORDER
);
1908 if ( aBoxSz
.Width() < 4 )
1909 aBoxSz
.setWidth( 0 );
1910 if ( aBoxSz
.Height() < 4 )
1911 aBoxSz
.setHeight( 0 );
1913 m_xBox
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBoxSz
);
1918 void StackWindow::UpdateCalls()
1920 m_xTreeListBox
->freeze();
1921 m_xTreeListBox
->clear();
1923 if (StarBASIC::IsRunning())
1925 ErrCode eOld
= SbxBase::GetError();
1926 m_xTreeListBox
->set_selection_mode(SelectionMode::Single
);
1928 sal_Int32 nScope
= 0;
1929 SbMethod
* pMethod
= StarBASIC::GetActiveMethod( nScope
);
1932 OUStringBuffer
aEntry( OUString::number(nScope
));
1933 if ( aEntry
.getLength() < 2 )
1934 aEntry
.insert(0, " ");
1935 aEntry
.append(": " + pMethod
->GetName());
1936 SbxArray
* pParams
= pMethod
->GetParameters();
1937 SbxInfo
* pInfo
= pMethod
->GetInfo();
1941 // 0 is the sub's name...
1942 for (sal_uInt32 nParam
= 1; nParam
< pParams
->Count(); nParam
++)
1944 SbxVariable
* pVar
= pParams
->Get(nParam
);
1945 assert(pVar
&& "Parameter?!");
1946 if ( !pVar
->GetName().isEmpty() )
1948 aEntry
.append(pVar
->GetName());
1952 assert(nParam
<= std::numeric_limits
<sal_uInt16
>::max());
1953 const SbxParamInfo
* pParam
= pInfo
->GetParam( sal::static_int_cast
<sal_uInt16
>(nParam
) );
1956 aEntry
.append(pParam
->aName
);
1960 SbxDataType eType
= pVar
->GetType();
1961 if( eType
& SbxARRAY
)
1963 aEntry
.append("...");
1965 else if( eType
!= SbxOBJECT
)
1967 aEntry
.append(pVar
->GetOUString());
1969 if (nParam
< (pParams
->Count() - 1))
1971 aEntry
.append(", ");
1976 m_xTreeListBox
->append_text(aEntry
.makeStringAndClear());
1978 pMethod
= StarBASIC::GetActiveMethod( nScope
);
1981 SbxBase::ResetError();
1982 if( eOld
!= ERRCODE_NONE
)
1983 SbxBase::SetError( eOld
);
1987 m_xTreeListBox
->set_selection_mode(SelectionMode::NONE
);
1988 m_xTreeListBox
->append_text(OUString());
1991 m_xTreeListBox
->thaw();
1994 ComplexEditorWindow::ComplexEditorWindow( ModulWindow
* pParent
) :
1995 Window( pParent
, WB_3DLOOK
| WB_CLIPCHILDREN
),
1996 aBrkWindow(VclPtr
<BreakPointWindow
>::Create(this, pParent
)),
1997 aLineNumberWindow(VclPtr
<LineNumberWindow
>::Create(this, pParent
)),
1998 aEdtWindow(VclPtr
<EditorWindow
>::Create(this, pParent
)),
1999 aEWVScrollBar(VclPtr
<ScrollAdaptor
>::Create(this, false)),
2000 aEWHScrollBar(VclPtr
<ScrollAdaptor
>::Create(this, true))
2005 aEWVScrollBar
->SetLineSize(nScrollLine
);
2006 aEWVScrollBar
->SetPageSize(nScrollPage
);
2007 aEWVScrollBar
->SetScrollHdl( LINK( this, ComplexEditorWindow
, ScrollHdl
) );
2008 aEWVScrollBar
->Show();
2010 aEWHScrollBar
->SetLineSize(nScrollLine
);
2011 aEWHScrollBar
->SetPageSize(nScrollPage
);
2012 aEWHScrollBar
->SetScrollHdl( LINK( this, ComplexEditorWindow
, ScrollHdl
) );
2013 aEWHScrollBar
->Show();
2016 ComplexEditorWindow::~ComplexEditorWindow()
2021 void ComplexEditorWindow::dispose()
2023 aBrkWindow
.disposeAndClear();
2024 aLineNumberWindow
.disposeAndClear();
2025 aEdtWindow
.disposeAndClear();
2026 aEWVScrollBar
.disposeAndClear();
2027 aEWHScrollBar
.disposeAndClear();
2028 vcl::Window::dispose();
2031 void ComplexEditorWindow::Resize()
2033 Size aOutSz
= GetOutputSizePixel();
2035 aSz
.AdjustWidth( -(2*DWBORDER
) );
2036 aSz
.AdjustHeight( -(2*DWBORDER
) );
2037 tools::Long nBrkWidth
= 20;
2038 tools::Long nSBWidth
= aEWVScrollBar
->GetSizePixel().Width();
2039 tools::Long nSBHeight
= aEWHScrollBar
->GetSizePixel().Height();
2041 Size
aBrkSz(nBrkWidth
, aSz
.Height() - nSBHeight
);
2043 if (aLineNumberWindow
->IsVisible())
2045 Size
aLnSz(aLineNumberWindow
->GetWidth(), aSz
.Height() - nSBHeight
);
2046 Size
aEWSz(aSz
.Width() - nBrkWidth
- aLineNumberWindow
->GetWidth() - nSBWidth
, aSz
.Height() - nSBHeight
);
2047 aBrkWindow
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBrkSz
);
2048 aLineNumberWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
, DWBORDER
), aLnSz
);
2049 aEdtWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
+ aLnSz
.Width(), DWBORDER
), aEWSz
);
2053 Size
aEWSz(aSz
.Width() - nBrkWidth
- nSBWidth
, aSz
.Height() - nSBHeight
);
2054 aBrkWindow
->SetPosSizePixel( Point( DWBORDER
, DWBORDER
), aBrkSz
);
2055 aEdtWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
, DWBORDER
), aEWSz
);
2058 aEWVScrollBar
->SetPosSizePixel(Point(aOutSz
.Width() - DWBORDER
- nSBWidth
, DWBORDER
),
2059 Size(nSBWidth
, aSz
.Height() - nSBHeight
));
2060 aEWHScrollBar
->SetPosSizePixel(Point(DWBORDER
, aOutSz
.Height() - DWBORDER
- nSBHeight
),
2061 Size(aSz
.Width() - nSBWidth
, nSBHeight
));
2064 IMPL_LINK_NOARG(ComplexEditorWindow
, ScrollHdl
, weld::Scrollbar
&, void)
2066 if (aEdtWindow
->GetEditView())
2068 tools::Long nXDiff
= aEdtWindow
->GetEditView()->GetStartDocPos().X() - aEWHScrollBar
->GetThumbPos();
2069 tools::Long nYDiff
= aEdtWindow
->GetEditView()->GetStartDocPos().Y() - aEWVScrollBar
->GetThumbPos();
2070 aEdtWindow
->GetEditView()->Scroll(nXDiff
, nYDiff
);
2071 aBrkWindow
->DoScroll( nYDiff
);
2072 aLineNumberWindow
->DoScroll( nYDiff
);
2073 aEdtWindow
->GetEditView()->ShowCursor(false);
2074 aEWVScrollBar
->SetThumbPos( aEdtWindow
->GetEditView()->GetStartDocPos().Y() );
2078 void ComplexEditorWindow::DataChanged(DataChangedEvent
const & rDCEvt
)
2080 Window::DataChanged(rDCEvt
);
2081 if (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
2082 && (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
2084 Color
aColor(GetSettings().GetStyleSettings().GetFaceColor());
2085 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
2086 if (!pOldSettings
|| aColor
!= pOldSettings
->GetStyleSettings().GetFaceColor())
2088 SetBackground(Wallpaper(aColor
));
2094 void ComplexEditorWindow::SetLineNumberDisplay(bool b
)
2096 aLineNumberWindow
->Show(b
);
2100 uno::Reference
< awt::XVclWindowPeer
>
2101 EditorWindow::GetComponentInterface(bool bCreate
)
2103 uno::Reference
< awt::XVclWindowPeer
> xPeer(
2104 Window::GetComponentInterface(false));
2105 if (!xPeer
.is() && bCreate
)
2107 // Make sure edit engine and view are available:
2111 xPeer
= createTextWindowPeer(*GetEditView());
2112 SetComponentInterface(xPeer
);
2117 static sal_uInt32
getCorrectedPropCount(SbxArray
* p
)
2119 sal_uInt32 nPropCount
= p
->Count();
2120 if (nPropCount
>= 3 && p
->Get(nPropCount
- 1)->GetName().equalsIgnoreAsciiCase("Dbg_Methods")
2121 && p
->Get(nPropCount
- 2)->GetName().equalsIgnoreAsciiCase("Dbg_Properties")
2122 && p
->Get(nPropCount
- 3)->GetName().equalsIgnoreAsciiCase("Dbg_SupportedInterfaces"))
2129 IMPL_LINK(WatchWindow
, RequestingChildrenHdl
, const weld::TreeIter
&, rParent
, bool)
2131 if( !StarBASIC::IsRunning() )
2134 if (m_xTreeListBox
->iter_has_child(rParent
))
2137 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rParent
));
2138 std::unique_ptr
<weld::TreeIter
> xRet
= m_xTreeListBox
->make_iterator();
2140 SbxDimArray
* pArray
= pItem
->mpArray
.get();
2141 SbxDimArray
* pRootArray
= pItem
->GetRootArray();
2142 bool bArrayIsRootArray
= false;
2143 if( !pArray
&& pRootArray
)
2145 pArray
= pRootArray
;
2146 bArrayIsRootArray
= true;
2149 SbxObject
* pObj
= pItem
->mpObject
.get();
2152 createAllObjectProperties( pObj
);
2153 SbxArray
* pProps
= pObj
->GetProperties();
2154 const sal_uInt32 nPropCount
= getCorrectedPropCount(pProps
);
2155 pItem
->maMemberList
.reserve(nPropCount
);
2157 for( sal_uInt32 i
= 0 ; i
< nPropCount
; ++i
)
2159 SbxVariable
* pVar
= pProps
->Get(i
);
2161 pItem
->maMemberList
.push_back(pVar
->GetName());
2162 OUString
const& rName
= pItem
->maMemberList
.back();
2164 WatchItem
* pWatchItem
= new WatchItem(rName
);
2165 OUString
sId(weld::toId(pWatchItem
));
2167 m_xTreeListBox
->insert(&rParent
, -1, &rName
, &sId
, nullptr, nullptr, false, xRet
.get());
2168 m_xTreeListBox
->set_text(*xRet
, "", 1);
2169 m_xTreeListBox
->set_text(*xRet
, "", 2);
2172 if (nPropCount
> 0 && !m_nUpdateWatchesId
)
2174 m_nUpdateWatchesId
= Application::PostUserEvent(LINK(this, WatchWindow
, ExecuteUpdateWatches
));
2179 sal_uInt16 nElementCount
= 0;
2181 // Loop through indices of current level
2182 int nParentLevel
= bArrayIsRootArray
? pItem
->nDimLevel
: 0;
2183 int nThisLevel
= nParentLevel
+ 1;
2184 sal_Int32 nMin
, nMax
;
2185 if (pArray
->GetDim(nThisLevel
, nMin
, nMax
))
2187 for (sal_Int32 i
= nMin
; i
<= nMax
; i
++)
2189 WatchItem
* pChildItem
= new WatchItem(pItem
->maName
);
2191 // Copy data and create name
2193 OUStringBuffer aIndexStr
= "(";
2194 pChildItem
->mpArrayParentItem
= pItem
;
2195 pChildItem
->nDimLevel
= nThisLevel
;
2196 pChildItem
->nDimCount
= pItem
->nDimCount
;
2197 pChildItem
->vIndices
.resize(pChildItem
->nDimCount
);
2199 for (j
= 0; j
< nParentLevel
; j
++)
2201 sal_Int32 n
= pChildItem
->vIndices
[j
] = pItem
->vIndices
[j
];
2202 aIndexStr
.append( OUString::number(n
) + "," );
2204 pChildItem
->vIndices
[nParentLevel
] = i
;
2205 aIndexStr
.append( OUString::number(i
) + ")" );
2207 OUString aDisplayName
;
2208 WatchItem
* pArrayRootItem
= pChildItem
->GetRootItem();
2209 if (pArrayRootItem
&& pArrayRootItem
->mpArrayParentItem
)
2210 aDisplayName
= pItem
->maDisplayName
;
2212 aDisplayName
= pItem
->maName
;
2213 aDisplayName
+= aIndexStr
;
2214 pChildItem
->maDisplayName
= aDisplayName
;
2216 OUString
sId(weld::toId(pChildItem
));
2218 m_xTreeListBox
->insert(&rParent
, -1, &aDisplayName
, &sId
, nullptr, nullptr, false,
2220 m_xTreeListBox
->set_text(*xRet
, "", 1);
2221 m_xTreeListBox
->set_text(*xRet
, "", 2);
2226 if (nElementCount
> 0 && !m_nUpdateWatchesId
)
2228 m_nUpdateWatchesId
= Application::PostUserEvent(LINK(this, WatchWindow
, ExecuteUpdateWatches
));
2235 IMPL_LINK_NOARG(WatchWindow
, ExecuteUpdateWatches
, void*, void)
2237 m_nUpdateWatchesId
= nullptr;
2241 SbxBase
* WatchWindow::ImplGetSBXForEntry(const weld::TreeIter
& rEntry
, bool& rbArrayElement
)
2243 SbxBase
* pSBX
= nullptr;
2244 rbArrayElement
= false;
2246 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
2247 OUString
aVName( pItem
->maName
);
2249 std::unique_ptr
<weld::TreeIter
> xParentEntry
= m_xTreeListBox
->make_iterator(&rEntry
);
2250 bool bParentEntry
= m_xTreeListBox
->iter_parent(*xParentEntry
);
2251 WatchItem
* pParentItem
= bParentEntry
? weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xParentEntry
)) : nullptr;
2254 SbxObject
* pObj
= pParentItem
->mpObject
.get();
2255 SbxDimArray
* pArray
;
2258 pSBX
= pObj
->Find( aVName
, SbxClassType::DontCare
);
2259 if (SbxVariable
const* pVar
= IsSbxVariable(pSBX
))
2261 // Force getting value
2263 aRes
.eType
= SbxVOID
;
2268 else if( (pArray
= pItem
->GetRootArray()) != nullptr )
2270 rbArrayElement
= true;
2271 if( pParentItem
->nDimLevel
+ 1 == pParentItem
->nDimCount
)
2272 pSBX
= pArray
->Get(pItem
->vIndices
.empty() ? nullptr : &*pItem
->vIndices
.begin());
2277 pSBX
= StarBASIC::FindSBXInCurrentScope( aVName
);
2282 IMPL_LINK(WatchWindow
, EditingEntryHdl
, const weld::TreeIter
&, rIter
, bool)
2284 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rIter
));
2287 if (StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError())
2289 // No out of scope entries
2291 SbxBase
* pSbx
= ImplGetSBXForEntry(rIter
, bArrayElement
);
2292 if (IsSbxVariable(pSbx
) || bArrayElement
)
2294 // Accept no objects and only end nodes of arrays for editing
2295 if( !pItem
->mpObject
.is() && ( !pItem
->mpArray
.is() || pItem
->nDimLevel
== pItem
->nDimCount
) )
2297 aEditingRes
= m_xTreeListBox
->get_text(rIter
, 1);
2298 aEditingRes
= comphelper::string::strip(aEditingRes
, ' ');
2307 IMPL_LINK(WatchWindow
, EditedEntryHdl
, const IterString
&, rIterString
, bool)
2309 const weld::TreeIter
& rIter
= rIterString
.first
;
2310 OUString aResult
= comphelper::string::strip(rIterString
.second
, ' ');
2312 sal_uInt16 nResultLen
= aResult
.getLength();
2313 sal_Unicode cFirst
= aResult
[0];
2314 sal_Unicode cLast
= aResult
[ nResultLen
- 1 ];
2315 if( cFirst
== '\"' && cLast
== '\"' )
2316 aResult
= aResult
.copy( 1, nResultLen
- 2 );
2318 if (aResult
== aEditingRes
)
2322 SbxBase
* pSBX
= ImplGetSBXForEntry(rIter
, bArrayElement
);
2324 if (SbxVariable
* pVar
= IsSbxVariable(pSBX
))
2326 SbxDataType eType
= pVar
->GetType();
2327 if ( static_cast<sal_uInt8
>(eType
) != sal_uInt8(SbxOBJECT
)
2328 && ( eType
& SbxARRAY
) == 0 )
2330 // If the type is variable, the conversion of the SBX does not matter,
2331 // else the string is converted.
2332 pVar
->PutStringExt( aResult
);
2336 if ( SbxBase::IsError() )
2338 SbxBase::ResetError();
2343 // The text should never be taken/copied 1:1,
2344 // as the UpdateWatches will be lost
2351 void implCollapseModifiedObjectEntry(const weld::TreeIter
& rParent
, weld::TreeView
& rTree
)
2353 rTree
.collapse_row(rParent
);
2355 std::unique_ptr
<weld::TreeIter
> xDeleteEntry
= rTree
.make_iterator(&rParent
);
2357 while (rTree
.iter_children(*xDeleteEntry
))
2359 implCollapseModifiedObjectEntry(*xDeleteEntry
, rTree
);
2361 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(rTree
.get_id(*xDeleteEntry
));
2363 rTree
.remove(*xDeleteEntry
);
2364 rTree
.copy_iterator(rParent
, *xDeleteEntry
);
2368 OUString
implCreateTypeStringForDimArray( WatchItem
* pItem
, SbxDataType eType
)
2370 OUString aRetStr
= getBasicTypeName( eType
);
2372 SbxDimArray
* pArray
= pItem
->mpArray
.get();
2374 pArray
= pItem
->GetRootArray();
2377 int nDimLevel
= pItem
->nDimLevel
;
2378 int nDims
= pItem
->nDimCount
;
2379 if( nDimLevel
< nDims
)
2382 for( int i
= nDimLevel
; i
< nDims
; i
++ )
2384 sal_Int32 nMin
, nMax
;
2385 pArray
->GetDim(sal::static_int_cast
<sal_Int32
>(i
+ 1), nMin
, nMax
);
2386 aRetStr
+= OUString::number(nMin
) + " to " + OUString::number(nMax
);
2398 void WatchWindow::implEnableChildren(const weld::TreeIter
& rEntry
, bool bEnable
)
2402 if (!m_xTreeListBox
->get_row_expanded(rEntry
))
2403 m_xTreeListBox
->set_children_on_demand(rEntry
, true);
2407 assert(!m_xTreeListBox
->get_row_expanded(rEntry
));
2408 m_xTreeListBox
->set_children_on_demand(rEntry
, false);
2412 void WatchWindow::UpdateWatches(bool bBasicStopped
)
2414 SbMethod
* pCurMethod
= StarBASIC::GetActiveMethod();
2416 ErrCode eOld
= SbxBase::GetError();
2417 setBasicWatchMode( true );
2419 m_xTreeListBox
->all_foreach([this, pCurMethod
, bBasicStopped
](weld::TreeIter
& rEntry
){
2420 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
2421 DBG_ASSERT( !pItem
->maName
.isEmpty(), "Var? - Must not be empty!" );
2426 bool bCollapse
= false;
2427 TriState eEnableChildren
= TRISTATE_INDET
;
2430 SbxBase
* pSBX
= ImplGetSBXForEntry(rEntry
, bArrayElement
);
2432 // Array? If no end node create type string
2433 if( bArrayElement
&& pItem
->nDimLevel
< pItem
->nDimCount
)
2435 SbxDimArray
* pRootArray
= pItem
->GetRootArray();
2436 SbxDataType eType
= pRootArray
->GetType();
2437 aTypeStr
= implCreateTypeStringForDimArray( pItem
, eType
);
2438 eEnableChildren
= TRISTATE_TRUE
;
2441 if (SbxVariable
* pVar
= dynamic_cast<SbxVariable
*>(pSBX
))
2443 // extra treatment of arrays
2444 SbxDataType eType
= pVar
->GetType();
2445 if ( eType
& SbxARRAY
)
2447 // consider multidimensional arrays!
2448 if (SbxDimArray
* pNewArray
= dynamic_cast<SbxDimArray
*>(pVar
->GetObject()))
2450 SbxDimArray
* pOldArray
= pItem
->mpArray
.get();
2452 bool bArrayChanged
= false;
2453 if (pOldArray
!= nullptr)
2455 // Compare Array dimensions to see if array has changed
2456 // Can be a copy, so comparing pointers does not work
2457 sal_Int32 nOldDims
= pOldArray
->GetDims();
2458 sal_Int32 nNewDims
= pNewArray
->GetDims();
2459 if( nOldDims
!= nNewDims
)
2461 bArrayChanged
= true;
2465 for( sal_Int32 i
= 0 ; i
< nOldDims
; i
++ )
2467 sal_Int32 nOldMin
, nOldMax
;
2468 sal_Int32 nNewMin
, nNewMax
;
2470 pOldArray
->GetDim(i
+ 1, nOldMin
, nOldMax
);
2471 pNewArray
->GetDim(i
+ 1, nNewMin
, nNewMax
);
2472 if( nOldMin
!= nNewMin
|| nOldMax
!= nNewMax
)
2474 bArrayChanged
= true;
2482 bArrayChanged
= true;
2484 eEnableChildren
= TRISTATE_TRUE
;
2485 // #i37227 Clear always and replace array
2486 if( pNewArray
!= pOldArray
)
2488 pItem
->clearWatchItem();
2489 eEnableChildren
= TRISTATE_TRUE
;
2491 pItem
->mpArray
= pNewArray
;
2492 sal_Int32 nDims
= pNewArray
->GetDims();
2493 pItem
->nDimLevel
= 0;
2494 pItem
->nDimCount
= nDims
;
2496 if( bArrayChanged
&& pOldArray
!= nullptr )
2500 aTypeStr
= implCreateTypeStringForDimArray( pItem
, eType
);
2507 else if ( static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxOBJECT
) )
2509 if (SbxObject
* pObj
= dynamic_cast<SbxObject
*>(pVar
->GetObject()))
2511 if ( pItem
->mpObject
.is() && !pItem
->maMemberList
.empty() )
2513 createAllObjectProperties(pObj
);
2514 SbxArray
* pProps
= pObj
->GetProperties();
2515 const sal_uInt32 nPropCount
= getCorrectedPropCount(pProps
);
2516 // Check if member list has changed
2517 bCollapse
= pItem
->maMemberList
.size() != nPropCount
;
2518 for( sal_uInt32 i
= 0 ; !bCollapse
&& i
< nPropCount
; i
++ )
2520 SbxVariable
* pVar_
= pProps
->Get(i
);
2521 if( pItem
->maMemberList
[i
] != pVar_
->GetName() )
2526 pItem
->mpObject
= pObj
;
2527 eEnableChildren
= TRISTATE_TRUE
;
2528 aTypeStr
= getBasicObjectTypeName( pObj
);
2533 if( pItem
->mpObject
.is() )
2536 eEnableChildren
= TRISTATE_FALSE
;
2542 if( pItem
->mpObject
.is() )
2545 eEnableChildren
= TRISTATE_FALSE
;
2548 bool bString
= (static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxSTRING
));
2549 OUString
aStrStr( "\"" );
2552 aWatchStr
+= aStrStr
;
2554 // tdf#57308 - avoid a second call to retrieve the data
2555 const SbxFlagBits nFlags
= pVar
->GetFlags();
2556 pVar
->SetFlag(SbxFlagBits::NoBroadcast
);
2557 aWatchStr
+= pVar
->GetOUString();
2558 pVar
->SetFlags(nFlags
);
2561 aWatchStr
+= aStrStr
;
2564 if( aTypeStr
.isEmpty() )
2566 if( !pVar
->IsFixed() )
2568 aTypeStr
= "Variant/";
2570 aTypeStr
+= getBasicTypeName( pVar
->GetType() );
2573 else if( !bArrayElement
)
2575 aWatchStr
+= "<Out of Scope>";
2580 implCollapseModifiedObjectEntry(rEntry
, *m_xTreeListBox
);
2581 pItem
->clearWatchItem();
2584 if (eEnableChildren
!= TRISTATE_INDET
)
2585 implEnableChildren(rEntry
, eEnableChildren
== TRISTATE_TRUE
);
2587 else if( bBasicStopped
)
2589 if( pItem
->mpObject
.is() || pItem
->mpArray
.is() )
2591 implCollapseModifiedObjectEntry(rEntry
, *m_xTreeListBox
);
2592 pItem
->mpObject
.clear();
2593 pItem
->mpArray
.clear();
2595 pItem
->clearWatchItem();
2598 m_xTreeListBox
->set_text(rEntry
, aWatchStr
, 1);
2599 m_xTreeListBox
->set_text(rEntry
, aTypeStr
, 2);
2604 SbxBase::ResetError();
2605 if( eOld
!= ERRCODE_NONE
)
2606 SbxBase::SetError( eOld
);
2607 setBasicWatchMode( false );
2610 IMPL_LINK_NOARG(CodeCompleteWindow
, ImplDoubleClickHdl
, weld::TreeView
&, bool)
2612 InsertSelectedEntry();
2616 IMPL_LINK_NOARG(CodeCompleteWindow
, ImplSelectHdl
, weld::TreeView
&, void)
2618 //give back the focus to the parent
2619 pParent
->GrabFocus();
2622 TextView
* CodeCompleteWindow::GetParentEditView()
2624 return pParent
->GetEditView();
2627 void CodeCompleteWindow::InsertSelectedEntry()
2629 OUString sSelectedEntry
= m_xListBox
->get_selected_text();
2631 if( !aFuncBuffer
.isEmpty() )
2633 // if the user typed in something: remove, and insert
2634 GetParentEditView()->SetSelection(pParent
->GetLastHighlightPortionTextSelection());
2635 GetParentEditView()->DeleteSelected();
2637 if (!sSelectedEntry
.isEmpty())
2639 // if the user selected something
2640 GetParentEditView()->InsertText(sSelectedEntry
);
2645 if (!sSelectedEntry
.isEmpty())
2647 // if the user selected something
2648 GetParentEditView()->InsertText(sSelectedEntry
);
2651 HideAndRestoreFocus();
2654 void CodeCompleteWindow::SetMatchingEntries()
2656 for (sal_Int32 i
= 0, nEntryCount
= m_xListBox
->n_children(); i
< nEntryCount
; ++i
)
2658 OUString sEntry
= m_xListBox
->get_text(i
);
2659 if (sEntry
.startsWithIgnoreAsciiCase(aFuncBuffer
))
2661 m_xListBox
->select(i
);
2667 IMPL_LINK(CodeCompleteWindow
, KeyInputHdl
, const KeyEvent
&, rKEvt
, bool)
2669 return HandleKeyInput(rKEvt
);
2672 bool CodeCompleteWindow::HandleKeyInput( const KeyEvent
& rKeyEvt
)
2674 bool bHandled
= true;
2676 sal_Unicode aChar
= rKeyEvt
.GetKeyCode().GetCode();
2677 if( (( aChar
>= KEY_A
) && ( aChar
<= KEY_Z
))
2678 || ((aChar
>= KEY_0
) && (aChar
<= KEY_9
)) )
2680 aFuncBuffer
.append(rKeyEvt
.GetCharCode());
2681 SetMatchingEntries();
2689 case KEY_ESCAPE
: // hide, do nothing
2690 HideAndRestoreFocus();
2694 TextSelection
aTextSelection( GetParentEditView()->GetSelection() );
2695 if( aTextSelection
.GetEnd().GetPara() != GetTextSelection().GetEnd().GetPara()-1 )
2697 HideAndRestoreFocus();
2703 TextSelection
aTextSelection( GetParentEditView()->GetSelection() );
2704 if( aTextSelection
.GetStart().GetIndex()-1 < GetTextSelection().GetStart().GetIndex() )
2705 {//leave the cursor where it is
2706 HideAndRestoreFocus();
2712 TextSelection aTextSelection
= pParent
->GetLastHighlightPortionTextSelection();
2713 OUString sTypedText
= pParent
->GetEditEngine()->GetText(aTextSelection
);
2714 if( !aFuncBuffer
.isEmpty() )
2716 sal_Int32 nInd
= m_xListBox
->get_selected_index();
2719 int nEntryCount
= m_xListBox
->n_children();
2720 //if there is something selected
2721 bool bFound
= false;
2722 for (sal_Int32 i
= nInd
; i
!= nEntryCount
; ++i
)
2724 OUString sEntry
= m_xListBox
->get_text(i
);
2725 if( sEntry
.startsWithIgnoreAsciiCase( aFuncBuffer
)
2726 && (std::u16string_view(aFuncBuffer
) != sTypedText
) && (i
!= nInd
) )
2728 m_xListBox
->select(i
);
2734 SetMatchingEntries();
2736 GetParentEditView()->SetSelection( aTextSelection
);
2737 GetParentEditView()->DeleteSelected();
2738 GetParentEditView()->InsertText(m_xListBox
->get_selected_text());
2744 HideAndRestoreFocus();
2746 case KEY_BACKSPACE
: case KEY_DELETE
:
2747 if( !aFuncBuffer
.isEmpty() )
2749 //if there was something inserted by tab: add it to aFuncBuffer
2750 TextSelection
aSel( GetParentEditView()->GetSelection() );
2751 TextPaM
aEnd( GetParentEditView()->CursorEndOfLine(GetTextSelection().GetEnd()) );
2752 GetParentEditView()->SetSelection(TextSelection(GetTextSelection().GetStart(), aEnd
) );
2753 OUString
aTabInsertedStr( GetParentEditView()->GetSelected() );
2754 GetParentEditView()->SetSelection( aSel
);
2756 if( !aTabInsertedStr
.isEmpty() && aTabInsertedStr
!= std::u16string_view(aFuncBuffer
) )
2758 aFuncBuffer
= aTabInsertedStr
;
2760 aFuncBuffer
.remove(aFuncBuffer
.getLength()-1, 1);
2761 SetMatchingEntries();
2770 InsertSelectedEntry();
2774 int nInd
= m_xListBox
->get_selected_index();
2776 m_xListBox
->select(nInd
- 1);
2781 int nInd
= m_xListBox
->get_selected_index();
2782 if (nInd
+ 1 < m_xListBox
->n_children())
2783 m_xListBox
->select(nInd
+ 1);
2795 void CodeCompleteWindow::HideAndRestoreFocus()
2798 pParent
->GrabFocus();
2801 CodeCompleteWindow::CodeCompleteWindow(EditorWindow
* pPar
)
2802 : InterimItemWindow(pPar
, "modules/BasicIDE/ui/codecomplete.ui", "CodeComplete")
2804 , m_xListBox(m_xBuilder
->weld_tree_view("treeview"))
2806 m_xListBox
->connect_row_activated(LINK(this, CodeCompleteWindow
, ImplDoubleClickHdl
));
2807 m_xListBox
->connect_changed(LINK(this, CodeCompleteWindow
, ImplSelectHdl
));
2808 m_xListBox
->connect_key_press(LINK(this, CodeCompleteWindow
, KeyInputHdl
));
2809 m_xListBox
->make_sorted();
2811 m_xListBox
->set_size_request(150, 150); // default, this will adopt the line length
2812 SetSizePixel(m_xContainer
->get_preferred_size());
2815 CodeCompleteWindow::~CodeCompleteWindow()
2820 void CodeCompleteWindow::dispose()
2824 InterimItemWindow::dispose();
2827 void CodeCompleteWindow::InsertEntry( const OUString
& aStr
)
2829 m_xListBox
->append_text(aStr
);
2832 void CodeCompleteWindow::ClearListBox()
2834 m_xListBox
->clear();
2835 aFuncBuffer
.setLength(0);
2838 void CodeCompleteWindow::SetTextSelection( const TextSelection
& aSel
)
2840 m_aTextSelection
= aSel
;
2843 void CodeCompleteWindow::ResizeAndPositionListBox()
2845 if (m_xListBox
->n_children() < 1)
2848 // if there is at least one element inside
2849 // calculate basic position: under the current line
2850 tools::Rectangle aRect
= static_cast<TextEngine
*>(pParent
->GetEditEngine())->PaMtoEditCursor( pParent
->GetEditView()->GetSelection().GetEnd() );
2851 tools::Long nViewYOffset
= pParent
->GetEditView()->GetStartDocPos().Y();
2852 Point aPos
= aRect
.BottomRight();// this variable will be used later (if needed)
2853 aPos
.setY( (aPos
.Y() - nViewYOffset
) + nBasePad
);
2856 const sal_uInt16 nLines
= static_cast<sal_uInt16
>(std::min(6, m_xListBox
->n_children()));
2858 m_xListBox
->set_size_request(-1, m_xListBox
->get_height_rows(nLines
));
2860 Size aSize
= m_xContainer
->get_preferred_size();
2862 SetSizePixel( aSize
);
2864 //calculate position
2865 const tools::Rectangle
aVisArea( pParent
->GetEditView()->GetStartDocPos(), pParent
->GetOutputSizePixel() ); //the visible area
2866 const Point
& aBottomPoint
= aVisArea
.BottomRight();
2868 if( aVisArea
.TopRight().getY() + aPos
.getY() + aSize
.getHeight() > aBottomPoint
.getY() )
2869 {//clipped at the bottom: move it up
2870 const tools::Long
& nParentFontHeight
= pParent
->GetEditEngine()->GetFont().GetFontHeight(); //parent's font (in the IDE): needed for height
2871 aPos
.AdjustY( -(aSize
.getHeight() + nParentFontHeight
+ nCursorPad
) );
2874 if( aVisArea
.TopLeft().getX() + aPos
.getX() + aSize
.getWidth() > aBottomPoint
.getX() )
2875 {//clipped at the right side, move it a bit left
2876 aPos
.AdjustX( -(aSize
.getWidth() + aVisArea
.TopLeft().getX()) );
2879 SetPosPixel( aPos
);
2882 void CodeCompleteWindow::SelectFirstEntry()
2884 if (m_xListBox
->n_children() > 0)
2885 m_xListBox
->select(0);
2888 void CodeCompleteWindow::ClearAndHide()
2891 HideAndRestoreFocus();
2894 UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector
< OUString
>& aVect
, const OUString
& sVarType
)
2895 : bCanComplete( true )
2897 if( aVect
.empty() || sVarType
.isEmpty() )
2899 bCanComplete
= false;//invalid parameters, nothing to code complete
2905 // Get the base class for reflection:
2906 xClass
= css::reflection::theCoreReflection::get(
2907 comphelper::getProcessComponentContext())->forName(sVarType
);
2909 catch( const Exception
& )
2911 bCanComplete
= false;
2915 //start from aVect[1]: aVect[0] is the variable name
2916 bCanComplete
= std::none_of(aVect
.begin() + 1, aVect
.end(), [this](const OUString
& rMethName
) {
2917 return (!CodeCompleteOptions::IsExtendedTypeDeclaration() || !CheckMethod(rMethName
)) && !CheckField(rMethName
); });
2920 std::vector
< OUString
> UnoTypeCodeCompletetor::GetXIdlClassMethods() const
2922 std::vector
< OUString
> aRetVect
;
2923 if( bCanComplete
&& ( xClass
!= nullptr ) )
2925 const Sequence
< Reference
< reflection::XIdlMethod
> > aMethods
= xClass
->getMethods();
2926 for(Reference
< reflection::XIdlMethod
> const & rMethod
: aMethods
)
2928 aRetVect
.push_back( rMethod
->getName() );
2931 return aRetVect
;//this is empty when cannot code complete
2934 std::vector
< OUString
> UnoTypeCodeCompletetor::GetXIdlClassFields() const
2936 std::vector
< OUString
> aRetVect
;
2937 if( bCanComplete
&& ( xClass
!= nullptr ) )
2939 const Sequence
< Reference
< reflection::XIdlField
> > aFields
= xClass
->getFields();
2940 for(Reference
< reflection::XIdlField
> const & rxField
: aFields
)
2942 aRetVect
.push_back( rxField
->getName() );
2945 return aRetVect
;//this is empty when cannot code complete
2949 bool UnoTypeCodeCompletetor::CheckField( const OUString
& sFieldName
)
2950 {// modifies xClass!!!
2952 if ( xClass
== nullptr )
2955 Reference
< reflection::XIdlField
> xField
= xClass
->getField( sFieldName
);
2956 if( xField
!= nullptr )
2958 xClass
= xField
->getType();
2959 if( xClass
!= nullptr )
2967 bool UnoTypeCodeCompletetor::CheckMethod( const OUString
& sMethName
)
2968 {// modifies xClass!!!
2971 if ( xClass
== nullptr )
2974 Reference
< reflection::XIdlMethod
> xMethod
= xClass
->getMethod( sMethName
);
2975 if( xMethod
!= nullptr ) //method OK, check return type
2977 xClass
= xMethod
->getReturnType();
2978 if( xClass
!= nullptr )
2986 } // namespace basctl
2988 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */