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>
77 using namespace ::com::sun::star
;
78 using namespace ::com::sun::star::uno
;
83 sal_uInt16
const NoMarker
= 0xFFFF;
84 tools::Long
const nBasePad
= 2;
85 tools::Long
const nCursorPad
= 5;
87 tools::Long nVirtToolBoxHeight
; // inited in WatchWindow, used in Stackwindow
89 // Returns pBase converted to SbxVariable if valid and is not an SbxMethod.
90 SbxVariable
* IsSbxVariable (SbxBase
* pBase
)
92 if (SbxVariable
* pVar
= dynamic_cast<SbxVariable
*>(pBase
))
93 if (!dynamic_cast<SbxMethod
*>(pVar
))
98 Image
GetImage(const OUString
& rId
)
100 return Image(StockImage::Yes
, rId
);
103 int const nScrollLine
= 12;
104 int const nScrollPage
= 60;
105 int const DWBORDER
= 3;
107 std::u16string_view
const cSuffixes
= u
"%&!#@$";
113 * Helper functions to get/set text in TextEngine using
114 * the stream interface.
116 * get/setText() only supports tools Strings limited to 64K).
118 OUString
getTextEngineText (ExtTextEngine
& rEngine
)
120 SvMemoryStream aMemStream
;
121 aMemStream
.SetStreamCharSet( RTL_TEXTENCODING_UTF8
);
122 aMemStream
.SetLineDelimiter( LINEEND_LF
);
123 rEngine
.Write( aMemStream
);
124 std::size_t nSize
= aMemStream
.Tell();
125 OUString
aText( static_cast<const char*>(aMemStream
.GetData()),
126 nSize
, RTL_TEXTENCODING_UTF8
);
130 void setTextEngineText (ExtTextEngine
& rEngine
, std::u16string_view aStr
)
132 rEngine
.SetText(OUString());
133 OString aUTF8Str
= OUStringToOString( aStr
, RTL_TEXTENCODING_UTF8
);
134 SvMemoryStream
aMemStream( const_cast<char *>(aUTF8Str
.getStr()), aUTF8Str
.getLength(),
136 aMemStream
.SetStreamCharSet( RTL_TEXTENCODING_UTF8
);
137 aMemStream
.SetLineDelimiter( LINEEND_LF
);
138 rEngine
.Read(aMemStream
);
144 void lcl_DrawIDEWindowFrame(DockingWindow
const * pWin
, vcl::RenderContext
& rRenderContext
)
146 if (pWin
->IsFloatingMode())
149 Size
aSz(pWin
->GetOutputSizePixel());
150 const Color
aOldLineColor(rRenderContext
.GetLineColor());
151 rRenderContext
.SetLineColor(COL_WHITE
);
153 rRenderContext
.DrawLine(Point(0, 0), Point(aSz
.Width(), 0));
154 // Black line at bottom
155 rRenderContext
.SetLineColor(COL_BLACK
);
156 rRenderContext
.DrawLine(Point(0, aSz
.Height() - 1),
157 Point(aSz
.Width(), aSz
.Height() - 1));
158 rRenderContext
.SetLineColor(aOldLineColor
);
161 void lcl_SeparateNameAndIndex( const OUString
& rVName
, OUString
& rVar
, OUString
& rIndex
)
165 sal_Int32 nIndexStart
= rVar
.indexOf( '(' );
166 if ( nIndexStart
!= -1 )
168 sal_Int32 nIndexEnd
= rVar
.indexOf( ')', nIndexStart
);
171 rIndex
= rVar
.copy(nIndexStart
+ 1, nIndexEnd
- nIndexStart
- 1);
172 rVar
= rVar
.copy(0, nIndexStart
);
173 rVar
= comphelper::string::stripEnd(rVar
, ' ');
174 rIndex
= comphelper::string::strip(rIndex
, ' ');
178 if ( !rVar
.isEmpty() )
180 sal_uInt16 nLastChar
= rVar
.getLength()-1;
181 if ( cSuffixes
.find(rVar
[ nLastChar
] ) != std::u16string_view::npos
)
182 rVar
= rVar
.replaceAt( nLastChar
, 1, u
"" );
184 if ( !rIndex
.isEmpty() )
186 sal_uInt16 nLastChar
= rIndex
.getLength()-1;
187 if ( cSuffixes
.find(rIndex
[ nLastChar
] ) != std::u16string_view::npos
)
188 rIndex
= rIndex
.replaceAt( nLastChar
, 1, u
"" );
198 class EditorWindow::ChangesListener
:
199 public cppu::WeakImplHelper
< beans::XPropertiesChangeListener
>
202 explicit ChangesListener(EditorWindow
& editor
): editor_(editor
) {}
205 virtual ~ChangesListener() override
{}
207 virtual void SAL_CALL
disposing(lang::EventObject
const &) override
209 std::unique_lock
g(editor_
.mutex_
);
210 editor_
.notifier_
.clear();
213 virtual void SAL_CALL
propertiesChange(
214 Sequence
< beans::PropertyChangeEvent
> const &) override
217 editor_
.ImplSetFont();
220 EditorWindow
& editor_
;
223 class EditorWindow::ProgressInfo
: public SfxProgress
226 ProgressInfo (SfxObjectShell
* pObjSh
, OUString
const& rText
, sal_uInt32 nRange
) :
227 SfxProgress(pObjSh
, rText
, nRange
),
233 SetState(++nCurState
);
237 sal_uInt32 nCurState
;
240 EditorWindow::EditorWindow (vcl::Window
* pParent
, ModulWindow
* pModulWindow
) :
241 Window(pParent
, WB_BORDER
),
242 rModulWindow(*pModulWindow
),
244 m_nSetSourceInBasicId(nullptr),
245 aHighlighter(HighlighterLanguage::Basic
),
246 aSyntaxIdle( "basctl EditorWindow aSyntaxIdle" ),
247 bHighlighting(false),
248 bDoSyntaxHighlight(true),
249 bDelayHighlight(true),
250 pCodeCompleteWnd(VclPtr
<CodeCompleteWindow
>::Create(this))
252 set_id("EditorWindow");
253 const Wallpaper
aBackground(rModulWindow
.GetLayout().GetSyntaxBackgroundColor());
254 SetBackground(aBackground
);
255 GetWindow(GetWindowType::Border
)->SetBackground(aBackground
);
256 SetPointer( PointerStyle::Text
);
257 SetHelpId( HID_BASICIDE_EDITORWINDOW
);
259 listener_
= new ChangesListener(*this);
260 Reference
< beans::XMultiPropertySet
> n(
261 officecfg::Office::Common::Font::SourceViewFont::get(),
264 std::unique_lock
g(mutex_
);
268 // The zoom level applied to the editor window is the zoom slider value in the shell
269 nCurrentZoomLevel
= GetShell()->GetCurrentZoomSliderValue();
271 const Sequence
<OUString
> aPropertyNames
{"FontHeight", "FontName"};
272 n
->addPropertiesChangeListener(aPropertyNames
, listener_
);
276 EditorWindow::~EditorWindow()
281 void EditorWindow::dispose()
283 if (m_nSetSourceInBasicId
)
285 Application::RemoveUserEvent(m_nSetSourceInBasicId
);
286 m_nSetSourceInBasicId
= nullptr;
289 Reference
< beans::XMultiPropertySet
> n
;
291 std::unique_lock
g(mutex_
);
295 n
->removePropertiesChangeListener(listener_
);
302 EndListening( *pEditEngine
);
303 pEditEngine
->RemoveView(pEditView
.get());
305 pCodeCompleteWnd
.disposeAndClear();
306 vcl::Window::dispose();
309 OUString
EditorWindow::GetWordAtCursor()
315 TextEngine
* pTextEngine
= pEditView
->GetTextEngine();
318 // check first, if the cursor is at a help URL
319 const TextSelection
& rSelection
= pEditView
->GetSelection();
320 const TextPaM
& rSelStart
= rSelection
.GetStart();
321 const TextPaM
& rSelEnd
= rSelection
.GetEnd();
322 OUString aText
= pTextEngine
->GetText( rSelEnd
.GetPara() );
323 CharClass
aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() );
324 sal_Int32 nSelStart
= rSelStart
.GetIndex();
325 sal_Int32 nSelEnd
= rSelEnd
.GetIndex();
326 sal_Int32 nLength
= aText
.getLength();
327 sal_Int32 nStart
= 0;
328 sal_Int32 nEnd
= nLength
;
329 while ( nStart
< nLength
)
331 OUString
aURL( URIHelper::FindFirstURLInText( aText
, nStart
, nEnd
, aClass
) );
332 INetURLObject
aURLObj( aURL
);
333 if ( aURLObj
.GetProtocol() == INetProtocol::VndSunStarHelp
334 && nSelStart
>= nStart
&& nSelStart
<= nEnd
&& nSelEnd
>= nStart
&& nSelEnd
<= nEnd
)
343 // Not the selected range, but at the CursorPosition,
344 // if a word is partially selected.
345 if ( aWord
.isEmpty() )
346 aWord
= pTextEngine
->GetWord( rSelEnd
);
348 // Can be empty when full word selected, as Cursor behind it
349 if ( aWord
.isEmpty() && pEditView
->HasSelection() )
350 aWord
= pTextEngine
->GetWord( rSelStart
);
357 void EditorWindow::RequestHelp( const HelpEvent
& rHEvt
)
361 // Should have been activated at some point
364 if ( rHEvt
.GetMode() & HelpEventMode::CONTEXT
)
366 OUString aKeyword
= GetWordAtCursor();
367 Application::GetHelp()->SearchKeyword( aKeyword
);
370 else if ( rHEvt
.GetMode() & HelpEventMode::QUICK
)
373 tools::Rectangle aHelpRect
;
374 if ( StarBASIC::IsRunning() )
376 Point aWindowPos
= rHEvt
.GetMousePosPixel();
377 aWindowPos
= ScreenToOutputPixel( aWindowPos
);
378 Point aDocPos
= GetEditView()->GetDocPos( aWindowPos
);
379 TextPaM aCursor
= GetEditView()->GetTextEngine()->GetPaM(aDocPos
);
380 TextPaM aStartOfWord
;
381 OUString aWord
= GetEditView()->GetTextEngine()->GetWord( aCursor
, &aStartOfWord
);
382 if ( !aWord
.isEmpty() && !comphelper::string::isdigitAsciiString(aWord
) )
384 sal_uInt16 nLastChar
= aWord
.getLength() - 1;
385 if ( cSuffixes
.find(aWord
[ nLastChar
] ) != std::u16string_view::npos
)
386 aWord
= aWord
.replaceAt( nLastChar
, 1, u
"" );
387 SbxBase
* pSBX
= StarBASIC::FindSBXInCurrentScope( aWord
);
388 if (SbxVariable
const* pVar
= IsSbxVariable(pSBX
))
390 SbxDataType eType
= pVar
->GetType();
391 if ( static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxOBJECT
) )
392 // might cause a crash e. g. at the selections-object
393 // Type == Object does not mean pVar == Object!
394 ; // aHelpText = ((SbxObject*)pVar)->GetClassName();
395 else if ( eType
& SbxARRAY
)
396 ; // aHelpText = "{...}";
397 else if ( static_cast<sal_uInt8
>(eType
) != sal_uInt8(SbxEMPTY
) )
399 aHelpText
= pVar
->GetName();
400 if ( aHelpText
.isEmpty() ) // name is not copied with the passed parameters
402 aHelpText
+= "=" + pVar
->GetOUString();
405 if ( !aHelpText
.isEmpty() )
407 tools::Rectangle
aStartWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aStartOfWord
));
408 TextPaM
aEndOfWord(aStartOfWord
.GetPara(), aStartOfWord
.GetIndex() + aWord
.getLength());
409 tools::Rectangle
aEndWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aEndOfWord
));
410 aHelpRect
= aStartWordRect
.GetUnion(aEndWordRect
);
412 Point aTopLeft
= GetEditView()->GetWindowPos(aHelpRect
.TopLeft());
413 aTopLeft
= GetEditView()->GetWindow()->OutputToScreenPixel(aTopLeft
);
415 aHelpRect
.SetPos(aTopLeft
);
419 Help::ShowQuickHelp( this, aHelpRect
, aHelpText
, QuickHelpFlags::NONE
);
425 Window::RequestHelp( rHEvt
);
429 void EditorWindow::Resize()
431 // ScrollBars, etc. happens in Adjust...
435 tools::Long nVisY
= pEditView
->GetStartDocPos().Y();
437 pEditView
->ShowCursor();
438 Size
aOutSz( GetOutputSizePixel() );
439 tools::Long nMaxVisAreaStart
= pEditView
->GetTextEngine()->GetTextHeight() - aOutSz
.Height();
440 if ( nMaxVisAreaStart
< 0 )
441 nMaxVisAreaStart
= 0;
442 if ( pEditView
->GetStartDocPos().Y() > nMaxVisAreaStart
)
444 Point
aStartDocPos( pEditView
->GetStartDocPos() );
445 aStartDocPos
.setY( nMaxVisAreaStart
);
446 pEditView
->SetStartDocPos( aStartDocPos
);
447 pEditView
->ShowCursor();
448 rModulWindow
.GetBreakPointWindow().GetCurYOffset() = aStartDocPos
.Y();
449 rModulWindow
.GetLineNumberWindow().GetCurYOffset() = aStartDocPos
.Y();
452 if ( nVisY
!= pEditView
->GetStartDocPos().Y() )
457 void EditorWindow::MouseMove( const MouseEvent
&rEvt
)
460 pEditView
->MouseMove( rEvt
);
464 void EditorWindow::MouseButtonUp( const MouseEvent
&rEvt
)
468 pEditView
->MouseButtonUp( rEvt
);
469 if (SfxBindings
* pBindings
= GetBindingsPtr())
471 pBindings
->Invalidate( SID_BASICIDE_STAT_POS
);
472 pBindings
->Invalidate( SID_BASICIDE_STAT_TITLE
);
477 void EditorWindow::MouseButtonDown( const MouseEvent
&rEvt
)
482 pEditView
->MouseButtonDown(rEvt
);
483 if( pCodeCompleteWnd
->IsVisible() )
485 if (pEditView
->GetSelection() != pCodeCompleteWnd
->GetTextSelection())
487 //selection changed, code complete window should be hidden
488 pCodeCompleteWnd
->HideAndRestoreFocus();
493 void EditorWindow::Command( const CommandEvent
& rCEvt
)
498 pEditView
->Command( rCEvt
);
499 if ( ( rCEvt
.GetCommand() == CommandEventId::Wheel
) ||
500 ( rCEvt
.GetCommand() == CommandEventId::StartAutoScroll
) ||
501 ( rCEvt
.GetCommand() == CommandEventId::AutoScroll
) )
503 const CommandWheelData
* pData
= rCEvt
.GetWheelData();
505 // Check if it is a Ctrl+Wheel zoom command
506 if (pData
&& pData
->IsMod1())
508 const sal_uInt16 nOldZoom
= GetCurrentZoom();
510 if( pData
->GetDelta() < 0 )
511 nNewZoom
= std::max
<sal_uInt16
>(basctl::Shell::GetMinZoom(),
512 basegfx::zoomtools::zoomOut(nOldZoom
));
514 nNewZoom
= std::min
<sal_uInt16
>(basctl::Shell::GetMaxZoom(),
515 basegfx::zoomtools::zoomIn(nOldZoom
));
516 GetShell()->SetGlobalEditorZoomLevel(nNewZoom
);
519 HandleScrollCommand(rCEvt
, &rModulWindow
.GetEditHScrollBar(), &rModulWindow
.GetEditVScrollBar());
521 else if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
) {
522 SfxDispatcher
* pDispatcher
= GetDispatcher();
525 SfxDispatcher::ExecutePopup();
527 if( pCodeCompleteWnd
->IsVisible() ) // hide the code complete window
528 pCodeCompleteWnd
->ClearAndHide();
532 bool EditorWindow::ImpCanModify()
534 bool bCanModify
= true;
535 if ( StarBASIC::IsRunning() && rModulWindow
.GetBasicStatus().bIsRunning
)
537 // If in Trace-mode, abort the trace or refuse input
538 // Remove markers in the modules in Notify at Basic::Stopped
539 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(nullptr,
540 VclMessageType::Question
, VclButtonsType::OkCancel
,
541 IDEResId(RID_STR_WILLSTOPPRG
)));
542 if (xQueryBox
->run() == RET_OK
)
544 rModulWindow
.GetBasicStatus().bIsRunning
= false;
553 void EditorWindow::KeyInput( const KeyEvent
& rKEvt
)
555 if ( !pEditView
) // Happens in Win95
558 bool const bWasModified
= pEditEngine
->IsModified();
559 // see if there is an accelerator to be processed first
560 SfxViewShell
*pVS( SfxViewShell::Current());
561 bool bDone
= pVS
&& pVS
->KeyInput( rKEvt
);
563 if (pCodeCompleteWnd
->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn())
565 if (pCodeCompleteWnd
->HandleKeyInput(rKEvt
))
569 if( (rKEvt
.GetKeyCode().GetCode() == KEY_SPACE
||
570 rKEvt
.GetKeyCode().GetCode() == KEY_TAB
||
571 rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
) && CodeCompleteOptions::IsAutoCorrectOn() )
576 if( rKEvt
.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() )
577 {//autoclose double quotes
578 HandleAutoCloseDoubleQuotes();
581 if( rKEvt
.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() )
582 {//autoclose parenthesis
583 HandleAutoCloseParen();
586 if( rKEvt
.GetKeyCode().GetCode() == KEY_RETURN
&& CodeCompleteOptions::IsProcedureAutoCompleteOn() )
587 {//autoclose implementation
588 HandleProcedureCompletion();
591 if( rKEvt
.GetKeyCode().GetCode() == KEY_POINT
&& CodeCompleteOptions::IsCodeCompleteOn() )
593 HandleCodeCompletion();
595 if ( !bDone
&& ( !TextEngine::DoesKeyChangeText( rKEvt
) || ImpCanModify() ) )
597 if ( ( rKEvt
.GetKeyCode().GetCode() == KEY_TAB
) && !rKEvt
.GetKeyCode().IsMod1() &&
598 !rKEvt
.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() )
600 TextSelection
aSel( pEditView
->GetSelection() );
601 if ( aSel
.GetStart().GetPara() != aSel
.GetEnd().GetPara() )
603 bDelayHighlight
= false;
604 if ( !rKEvt
.GetKeyCode().IsShift() )
605 pEditView
->IndentBlock();
607 pEditView
->UnindentBlock();
608 bDelayHighlight
= true;
613 bDone
= pEditView
->KeyInput( rKEvt
);
617 Window::KeyInput( rKEvt
);
621 if (SfxBindings
* pBindings
= GetBindingsPtr())
623 pBindings
->Invalidate( SID_BASICIDE_STAT_POS
);
624 pBindings
->Invalidate( SID_BASICIDE_STAT_TITLE
);
625 if ( rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_CURSOR
)
627 pBindings
->Update( SID_BASICIDE_STAT_POS
);
628 pBindings
->Update( SID_BASICIDE_STAT_TITLE
);
630 if ( rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_ALPHA
||
631 rKEvt
.GetKeyCode().GetGroup() == KEYGROUP_NUM
)
633 // If the module is read-only, warn that it can't be edited
634 if ( rModulWindow
.IsReadOnly() )
635 rModulWindow
.ShowReadOnlyInfoBar();
637 if ( !bWasModified
&& pEditEngine
->IsModified() )
639 pBindings
->Invalidate( SID_SAVEDOC
);
640 pBindings
->Invalidate( SID_DOC_MODIFIED
);
641 pBindings
->Invalidate( SID_UNDO
);
643 if ( rKEvt
.GetKeyCode().GetCode() == KEY_INSERT
)
644 pBindings
->Invalidate( SID_ATTR_INSERT
);
649 void EditorWindow::HandleAutoCorrect()
651 TextSelection aSel
= GetEditView()->GetSelection();
652 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
653 const sal_Int32 nIndex
= aSel
.GetStart().GetIndex();
654 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
655 const OUString
& sActSubName
= GetActualSubName( nLine
); // the actual procedure
657 std::vector
<HighlightPortion
> aPortions
;
658 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
660 if( aPortions
.empty() )
663 HighlightPortion
& r
= aPortions
.back();
664 if( static_cast<size_t>(nIndex
) != aPortions
.size()-1 )
665 {//cursor is not standing at the end of the line
666 for (auto const& portion
: aPortions
)
668 if( portion
.nEnd
== nIndex
)
676 OUString sStr
= aLine
.copy( r
.nBegin
, r
.nEnd
- r
.nBegin
);
677 //if WS or empty string: stop, nothing to do
678 if( ( r
.tokenType
== TokenType::Whitespace
) || sStr
.isEmpty() )
680 //create the appropriate TextSelection, and update the cache
681 TextPaM
aStart( nLine
, r
.nBegin
);
682 TextPaM
aEnd( nLine
, r
.nBegin
+ sStr
.getLength() );
683 TextSelection
sTextSelection( aStart
, aEnd
);
684 rModulWindow
.UpdateModule();
685 rModulWindow
.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache
);
686 // correct the last entered keyword
687 if( r
.tokenType
== TokenType::Keywords
)
689 sStr
= sStr
.toAsciiLowerCase();
690 if( !SbModule::GetKeywordCase(sStr
).isEmpty() )
691 // if it is a keyword, get its correct case
692 sStr
= SbModule::GetKeywordCase(sStr
);
694 // else capitalize first letter/select the correct one, and replace
695 sStr
= sStr
.replaceAt( 0, 1, OUString(sStr
[0]).toAsciiUpperCase() );
697 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
698 pEditView
->SetSelection( aSel
);
700 if( r
.tokenType
!= TokenType::Identifier
)
704 if( !aCodeCompleteCache
.GetCorrectCaseVarName( sStr
, sActSubName
).isEmpty() )
706 sStr
= aCodeCompleteCache
.GetCorrectCaseVarName( sStr
, sActSubName
);
707 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
708 pEditView
->SetSelection( aSel
);
712 //autocorrect procedures
713 SbxArray
* pArr
= rModulWindow
.GetSbModule()->GetMethods().get();
714 for (sal_uInt32 i
= 0; i
< pArr
->Count(); ++i
)
716 if (pArr
->Get(i
)->GetName().equalsIgnoreAsciiCase(sStr
))
718 sStr
= pArr
->Get(i
)->GetName(); //if found, get the correct case
719 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
720 pEditView
->SetSelection( aSel
);
727 TextSelection
EditorWindow::GetLastHighlightPortionTextSelection() const
728 {//creates a text selection from the highlight portion on the cursor
729 const sal_uInt32 nLine
= GetEditView()->GetSelection().GetStart().GetPara();
730 const sal_Int32 nIndex
= GetEditView()->GetSelection().GetStart().GetIndex();
731 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
732 std::vector
<HighlightPortion
> aPortions
;
733 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
735 assert(!aPortions
.empty());
736 HighlightPortion
& r
= aPortions
.back();
737 if( static_cast<size_t>(nIndex
) != aPortions
.size()-1 )
738 {//cursor is not standing at the end of the line
739 for (auto const& portion
: aPortions
)
741 if( portion
.nEnd
== nIndex
)
749 if( aPortions
.empty() )
750 return TextSelection();
752 std::u16string_view sStr
= aLine
.subView( r
.nBegin
, r
.nEnd
- r
.nBegin
);
753 TextPaM
aStart( nLine
, r
.nBegin
);
754 TextPaM
aEnd( nLine
, r
.nBegin
+ sStr
.size() );
755 return TextSelection( aStart
, aEnd
);
758 void EditorWindow::HandleAutoCloseParen()
760 TextSelection aSel
= GetEditView()->GetSelection();
761 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
762 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
764 if( aLine
.getLength() > 0 && aLine
[aSel
.GetEnd().GetIndex()-1] != '(' )
766 GetEditView()->InsertText(")");
767 //leave the cursor on its place: inside the parenthesis
768 TextPaM
aEnd(nLine
, aSel
.GetEnd().GetIndex());
769 GetEditView()->SetSelection( TextSelection( aEnd
, aEnd
) );
773 void EditorWindow::HandleAutoCloseDoubleQuotes()
775 TextSelection aSel
= GetEditView()->GetSelection();
776 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
777 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
779 std::vector
<HighlightPortion
> aPortions
;
780 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
782 if( aPortions
.empty() )
785 if( aLine
.getLength() > 0 && !aLine
.endsWith("\"") && (aPortions
.back().tokenType
!= TokenType::String
) )
787 GetEditView()->InsertText("\"");
788 //leave the cursor on its place: inside the two double quotes
789 TextPaM
aEnd(nLine
, aSel
.GetEnd().GetIndex());
790 GetEditView()->SetSelection( TextSelection( aEnd
, aEnd
) );
794 void EditorWindow::HandleProcedureCompletion()
797 TextSelection aSel
= GetEditView()->GetSelection();
798 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
799 OUString
aLine( pEditEngine
->GetText( nLine
) );
803 bool bFoundName
= GetProcedureName(aLine
, sProcType
, sProcName
);
807 OUString
sText("\nEnd ");
808 aSel
= GetEditView()->GetSelection();
809 if( sProcType
.equalsIgnoreAsciiCase("function") )
810 sText
+= "Function\n";
811 if( sProcType
.equalsIgnoreAsciiCase("sub") )
814 if( nLine
+1 == pEditEngine
->GetParagraphCount() )
816 pEditView
->InsertText( sText
);//append to the end
817 GetEditView()->SetSelection(aSel
);
821 for( sal_uInt32 i
= nLine
+1; i
< pEditEngine
->GetParagraphCount(); ++i
)
822 {//searching forward for end token, or another sub/function definition
823 OUString aCurrLine
= pEditEngine
->GetText( i
);
824 std::vector
<HighlightPortion
> aCurrPortions
;
825 aHighlighter
.getHighlightPortions( aCurrLine
, aCurrPortions
);
827 if( aCurrPortions
.size() >= 3 )
828 {//at least 3 tokens: (sub|function) whitespace identifier...
829 HighlightPortion
& r
= aCurrPortions
.front();
830 std::u16string_view sStr
= aCurrLine
.subView(r
.nBegin
, r
.nEnd
- r
.nBegin
);
832 if( r
.tokenType
== TokenType::Keywords
)
834 if( o3tl::equalsIgnoreAsciiCase(sStr
, u
"sub") || o3tl::equalsIgnoreAsciiCase(sStr
, u
"function") )
836 pEditView
->InsertText( sText
);//append to the end
837 GetEditView()->SetSelection(aSel
);
840 if( o3tl::equalsIgnoreAsciiCase(sStr
, u
"end") )
848 bool EditorWindow::GetProcedureName(std::u16string_view rLine
, OUString
& rProcType
, OUString
& rProcName
) const
850 std::vector
<HighlightPortion
> aPortions
;
851 aHighlighter
.getHighlightPortions(rLine
, aPortions
);
853 if( aPortions
.empty() )
856 bool bFoundType
= false;
857 bool bFoundName
= false;
859 for (auto const& portion
: aPortions
)
861 std::u16string_view sTokStr
= rLine
.substr(portion
.nBegin
, portion
.nEnd
- portion
.nBegin
);
863 if( portion
.tokenType
== TokenType::Keywords
&& ( o3tl::equalsIgnoreAsciiCase(sTokStr
, u
"sub")
864 || o3tl::equalsIgnoreAsciiCase(sTokStr
, u
"function")) )
869 if( portion
.tokenType
== TokenType::Identifier
&& bFoundType
)
877 if( !bFoundType
|| !bFoundName
)
878 return false;// no sub/function keyword or there is no identifier
884 void EditorWindow::HandleCodeCompletion()
886 rModulWindow
.UpdateModule();
887 rModulWindow
.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache
);
888 TextSelection aSel
= GetEditView()->GetSelection();
889 const sal_uInt32 nLine
= aSel
.GetStart().GetPara();
890 OUString
aLine( pEditEngine
->GetText( nLine
) ); // the line being modified
891 std::vector
< OUString
> aVect
; //vector to hold the base variable+methods for the nested reflection
893 std::vector
<HighlightPortion
> aPortions
;
894 aLine
= aLine
.copy(0, aSel
.GetEnd().GetIndex());
895 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
896 if( aPortions
.empty() )
899 //use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod ..
900 for( std::vector
<HighlightPortion
>::reverse_iterator
i(
902 i
!= aPortions
.rend(); ++i
)
904 if( i
->tokenType
== TokenType::Whitespace
) // a whitespace: stop; if there is no ws, it goes to the beginning of the line
906 if( i
->tokenType
== TokenType::Identifier
|| i
->tokenType
== TokenType::Keywords
) // extract the identifiers(methods, base variable)
907 /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue
908 * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!)
910 aVect
.insert( aVect
.begin(), aLine
.copy(i
->nBegin
, i
->nEnd
- i
->nBegin
) );
913 if( aVect
.empty() )//nothing to do
916 OUString sBaseName
= aVect
[aVect
.size()-1];//variable name
917 OUString sVarType
= aCodeCompleteCache
.GetVarType( sBaseName
);
919 if( !sVarType
.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() )
920 {//correct variable name, if autocorrection on
921 const OUString
& sStr
= aCodeCompleteCache
.GetCorrectCaseVarName( sBaseName
, GetActualSubName(nLine
) );
922 if( !sStr
.isEmpty() )
924 TextPaM
aStart(nLine
, aSel
.GetStart().GetIndex() - sStr
.getLength() );
925 TextSelection
sTextSelection(aStart
, TextPaM(nLine
, aSel
.GetStart().GetIndex()));
926 pEditEngine
->ReplaceText( sTextSelection
, sStr
);
927 pEditView
->SetSelection( aSel
);
931 UnoTypeCodeCompletetor
aTypeCompletor( aVect
, sVarType
);
933 if( !aTypeCompletor
.CanCodeComplete() )
936 std::vector
< OUString
> aEntryVect
;//entries to be inserted into the list
937 std::vector
< OUString
> aFieldVect
= aTypeCompletor
.GetXIdlClassFields();//fields
938 aEntryVect
.insert(aEntryVect
.end(), aFieldVect
.begin(), aFieldVect
.end() );
939 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
940 {// if extended types on, reflect classes, else just the structs (XIdlClass without methods)
941 std::vector
< OUString
> aMethVect
= aTypeCompletor
.GetXIdlClassMethods();//methods
942 aEntryVect
.insert(aEntryVect
.end(), aMethVect
.begin(), aMethVect
.end() );
944 if( !aEntryVect
.empty() )
945 SetupAndShowCodeCompleteWnd( aEntryVect
, aSel
);
948 void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector
< OUString
>& aEntryVect
, TextSelection aSel
)
951 pCodeCompleteWnd
->ClearListBox();
953 for(const auto & l
: aEntryVect
)
955 pCodeCompleteWnd
->InsertEntry( l
);
958 pCodeCompleteWnd
->Show();
959 pCodeCompleteWnd
->ResizeAndPositionListBox();
960 pCodeCompleteWnd
->SelectFirstEntry();
961 // correct text selection, and set it
962 ++aSel
.GetStart().GetIndex();
963 ++aSel
.GetEnd().GetIndex();
964 pCodeCompleteWnd
->SetTextSelection( aSel
);
965 //give the focus to the EditView
966 pEditView
->GetWindow()->GrabFocus();
969 void EditorWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
971 if (!pEditEngine
) // We need it now at latest
974 pEditView
->Paint(rRenderContext
, rRect
);
977 void EditorWindow::LoseFocus()
979 // tdf#114258 wait until the next event loop cycle to do this so it doesn't
980 // happen during a mouse down/up selection in the treeview whose contents
982 if (!m_nSetSourceInBasicId
)
983 m_nSetSourceInBasicId
= Application::PostUserEvent(LINK(this, EditorWindow
, SetSourceInBasicHdl
));
987 IMPL_LINK_NOARG(EditorWindow
, SetSourceInBasicHdl
, void*, void)
989 m_nSetSourceInBasicId
= nullptr;
993 void EditorWindow::SetSourceInBasic()
995 if ( pEditEngine
&& pEditEngine
->IsModified()
996 && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise
997 // any read only bug in the text engine could lead to a crash later
999 if ( !StarBASIC::IsRunning() ) // Not at runtime!
1001 rModulWindow
.UpdateModule();
1006 // Returns the position of the last character of any of the following
1007 // EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found
1008 sal_Int32
searchEOL( std::u16string_view rStr
, sal_Int32 fromIndex
)
1010 size_t iLF
= rStr
.find( LINE_SEP
, fromIndex
);
1011 if( iLF
!= std::u16string_view::npos
)
1014 size_t iCR
= rStr
.find( LINE_SEP_CR
, fromIndex
);
1015 return iCR
== std::u16string_view::npos
? -1 : iCR
;
1018 void EditorWindow::CreateEditEngine()
1023 pEditEngine
.reset(new ExtTextEngine
);
1024 pEditView
.reset(new TextView(pEditEngine
.get(), this));
1025 pEditView
->SetAutoIndentMode(true);
1026 pEditEngine
->SetUpdateMode(false);
1027 pEditEngine
->InsertView(pEditView
.get());
1031 aSyntaxIdle
.SetInvokeHandler( LINK( this, EditorWindow
, SyntaxTimerHdl
) );
1033 bool bWasDoSyntaxHighlight
= bDoSyntaxHighlight
;
1034 bDoSyntaxHighlight
= false; // too slow for large texts...
1035 OUString
aOUSource(rModulWindow
.GetModule());
1036 sal_Int32 nLines
= 0;
1037 sal_Int32 nIndex
= -1;
1041 nIndex
= searchEOL( aOUSource
, nIndex
+1 );
1043 while (nIndex
>= 0);
1045 // nLines*4: SetText+Formatting+DoHighlight+Formatting
1046 // it could be cut down on one formatting but you would wait even longer
1047 // for the text then if the source code is long...
1048 pProgress
.reset(new ProgressInfo(GetShell()->GetViewFrame().GetObjectShell(),
1049 IDEResId(RID_STR_GENERATESOURCE
),
1051 setTextEngineText(*pEditEngine
, aOUSource
);
1053 pEditView
->SetStartDocPos(Point(0, 0));
1054 pEditView
->SetSelection(TextSelection());
1055 rModulWindow
.GetBreakPointWindow().GetCurYOffset() = 0;
1056 rModulWindow
.GetLineNumberWindow().GetCurYOffset() = 0;
1057 pEditEngine
->SetUpdateMode(true);
1058 rModulWindow
.PaintImmediately(); // has only been invalidated at UpdateMode = true
1060 pEditView
->ShowCursor();
1062 StartListening(*pEditEngine
);
1065 bDoSyntaxHighlight
= bWasDoSyntaxHighlight
;
1067 for (sal_Int32 nLine
= 0; nLine
< nLines
; nLine
++)
1068 aSyntaxLineTable
.insert(nLine
);
1069 ForceSyntaxTimeout();
1073 pEditEngine
->SetModified( false );
1074 pEditEngine
->EnableUndo( true );
1078 if (SfxBindings
* pBindings
= GetBindingsPtr())
1080 pBindings
->Invalidate(SID_BASICIDE_STAT_POS
);
1081 pBindings
->Invalidate(SID_BASICIDE_STAT_TITLE
);
1084 DBG_ASSERT(rModulWindow
.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?");
1086 // set readonly mode for readonly libraries
1087 ScriptDocument
aDocument(rModulWindow
.GetDocument());
1088 OUString
aOULibName(rModulWindow
.GetLibName());
1089 Reference
< script::XLibraryContainer2
> xModLibContainer( aDocument
.getLibraryContainer( E_SCRIPTS
), UNO_QUERY
);
1090 if (xModLibContainer
.is()
1091 && xModLibContainer
->hasByName(aOULibName
)
1092 && xModLibContainer
->isLibraryReadOnly(aOULibName
))
1094 rModulWindow
.SetReadOnly(true);
1097 if (aDocument
.isDocument() && aDocument
.isReadOnly())
1098 rModulWindow
.SetReadOnly(true);
1101 void EditorWindow::Notify( SfxBroadcaster
& /*rBC*/, const SfxHint
& rHint
)
1103 TextHint
const* pTextHint
= dynamic_cast<TextHint
const*>(&rHint
);
1107 TextHint
const& rTextHint
= *pTextHint
;
1108 if( rTextHint
.GetId() == SfxHintId::TextViewScrolled
)
1110 rModulWindow
.GetEditVScrollBar().SetThumbPos( pEditView
->GetStartDocPos().Y() );
1111 rModulWindow
.GetEditHScrollBar().SetThumbPos( pEditView
->GetStartDocPos().X() );
1112 rModulWindow
.GetBreakPointWindow().DoScroll
1113 ( rModulWindow
.GetBreakPointWindow().GetCurYOffset() - pEditView
->GetStartDocPos().Y() );
1114 rModulWindow
.GetLineNumberWindow().DoScroll
1115 ( rModulWindow
.GetLineNumberWindow().GetCurYOffset() - pEditView
->GetStartDocPos().Y() );
1117 else if( rTextHint
.GetId() == SfxHintId::TextHeightChanged
)
1119 if ( pEditView
->GetStartDocPos().Y() )
1121 tools::Long nOutHeight
= GetOutputSizePixel().Height();
1122 tools::Long nTextHeight
= pEditEngine
->GetTextHeight();
1123 if ( nTextHeight
< nOutHeight
)
1124 pEditView
->Scroll( 0, pEditView
->GetStartDocPos().Y() );
1126 rModulWindow
.GetLineNumberWindow().Invalidate();
1129 SetScrollBarRanges();
1131 else if( rTextHint
.GetId() == SfxHintId::TextFormatted
)
1134 const tools::Long nWidth
= pEditEngine
->CalcTextWidth();
1135 if ( nWidth
!= nCurTextWidth
)
1137 nCurTextWidth
= nWidth
;
1138 rModulWindow
.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth
-1) );
1139 rModulWindow
.GetEditHScrollBar().SetThumbPos( pEditView
->GetStartDocPos().X() );
1141 tools::Long nPrevTextWidth
= nCurTextWidth
;
1142 nCurTextWidth
= pEditEngine
->CalcTextWidth();
1143 if ( nCurTextWidth
!= nPrevTextWidth
)
1144 SetScrollBarRanges();
1146 else if( rTextHint
.GetId() == SfxHintId::TextParaInserted
)
1148 ParagraphInsertedDeleted( rTextHint
.GetValue(), true );
1149 DoDelayedSyntaxHighlight( rTextHint
.GetValue() );
1151 else if( rTextHint
.GetId() == SfxHintId::TextParaRemoved
)
1153 ParagraphInsertedDeleted( rTextHint
.GetValue(), false );
1155 else if( rTextHint
.GetId() == SfxHintId::TextParaContentChanged
)
1157 DoDelayedSyntaxHighlight( rTextHint
.GetValue() );
1159 else if( rTextHint
.GetId() == SfxHintId::TextViewSelectionChanged
)
1161 if (SfxBindings
* pBindings
= GetBindingsPtr())
1163 pBindings
->Invalidate( SID_CUT
);
1164 pBindings
->Invalidate( SID_COPY
);
1169 OUString
EditorWindow::GetActualSubName( sal_uInt32 nLine
)
1171 SbxArrayRef pMethods
= rModulWindow
.GetSbModule()->GetMethods();
1172 for (sal_uInt32 i
= 0; i
< pMethods
->Count(); i
++)
1174 SbMethod
* pMeth
= dynamic_cast<SbMethod
*>(pMethods
->Get(i
));
1178 pMeth
->GetLineRange(l1
,l2
);
1179 if( (l1
<= nLine
+1) && (nLine
+1 <= l2
) )
1181 return pMeth
->GetName();
1188 void EditorWindow::SetScrollBarRanges()
1190 // extra method, not InitScrollBars, because for EditEngine events too
1194 rModulWindow
.GetEditVScrollBar().SetRange( Range( 0, pEditEngine
->GetTextHeight()-1 ) );
1195 rModulWindow
.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth
-1 ) );
1198 void EditorWindow::InitScrollBars()
1203 SetScrollBarRanges();
1204 Size
aOutSz(GetOutputSizePixel());
1205 rModulWindow
.GetEditVScrollBar().SetVisibleSize(aOutSz
.Height());
1206 rModulWindow
.GetEditVScrollBar().SetPageSize(aOutSz
.Height() * 8 / 10);
1207 rModulWindow
.GetEditVScrollBar().SetLineSize(GetTextHeight());
1208 rModulWindow
.GetEditVScrollBar().SetThumbPos(pEditView
->GetStartDocPos().Y());
1209 rModulWindow
.GetEditVScrollBar().Show();
1211 rModulWindow
.GetEditHScrollBar().SetVisibleSize(aOutSz
.Width());
1212 rModulWindow
.GetEditHScrollBar().SetPageSize(aOutSz
.Width() * 8 / 10);
1213 rModulWindow
.GetEditHScrollBar().SetLineSize(GetTextWidth( "x" ));
1214 rModulWindow
.GetEditHScrollBar().SetThumbPos(pEditView
->GetStartDocPos().X());
1215 rModulWindow
.GetEditHScrollBar().Show();
1218 void EditorWindow::ImpDoHighlight( sal_uInt32 nLine
)
1220 if ( !bDoSyntaxHighlight
)
1223 OUString
aLine( pEditEngine
->GetText( nLine
) );
1224 bool const bWasModified
= pEditEngine
->IsModified();
1225 pEditEngine
->RemoveAttribs( nLine
);
1226 std::vector
<HighlightPortion
> aPortions
;
1227 aHighlighter
.getHighlightPortions( aLine
, aPortions
);
1229 for (auto const& portion
: aPortions
)
1231 Color
const aColor
= rModulWindow
.GetLayout().GetSyntaxColor(portion
.tokenType
);
1232 pEditEngine
->SetAttrib(TextAttribFontColor(aColor
), nLine
, portion
.nBegin
, portion
.nEnd
);
1235 pEditEngine
->SetModified(bWasModified
);
1238 void EditorWindow::ChangeFontColor( Color aColor
)
1242 vcl::Font
aFont(pEditEngine
->GetFont());
1243 aFont
.SetColor(aColor
);
1244 pEditEngine
->SetFont(aFont
);
1248 void EditorWindow::UpdateSyntaxHighlighting ()
1250 const sal_uInt32 nCount
= pEditEngine
->GetParagraphCount();
1251 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
1252 DoDelayedSyntaxHighlight(i
);
1255 void EditorWindow::ImplSetFont()
1257 // Get default font name and height defined in the Options dialog
1258 OUString
sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString()));
1259 if (sFontName
.isEmpty())
1261 vcl::Font
aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED
,
1262 Application::GetSettings().GetUILanguageTag().getLanguageType(),
1263 GetDefaultFontFlags::NONE
, GetOutDev()));
1264 sFontName
= aTmpFont
.GetFamilyName();
1266 sal_uInt16 nDefaultFontHeight
= officecfg::Office::Common::Font::SourceViewFont::FontHeight::get();
1268 // Calculate font size considering zoom level
1269 sal_uInt16 nNewFontHeight
= nDefaultFontHeight
* (static_cast<float>(nCurrentZoomLevel
) / 100);
1270 Size
aFontSize(0, nNewFontHeight
);
1272 vcl::Font
aFont(sFontName
, aFontSize
);
1273 aFont
.SetColor(rModulWindow
.GetLayout().GetFontColor());
1274 SetPointFont(*GetOutDev(), aFont
); // FIXME RenderContext
1277 rModulWindow
.GetBreakPointWindow().SetFont(aFont
);
1278 rModulWindow
.GetLineNumberWindow().SetFont(aFont
);
1279 rModulWindow
.Invalidate();
1283 bool const bModified
= pEditEngine
->IsModified();
1284 pEditEngine
->SetFont(aFont
);
1285 pEditEngine
->SetModified(bModified
);
1289 if (SfxBindings
* pBindings
= GetBindingsPtr())
1291 pBindings
->Invalidate( SID_BASICIDE_CURRENT_ZOOM
);
1292 pBindings
->Invalidate( SID_ATTR_ZOOMSLIDER
);
1296 void EditorWindow::SetEditorZoomLevel(sal_uInt16 nNewZoomLevel
)
1298 if (nCurrentZoomLevel
== nNewZoomLevel
)
1301 if (nNewZoomLevel
< MIN_ZOOM_LEVEL
|| nNewZoomLevel
> MAX_ZOOM_LEVEL
)
1304 nCurrentZoomLevel
= nNewZoomLevel
;
1308 void EditorWindow::DoSyntaxHighlight( sal_uInt32 nPara
)
1310 // because of the DelayedSyntaxHighlight it's possible
1311 // that this line does not exist anymore!
1312 if ( nPara
< pEditEngine
->GetParagraphCount() )
1314 // unfortunately I'm not sure that exactly this line does Modified()...
1316 pProgress
->StepProgress();
1317 ImpDoHighlight( nPara
);
1321 void EditorWindow::DoDelayedSyntaxHighlight( sal_uInt32 nPara
)
1323 // line is only added to list, processed in TimerHdl
1324 // => don't manipulate breaks while EditEngine is formatting
1326 pProgress
->StepProgress();
1328 if ( !bHighlighting
&& bDoSyntaxHighlight
)
1330 if ( bDelayHighlight
)
1332 aSyntaxLineTable
.insert( nPara
);
1333 aSyntaxIdle
.Start();
1336 DoSyntaxHighlight( nPara
);
1340 IMPL_LINK_NOARG(EditorWindow
, SyntaxTimerHdl
, Timer
*, void)
1342 DBG_ASSERT( pEditView
, "Not yet a View, but Syntax-Highlight?!" );
1344 bool const bWasModified
= pEditEngine
->IsModified();
1345 //pEditEngine->SetUpdateMode(false);
1347 bHighlighting
= true;
1348 for (auto const& syntaxLine
: aSyntaxLineTable
)
1350 DoSyntaxHighlight(syntaxLine
);
1355 pEditView
->ShowCursor( false );
1357 pEditEngine
->SetModified( bWasModified
);
1359 aSyntaxLineTable
.clear();
1360 bHighlighting
= false;
1363 void EditorWindow::ParagraphInsertedDeleted( sal_uInt32 nPara
, bool bInserted
)
1366 pProgress
->StepProgress();
1368 if ( !bInserted
&& ( nPara
== TEXT_PARA_ALL
) )
1370 rModulWindow
.GetBreakPoints().reset();
1371 rModulWindow
.GetBreakPointWindow().Invalidate();
1372 rModulWindow
.GetLineNumberWindow().Invalidate();
1376 rModulWindow
.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16
>(nPara
)+1, bInserted
);
1378 tools::Long nLineHeight
= GetTextHeight();
1379 Size aSz
= rModulWindow
.GetBreakPointWindow().GetOutDev()->GetOutputSize();
1380 tools::Rectangle
aInvRect( Point( 0, 0 ), aSz
);
1381 tools::Long nY
= nPara
*nLineHeight
- rModulWindow
.GetBreakPointWindow().GetCurYOffset();
1382 aInvRect
.SetTop( nY
);
1383 rModulWindow
.GetBreakPointWindow().Invalidate( aInvRect
);
1385 Size
aLnSz(rModulWindow
.GetLineNumberWindow().GetWidth(),
1386 GetOutputSizePixel().Height() - 2 * DWBORDER
);
1387 rModulWindow
.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER
+ 19, DWBORDER
), aLnSz
);
1388 rModulWindow
.GetLineNumberWindow().Invalidate();
1392 void EditorWindow::CreateProgress( const OUString
& rText
, sal_uInt32 nRange
)
1394 DBG_ASSERT( !pProgress
, "ProgressInfo exists already" );
1395 pProgress
.reset(new ProgressInfo(
1396 GetShell()->GetViewFrame().GetObjectShell(),
1402 void EditorWindow::DestroyProgress()
1407 void EditorWindow::ForceSyntaxTimeout()
1410 aSyntaxIdle
.Invoke();
1413 FactoryFunction
EditorWindow::GetUITestFactory() const
1415 return EditorWindowUIObject::create
;
1421 BreakPointWindow::BreakPointWindow (vcl::Window
* pParent
, ModulWindow
* pModulWindow
)
1422 : Window(pParent
, WB_BORDER
)
1423 , rModulWindow(*pModulWindow
)
1424 , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine
1425 , nMarkerPos(NoMarker
)
1426 , bErrorMarker(false)
1428 setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor());
1429 SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW
);
1432 void BreakPointWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1437 Size
const aOutSz
= rRenderContext
.GetOutputSize();
1438 tools::Long
const nLineHeight
= rRenderContext
.GetTextHeight();
1440 Image
const aBrk
[2] =
1442 GetImage(RID_BMP_BRKDISABLED
),
1443 GetImage(RID_BMP_BRKENABLED
)
1446 Size
const aBmpSz
= rRenderContext
.PixelToLogic(aBrk
[1].GetSizePixel());
1447 Point
const aBmpOff((aOutSz
.Width() - aBmpSz
.Width()) / 2,
1448 (nLineHeight
- aBmpSz
.Height()) / 2);
1450 for (size_t i
= 0, n
= GetBreakPoints().size(); i
< n
; ++i
)
1452 BreakPoint
& rBrk
= GetBreakPoints().at(i
);
1453 sal_uInt16
const nLine
= rBrk
.nLine
- 1;
1454 size_t const nY
= nLine
*nLineHeight
- nCurYOffset
;
1455 rRenderContext
.DrawImage(Point(0, nY
) + aBmpOff
, aBrk
[rBrk
.bEnabled
]);
1458 ShowMarker(rRenderContext
);
1461 void BreakPointWindow::ShowMarker(vcl::RenderContext
& rRenderContext
)
1463 if (nMarkerPos
== NoMarker
)
1466 Size
const aOutSz
= GetOutDev()->GetOutputSize();
1467 tools::Long
const nLineHeight
= GetTextHeight();
1469 Image aMarker
= GetImage(bErrorMarker
? OUString(RID_BMP_ERRORMARKER
) : OUString(RID_BMP_STEPMARKER
));
1471 Size
aMarkerSz(aMarker
.GetSizePixel());
1472 aMarkerSz
= rRenderContext
.PixelToLogic(aMarkerSz
);
1473 Point
aMarkerOff(0, 0);
1474 aMarkerOff
.setX( (aOutSz
.Width() - aMarkerSz
.Width()) / 2 );
1475 aMarkerOff
.setY( (nLineHeight
- aMarkerSz
.Height()) / 2 );
1477 tools::Long nY
= nMarkerPos
* nLineHeight
- nCurYOffset
;
1481 rRenderContext
.DrawImage(aPos
, aMarker
);
1484 void BreakPointWindow::DoScroll( tools::Long nVertScroll
)
1486 nCurYOffset
-= nVertScroll
;
1487 Window::Scroll( 0, nVertScroll
);
1490 void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine
, bool bError
)
1492 if ( SyncYOffset() )
1496 bErrorMarker
= bError
;
1500 void BreakPointWindow::SetNoMarker ()
1502 SetMarkerPos(NoMarker
);
1505 BreakPoint
* BreakPointWindow::FindBreakPoint( const Point
& rMousePos
)
1507 size_t nLineHeight
= GetTextHeight();
1508 nLineHeight
= nLineHeight
> 0 ? nLineHeight
: 1;
1509 size_t nYPos
= rMousePos
.Y() + nCurYOffset
;
1511 for ( size_t i
= 0, n
= GetBreakPoints().size(); i
< n
; ++i
)
1513 BreakPoint
& rBrk
= GetBreakPoints().at( i
);
1514 sal_uInt16 nLine
= rBrk
.nLine
-1;
1515 size_t nY
= nLine
*nLineHeight
;
1516 if ( ( nYPos
> nY
) && ( nYPos
< ( nY
+ nLineHeight
) ) )
1522 void BreakPointWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
1524 if ( rMEvt
.GetClicks() == 2 )
1526 Point
aMousePos( PixelToLogic( rMEvt
.GetPosPixel() ) );
1527 tools::Long nLineHeight
= GetTextHeight();
1530 tools::Long nYPos
= aMousePos
.Y() + nCurYOffset
;
1531 tools::Long nLine
= nYPos
/ nLineHeight
+ 1;
1532 rModulWindow
.ToggleBreakPoint( static_cast<sal_uInt16
>(nLine
) );
1538 void BreakPointWindow::Command( const CommandEvent
& rCEvt
)
1540 if ( rCEvt
.GetCommand() != CommandEventId::ContextMenu
)
1543 Point
aPos( rCEvt
.IsMouseEvent() ? rCEvt
.GetMousePosPixel() : Point(1,1) );
1544 tools::Rectangle
aRect(aPos
, Size(1, 1));
1545 weld::Window
* pPopupParent
= weld::GetPopupParent(*this, aRect
);
1547 std::unique_ptr
<weld::Builder
> xUIBuilder(Application::CreateBuilder(pPopupParent
, "modules/BasicIDE/ui/breakpointmenus.ui"));
1549 Point
aEventPos( PixelToLogic( aPos
) );
1550 BreakPoint
* pBrk
= rCEvt
.IsMouseEvent() ? FindBreakPoint( aEventPos
) : nullptr;
1553 // test if break point is enabled...
1554 std::unique_ptr
<weld::Menu
> xBrkPropMenu
= xUIBuilder
->weld_menu("breakmenu");
1555 xBrkPropMenu
->set_active("active", pBrk
->bEnabled
);
1556 OUString sCommand
= xBrkPropMenu
->popup_at_rect(pPopupParent
, aRect
);
1557 if (sCommand
== "active")
1559 pBrk
->bEnabled
= !pBrk
->bEnabled
;
1560 rModulWindow
.UpdateBreakPoint( *pBrk
);
1563 else if (sCommand
== "properties")
1565 BreakPointDialog
aBrkDlg(pPopupParent
, GetBreakPoints());
1566 aBrkDlg
.SetCurrentBreakPoint( *pBrk
);
1573 std::unique_ptr
<weld::Menu
> xBrkListMenu
= xUIBuilder
->weld_menu("breaklistmenu");
1574 OUString sCommand
= xBrkListMenu
->popup_at_rect(pPopupParent
, aRect
);
1575 if (sCommand
== "manage")
1577 BreakPointDialog
aBrkDlg(pPopupParent
, GetBreakPoints());
1584 bool BreakPointWindow::SyncYOffset()
1586 TextView
* pView
= rModulWindow
.GetEditView();
1589 tools::Long nViewYOffset
= pView
->GetStartDocPos().Y();
1590 if ( nCurYOffset
!= nViewYOffset
)
1592 nCurYOffset
= nViewYOffset
;
1601 void BreakPointWindow::DataChanged(DataChangedEvent
const & rDCEvt
)
1603 Window::DataChanged(rDCEvt
);
1604 if (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
1605 && (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
1607 Color
aColor(GetSettings().GetStyleSettings().GetFieldColor());
1608 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
1609 if (!pOldSettings
|| aColor
!= pOldSettings
->GetStyleSettings().GetFieldColor())
1611 setBackgroundColor(aColor
);
1617 void BreakPointWindow::setBackgroundColor(Color aColor
)
1619 SetBackground(Wallpaper(aColor
));
1627 OUString maDisplayName
;
1628 SbxObjectRef mpObject
;
1629 std::vector
<OUString
> maMemberList
;
1631 SbxDimArrayRef mpArray
;
1632 int nDimLevel
; // 0 = Root
1634 std::vector
<sal_Int32
> vIndices
;
1636 WatchItem
* mpArrayParentItem
;
1638 explicit WatchItem (OUString aName
):
1639 maName(std::move(aName
)),
1642 mpArrayParentItem(nullptr)
1645 void clearWatchItem ()
1647 maMemberList
.clear();
1650 WatchItem
* GetRootItem();
1651 SbxDimArray
* GetRootArray();
1656 WatchWindow::WatchWindow(Layout
* pParent
)
1657 : DockingWindow(pParent
, "modules/BasicIDE/ui/dockingwatch.ui", "DockingWatch")
1658 , m_nUpdateWatchesId(nullptr)
1660 m_xTitleArea
= m_xBuilder
->weld_container("titlearea");
1662 nVirtToolBoxHeight
= m_xTitleArea
->get_preferred_size().Height();
1664 m_xTitle
= m_xBuilder
->weld_label("title");
1665 m_xTitle
->set_label(IDEResId(RID_STR_REMOVEWATCH
));
1667 m_xEdit
= m_xBuilder
->weld_entry("edit");
1668 m_xRemoveWatchButton
= m_xBuilder
->weld_button("remove");
1669 m_xTreeListBox
= m_xBuilder
->weld_tree_view("treeview");
1671 m_xEdit
->set_accessible_name(IDEResId(RID_STR_WATCHNAME
));
1672 m_xEdit
->set_help_id(HID_BASICIDE_WATCHWINDOW_EDIT
);
1673 m_xEdit
->set_size_request(LogicToPixel(Size(80, 0), MapMode(MapUnit::MapAppFont
)).Width(), -1);
1674 m_xEdit
->connect_activate(LINK( this, WatchWindow
, ActivateHdl
));
1675 m_xEdit
->connect_key_press(LINK( this, WatchWindow
, KeyInputHdl
));
1676 m_xTreeListBox
->set_accessible_name(IDEResId(RID_STR_WATCHNAME
));
1678 m_xRemoveWatchButton
->set_sensitive(false);
1679 m_xRemoveWatchButton
->connect_clicked(LINK( this, WatchWindow
, ButtonHdl
));
1680 m_xRemoveWatchButton
->set_help_id(HID_BASICIDE_REMOVEWATCH
);
1681 m_xRemoveWatchButton
->set_tooltip_text(IDEResId(RID_STR_REMOVEWATCHTIP
));
1683 m_xTreeListBox
->set_help_id(HID_BASICIDE_WATCHWINDOW_LIST
);
1684 m_xTreeListBox
->connect_editing(LINK(this, WatchWindow
, EditingEntryHdl
),
1685 LINK(this, WatchWindow
, EditedEntryHdl
));
1686 m_xTreeListBox
->connect_changed( LINK( this, WatchWindow
, TreeListHdl
) );
1687 m_xTreeListBox
->connect_expanding(LINK(this, WatchWindow
, RequestingChildrenHdl
));
1689 // VarTabWidth, ValueTabWidth, TypeTabWidth
1690 std::vector
<int> aWidths
{ 220, 100, 1250 };
1691 std::vector
<bool> aEditables
{ false, true, false };
1692 m_xTreeListBox
->set_column_fixed_widths(aWidths
);
1693 m_xTreeListBox
->set_column_editables(aEditables
);
1695 SetText(IDEResId(RID_STR_WATCHNAME
));
1697 SetHelpId( HID_BASICIDE_WATCHWINDOW
);
1699 // make watch window keyboard accessible
1700 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1703 WatchWindow::~WatchWindow()
1708 void WatchWindow::dispose()
1710 if (m_nUpdateWatchesId
)
1712 Application::RemoveUserEvent(m_nUpdateWatchesId
);
1713 m_nUpdateWatchesId
= nullptr;
1716 // Destroy user data
1717 m_xTreeListBox
->all_foreach([this](weld::TreeIter
& rEntry
){
1718 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
1725 m_xRemoveWatchButton
.reset();
1726 m_xTitleArea
.reset();
1727 m_xTreeListBox
.reset();
1728 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1729 DockingWindow::dispose();
1732 void WatchWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1734 lcl_DrawIDEWindowFrame(this, rRenderContext
);
1737 void WatchWindow::Resize()
1739 Size aSz
= GetOutputSizePixel();
1740 Size
aBoxSz(aSz
.Width() - 2*DWBORDER
, aSz
.Height() - 2*DWBORDER
);
1742 if ( aBoxSz
.Width() < 4 )
1743 aBoxSz
.setWidth( 0 );
1744 if ( aBoxSz
.Height() < 4 )
1745 aBoxSz
.setHeight( 0 );
1747 m_xBox
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBoxSz
);
1752 WatchItem
* WatchItem::GetRootItem()
1754 WatchItem
* pItem
= mpArrayParentItem
;
1757 if( pItem
->mpArray
.is() )
1759 pItem
= pItem
->mpArrayParentItem
;
1764 SbxDimArray
* WatchItem::GetRootArray()
1766 WatchItem
* pRootItem
= GetRootItem();
1767 SbxDimArray
* pRet
= nullptr;
1769 pRet
= pRootItem
->mpArray
.get();
1773 void WatchWindow::AddWatch( const OUString
& rVName
)
1775 OUString aVar
, aIndex
;
1776 lcl_SeparateNameAndIndex( rVName
, aVar
, aIndex
);
1777 WatchItem
* pWatchItem
= new WatchItem(aVar
);
1779 OUString
sId(weld::toId(pWatchItem
));
1780 std::unique_ptr
<weld::TreeIter
> xRet
= m_xTreeListBox
->make_iterator();
1781 m_xTreeListBox
->insert(nullptr, -1, &aVar
, &sId
, nullptr, nullptr, false, xRet
.get());
1782 m_xTreeListBox
->set_text(*xRet
, "", 1);
1783 m_xTreeListBox
->set_text(*xRet
, "", 2);
1785 m_xTreeListBox
->set_cursor(*xRet
);
1786 m_xTreeListBox
->select(*xRet
);
1787 m_xTreeListBox
->scroll_to_row(*xRet
);
1788 m_xRemoveWatchButton
->set_sensitive(true);
1790 UpdateWatches(false);
1793 void WatchWindow::RemoveSelectedWatch()
1795 std::unique_ptr
<weld::TreeIter
> xEntry
= m_xTreeListBox
->make_iterator();
1796 bool bEntry
= m_xTreeListBox
->get_cursor(xEntry
.get());
1799 m_xTreeListBox
->remove(*xEntry
);
1800 bEntry
= m_xTreeListBox
->get_cursor(xEntry
.get());
1802 m_xEdit
->set_text(weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xEntry
))->maName
);
1804 m_xEdit
->set_text(OUString());
1805 if ( !m_xTreeListBox
->n_children() )
1806 m_xRemoveWatchButton
->set_sensitive(false);
1810 IMPL_STATIC_LINK_NOARG(WatchWindow
, ButtonHdl
, weld::Button
&, void)
1812 if (SfxDispatcher
* pDispatcher
= GetDispatcher())
1813 pDispatcher
->Execute(SID_BASICIDE_REMOVEWATCH
);
1816 IMPL_LINK_NOARG(WatchWindow
, TreeListHdl
, weld::TreeView
&, void)
1818 std::unique_ptr
<weld::TreeIter
> xCurEntry
= m_xTreeListBox
->make_iterator();
1819 bool bCurEntry
= m_xTreeListBox
->get_cursor(xCurEntry
.get());
1822 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xCurEntry
));
1825 m_xEdit
->set_text(pItem
->maName
);
1828 IMPL_LINK_NOARG(WatchWindow
, ActivateHdl
, weld::Entry
&, bool)
1830 OUString
aCurText(m_xEdit
->get_text());
1831 if (!aCurText
.isEmpty())
1834 m_xEdit
->select_region(0, -1);
1839 IMPL_LINK(WatchWindow
, KeyInputHdl
, const KeyEvent
&, rKEvt
, bool)
1841 bool bHandled
= false;
1843 sal_uInt16 nKeyCode
= rKEvt
.GetKeyCode().GetCode();
1844 if (nKeyCode
== KEY_ESCAPE
)
1846 m_xEdit
->set_text(OUString());
1854 StackWindow::StackWindow(Layout
* pParent
)
1855 : DockingWindow(pParent
, "modules/BasicIDE/ui/dockingstack.ui", "DockingStack")
1857 m_xTitle
= m_xBuilder
->weld_label("title");
1858 m_xTitle
->set_label(IDEResId(RID_STR_STACK
));
1860 m_xTitle
->set_size_request(-1, nVirtToolBoxHeight
); // so the two title areas are the same height
1862 m_xTreeListBox
= m_xBuilder
->weld_tree_view("stack");
1864 m_xTreeListBox
->set_help_id(HID_BASICIDE_STACKWINDOW_LIST
);
1865 m_xTreeListBox
->set_accessible_name(IDEResId(RID_STR_STACKNAME
));
1866 m_xTreeListBox
->set_selection_mode(SelectionMode::NONE
);
1867 m_xTreeListBox
->append_text(OUString());
1869 SetText(IDEResId(RID_STR_STACKNAME
));
1871 SetHelpId( HID_BASICIDE_STACKWINDOW
);
1873 // make stack window keyboard accessible
1874 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1877 StackWindow::~StackWindow()
1882 void StackWindow::dispose()
1884 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1886 m_xTreeListBox
.reset();
1887 DockingWindow::dispose();
1890 void StackWindow::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
&)
1892 lcl_DrawIDEWindowFrame(this, rRenderContext
);
1895 void StackWindow::Resize()
1897 Size aSz
= GetOutputSizePixel();
1898 Size
aBoxSz(aSz
.Width() - 2*DWBORDER
, aSz
.Height() - 2*DWBORDER
);
1900 if ( aBoxSz
.Width() < 4 )
1901 aBoxSz
.setWidth( 0 );
1902 if ( aBoxSz
.Height() < 4 )
1903 aBoxSz
.setHeight( 0 );
1905 m_xBox
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBoxSz
);
1910 void StackWindow::UpdateCalls()
1912 m_xTreeListBox
->freeze();
1913 m_xTreeListBox
->clear();
1915 if (StarBASIC::IsRunning())
1917 ErrCode eOld
= SbxBase::GetError();
1918 m_xTreeListBox
->set_selection_mode(SelectionMode::Single
);
1920 sal_Int32 nScope
= 0;
1921 SbMethod
* pMethod
= StarBASIC::GetActiveMethod( nScope
);
1924 OUStringBuffer
aEntry( OUString::number(nScope
));
1925 if ( aEntry
.getLength() < 2 )
1926 aEntry
.insert(0, " ");
1927 aEntry
.append(": " + pMethod
->GetName());
1928 SbxArray
* pParams
= pMethod
->GetParameters();
1929 SbxInfo
* pInfo
= pMethod
->GetInfo();
1933 // 0 is the sub's name...
1934 for (sal_uInt32 nParam
= 1; nParam
< pParams
->Count(); nParam
++)
1936 SbxVariable
* pVar
= pParams
->Get(nParam
);
1937 assert(pVar
&& "Parameter?!");
1938 if ( !pVar
->GetName().isEmpty() )
1940 aEntry
.append(pVar
->GetName());
1944 assert(nParam
<= std::numeric_limits
<sal_uInt16
>::max());
1945 const SbxParamInfo
* pParam
= pInfo
->GetParam( sal::static_int_cast
<sal_uInt16
>(nParam
) );
1948 aEntry
.append(pParam
->aName
);
1952 SbxDataType eType
= pVar
->GetType();
1953 if( eType
& SbxARRAY
)
1955 aEntry
.append("...");
1957 else if( eType
!= SbxOBJECT
)
1959 aEntry
.append(pVar
->GetOUString());
1961 if (nParam
< (pParams
->Count() - 1))
1963 aEntry
.append(", ");
1968 m_xTreeListBox
->append_text(aEntry
.makeStringAndClear());
1970 pMethod
= StarBASIC::GetActiveMethod( nScope
);
1973 SbxBase::ResetError();
1974 if( eOld
!= ERRCODE_NONE
)
1975 SbxBase::SetError( eOld
);
1979 m_xTreeListBox
->set_selection_mode(SelectionMode::NONE
);
1980 m_xTreeListBox
->append_text(OUString());
1983 m_xTreeListBox
->thaw();
1986 ComplexEditorWindow::ComplexEditorWindow( ModulWindow
* pParent
) :
1987 Window( pParent
, WB_3DLOOK
| WB_CLIPCHILDREN
),
1988 aBrkWindow(VclPtr
<BreakPointWindow
>::Create(this, pParent
)),
1989 aLineNumberWindow(VclPtr
<LineNumberWindow
>::Create(this, pParent
)),
1990 aEdtWindow(VclPtr
<EditorWindow
>::Create(this, pParent
)),
1991 aEWVScrollBar(VclPtr
<ScrollAdaptor
>::Create(this, false)),
1992 aEWHScrollBar(VclPtr
<ScrollAdaptor
>::Create(this, true))
1997 aEWVScrollBar
->SetLineSize(nScrollLine
);
1998 aEWVScrollBar
->SetPageSize(nScrollPage
);
1999 aEWVScrollBar
->SetScrollHdl( LINK( this, ComplexEditorWindow
, ScrollHdl
) );
2000 aEWVScrollBar
->Show();
2002 aEWHScrollBar
->SetLineSize(nScrollLine
);
2003 aEWHScrollBar
->SetPageSize(nScrollPage
);
2004 aEWHScrollBar
->SetScrollHdl( LINK( this, ComplexEditorWindow
, ScrollHdl
) );
2005 aEWHScrollBar
->Show();
2008 ComplexEditorWindow::~ComplexEditorWindow()
2013 void ComplexEditorWindow::dispose()
2015 aBrkWindow
.disposeAndClear();
2016 aLineNumberWindow
.disposeAndClear();
2017 aEdtWindow
.disposeAndClear();
2018 aEWVScrollBar
.disposeAndClear();
2019 aEWHScrollBar
.disposeAndClear();
2020 vcl::Window::dispose();
2023 void ComplexEditorWindow::Resize()
2025 Size aOutSz
= GetOutputSizePixel();
2027 aSz
.AdjustWidth( -(2*DWBORDER
) );
2028 aSz
.AdjustHeight( -(2*DWBORDER
) );
2029 tools::Long nBrkWidth
= 20;
2030 tools::Long nSBWidth
= aEWVScrollBar
->GetSizePixel().Width();
2031 tools::Long nSBHeight
= aEWHScrollBar
->GetSizePixel().Height();
2033 Size
aBrkSz(nBrkWidth
, aSz
.Height() - nSBHeight
);
2035 if (aLineNumberWindow
->IsVisible())
2037 Size
aLnSz(aLineNumberWindow
->GetWidth(), aSz
.Height() - nSBHeight
);
2038 Size
aEWSz(aSz
.Width() - nBrkWidth
- aLineNumberWindow
->GetWidth() - nSBWidth
, aSz
.Height() - nSBHeight
);
2039 aBrkWindow
->SetPosSizePixel(Point(DWBORDER
, DWBORDER
), aBrkSz
);
2040 aLineNumberWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
, DWBORDER
), aLnSz
);
2041 aEdtWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
+ aLnSz
.Width(), DWBORDER
), aEWSz
);
2045 Size
aEWSz(aSz
.Width() - nBrkWidth
- nSBWidth
, aSz
.Height() - nSBHeight
);
2046 aBrkWindow
->SetPosSizePixel( Point( DWBORDER
, DWBORDER
), aBrkSz
);
2047 aEdtWindow
->SetPosSizePixel(Point(DWBORDER
+ nBrkWidth
, DWBORDER
), aEWSz
);
2050 aEWVScrollBar
->SetPosSizePixel(Point(aOutSz
.Width() - DWBORDER
- nSBWidth
, DWBORDER
),
2051 Size(nSBWidth
, aSz
.Height() - nSBHeight
));
2052 aEWHScrollBar
->SetPosSizePixel(Point(DWBORDER
, aOutSz
.Height() - DWBORDER
- nSBHeight
),
2053 Size(aSz
.Width() - nSBWidth
, nSBHeight
));
2056 IMPL_LINK_NOARG(ComplexEditorWindow
, ScrollHdl
, weld::Scrollbar
&, void)
2058 if (aEdtWindow
->GetEditView())
2060 tools::Long nXDiff
= aEdtWindow
->GetEditView()->GetStartDocPos().X() - aEWHScrollBar
->GetThumbPos();
2061 tools::Long nYDiff
= aEdtWindow
->GetEditView()->GetStartDocPos().Y() - aEWVScrollBar
->GetThumbPos();
2062 aEdtWindow
->GetEditView()->Scroll(nXDiff
, nYDiff
);
2063 aBrkWindow
->DoScroll( nYDiff
);
2064 aLineNumberWindow
->DoScroll( nYDiff
);
2065 aEdtWindow
->GetEditView()->ShowCursor(false);
2066 aEWVScrollBar
->SetThumbPos( aEdtWindow
->GetEditView()->GetStartDocPos().Y() );
2070 void ComplexEditorWindow::DataChanged(DataChangedEvent
const & rDCEvt
)
2072 Window::DataChanged(rDCEvt
);
2073 if (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
2074 && (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
))
2076 Color
aColor(GetSettings().GetStyleSettings().GetFaceColor());
2077 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
2078 if (!pOldSettings
|| aColor
!= pOldSettings
->GetStyleSettings().GetFaceColor())
2080 SetBackground(Wallpaper(aColor
));
2086 void ComplexEditorWindow::SetLineNumberDisplay(bool b
)
2088 aLineNumberWindow
->Show(b
);
2092 uno::Reference
< awt::XVclWindowPeer
>
2093 EditorWindow::GetComponentInterface(bool bCreate
)
2095 uno::Reference
< awt::XVclWindowPeer
> xPeer(
2096 Window::GetComponentInterface(false));
2097 if (!xPeer
.is() && bCreate
)
2099 // Make sure edit engine and view are available:
2103 xPeer
= createTextWindowPeer(*GetEditView());
2104 SetComponentInterface(xPeer
);
2109 static sal_uInt32
getCorrectedPropCount(SbxArray
* p
)
2111 sal_uInt32 nPropCount
= p
->Count();
2112 if (nPropCount
>= 3 && p
->Get(nPropCount
- 1)->GetName().equalsIgnoreAsciiCase("Dbg_Methods")
2113 && p
->Get(nPropCount
- 2)->GetName().equalsIgnoreAsciiCase("Dbg_Properties")
2114 && p
->Get(nPropCount
- 3)->GetName().equalsIgnoreAsciiCase("Dbg_SupportedInterfaces"))
2121 IMPL_LINK(WatchWindow
, RequestingChildrenHdl
, const weld::TreeIter
&, rParent
, bool)
2123 if( !StarBASIC::IsRunning() )
2126 if (m_xTreeListBox
->iter_has_child(rParent
))
2129 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rParent
));
2130 std::unique_ptr
<weld::TreeIter
> xRet
= m_xTreeListBox
->make_iterator();
2132 SbxDimArray
* pArray
= pItem
->mpArray
.get();
2133 SbxDimArray
* pRootArray
= pItem
->GetRootArray();
2134 bool bArrayIsRootArray
= false;
2135 if( !pArray
&& pRootArray
)
2137 pArray
= pRootArray
;
2138 bArrayIsRootArray
= true;
2141 SbxObject
* pObj
= pItem
->mpObject
.get();
2144 createAllObjectProperties( pObj
);
2145 SbxArray
* pProps
= pObj
->GetProperties();
2146 const sal_uInt32 nPropCount
= getCorrectedPropCount(pProps
);
2147 pItem
->maMemberList
.reserve(nPropCount
);
2149 for( sal_uInt32 i
= 0 ; i
< nPropCount
; ++i
)
2151 SbxVariable
* pVar
= pProps
->Get(i
);
2153 pItem
->maMemberList
.push_back(pVar
->GetName());
2154 OUString
const& rName
= pItem
->maMemberList
.back();
2156 WatchItem
* pWatchItem
= new WatchItem(rName
);
2157 OUString
sId(weld::toId(pWatchItem
));
2159 m_xTreeListBox
->insert(&rParent
, -1, &rName
, &sId
, nullptr, nullptr, false, xRet
.get());
2160 m_xTreeListBox
->set_text(*xRet
, "", 1);
2161 m_xTreeListBox
->set_text(*xRet
, "", 2);
2164 if (nPropCount
> 0 && !m_nUpdateWatchesId
)
2166 m_nUpdateWatchesId
= Application::PostUserEvent(LINK(this, WatchWindow
, ExecuteUpdateWatches
));
2171 sal_uInt16 nElementCount
= 0;
2173 // Loop through indices of current level
2174 int nParentLevel
= bArrayIsRootArray
? pItem
->nDimLevel
: 0;
2175 int nThisLevel
= nParentLevel
+ 1;
2176 sal_Int32 nMin
, nMax
;
2177 if (pArray
->GetDim(nThisLevel
, nMin
, nMax
))
2179 for (sal_Int32 i
= nMin
; i
<= nMax
; i
++)
2181 WatchItem
* pChildItem
= new WatchItem(pItem
->maName
);
2183 // Copy data and create name
2185 OUStringBuffer aIndexStr
= "(";
2186 pChildItem
->mpArrayParentItem
= pItem
;
2187 pChildItem
->nDimLevel
= nThisLevel
;
2188 pChildItem
->nDimCount
= pItem
->nDimCount
;
2189 pChildItem
->vIndices
.resize(pChildItem
->nDimCount
);
2191 for (j
= 0; j
< nParentLevel
; j
++)
2193 sal_Int32 n
= pChildItem
->vIndices
[j
] = pItem
->vIndices
[j
];
2194 aIndexStr
.append( OUString::number(n
) + "," );
2196 pChildItem
->vIndices
[nParentLevel
] = i
;
2197 aIndexStr
.append( OUString::number(i
) + ")" );
2199 OUString aDisplayName
;
2200 WatchItem
* pArrayRootItem
= pChildItem
->GetRootItem();
2201 if (pArrayRootItem
&& pArrayRootItem
->mpArrayParentItem
)
2202 aDisplayName
= pItem
->maDisplayName
;
2204 aDisplayName
= pItem
->maName
;
2205 aDisplayName
+= aIndexStr
;
2206 pChildItem
->maDisplayName
= aDisplayName
;
2208 OUString
sId(weld::toId(pChildItem
));
2210 m_xTreeListBox
->insert(&rParent
, -1, &aDisplayName
, &sId
, nullptr, nullptr, false,
2212 m_xTreeListBox
->set_text(*xRet
, "", 1);
2213 m_xTreeListBox
->set_text(*xRet
, "", 2);
2218 if (nElementCount
> 0 && !m_nUpdateWatchesId
)
2220 m_nUpdateWatchesId
= Application::PostUserEvent(LINK(this, WatchWindow
, ExecuteUpdateWatches
));
2227 IMPL_LINK_NOARG(WatchWindow
, ExecuteUpdateWatches
, void*, void)
2229 m_nUpdateWatchesId
= nullptr;
2233 SbxBase
* WatchWindow::ImplGetSBXForEntry(const weld::TreeIter
& rEntry
, bool& rbArrayElement
)
2235 SbxBase
* pSBX
= nullptr;
2236 rbArrayElement
= false;
2238 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
2239 OUString
aVName( pItem
->maName
);
2241 std::unique_ptr
<weld::TreeIter
> xParentEntry
= m_xTreeListBox
->make_iterator(&rEntry
);
2242 bool bParentEntry
= m_xTreeListBox
->iter_parent(*xParentEntry
);
2243 WatchItem
* pParentItem
= bParentEntry
? weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(*xParentEntry
)) : nullptr;
2246 SbxObject
* pObj
= pParentItem
->mpObject
.get();
2247 SbxDimArray
* pArray
;
2250 pSBX
= pObj
->Find( aVName
, SbxClassType::DontCare
);
2251 if (SbxVariable
const* pVar
= IsSbxVariable(pSBX
))
2253 // Force getting value
2255 aRes
.eType
= SbxVOID
;
2260 else if( (pArray
= pItem
->GetRootArray()) != nullptr )
2262 rbArrayElement
= true;
2263 if( pParentItem
->nDimLevel
+ 1 == pParentItem
->nDimCount
)
2264 pSBX
= pArray
->Get(pItem
->vIndices
.empty() ? nullptr : &*pItem
->vIndices
.begin());
2269 pSBX
= StarBASIC::FindSBXInCurrentScope( aVName
);
2274 IMPL_LINK(WatchWindow
, EditingEntryHdl
, const weld::TreeIter
&, rIter
, bool)
2276 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rIter
));
2279 if (StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError())
2281 // No out of scope entries
2283 SbxBase
* pSbx
= ImplGetSBXForEntry(rIter
, bArrayElement
);
2284 if (IsSbxVariable(pSbx
) || bArrayElement
)
2286 // Accept no objects and only end nodes of arrays for editing
2287 if( !pItem
->mpObject
.is() && ( !pItem
->mpArray
.is() || pItem
->nDimLevel
== pItem
->nDimCount
) )
2289 aEditingRes
= m_xTreeListBox
->get_text(rIter
, 1);
2290 aEditingRes
= comphelper::string::strip(aEditingRes
, ' ');
2299 IMPL_LINK(WatchWindow
, EditedEntryHdl
, const IterString
&, rIterString
, bool)
2301 const weld::TreeIter
& rIter
= rIterString
.first
;
2302 OUString aResult
= comphelper::string::strip(rIterString
.second
, ' ');
2304 sal_uInt16 nResultLen
= aResult
.getLength();
2305 sal_Unicode cFirst
= aResult
[0];
2306 sal_Unicode cLast
= aResult
[ nResultLen
- 1 ];
2307 if( cFirst
== '\"' && cLast
== '\"' )
2308 aResult
= aResult
.copy( 1, nResultLen
- 2 );
2310 if (aResult
== aEditingRes
)
2314 SbxBase
* pSBX
= ImplGetSBXForEntry(rIter
, bArrayElement
);
2316 if (SbxVariable
* pVar
= IsSbxVariable(pSBX
))
2318 SbxDataType eType
= pVar
->GetType();
2319 if ( static_cast<sal_uInt8
>(eType
) != sal_uInt8(SbxOBJECT
)
2320 && ( eType
& SbxARRAY
) == 0 )
2322 // If the type is variable, the conversion of the SBX does not matter,
2323 // else the string is converted.
2324 pVar
->PutStringExt( aResult
);
2328 if ( SbxBase::IsError() )
2330 SbxBase::ResetError();
2335 // The text should never be taken/copied 1:1,
2336 // as the UpdateWatches will be lost
2343 void implCollapseModifiedObjectEntry(const weld::TreeIter
& rParent
, weld::TreeView
& rTree
)
2345 rTree
.collapse_row(rParent
);
2347 std::unique_ptr
<weld::TreeIter
> xDeleteEntry
= rTree
.make_iterator(&rParent
);
2349 while (rTree
.iter_children(*xDeleteEntry
))
2351 implCollapseModifiedObjectEntry(*xDeleteEntry
, rTree
);
2353 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(rTree
.get_id(*xDeleteEntry
));
2355 rTree
.remove(*xDeleteEntry
);
2356 rTree
.copy_iterator(rParent
, *xDeleteEntry
);
2360 OUString
implCreateTypeStringForDimArray( WatchItem
* pItem
, SbxDataType eType
)
2362 OUString aRetStr
= getBasicTypeName( eType
);
2364 SbxDimArray
* pArray
= pItem
->mpArray
.get();
2366 pArray
= pItem
->GetRootArray();
2369 int nDimLevel
= pItem
->nDimLevel
;
2370 int nDims
= pItem
->nDimCount
;
2371 if( nDimLevel
< nDims
)
2374 for( int i
= nDimLevel
; i
< nDims
; i
++ )
2376 sal_Int32 nMin
, nMax
;
2377 pArray
->GetDim(sal::static_int_cast
<sal_Int32
>(i
+ 1), nMin
, nMax
);
2378 aRetStr
+= OUString::number(nMin
) + " to " + OUString::number(nMax
);
2390 void WatchWindow::implEnableChildren(const weld::TreeIter
& rEntry
, bool bEnable
)
2394 if (!m_xTreeListBox
->get_row_expanded(rEntry
))
2395 m_xTreeListBox
->set_children_on_demand(rEntry
, true);
2399 assert(!m_xTreeListBox
->get_row_expanded(rEntry
));
2400 m_xTreeListBox
->set_children_on_demand(rEntry
, false);
2404 void WatchWindow::UpdateWatches(bool bBasicStopped
)
2406 SbMethod
* pCurMethod
= StarBASIC::GetActiveMethod();
2408 ErrCode eOld
= SbxBase::GetError();
2409 setBasicWatchMode( true );
2411 m_xTreeListBox
->all_foreach([this, pCurMethod
, bBasicStopped
](weld::TreeIter
& rEntry
){
2412 WatchItem
* pItem
= weld::fromId
<WatchItem
*>(m_xTreeListBox
->get_id(rEntry
));
2413 DBG_ASSERT( !pItem
->maName
.isEmpty(), "Var? - Must not be empty!" );
2418 bool bCollapse
= false;
2419 TriState eEnableChildren
= TRISTATE_INDET
;
2422 SbxBase
* pSBX
= ImplGetSBXForEntry(rEntry
, bArrayElement
);
2424 // Array? If no end node create type string
2425 if( bArrayElement
&& pItem
->nDimLevel
< pItem
->nDimCount
)
2427 SbxDimArray
* pRootArray
= pItem
->GetRootArray();
2428 SbxDataType eType
= pRootArray
->GetType();
2429 aTypeStr
= implCreateTypeStringForDimArray( pItem
, eType
);
2430 eEnableChildren
= TRISTATE_TRUE
;
2433 if (SbxVariable
* pVar
= dynamic_cast<SbxVariable
*>(pSBX
))
2435 // extra treatment of arrays
2436 SbxDataType eType
= pVar
->GetType();
2437 if ( eType
& SbxARRAY
)
2439 // consider multidimensional arrays!
2440 if (SbxDimArray
* pNewArray
= dynamic_cast<SbxDimArray
*>(pVar
->GetObject()))
2442 SbxDimArray
* pOldArray
= pItem
->mpArray
.get();
2444 bool bArrayChanged
= false;
2445 if (pOldArray
!= nullptr)
2447 // Compare Array dimensions to see if array has changed
2448 // Can be a copy, so comparing pointers does not work
2449 sal_Int32 nOldDims
= pOldArray
->GetDims();
2450 sal_Int32 nNewDims
= pNewArray
->GetDims();
2451 if( nOldDims
!= nNewDims
)
2453 bArrayChanged
= true;
2457 for( sal_Int32 i
= 0 ; i
< nOldDims
; i
++ )
2459 sal_Int32 nOldMin
, nOldMax
;
2460 sal_Int32 nNewMin
, nNewMax
;
2462 pOldArray
->GetDim(i
+ 1, nOldMin
, nOldMax
);
2463 pNewArray
->GetDim(i
+ 1, nNewMin
, nNewMax
);
2464 if( nOldMin
!= nNewMin
|| nOldMax
!= nNewMax
)
2466 bArrayChanged
= true;
2474 bArrayChanged
= true;
2476 eEnableChildren
= TRISTATE_TRUE
;
2477 // #i37227 Clear always and replace array
2478 if( pNewArray
!= pOldArray
)
2480 pItem
->clearWatchItem();
2481 eEnableChildren
= TRISTATE_TRUE
;
2483 pItem
->mpArray
= pNewArray
;
2484 sal_Int32 nDims
= pNewArray
->GetDims();
2485 pItem
->nDimLevel
= 0;
2486 pItem
->nDimCount
= nDims
;
2488 if( bArrayChanged
&& pOldArray
!= nullptr )
2492 aTypeStr
= implCreateTypeStringForDimArray( pItem
, eType
);
2499 else if ( static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxOBJECT
) )
2501 if (SbxObject
* pObj
= dynamic_cast<SbxObject
*>(pVar
->GetObject()))
2503 if ( pItem
->mpObject
.is() && !pItem
->maMemberList
.empty() )
2505 createAllObjectProperties(pObj
);
2506 SbxArray
* pProps
= pObj
->GetProperties();
2507 const sal_uInt32 nPropCount
= getCorrectedPropCount(pProps
);
2508 // Check if member list has changed
2509 bCollapse
= pItem
->maMemberList
.size() != nPropCount
;
2510 for( sal_uInt32 i
= 0 ; !bCollapse
&& i
< nPropCount
; i
++ )
2512 SbxVariable
* pVar_
= pProps
->Get(i
);
2513 if( pItem
->maMemberList
[i
] != pVar_
->GetName() )
2518 pItem
->mpObject
= pObj
;
2519 eEnableChildren
= TRISTATE_TRUE
;
2520 aTypeStr
= getBasicObjectTypeName( pObj
);
2525 if( pItem
->mpObject
.is() )
2528 eEnableChildren
= TRISTATE_FALSE
;
2534 if( pItem
->mpObject
.is() )
2537 eEnableChildren
= TRISTATE_FALSE
;
2540 bool bString
= (static_cast<sal_uInt8
>(eType
) == sal_uInt8(SbxSTRING
));
2541 OUString
aStrStr( "\"" );
2544 aWatchStr
+= aStrStr
;
2546 // tdf#57308 - avoid a second call to retrieve the data
2547 const SbxFlagBits nFlags
= pVar
->GetFlags();
2548 pVar
->SetFlag(SbxFlagBits::NoBroadcast
);
2549 aWatchStr
+= pVar
->GetOUString();
2550 pVar
->SetFlags(nFlags
);
2553 aWatchStr
+= aStrStr
;
2556 if( aTypeStr
.isEmpty() )
2558 if( !pVar
->IsFixed() )
2560 aTypeStr
= "Variant/";
2562 aTypeStr
+= getBasicTypeName( pVar
->GetType() );
2565 else if( !bArrayElement
)
2567 aWatchStr
+= "<Out of Scope>";
2572 implCollapseModifiedObjectEntry(rEntry
, *m_xTreeListBox
);
2573 pItem
->clearWatchItem();
2576 if (eEnableChildren
!= TRISTATE_INDET
)
2577 implEnableChildren(rEntry
, eEnableChildren
== TRISTATE_TRUE
);
2579 else if( bBasicStopped
)
2581 if( pItem
->mpObject
.is() || pItem
->mpArray
.is() )
2583 implCollapseModifiedObjectEntry(rEntry
, *m_xTreeListBox
);
2584 pItem
->mpObject
.clear();
2585 pItem
->mpArray
.clear();
2587 pItem
->clearWatchItem();
2590 m_xTreeListBox
->set_text(rEntry
, aWatchStr
, 1);
2591 m_xTreeListBox
->set_text(rEntry
, aTypeStr
, 2);
2596 SbxBase::ResetError();
2597 if( eOld
!= ERRCODE_NONE
)
2598 SbxBase::SetError( eOld
);
2599 setBasicWatchMode( false );
2602 IMPL_LINK_NOARG(CodeCompleteWindow
, ImplDoubleClickHdl
, weld::TreeView
&, bool)
2604 InsertSelectedEntry();
2608 IMPL_LINK_NOARG(CodeCompleteWindow
, ImplSelectHdl
, weld::TreeView
&, void)
2610 //give back the focus to the parent
2611 pParent
->GrabFocus();
2614 TextView
* CodeCompleteWindow::GetParentEditView()
2616 return pParent
->GetEditView();
2619 void CodeCompleteWindow::InsertSelectedEntry()
2621 OUString sSelectedEntry
= m_xListBox
->get_selected_text();
2623 if( !aFuncBuffer
.isEmpty() )
2625 // if the user typed in something: remove, and insert
2626 GetParentEditView()->SetSelection(pParent
->GetLastHighlightPortionTextSelection());
2627 GetParentEditView()->DeleteSelected();
2629 if (!sSelectedEntry
.isEmpty())
2631 // if the user selected something
2632 GetParentEditView()->InsertText(sSelectedEntry
);
2637 if (!sSelectedEntry
.isEmpty())
2639 // if the user selected something
2640 GetParentEditView()->InsertText(sSelectedEntry
);
2643 HideAndRestoreFocus();
2646 void CodeCompleteWindow::SetMatchingEntries()
2648 for (sal_Int32 i
= 0, nEntryCount
= m_xListBox
->n_children(); i
< nEntryCount
; ++i
)
2650 OUString sEntry
= m_xListBox
->get_text(i
);
2651 if (sEntry
.startsWithIgnoreAsciiCase(aFuncBuffer
))
2653 m_xListBox
->select(i
);
2659 IMPL_LINK(CodeCompleteWindow
, KeyInputHdl
, const KeyEvent
&, rKEvt
, bool)
2661 return HandleKeyInput(rKEvt
);
2664 bool CodeCompleteWindow::HandleKeyInput( const KeyEvent
& rKeyEvt
)
2666 bool bHandled
= true;
2668 sal_Unicode aChar
= rKeyEvt
.GetKeyCode().GetCode();
2669 if( (( aChar
>= KEY_A
) && ( aChar
<= KEY_Z
))
2670 || ((aChar
>= KEY_0
) && (aChar
<= KEY_9
)) )
2672 aFuncBuffer
.append(rKeyEvt
.GetCharCode());
2673 SetMatchingEntries();
2681 case KEY_ESCAPE
: // hide, do nothing
2682 HideAndRestoreFocus();
2686 TextSelection
aTextSelection( GetParentEditView()->GetSelection() );
2687 if( aTextSelection
.GetEnd().GetPara() != GetTextSelection().GetEnd().GetPara()-1 )
2689 HideAndRestoreFocus();
2695 TextSelection
aTextSelection( GetParentEditView()->GetSelection() );
2696 if( aTextSelection
.GetStart().GetIndex()-1 < GetTextSelection().GetStart().GetIndex() )
2697 {//leave the cursor where it is
2698 HideAndRestoreFocus();
2704 TextSelection aTextSelection
= pParent
->GetLastHighlightPortionTextSelection();
2705 OUString sTypedText
= pParent
->GetEditEngine()->GetText(aTextSelection
);
2706 if( !aFuncBuffer
.isEmpty() )
2708 sal_Int32 nInd
= m_xListBox
->get_selected_index();
2711 int nEntryCount
= m_xListBox
->n_children();
2712 //if there is something selected
2713 bool bFound
= false;
2714 for (sal_Int32 i
= nInd
; i
!= nEntryCount
; ++i
)
2716 OUString sEntry
= m_xListBox
->get_text(i
);
2717 if( sEntry
.startsWithIgnoreAsciiCase( aFuncBuffer
)
2718 && (std::u16string_view(aFuncBuffer
) != sTypedText
) && (i
!= nInd
) )
2720 m_xListBox
->select(i
);
2726 SetMatchingEntries();
2728 GetParentEditView()->SetSelection( aTextSelection
);
2729 GetParentEditView()->DeleteSelected();
2730 GetParentEditView()->InsertText(m_xListBox
->get_selected_text());
2736 HideAndRestoreFocus();
2738 case KEY_BACKSPACE
: case KEY_DELETE
:
2739 if( !aFuncBuffer
.isEmpty() )
2741 //if there was something inserted by tab: add it to aFuncBuffer
2742 TextSelection
aSel( GetParentEditView()->GetSelection() );
2743 TextPaM
aEnd( GetParentEditView()->CursorEndOfLine(GetTextSelection().GetEnd()) );
2744 GetParentEditView()->SetSelection(TextSelection(GetTextSelection().GetStart(), aEnd
) );
2745 OUString
aTabInsertedStr( GetParentEditView()->GetSelected() );
2746 GetParentEditView()->SetSelection( aSel
);
2748 if( !aTabInsertedStr
.isEmpty() && aTabInsertedStr
!= std::u16string_view(aFuncBuffer
) )
2750 aFuncBuffer
= aTabInsertedStr
;
2752 aFuncBuffer
.remove(aFuncBuffer
.getLength()-1, 1);
2753 SetMatchingEntries();
2762 InsertSelectedEntry();
2766 int nInd
= m_xListBox
->get_selected_index();
2768 m_xListBox
->select(nInd
- 1);
2773 int nInd
= m_xListBox
->get_selected_index();
2774 if (nInd
+ 1 < m_xListBox
->n_children())
2775 m_xListBox
->select(nInd
+ 1);
2787 void CodeCompleteWindow::HideAndRestoreFocus()
2790 pParent
->GrabFocus();
2793 CodeCompleteWindow::CodeCompleteWindow(EditorWindow
* pPar
)
2794 : InterimItemWindow(pPar
, "modules/BasicIDE/ui/codecomplete.ui", "CodeComplete")
2796 , m_xListBox(m_xBuilder
->weld_tree_view("treeview"))
2798 m_xListBox
->connect_row_activated(LINK(this, CodeCompleteWindow
, ImplDoubleClickHdl
));
2799 m_xListBox
->connect_changed(LINK(this, CodeCompleteWindow
, ImplSelectHdl
));
2800 m_xListBox
->connect_key_press(LINK(this, CodeCompleteWindow
, KeyInputHdl
));
2801 m_xListBox
->make_sorted();
2803 m_xListBox
->set_size_request(150, 150); // default, this will adopt the line length
2804 SetSizePixel(m_xContainer
->get_preferred_size());
2807 CodeCompleteWindow::~CodeCompleteWindow()
2812 void CodeCompleteWindow::dispose()
2816 InterimItemWindow::dispose();
2819 void CodeCompleteWindow::InsertEntry( const OUString
& aStr
)
2821 m_xListBox
->append_text(aStr
);
2824 void CodeCompleteWindow::ClearListBox()
2826 m_xListBox
->clear();
2827 aFuncBuffer
.setLength(0);
2830 void CodeCompleteWindow::SetTextSelection( const TextSelection
& aSel
)
2832 m_aTextSelection
= aSel
;
2835 void CodeCompleteWindow::ResizeAndPositionListBox()
2837 if (m_xListBox
->n_children() < 1)
2840 // if there is at least one element inside
2841 // calculate basic position: under the current line
2842 tools::Rectangle aRect
= static_cast<TextEngine
*>(pParent
->GetEditEngine())->PaMtoEditCursor( pParent
->GetEditView()->GetSelection().GetEnd() );
2843 tools::Long nViewYOffset
= pParent
->GetEditView()->GetStartDocPos().Y();
2844 Point aPos
= aRect
.BottomRight();// this variable will be used later (if needed)
2845 aPos
.setY( (aPos
.Y() - nViewYOffset
) + nBasePad
);
2848 const sal_uInt16 nLines
= static_cast<sal_uInt16
>(std::min(6, m_xListBox
->n_children()));
2850 m_xListBox
->set_size_request(-1, m_xListBox
->get_height_rows(nLines
));
2852 Size aSize
= m_xContainer
->get_preferred_size();
2854 SetSizePixel( aSize
);
2856 //calculate position
2857 const tools::Rectangle
aVisArea( pParent
->GetEditView()->GetStartDocPos(), pParent
->GetOutputSizePixel() ); //the visible area
2858 const Point
& aBottomPoint
= aVisArea
.BottomRight();
2860 if( aVisArea
.TopRight().getY() + aPos
.getY() + aSize
.getHeight() > aBottomPoint
.getY() )
2861 {//clipped at the bottom: move it up
2862 const tools::Long
& nParentFontHeight
= pParent
->GetEditEngine()->GetFont().GetFontHeight(); //parent's font (in the IDE): needed for height
2863 aPos
.AdjustY( -(aSize
.getHeight() + nParentFontHeight
+ nCursorPad
) );
2866 if( aVisArea
.TopLeft().getX() + aPos
.getX() + aSize
.getWidth() > aBottomPoint
.getX() )
2867 {//clipped at the right side, move it a bit left
2868 aPos
.AdjustX( -(aSize
.getWidth() + aVisArea
.TopLeft().getX()) );
2871 SetPosPixel( aPos
);
2874 void CodeCompleteWindow::SelectFirstEntry()
2876 if (m_xListBox
->n_children() > 0)
2877 m_xListBox
->select(0);
2880 void CodeCompleteWindow::ClearAndHide()
2883 HideAndRestoreFocus();
2886 UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector
< OUString
>& aVect
, const OUString
& sVarType
)
2887 : bCanComplete( true )
2889 if( aVect
.empty() || sVarType
.isEmpty() )
2891 bCanComplete
= false;//invalid parameters, nothing to code complete
2897 // Get the base class for reflection:
2898 xClass
= css::reflection::theCoreReflection::get(
2899 comphelper::getProcessComponentContext())->forName(sVarType
);
2901 catch( const Exception
& )
2903 bCanComplete
= false;
2907 //start from aVect[1]: aVect[0] is the variable name
2908 bCanComplete
= std::none_of(aVect
.begin() + 1, aVect
.end(), [this](const OUString
& rMethName
) {
2909 return (!CodeCompleteOptions::IsExtendedTypeDeclaration() || !CheckMethod(rMethName
)) && !CheckField(rMethName
); });
2912 std::vector
< OUString
> UnoTypeCodeCompletetor::GetXIdlClassMethods() const
2914 std::vector
< OUString
> aRetVect
;
2915 if( bCanComplete
&& ( xClass
!= nullptr ) )
2917 const Sequence
< Reference
< reflection::XIdlMethod
> > aMethods
= xClass
->getMethods();
2918 for(Reference
< reflection::XIdlMethod
> const & rMethod
: aMethods
)
2920 aRetVect
.push_back( rMethod
->getName() );
2923 return aRetVect
;//this is empty when cannot code complete
2926 std::vector
< OUString
> UnoTypeCodeCompletetor::GetXIdlClassFields() const
2928 std::vector
< OUString
> aRetVect
;
2929 if( bCanComplete
&& ( xClass
!= nullptr ) )
2931 const Sequence
< Reference
< reflection::XIdlField
> > aFields
= xClass
->getFields();
2932 for(Reference
< reflection::XIdlField
> const & rxField
: aFields
)
2934 aRetVect
.push_back( rxField
->getName() );
2937 return aRetVect
;//this is empty when cannot code complete
2941 bool UnoTypeCodeCompletetor::CheckField( const OUString
& sFieldName
)
2942 {// modifies xClass!!!
2944 if ( xClass
== nullptr )
2947 Reference
< reflection::XIdlField
> xField
= xClass
->getField( sFieldName
);
2948 if( xField
!= nullptr )
2950 xClass
= xField
->getType();
2951 if( xClass
!= nullptr )
2959 bool UnoTypeCodeCompletetor::CheckMethod( const OUString
& sMethName
)
2960 {// modifies xClass!!!
2963 if ( xClass
== nullptr )
2966 Reference
< reflection::XIdlMethod
> xMethod
= xClass
->getMethod( sMethName
);
2967 if( xMethod
!= nullptr ) //method OK, check return type
2969 xClass
= xMethod
->getReturnType();
2970 if( xClass
!= nullptr )
2978 } // namespace basctl
2980 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */