Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / basctl / source / basicide / baside2b.cxx
blob27da2dc9d82889f65832320814949327336698ac
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <cassert>
24 #include <helpids.h>
25 #include <strings.hrc>
26 #include <bitmaps.hlst>
28 #include "baside2.hxx"
29 #include "brkdlg.hxx"
30 #include <iderdll.hxx>
32 #include <basic/sbmeth.hxx>
33 #include <basic/sbuno.hxx>
34 #include <com/sun/star/beans/XMultiPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
36 #include <com/sun/star/script/XLibraryContainer2.hpp>
37 #include <comphelper/string.hxx>
38 #include <officecfg/Office/Common.hxx>
39 #include <sfx2/dispatch.hxx>
40 #include <vcl/weld.hxx>
41 #include <svl/urihelper.hxx>
42 #include <svx/svxids.hrc>
43 #include <vcl/xtextedt.hxx>
44 #include <vcl/txtattr.hxx>
45 #include <vcl/settings.hxx>
46 #include <svtools/textwindowpeer.hxx>
47 #include <svtools/treelistentry.hxx>
48 #include <vcl/taskpanelist.hxx>
49 #include <vcl/help.hxx>
50 #include <cppuhelper/implbase.hxx>
51 #include <vector>
52 #include <com/sun/star/reflection/theCoreReflection.hpp>
54 namespace basctl
57 using namespace ::com::sun::star;
58 using namespace ::com::sun::star::uno;
60 namespace
63 sal_uInt16 const NoMarker = 0xFFFF;
64 long const nBasePad = 2;
65 long const nCursorPad = 5;
67 long nVirtToolBoxHeight; // inited in WatchWindow, used in Stackwindow
68 long nHeaderBarHeight;
70 // Returns pBase converted to SbxVariable if valid and is not an SbxMethod.
71 SbxVariable* IsSbxVariable (SbxBase* pBase)
73 if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pBase))
74 if (!dynamic_cast<SbxMethod*>(pVar))
75 return pVar;
76 return nullptr;
79 Image GetImage(const OUString& rId)
81 return Image(BitmapEx(rId));
84 int const nScrollLine = 12;
85 int const nScrollPage = 60;
86 int const DWBORDER = 3;
88 char const cSuffixes[] = "%&!#@$";
90 } // namespace
93 /**
94 * Helper functions to get/set text in TextEngine using
95 * the stream interface.
97 * get/setText() only supports tools Strings limited to 64K).
99 OUString getTextEngineText (ExtTextEngine& rEngine)
101 SvMemoryStream aMemStream;
102 aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
103 aMemStream.SetLineDelimiter( LINEEND_LF );
104 rEngine.Write( aMemStream );
105 std::size_t nSize = aMemStream.Tell();
106 OUString aText( static_cast<const sal_Char*>(aMemStream.GetData()),
107 nSize, RTL_TEXTENCODING_UTF8 );
108 return aText;
111 void setTextEngineText (ExtTextEngine& rEngine, OUString const& aStr)
113 rEngine.SetText(OUString());
114 OString aUTF8Str = OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 );
115 SvMemoryStream aMemStream( const_cast<char *>(aUTF8Str.getStr()), aUTF8Str.getLength(),
116 StreamMode::READ );
117 aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
118 aMemStream.SetLineDelimiter( LINEEND_LF );
119 rEngine.Read(aMemStream);
122 namespace
125 void lcl_DrawIDEWindowFrame(DockingWindow const * pWin, vcl::RenderContext& rRenderContext)
127 if (pWin->IsFloatingMode())
128 return;
130 Size aSz(pWin->GetOutputSizePixel());
131 const Color aOldLineColor(rRenderContext.GetLineColor());
132 rRenderContext.SetLineColor(COL_WHITE);
133 // White line on top
134 rRenderContext.DrawLine(Point(0, 0), Point(aSz.Width(), 0));
135 // Black line at bottom
136 rRenderContext.SetLineColor(COL_BLACK);
137 rRenderContext.DrawLine(Point(0, aSz.Height() - 1),
138 Point(aSz.Width(), aSz.Height() - 1));
139 rRenderContext.SetLineColor(aOldLineColor);
142 void lcl_SeparateNameAndIndex( const OUString& rVName, OUString& rVar, OUString& rIndex )
144 rVar = rVName;
145 rIndex.clear();
146 sal_Int32 nIndexStart = rVar.indexOf( '(' );
147 if ( nIndexStart != -1 )
149 sal_Int32 nIndexEnd = rVar.indexOf( ')', nIndexStart );
150 if ( nIndexStart != -1 )
152 rIndex = rVar.copy( nIndexStart+1, nIndexEnd-nIndexStart-1 );
153 rVar = rVar.copy( 0, nIndexStart );
154 rVar = comphelper::string::stripEnd(rVar, ' ');
155 rIndex = comphelper::string::strip(rIndex, ' ');
159 if ( !rVar.isEmpty() )
161 sal_uInt16 nLastChar = rVar.getLength()-1;
162 if ( strchr( cSuffixes, rVar[ nLastChar ] ) )
163 rVar = rVar.replaceAt( nLastChar, 1, "" );
165 if ( !rIndex.isEmpty() )
167 sal_uInt16 nLastChar = rIndex.getLength()-1;
168 if ( strchr( cSuffixes, rIndex[ nLastChar ] ) )
169 rIndex = rIndex.replaceAt( nLastChar, 1, "" );
173 } // namespace
176 // EditorWindow
179 class EditorWindow::ChangesListener:
180 public cppu::WeakImplHelper< beans::XPropertiesChangeListener >
182 public:
183 explicit ChangesListener(EditorWindow & editor): editor_(editor) {}
185 private:
186 virtual ~ChangesListener() override {}
188 virtual void SAL_CALL disposing(lang::EventObject const &) override
190 osl::MutexGuard g(editor_.mutex_);
191 editor_.notifier_.clear();
194 virtual void SAL_CALL propertiesChange(
195 Sequence< beans::PropertyChangeEvent > const &) override
197 SolarMutexGuard g;
198 editor_.ImplSetFont();
201 EditorWindow & editor_;
204 class EditorWindow::ProgressInfo : public SfxProgress
206 public:
207 ProgressInfo (SfxObjectShell* pObjSh, OUString const& rText, sal_uInt32 nRange) :
208 SfxProgress(pObjSh, rText, nRange),
209 nCurState(0)
212 void StepProgress ()
214 SetState(++nCurState);
217 private:
218 sal_uLong nCurState;
221 EditorWindow::EditorWindow (vcl::Window* pParent, ModulWindow* pModulWindow) :
222 Window(pParent, WB_BORDER),
223 rModulWindow(*pModulWindow),
224 nCurTextWidth(0),
225 aHighlighter(HighlighterLanguage::Basic),
226 bHighlighting(false),
227 bDoSyntaxHighlight(true),
228 bDelayHighlight(true),
229 pCodeCompleteWnd(VclPtr<CodeCompleteWindow>::Create(this))
231 SetBackground(Wallpaper(rModulWindow.GetLayout().GetBackgroundColor()));
232 SetPointer( Pointer( PointerStyle::Text ) );
233 SetHelpId( HID_BASICIDE_EDITORWINDOW );
235 listener_ = new ChangesListener(*this);
236 Reference< beans::XMultiPropertySet > n(
237 officecfg::Office::Common::Font::SourceViewFont::get(),
238 UNO_QUERY_THROW);
240 osl::MutexGuard g(mutex_);
241 notifier_ = n;
243 const Sequence<OUString> aPropertyNames{"FontHeight", "FontName"};
244 n->addPropertiesChangeListener(aPropertyNames, listener_.get());
248 EditorWindow::~EditorWindow()
250 disposeOnce();
253 void EditorWindow::dispose()
255 Reference< beans::XMultiPropertySet > n;
257 osl::MutexGuard g(mutex_);
258 n = notifier_;
260 if (n.is()) {
261 n->removePropertiesChangeListener(listener_.get());
264 aSyntaxIdle.Stop();
266 if ( pEditEngine )
268 EndListening( *pEditEngine );
269 pEditEngine->RemoveView(pEditView.get());
271 pCodeCompleteWnd.disposeAndClear();
272 vcl::Window::dispose();
275 OUString EditorWindow::GetWordAtCursor()
277 OUString aWord;
279 if ( pEditView )
281 TextEngine* pTextEngine = pEditView->GetTextEngine();
282 if ( pTextEngine )
284 // check first, if the cursor is at a help URL
285 const TextSelection& rSelection = pEditView->GetSelection();
286 const TextPaM& rSelStart = rSelection.GetStart();
287 const TextPaM& rSelEnd = rSelection.GetEnd();
288 OUString aText = pTextEngine->GetText( rSelEnd.GetPara() );
289 CharClass aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() );
290 sal_Int32 nSelStart = rSelStart.GetIndex();
291 sal_Int32 nSelEnd = rSelEnd.GetIndex();
292 sal_Int32 nLength = aText.getLength();
293 sal_Int32 nStart = 0;
294 sal_Int32 nEnd = nLength;
295 while ( nStart < nLength )
297 OUString aURL( URIHelper::FindFirstURLInText( aText, nStart, nEnd, aClass ) );
298 INetURLObject aURLObj( aURL );
299 if ( aURLObj.GetProtocol() == INetProtocol::VndSunStarHelp
300 && nSelStart >= nStart && nSelStart <= nEnd && nSelEnd >= nStart && nSelEnd <= nEnd )
302 aWord = aURL;
303 break;
305 nStart = nEnd;
306 nEnd = nLength;
309 // Not the selected range, but at the CursorPosition,
310 // if a word is partially selected.
311 if ( aWord.isEmpty() )
312 aWord = pTextEngine->GetWord( rSelEnd );
314 // Can be empty when full word selected, as Cursor behind it
315 if ( aWord.isEmpty() && pEditView->HasSelection() )
316 aWord = pTextEngine->GetWord( rSelStart );
320 return aWord;
323 void EditorWindow::RequestHelp( const HelpEvent& rHEvt )
325 bool bDone = false;
327 // Should have been activated at some point
328 if ( pEditEngine )
330 if ( rHEvt.GetMode() & HelpEventMode::CONTEXT )
332 OUString aKeyword = GetWordAtCursor();
333 Application::GetHelp()->SearchKeyword( aKeyword );
334 bDone = true;
336 else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
338 OUString aHelpText;
339 Point aTopLeft;
340 if ( StarBASIC::IsRunning() )
342 Point aWindowPos = rHEvt.GetMousePosPixel();
343 aWindowPos = ScreenToOutputPixel( aWindowPos );
344 Point aDocPos = GetEditView()->GetDocPos( aWindowPos );
345 TextPaM aCursor = GetEditView()->GetTextEngine()->GetPaM(aDocPos);
346 TextPaM aStartOfWord;
347 OUString aWord = GetEditView()->GetTextEngine()->GetWord( aCursor, &aStartOfWord );
348 if ( !aWord.isEmpty() && !comphelper::string::isdigitAsciiString(aWord) )
350 sal_uInt16 nLastChar = aWord.getLength() - 1;
351 if ( strchr( cSuffixes, aWord[ nLastChar ] ) )
352 aWord = aWord.replaceAt( nLastChar, 1, "" );
353 SbxBase* pSBX = StarBASIC::FindSBXInCurrentScope( aWord );
354 if (SbxVariable const* pVar = IsSbxVariable(pSBX))
356 SbxDataType eType = pVar->GetType();
357 if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) )
358 // might cause a crash e. g. at the selections-object
359 // Type == Object does not mean pVar == Object!
360 ; // aHelpText = ((SbxObject*)pVar)->GetClassName();
361 else if ( eType & SbxARRAY )
362 ; // aHelpText = "{...}";
363 else if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxEMPTY) )
365 aHelpText = pVar->GetName();
366 if ( aHelpText.isEmpty() ) // name is not copied with the passed parameters
367 aHelpText = aWord;
368 aHelpText += "=" + pVar->GetOUString();
371 if ( !aHelpText.isEmpty() )
373 aTopLeft = GetEditView()->GetTextEngine()->PaMtoEditCursor( aStartOfWord ).BottomLeft();
374 aTopLeft = GetEditView()->GetWindowPos( aTopLeft );
375 aTopLeft.AdjustX(5 );
376 aTopLeft.AdjustY(5 );
377 aTopLeft = OutputToScreenPixel( aTopLeft );
381 Help::ShowQuickHelp( this, tools::Rectangle( aTopLeft, Size( 1, 1 ) ), aHelpText, QuickHelpFlags::Top|QuickHelpFlags::Left);
382 bDone = true;
386 if ( !bDone )
387 Window::RequestHelp( rHEvt );
391 void EditorWindow::Resize()
393 // ScrollBars, etc. happens in Adjust...
394 if ( pEditView )
396 long nVisY = pEditView->GetStartDocPos().Y();
398 pEditView->ShowCursor();
399 Size aOutSz( GetOutputSizePixel() );
400 long nMaxVisAreaStart = pEditView->GetTextEngine()->GetTextHeight() - aOutSz.Height();
401 if ( nMaxVisAreaStart < 0 )
402 nMaxVisAreaStart = 0;
403 if ( pEditView->GetStartDocPos().Y() > nMaxVisAreaStart )
405 Point aStartDocPos( pEditView->GetStartDocPos() );
406 aStartDocPos.setY( nMaxVisAreaStart );
407 pEditView->SetStartDocPos( aStartDocPos );
408 pEditView->ShowCursor();
409 rModulWindow.GetBreakPointWindow().GetCurYOffset() = aStartDocPos.Y();
410 rModulWindow.GetLineNumberWindow().GetCurYOffset() = aStartDocPos.Y();
412 InitScrollBars();
413 if ( nVisY != pEditView->GetStartDocPos().Y() )
414 Invalidate();
419 void EditorWindow::MouseMove( const MouseEvent &rEvt )
421 if ( pEditView )
422 pEditView->MouseMove( rEvt );
426 void EditorWindow::MouseButtonUp( const MouseEvent &rEvt )
428 if ( pEditView )
430 pEditView->MouseButtonUp( rEvt );
431 if (SfxBindings* pBindings = GetBindingsPtr())
433 pBindings->Invalidate( SID_BASICIDE_STAT_POS );
434 pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
439 void EditorWindow::MouseButtonDown( const MouseEvent &rEvt )
441 GrabFocus();
442 if ( pEditView )
443 pEditView->MouseButtonDown( rEvt );
444 if( pCodeCompleteWnd->IsVisible() )
446 if( pEditView->GetSelection() != pCodeCompleteWnd->GetTextSelection() )
447 {//selection changed, code complete window should be hidden
448 pCodeCompleteWnd->GetListBox()->HideAndRestoreFocus();
453 void EditorWindow::Command( const CommandEvent& rCEvt )
455 if ( pEditView )
457 pEditView->Command( rCEvt );
458 if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) ||
459 ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) ||
460 ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) )
462 HandleScrollCommand( rCEvt, rModulWindow.GetHScrollBar(), &rModulWindow.GetEditVScrollBar() );
463 } else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) {
464 SfxDispatcher* pDispatcher = GetDispatcher();
465 if ( pDispatcher )
467 SfxDispatcher::ExecutePopup();
469 if( pCodeCompleteWnd->IsVisible() ) // hide the code complete window
470 pCodeCompleteWnd->ClearAndHide();
475 bool EditorWindow::ImpCanModify()
477 bool bCanModify = true;
478 if ( StarBASIC::IsRunning() && rModulWindow.GetBasicStatus().bIsRunning )
480 // If in Trace-mode, abort the trace or refuse input
481 // Remove markers in the modules in Notify at Basic::Stopped
482 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
483 VclMessageType::Question, VclButtonsType::OkCancel,
484 IDEResId(RID_STR_WILLSTOPPRG)));
485 if (xQueryBox->run() == RET_OK)
487 rModulWindow.GetBasicStatus().bIsRunning = false;
488 StopBasic();
490 else
491 bCanModify = false;
493 return bCanModify;
496 void EditorWindow::KeyInput( const KeyEvent& rKEvt )
498 if ( !pEditView ) // Happens in Win95
499 return;
501 bool const bWasModified = pEditEngine->IsModified();
502 // see if there is an accelerator to be processed first
503 SfxViewShell *pVS( SfxViewShell::Current());
504 bool bDone = pVS && pVS->KeyInput( rKEvt );
506 if( pCodeCompleteWnd->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn() )
508 pCodeCompleteWnd->GetListBox()->KeyInput(rKEvt);
509 if( rKEvt.GetKeyCode().GetCode() == KEY_UP
510 || rKEvt.GetKeyCode().GetCode() == KEY_DOWN
511 || rKEvt.GetKeyCode().GetCode() == KEY_TAB
512 || rKEvt.GetKeyCode().GetCode() == KEY_POINT)
513 return;
516 if( (rKEvt.GetKeyCode().GetCode() == KEY_SPACE ||
517 rKEvt.GetKeyCode().GetCode() == KEY_TAB ||
518 rKEvt.GetKeyCode().GetCode() == KEY_RETURN ) && CodeCompleteOptions::IsAutoCorrectOn() )
520 HandleAutoCorrect();
523 if( rKEvt.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() )
524 {//autoclose double quotes
525 HandleAutoCloseDoubleQuotes();
528 if( rKEvt.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() )
529 {//autoclose parenthesis
530 HandleAutoCloseParen();
533 if( rKEvt.GetKeyCode().GetCode() == KEY_RETURN && CodeCompleteOptions::IsProcedureAutoCompleteOn() )
534 {//autoclose implementation
535 HandleProcedureCompletion();
538 if( rKEvt.GetKeyCode().GetCode() == KEY_POINT && CodeCompleteOptions::IsCodeCompleteOn() )
540 HandleCodeCompletion();
542 if ( !bDone && ( !TextEngine::DoesKeyChangeText( rKEvt ) || ImpCanModify() ) )
544 if ( ( rKEvt.GetKeyCode().GetCode() == KEY_TAB ) && !rKEvt.GetKeyCode().IsMod1() &&
545 !rKEvt.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() )
547 TextSelection aSel( pEditView->GetSelection() );
548 if ( aSel.GetStart().GetPara() != aSel.GetEnd().GetPara() )
550 bDelayHighlight = false;
551 if ( !rKEvt.GetKeyCode().IsShift() )
552 pEditView->IndentBlock();
553 else
554 pEditView->UnindentBlock();
555 bDelayHighlight = true;
556 bDone = true;
559 if ( !bDone )
560 bDone = pEditView->KeyInput( rKEvt );
562 if ( !bDone )
564 Window::KeyInput( rKEvt );
566 else
568 if (SfxBindings* pBindings = GetBindingsPtr())
570 pBindings->Invalidate( SID_BASICIDE_STAT_POS );
571 pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
572 if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR )
574 pBindings->Update( SID_BASICIDE_STAT_POS );
575 pBindings->Update( SID_BASICIDE_STAT_TITLE );
577 if ( !bWasModified && pEditEngine->IsModified() )
579 pBindings->Invalidate( SID_SAVEDOC );
580 pBindings->Invalidate( SID_DOC_MODIFIED );
581 pBindings->Invalidate( SID_UNDO );
583 if ( rKEvt.GetKeyCode().GetCode() == KEY_INSERT )
584 pBindings->Invalidate( SID_ATTR_INSERT );
589 void EditorWindow::HandleAutoCorrect()
591 TextSelection aSel = GetEditView()->GetSelection();
592 const sal_uInt32 nLine = aSel.GetStart().GetPara();
593 const sal_Int32 nIndex = aSel.GetStart().GetIndex();
594 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
595 const OUString& sActSubName = GetActualSubName( nLine ); // the actual procedure
597 std::vector<HighlightPortion> aPortions;
598 aHighlighter.getHighlightPortions( aLine, aPortions );
600 if( aPortions.empty() )
601 return;
603 HighlightPortion& r = aPortions.back();
604 if( static_cast<size_t>(nIndex) != aPortions.size()-1 )
605 {//cursor is not standing at the end of the line
606 for (auto const& portion : aPortions)
608 if( portion.nEnd == nIndex )
610 r = portion;
611 break;
616 OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin );
617 //if WS or empty string: stop, nothing to do
618 if( ( r.tokenType == TokenType::Whitespace ) || sStr.isEmpty() )
619 return;
620 //create the appropriate TextSelection, and update the cache
621 TextPaM aStart( nLine, r.nBegin );
622 TextPaM aEnd( nLine, r.nBegin + sStr.getLength() );
623 TextSelection sTextSelection( aStart, aEnd );
624 rModulWindow.UpdateModule();
625 rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache );
626 // correct the last entered keyword
627 if( r.tokenType == TokenType::Keywords )
629 sStr = sStr.toAsciiLowerCase();
630 if( !SbModule::GetKeywordCase(sStr).isEmpty() )
631 // if it is a keyword, get its correct case
632 sStr = SbModule::GetKeywordCase(sStr);
633 else
634 // else capitalize first letter/select the correct one, and replace
635 sStr = sStr.replaceAt( 0, 1, OUString(sStr[0]).toAsciiUpperCase() );
637 pEditEngine->ReplaceText( sTextSelection, sStr );
638 pEditView->SetSelection( aSel );
640 if( r.tokenType == TokenType::Identifier )
641 {// correct variables
642 if( !aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ).isEmpty() )
644 sStr = aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName );
645 pEditEngine->ReplaceText( sTextSelection, sStr );
646 pEditView->SetSelection( aSel );
648 else
650 //autocorrect procedures
651 SbxArray* pArr = rModulWindow.GetSbModule()->GetMethods().get();
652 for( sal_uInt32 i=0; i < pArr->Count32(); ++i )
654 if( pArr->Get32(i)->GetName().equalsIgnoreAsciiCase( sStr ) )
656 sStr = pArr->Get32(i)->GetName(); //if found, get the correct case
657 pEditEngine->ReplaceText( sTextSelection, sStr );
658 pEditView->SetSelection( aSel );
659 return;
666 TextSelection EditorWindow::GetLastHighlightPortionTextSelection()
667 {//creates a text selection from the highlight portion on the cursor
668 const sal_uInt32 nLine = GetEditView()->GetSelection().GetStart().GetPara();
669 const sal_Int32 nIndex = GetEditView()->GetSelection().GetStart().GetIndex();
670 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
671 std::vector<HighlightPortion> aPortions;
672 aHighlighter.getHighlightPortions( aLine, aPortions );
674 assert(!aPortions.empty());
675 HighlightPortion& r = aPortions.back();
676 if( static_cast<size_t>(nIndex) != aPortions.size()-1 )
677 {//cursor is not standing at the end of the line
678 for (auto const& portion : aPortions)
680 if( portion.nEnd == nIndex )
682 r = portion;
683 break;
688 if( aPortions.empty() )
689 return TextSelection();
691 OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin );
692 TextPaM aStart( nLine, r.nBegin );
693 TextPaM aEnd( nLine, r.nBegin + sStr.getLength() );
694 return TextSelection( aStart, aEnd );
697 void EditorWindow::HandleAutoCloseParen()
699 TextSelection aSel = GetEditView()->GetSelection();
700 const sal_uInt32 nLine = aSel.GetStart().GetPara();
701 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
703 if( aLine.getLength() > 0 && aLine[aSel.GetEnd().GetIndex()-1] != '(' )
705 GetEditView()->InsertText(")");
706 //leave the cursor on its place: inside the parenthesis
707 TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
708 GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
712 void EditorWindow::HandleAutoCloseDoubleQuotes()
714 TextSelection aSel = GetEditView()->GetSelection();
715 const sal_uInt32 nLine = aSel.GetStart().GetPara();
716 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
718 std::vector<HighlightPortion> aPortions;
719 aHighlighter.getHighlightPortions( aLine, aPortions );
721 if( aPortions.empty() )
722 return;
724 if( aLine.getLength() > 0 && !aLine.endsWith("\"") && (aPortions.back().tokenType != TokenType::String) )
726 GetEditView()->InsertText("\"");
727 //leave the cursor on its place: inside the two double quotes
728 TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
729 GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
733 void EditorWindow::HandleProcedureCompletion()
736 TextSelection aSel = GetEditView()->GetSelection();
737 const sal_uInt32 nLine = aSel.GetStart().GetPara();
738 OUString aLine( pEditEngine->GetText( nLine ) );
740 OUString sProcType;
741 OUString sProcName;
742 bool bFoundName = GetProcedureName(aLine, sProcType, sProcName);
743 if (!bFoundName)
744 return;
746 OUString sText("\nEnd ");
747 aSel = GetEditView()->GetSelection();
748 if( sProcType.equalsIgnoreAsciiCase("function") )
749 sText += "Function\n";
750 if( sProcType.equalsIgnoreAsciiCase("sub") )
751 sText += "Sub\n";
753 if( nLine+1 == pEditEngine->GetParagraphCount() )
755 pEditView->InsertText( sText );//append to the end
756 GetEditView()->SetSelection(aSel);
758 else
760 for( sal_uInt32 i = nLine+1; i < pEditEngine->GetParagraphCount(); ++i )
761 {//searching forward for end token, or another sub/function definition
762 OUString aCurrLine = pEditEngine->GetText( i );
763 std::vector<HighlightPortion> aCurrPortions;
764 aHighlighter.getHighlightPortions( aCurrLine, aCurrPortions );
766 if( aCurrPortions.size() >= 3 )
767 {//at least 3 tokens: (sub|function) whitespace identifier...
768 HighlightPortion& r = aCurrPortions.front();
769 OUString sStr = aCurrLine.copy(r.nBegin, r.nEnd - r.nBegin);
771 if( r.tokenType == TokenType::Keywords )
773 if( sStr.equalsIgnoreAsciiCase("sub") || sStr.equalsIgnoreAsciiCase("function") )
775 pEditView->InsertText( sText );//append to the end
776 GetEditView()->SetSelection(aSel);
777 break;
779 if( sStr.equalsIgnoreAsciiCase("end") )
780 break;
787 bool EditorWindow::GetProcedureName(OUString const & rLine, OUString& rProcType, OUString& rProcName) const
789 std::vector<HighlightPortion> aPortions;
790 aHighlighter.getHighlightPortions(rLine, aPortions);
792 if( aPortions.empty() )
793 return false;
795 bool bFoundType = false;
796 bool bFoundName = false;
798 for (auto const& portion : aPortions)
800 OUString sTokStr = rLine.copy(portion.nBegin, portion.nEnd - portion.nBegin);
802 if( portion.tokenType == TokenType::Keywords && ( sTokStr.equalsIgnoreAsciiCase("sub")
803 || sTokStr.equalsIgnoreAsciiCase("function")) )
805 rProcType = sTokStr;
806 bFoundType = true;
808 if( portion.tokenType == TokenType::Identifier && bFoundType )
810 rProcName = sTokStr;
811 bFoundName = true;
812 break;
816 if( !bFoundType || !bFoundName )
817 return false;// no sub/function keyword or there is no identifier
819 return true;
823 void EditorWindow::HandleCodeCompletion()
825 rModulWindow.UpdateModule();
826 rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache);
827 TextSelection aSel = GetEditView()->GetSelection();
828 const sal_uInt32 nLine = aSel.GetStart().GetPara();
829 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
830 std::vector< OUString > aVect; //vector to hold the base variable+methods for the nested reflection
832 std::vector<HighlightPortion> aPortions;
833 aLine = aLine.copy(0, aSel.GetEnd().GetIndex());
834 aHighlighter.getHighlightPortions( aLine, aPortions );
835 if( !aPortions.empty() )
836 {//use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod ..
837 for( std::vector<HighlightPortion>::reverse_iterator i(
838 aPortions.rbegin());
839 i != aPortions.rend(); ++i)
841 if( i->tokenType == TokenType::Whitespace ) // a whitespace: stop; if there is no ws, it goes to the beginning of the line
842 break;
843 if( i->tokenType == TokenType::Identifier || i->tokenType == TokenType::Keywords ) // extract the identifiers(methods, base variable)
844 /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue
845 * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!)
846 * */
847 aVect.insert( aVect.begin(), aLine.copy(i->nBegin, i->nEnd - i->nBegin) );
850 if( aVect.empty() )//nothing to do
851 return;
853 OUString sBaseName = aVect[aVect.size()-1];//variable name
854 OUString sVarType = aCodeCompleteCache.GetVarType( sBaseName );
856 if( !sVarType.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() )
857 {//correct variable name, if autocorrection on
858 const OUString& sStr = aCodeCompleteCache.GetCorrectCaseVarName( sBaseName, GetActualSubName(nLine) );
859 if( !sStr.isEmpty() )
861 TextPaM aStart(nLine, aSel.GetStart().GetIndex() - sStr.getLength() );
862 TextSelection sTextSelection(aStart, TextPaM(nLine, aSel.GetStart().GetIndex()));
863 pEditEngine->ReplaceText( sTextSelection, sStr );
864 pEditView->SetSelection( aSel );
868 UnoTypeCodeCompletetor aTypeCompletor( aVect, sVarType );
870 if( aTypeCompletor.CanCodeComplete() )
872 std::vector< OUString > aEntryVect;//entries to be inserted into the list
873 std::vector< OUString > aFieldVect = aTypeCompletor.GetXIdlClassFields();//fields
874 aEntryVect.insert(aEntryVect.end(), aFieldVect.begin(), aFieldVect.end() );
875 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
876 {// if extended types on, reflect classes, else just the structs (XIdlClass without methods)
877 std::vector< OUString > aMethVect = aTypeCompletor.GetXIdlClassMethods();//methods
878 aEntryVect.insert(aEntryVect.end(), aMethVect.begin(), aMethVect.end() );
880 if( aEntryVect.size() > 0 )
881 SetupAndShowCodeCompleteWnd( aEntryVect, aSel );
886 void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector< OUString >& aEntryVect, TextSelection aSel )
888 // clear the listbox
889 pCodeCompleteWnd->ClearListBox();
890 // fill the listbox
891 for(const auto & l : aEntryVect)
893 pCodeCompleteWnd->InsertEntry( l );
895 // show it
896 pCodeCompleteWnd->Show();
897 pCodeCompleteWnd->ResizeAndPositionListBox();
898 pCodeCompleteWnd->SelectFirstEntry();
899 // correct text selection, and set it
900 ++aSel.GetStart().GetIndex();
901 ++aSel.GetEnd().GetIndex();
902 pCodeCompleteWnd->SetTextSelection( aSel );
903 //give the focus to the EditView
904 pEditView->GetWindow()->GrabFocus();
907 void EditorWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
909 if (!pEditEngine) // We need it now at latest
910 CreateEditEngine();
912 pEditView->Paint(rRenderContext, rRect);
915 void EditorWindow::LoseFocus()
917 SetSourceInBasic();
918 Window::LoseFocus();
921 void EditorWindow::SetSourceInBasic()
923 if ( pEditEngine && pEditEngine->IsModified()
924 && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise
925 // any read only bug in the text engine could lead to a crash later
927 if ( !StarBASIC::IsRunning() ) // Not at runtime!
929 rModulWindow.UpdateModule();
934 // Returns the position of the last character of any of the following
935 // EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found
936 sal_Int32 searchEOL( const OUString& rStr, sal_Int32 fromIndex )
938 sal_Int32 iRetPos = -1;
940 sal_Int32 iLF = rStr.indexOf( LINE_SEP, fromIndex );
941 if( iLF != -1 )
943 iRetPos = iLF;
945 else
947 iRetPos = rStr.indexOf( LINE_SEP_CR, fromIndex );
949 return iRetPos;
952 void EditorWindow::CreateEditEngine()
954 if (pEditEngine)
955 return;
957 pEditEngine.reset(new ExtTextEngine);
958 pEditView.reset(new TextView(pEditEngine.get(), this));
959 pEditView->SetAutoIndentMode(true);
960 pEditEngine->SetUpdateMode(false);
961 pEditEngine->InsertView(pEditView.get());
963 ImplSetFont();
965 aSyntaxIdle.SetInvokeHandler( LINK( this, EditorWindow, SyntaxTimerHdl ) );
967 bool bWasDoSyntaxHighlight = bDoSyntaxHighlight;
968 bDoSyntaxHighlight = false; // too slow for large texts...
969 OUString aOUSource(rModulWindow.GetModule());
970 sal_Int32 nLines = 0;
971 sal_Int32 nIndex = -1;
974 nLines++;
975 nIndex = searchEOL( aOUSource, nIndex+1 );
977 while (nIndex >= 0);
979 // nLines*4: SetText+Formatting+DoHighlight+Formatting
980 // it could be cut down on one formatting but you would wait even longer
981 // for the text then if the source code is long...
982 pProgress.reset(new ProgressInfo(GetShell()->GetViewFrame()->GetObjectShell(),
983 IDEResId(RID_STR_GENERATESOURCE),
984 nLines * 4));
985 setTextEngineText(*pEditEngine, aOUSource);
987 pEditView->SetStartDocPos(Point(0, 0));
988 pEditView->SetSelection(TextSelection());
989 rModulWindow.GetBreakPointWindow().GetCurYOffset() = 0;
990 rModulWindow.GetLineNumberWindow().GetCurYOffset() = 0;
991 pEditEngine->SetUpdateMode(true);
992 rModulWindow.Update(); // has only been invalidated at UpdateMode = true
994 pEditView->ShowCursor();
996 StartListening(*pEditEngine);
998 aSyntaxIdle.Stop();
999 bDoSyntaxHighlight = bWasDoSyntaxHighlight;
1001 for (sal_Int32 nLine = 0; nLine < nLines; nLine++)
1002 aSyntaxLineTable.insert(nLine);
1003 ForceSyntaxTimeout();
1005 pProgress.reset();
1007 pEditEngine->SetModified( false );
1008 pEditEngine->EnableUndo( true );
1010 InitScrollBars();
1012 if (SfxBindings* pBindings = GetBindingsPtr())
1014 pBindings->Invalidate(SID_BASICIDE_STAT_POS);
1015 pBindings->Invalidate(SID_BASICIDE_STAT_TITLE);
1018 DBG_ASSERT(rModulWindow.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?");
1020 // set readonly mode for readonly libraries
1021 ScriptDocument aDocument(rModulWindow.GetDocument());
1022 OUString aOULibName(rModulWindow.GetLibName());
1023 Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
1024 if (xModLibContainer.is()
1025 && xModLibContainer->hasByName(aOULibName)
1026 && xModLibContainer->isLibraryReadOnly(aOULibName))
1028 rModulWindow.SetReadOnly(true);
1031 if (aDocument.isDocument() && aDocument.isReadOnly())
1032 rModulWindow.SetReadOnly(true);
1035 void EditorWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1037 if (TextHint const* pTextHint = dynamic_cast<TextHint const*>(&rHint))
1039 TextHint const& rTextHint = *pTextHint;
1040 if( rTextHint.GetId() == SfxHintId::TextViewScrolled )
1042 if ( rModulWindow.GetHScrollBar() )
1043 rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() );
1044 rModulWindow.GetEditVScrollBar().SetThumbPos( pEditView->GetStartDocPos().Y() );
1045 rModulWindow.GetBreakPointWindow().DoScroll
1046 ( rModulWindow.GetBreakPointWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
1047 rModulWindow.GetLineNumberWindow().DoScroll
1048 ( rModulWindow.GetLineNumberWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
1050 else if( rTextHint.GetId() == SfxHintId::TextHeightChanged )
1052 if ( pEditView->GetStartDocPos().Y() )
1054 long nOutHeight = GetOutputSizePixel().Height();
1055 long nTextHeight = pEditEngine->GetTextHeight();
1056 if ( nTextHeight < nOutHeight )
1057 pEditView->Scroll( 0, pEditView->GetStartDocPos().Y() );
1059 rModulWindow.GetLineNumberWindow().Invalidate();
1062 SetScrollBarRanges();
1064 else if( rTextHint.GetId() == SfxHintId::TextFormatted )
1066 if ( rModulWindow.GetHScrollBar() )
1068 const long nWidth = pEditEngine->CalcTextWidth();
1069 if ( nWidth != nCurTextWidth )
1071 nCurTextWidth = nWidth;
1072 rModulWindow.GetHScrollBar()->SetRange( Range( 0, nCurTextWidth-1) );
1073 rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() );
1076 long nPrevTextWidth = nCurTextWidth;
1077 nCurTextWidth = pEditEngine->CalcTextWidth();
1078 if ( nCurTextWidth != nPrevTextWidth )
1079 SetScrollBarRanges();
1081 else if( rTextHint.GetId() == SfxHintId::TextParaInserted )
1083 ParagraphInsertedDeleted( rTextHint.GetValue(), true );
1084 DoDelayedSyntaxHighlight( rTextHint.GetValue() );
1086 else if( rTextHint.GetId() == SfxHintId::TextParaRemoved )
1088 ParagraphInsertedDeleted( rTextHint.GetValue(), false );
1090 else if( rTextHint.GetId() == SfxHintId::TextParaContentChanged )
1092 DoDelayedSyntaxHighlight( rTextHint.GetValue() );
1094 else if( rTextHint.GetId() == SfxHintId::TextViewSelectionChanged )
1096 if (SfxBindings* pBindings = GetBindingsPtr())
1098 pBindings->Invalidate( SID_CUT );
1099 pBindings->Invalidate( SID_COPY );
1105 OUString EditorWindow::GetActualSubName( sal_uLong nLine )
1107 SbxArrayRef pMethods = rModulWindow.GetSbModule()->GetMethods();
1108 for( sal_uInt16 i=0; i < pMethods->Count(); i++ )
1110 SbMethod* pMeth = dynamic_cast<SbMethod*>( pMethods->Get( i ) );
1111 if( pMeth )
1113 sal_uInt16 l1,l2;
1114 pMeth->GetLineRange(l1,l2);
1115 if( (l1 <= nLine+1) && (nLine+1 <= l2) )
1117 return pMeth->GetName();
1121 return OUString();
1124 void EditorWindow::SetScrollBarRanges()
1126 // extra method, not InitScrollBars, because for EditEngine events too
1127 if ( !pEditEngine )
1128 return;
1130 if ( rModulWindow.GetHScrollBar() )
1131 rModulWindow.GetHScrollBar()->SetRange( Range( 0, nCurTextWidth-1 ) );
1133 rModulWindow.GetEditVScrollBar().SetRange( Range( 0, pEditEngine->GetTextHeight()-1 ) );
1136 void EditorWindow::InitScrollBars()
1138 if (!pEditEngine)
1139 return;
1141 SetScrollBarRanges();
1142 Size aOutSz(GetOutputSizePixel());
1143 rModulWindow.GetEditVScrollBar().SetVisibleSize(aOutSz.Height());
1144 rModulWindow.GetEditVScrollBar().SetPageSize(aOutSz.Height() * 8 / 10);
1145 rModulWindow.GetEditVScrollBar().SetLineSize(GetTextHeight());
1146 rModulWindow.GetEditVScrollBar().SetThumbPos(pEditView->GetStartDocPos().Y());
1147 rModulWindow.GetEditVScrollBar().Show();
1149 if (rModulWindow.GetHScrollBar())
1151 rModulWindow.GetHScrollBar()->SetVisibleSize(aOutSz.Width());
1152 rModulWindow.GetHScrollBar()->SetPageSize(aOutSz.Width() * 8 / 10);
1153 rModulWindow.GetHScrollBar()->SetLineSize(GetTextWidth( "x" ) );
1154 rModulWindow.GetHScrollBar()->SetThumbPos(pEditView->GetStartDocPos().X());
1155 rModulWindow.GetHScrollBar()->Show();
1159 void EditorWindow::ImpDoHighlight( sal_uLong nLine )
1161 if ( bDoSyntaxHighlight )
1163 OUString aLine( pEditEngine->GetText( nLine ) );
1164 bool const bWasModified = pEditEngine->IsModified();
1165 pEditEngine->RemoveAttribs( nLine );
1166 std::vector<HighlightPortion> aPortions;
1167 aHighlighter.getHighlightPortions( aLine, aPortions );
1169 for (auto const& portion : aPortions)
1171 Color const aColor = rModulWindow.GetLayout().GetSyntaxColor(portion.tokenType);
1172 pEditEngine->SetAttrib(TextAttribFontColor(aColor), nLine, portion.nBegin, portion.nEnd);
1175 pEditEngine->SetModified(bWasModified);
1179 void EditorWindow::ChangeFontColor( Color aColor )
1181 if (pEditEngine)
1183 vcl::Font aFont(pEditEngine->GetFont());
1184 aFont.SetColor(aColor);
1185 pEditEngine->SetFont(aFont);
1189 void EditorWindow::UpdateSyntaxHighlighting ()
1191 const sal_uInt32 nCount = pEditEngine->GetParagraphCount();
1192 for (sal_uInt32 i = 0; i < nCount; ++i)
1193 DoDelayedSyntaxHighlight(i);
1196 void EditorWindow::ImplSetFont()
1198 OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().get_value_or(OUString()));
1199 if (sFontName.isEmpty())
1201 vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED,
1202 Application::GetSettings().GetUILanguageTag().getLanguageType(),
1203 GetDefaultFontFlags::NONE, this));
1204 sFontName = aTmpFont.GetFamilyName();
1206 Size aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get());
1207 vcl::Font aFont(sFontName, aFontSize);
1208 aFont.SetColor(rModulWindow.GetLayout().GetFontColor());
1209 SetPointFont(*this, aFont); // FIXME RenderContext
1210 aFont = GetFont();
1212 rModulWindow.GetBreakPointWindow().SetFont(aFont);
1213 rModulWindow.GetLineNumberWindow().SetFont(aFont);
1215 if (pEditEngine)
1217 bool const bModified = pEditEngine->IsModified();
1218 pEditEngine->SetFont(aFont);
1219 pEditEngine->SetModified(bModified);
1223 void EditorWindow::DoSyntaxHighlight( sal_uLong nPara )
1225 // because of the DelayedSyntaxHighlight it's possible
1226 // that this line does not exist anymore!
1227 if ( nPara < pEditEngine->GetParagraphCount() )
1229 // unfortunately I'm not sure that exactly this line does Modified()...
1230 if ( pProgress )
1231 pProgress->StepProgress();
1232 ImpDoHighlight( nPara );
1236 void EditorWindow::DoDelayedSyntaxHighlight( sal_uLong nPara )
1238 // line is only added to list, processed in TimerHdl
1239 // => don't manipulate breaks while EditEngine is formatting
1240 if ( pProgress )
1241 pProgress->StepProgress();
1243 if ( !bHighlighting && bDoSyntaxHighlight )
1245 if ( bDelayHighlight )
1247 aSyntaxLineTable.insert( nPara );
1248 aSyntaxIdle.Start();
1250 else
1251 DoSyntaxHighlight( nPara );
1255 IMPL_LINK_NOARG(EditorWindow, SyntaxTimerHdl, Timer *, void)
1257 DBG_ASSERT( pEditView, "Not yet a View, but Syntax-Highlight?!" );
1259 bool const bWasModified = pEditEngine->IsModified();
1260 //pEditEngine->SetUpdateMode(false);
1262 bHighlighting = true;
1263 for (auto const& syntaxLine : aSyntaxLineTable)
1265 DoSyntaxHighlight(syntaxLine);
1268 // #i45572#
1269 if ( pEditView )
1270 pEditView->ShowCursor( false );
1272 pEditEngine->SetModified( bWasModified );
1274 aSyntaxLineTable.clear();
1275 bHighlighting = false;
1278 void EditorWindow::ParagraphInsertedDeleted( sal_uLong nPara, bool bInserted )
1280 if ( pProgress )
1281 pProgress->StepProgress();
1283 if ( !bInserted && ( nPara == TEXT_PARA_ALL ) )
1285 rModulWindow.GetBreakPoints().reset();
1286 rModulWindow.GetBreakPointWindow().Invalidate();
1287 rModulWindow.GetLineNumberWindow().Invalidate();
1289 else
1291 rModulWindow.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16>(nPara)+1, bInserted );
1293 long nLineHeight = GetTextHeight();
1294 Size aSz = rModulWindow.GetBreakPointWindow().GetOutputSize();
1295 tools::Rectangle aInvRect( Point( 0, 0 ), aSz );
1296 long nY = nPara*nLineHeight - rModulWindow.GetBreakPointWindow().GetCurYOffset();
1297 aInvRect.SetTop( nY );
1298 rModulWindow.GetBreakPointWindow().Invalidate( aInvRect );
1300 Size aLnSz(rModulWindow.GetLineNumberWindow().GetWidth(),
1301 GetOutputSizePixel().Height() - 2 * DWBORDER);
1302 rModulWindow.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER + 19, DWBORDER), aLnSz);
1303 rModulWindow.GetLineNumberWindow().Invalidate();
1307 void EditorWindow::CreateProgress( const OUString& rText, sal_uInt32 nRange )
1309 DBG_ASSERT( !pProgress, "ProgressInfo exists already" );
1310 pProgress.reset(new ProgressInfo(
1311 GetShell()->GetViewFrame()->GetObjectShell(),
1312 rText,
1313 nRange
1317 void EditorWindow::DestroyProgress()
1319 pProgress.reset();
1322 void EditorWindow::ForceSyntaxTimeout()
1324 aSyntaxIdle.Stop();
1325 aSyntaxIdle.Invoke();
1328 // BreakPointWindow
1330 BreakPointWindow::BreakPointWindow (vcl::Window* pParent, ModulWindow* pModulWindow)
1331 : Window(pParent, WB_BORDER)
1332 , rModulWindow(*pModulWindow)
1333 , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine
1334 , nMarkerPos(NoMarker)
1335 , bErrorMarker(false)
1337 setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor());
1338 SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW);
1341 void BreakPointWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1343 if (SyncYOffset())
1344 return;
1346 Size const aOutSz = rRenderContext.GetOutputSize();
1347 long const nLineHeight = rRenderContext.GetTextHeight();
1349 Image const aBrk[2] =
1351 GetImage(RID_BMP_BRKDISABLED),
1352 GetImage(RID_BMP_BRKENABLED)
1355 Size const aBmpSz = rRenderContext.PixelToLogic(aBrk[1].GetSizePixel());
1356 Point const aBmpOff((aOutSz.Width() - aBmpSz.Width()) / 2,
1357 (nLineHeight - aBmpSz.Height()) / 2);
1359 for (size_t i = 0, n = GetBreakPoints().size(); i < n; ++i)
1361 BreakPoint& rBrk = *GetBreakPoints().at(i);
1362 size_t const nLine = rBrk.nLine - 1;
1363 size_t const nY = nLine*nLineHeight - nCurYOffset;
1364 rRenderContext.DrawImage(Point(0, nY) + aBmpOff, aBrk[rBrk.bEnabled]);
1367 ShowMarker(rRenderContext);
1370 void BreakPointWindow::ShowMarker(vcl::RenderContext& rRenderContext)
1372 if (nMarkerPos == NoMarker)
1373 return;
1375 Size const aOutSz = GetOutputSize();
1376 long const nLineHeight = GetTextHeight();
1378 Image aMarker = GetImage(bErrorMarker ? OUStringLiteral(RID_BMP_ERRORMARKER) : OUStringLiteral(RID_BMP_STEPMARKER));
1380 Size aMarkerSz(aMarker.GetSizePixel());
1381 aMarkerSz = rRenderContext.PixelToLogic(aMarkerSz);
1382 Point aMarkerOff(0, 0);
1383 aMarkerOff.setX( (aOutSz.Width() - aMarkerSz.Width()) / 2 );
1384 aMarkerOff.setY( (nLineHeight - aMarkerSz.Height()) / 2 );
1386 sal_uLong nY = nMarkerPos * nLineHeight - nCurYOffset;
1387 Point aPos(0, nY);
1388 aPos += aMarkerOff;
1390 rRenderContext.DrawImage(aPos, aMarker);
1393 void BreakPointWindow::DoScroll( long nVertScroll )
1395 nCurYOffset -= nVertScroll;
1396 Window::Scroll( 0, nVertScroll );
1399 void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine, bool bError )
1401 if ( SyncYOffset() )
1402 Update();
1404 nMarkerPos = nLine;
1405 bErrorMarker = bError;
1406 Invalidate();
1409 void BreakPointWindow::SetNoMarker ()
1411 SetMarkerPos(NoMarker);
1414 BreakPoint* BreakPointWindow::FindBreakPoint( const Point& rMousePos )
1416 size_t nLineHeight = GetTextHeight();
1417 nLineHeight = nLineHeight > 0 ? nLineHeight : 1;
1418 size_t nYPos = rMousePos.Y() + nCurYOffset;
1420 for ( size_t i = 0, n = GetBreakPoints().size(); i < n ; ++i )
1422 BreakPoint* pBrk = GetBreakPoints().at( i );
1423 size_t nLine = pBrk->nLine-1;
1424 size_t nY = nLine*nLineHeight;
1425 if ( ( nYPos > nY ) && ( nYPos < ( nY + nLineHeight ) ) )
1426 return pBrk;
1428 return nullptr;
1431 void BreakPointWindow::MouseButtonDown( const MouseEvent& rMEvt )
1433 if ( rMEvt.GetClicks() == 2 )
1435 Point aMousePos( PixelToLogic( rMEvt.GetPosPixel() ) );
1436 long nLineHeight = GetTextHeight();
1437 if(nLineHeight)
1439 long nYPos = aMousePos.Y() + nCurYOffset;
1440 long nLine = nYPos / nLineHeight + 1;
1441 rModulWindow.ToggleBreakPoint( static_cast<sal_uLong>(nLine) );
1442 Invalidate();
1447 void BreakPointWindow::Command( const CommandEvent& rCEvt )
1449 if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
1451 if (!mpUIBuilder)
1452 mpUIBuilder.reset(new VclBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/BasicIDE/ui/breakpointmenus.ui", ""));
1454 Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) );
1455 Point aEventPos( PixelToLogic( aPos ) );
1456 BreakPoint* pBrk = rCEvt.IsMouseEvent() ? FindBreakPoint( aEventPos ) : nullptr;
1457 if ( pBrk )
1459 // test if break point is enabled...
1460 VclPtr<PopupMenu> xBrkPropMenu = mpUIBuilder->get_menu("breakmenu");
1461 xBrkPropMenu->CheckItem(xBrkPropMenu->GetItemId("active"), pBrk->bEnabled);
1462 OString sCommand = xBrkPropMenu->GetItemIdent(xBrkPropMenu->Execute(this, aPos));
1463 if (sCommand == "active")
1465 pBrk->bEnabled = !pBrk->bEnabled;
1466 rModulWindow.UpdateBreakPoint( *pBrk );
1467 Invalidate();
1469 else if (sCommand == "properties")
1471 ScopedVclPtrInstance<BreakPointDialog> aBrkDlg(this, GetBreakPoints());
1472 aBrkDlg->SetCurrentBreakPoint( pBrk );
1473 aBrkDlg->Execute();
1474 Invalidate();
1477 else
1479 VclPtr<PopupMenu> xBrkListMenu = mpUIBuilder->get_menu("breaklistmenu");
1480 OString sCommand = xBrkListMenu->GetItemIdent(xBrkListMenu->Execute(this, aPos));
1481 if (sCommand == "manage")
1483 ScopedVclPtrInstance< BreakPointDialog > aBrkDlg( this, GetBreakPoints() );
1484 aBrkDlg->Execute();
1485 Invalidate();
1491 bool BreakPointWindow::SyncYOffset()
1493 TextView* pView = rModulWindow.GetEditView();
1494 if ( pView )
1496 long nViewYOffset = pView->GetStartDocPos().Y();
1497 if ( nCurYOffset != nViewYOffset )
1499 nCurYOffset = nViewYOffset;
1500 Invalidate();
1501 return true;
1504 return false;
1507 // virtual
1508 void BreakPointWindow::DataChanged(DataChangedEvent const & rDCEvt)
1510 Window::DataChanged(rDCEvt);
1511 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
1512 && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
1514 Color aColor(GetSettings().GetStyleSettings().GetFieldColor());
1515 const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
1516 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor())
1518 setBackgroundColor(aColor);
1519 Invalidate();
1524 void BreakPointWindow::setBackgroundColor(Color aColor)
1526 SetBackground(Wallpaper(aColor));
1529 void BreakPointWindow::dispose()
1531 mpUIBuilder.reset();
1532 Window::dispose();
1535 namespace
1537 const sal_uInt16 ITEM_ID_VARIABLE = 1;
1538 const sal_uInt16 ITEM_ID_VALUE = 2;
1539 const sal_uInt16 ITEM_ID_TYPE = 3;
1542 WatchWindow::WatchWindow (Layout* pParent)
1543 : DockingWindow(pParent)
1544 , aWatchStr(IDEResId( RID_STR_REMOVEWATCH))
1545 , aXEdit(VclPtr<ExtendedEdit>::Create(this, WB_BORDER | WB_3DLOOK))
1546 , aRemoveWatchButton(VclPtr<ImageButton>::Create(this, WB_SMALLSTYLE))
1547 , aTreeListBox(VclPtr<WatchTreeListBox>::Create(this, WB_BORDER | WB_3DLOOK | WB_HASBUTTONS |
1548 WB_HASLINES | WB_HSCROLL | WB_TABSTOP |
1549 WB_HASLINESATROOT | WB_HASBUTTONSATROOT))
1550 , aHeaderBar(VclPtr<HeaderBar>::Create(this, WB_BUTTONSTYLE | WB_BORDER))
1552 aXEdit->SetAccessibleName(IDEResId(RID_STR_WATCHNAME));
1553 aXEdit->SetHelpId(HID_BASICIDE_WATCHWINDOW_EDIT);
1554 aXEdit->SetSizePixel(aXEdit->LogicToPixel(Size(80, 12), MapMode(MapUnit::MapAppFont)));
1555 aTreeListBox->SetAccessibleName(IDEResId(RID_STR_WATCHNAME));
1557 long nTextLen = GetTextWidth( aWatchStr ) + DWBORDER + 3;
1558 aXEdit->SetPosPixel( Point( nTextLen, 3 ) );
1559 aXEdit->SetAccHdl( LINK( this, WatchWindow, EditAccHdl ) );
1560 aXEdit->GetAccelerator().InsertItem( 1, vcl::KeyCode( KEY_RETURN ) );
1561 aXEdit->GetAccelerator().InsertItem( 2, vcl::KeyCode( KEY_ESCAPE ) );
1562 aXEdit->Show();
1564 aRemoveWatchButton->Disable();
1565 aRemoveWatchButton->SetClickHdl( LINK( this, WatchWindow, ButtonHdl ) );
1566 aRemoveWatchButton->SetPosPixel( Point( nTextLen + aXEdit->GetSizePixel().Width() + 4, 2 ) );
1567 aRemoveWatchButton->SetHelpId(HID_BASICIDE_REMOVEWATCH);
1568 aRemoveWatchButton->SetModeImage(Image(BitmapEx(RID_BMP_REMOVEWATCH)));
1569 aRemoveWatchButton->SetQuickHelpText(IDEResId(RID_STR_REMOVEWATCHTIP));
1570 Size aSz( aRemoveWatchButton->GetModeImage().GetSizePixel() );
1571 aSz.AdjustWidth(6 );
1572 aSz.AdjustHeight(6 );
1573 aRemoveWatchButton->SetSizePixel( aSz );
1574 aRemoveWatchButton->Show();
1576 long nRWBtnSize = aRemoveWatchButton->GetModeImage().GetSizePixel().Height() + 10;
1577 nVirtToolBoxHeight = aXEdit->GetSizePixel().Height() + 7;
1579 if ( nRWBtnSize > nVirtToolBoxHeight )
1580 nVirtToolBoxHeight = nRWBtnSize;
1582 nHeaderBarHeight = 16;
1584 aTreeListBox->SetHelpId(HID_BASICIDE_WATCHWINDOW_LIST);
1585 aTreeListBox->EnableInplaceEditing(true);
1586 aTreeListBox->SetSelectHdl( LINK( this, WatchWindow, TreeListHdl ) );
1587 aTreeListBox->SetPosPixel( Point( DWBORDER, nVirtToolBoxHeight + nHeaderBarHeight ) );
1588 aTreeListBox->SetHighlightRange( 1, 5 );
1590 Point aPnt( DWBORDER, nVirtToolBoxHeight + 1 );
1591 aHeaderBar->SetPosPixel( aPnt );
1592 aHeaderBar->SetEndDragHdl( LINK( this, WatchWindow, implEndDragHdl ) );
1594 long nVarTabWidth = 220;
1595 long nValueTabWidth = 100;
1596 long const nTypeTabWidth = 1250;
1597 aHeaderBar->InsertItem( ITEM_ID_VARIABLE, IDEResId(RID_STR_WATCHVARIABLE), nVarTabWidth );
1598 aHeaderBar->InsertItem( ITEM_ID_VALUE, IDEResId(RID_STR_WATCHVALUE), nValueTabWidth );
1599 aHeaderBar->InsertItem( ITEM_ID_TYPE, IDEResId(RID_STR_WATCHTYPE), nTypeTabWidth );
1601 long aTabPositions[] = { 0, nVarTabWidth, nVarTabWidth + nValueTabWidth };
1602 aTreeListBox->SvHeaderTabListBox::SetTabs( SAL_N_ELEMENTS(aTabPositions), aTabPositions, MapUnit::MapPixel );
1603 aTreeListBox->InitHeaderBar( aHeaderBar.get() );
1605 aTreeListBox->SetNodeDefaultImages( );
1607 aHeaderBar->Show();
1609 aTreeListBox->Show();
1611 SetText(IDEResId(RID_STR_WATCHNAME));
1613 SetHelpId( HID_BASICIDE_WATCHWINDOW );
1615 // make watch window keyboard accessible
1616 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1620 WatchWindow::~WatchWindow()
1622 disposeOnce();
1625 void WatchWindow::dispose()
1627 aXEdit.disposeAndClear();
1628 aRemoveWatchButton.disposeAndClear();
1629 aHeaderBar.disposeAndClear();
1630 aTreeListBox.disposeAndClear();
1631 if (!IsDisposed())
1632 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1633 DockingWindow::dispose();
1636 void WatchWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1638 rRenderContext.DrawText(Point(DWBORDER, 7), aWatchStr);
1639 lcl_DrawIDEWindowFrame(this, rRenderContext);
1642 void WatchWindow::Resize()
1644 Size aSz = GetOutputSizePixel();
1645 Size aBoxSz( aSz.Width() - 2*DWBORDER, aSz.Height() - nVirtToolBoxHeight - DWBORDER );
1647 if ( aBoxSz.Width() < 4 )
1648 aBoxSz.setWidth( 0 );
1649 if ( aBoxSz.Height() < 4 )
1650 aBoxSz.setHeight( 0 );
1652 aBoxSz.AdjustHeight( -nHeaderBarHeight );
1653 aTreeListBox->SetSizePixel( aBoxSz );
1654 aTreeListBox->GetHScroll()->SetPageSize( aTreeListBox->GetHScroll()->GetVisibleSize() );
1656 aBoxSz.setHeight( nHeaderBarHeight );
1657 aHeaderBar->SetSizePixel( aBoxSz );
1659 Invalidate();
1662 struct WatchItem
1664 OUString maName;
1665 OUString maDisplayName;
1666 SbxObjectRef mpObject;
1667 std::vector<OUString> maMemberList;
1669 SbxDimArrayRef mpArray;
1670 int nDimLevel; // 0 = Root
1671 int nDimCount;
1672 std::vector<short> vIndices;
1674 WatchItem* mpArrayParentItem;
1676 explicit WatchItem (OUString const& rName):
1677 maName(rName),
1678 nDimLevel(0),
1679 nDimCount(0),
1680 mpArrayParentItem(nullptr)
1683 void clearWatchItem ()
1685 maMemberList.clear();
1688 WatchItem* GetRootItem();
1689 SbxDimArray* GetRootArray();
1692 WatchItem* WatchItem::GetRootItem()
1694 WatchItem* pItem = mpArrayParentItem;
1695 while( pItem )
1697 if( pItem->mpArray.is() )
1698 break;
1699 pItem = pItem->mpArrayParentItem;
1701 return pItem;
1704 SbxDimArray* WatchItem::GetRootArray()
1706 WatchItem* pRootItem = GetRootItem();
1707 SbxDimArray* pRet = nullptr;
1708 if( pRootItem )
1709 pRet = pRootItem->mpArray.get();
1710 return pRet;
1713 void WatchWindow::AddWatch( const OUString& rVName )
1715 OUString aVar, aIndex;
1716 lcl_SeparateNameAndIndex( rVName, aVar, aIndex );
1717 WatchItem* pWatchItem = new WatchItem(aVar);
1719 OUString aWatchStr_ = aVar + "\t\t";
1720 SvTreeListEntry* pNewEntry = aTreeListBox->InsertEntry( aWatchStr_, nullptr, true );
1721 pNewEntry->SetUserData( pWatchItem );
1723 aTreeListBox->Select(pNewEntry);
1724 aTreeListBox->MakeVisible(pNewEntry);
1725 aRemoveWatchButton->Enable();
1727 UpdateWatches(false);
1730 void WatchWindow::RemoveSelectedWatch()
1732 SvTreeListEntry* pEntry = aTreeListBox->GetCurEntry();
1733 if ( pEntry )
1735 aTreeListBox->GetModel()->Remove( pEntry );
1736 pEntry = aTreeListBox->GetCurEntry();
1737 if ( pEntry )
1738 aXEdit->SetText( static_cast<WatchItem*>(pEntry->GetUserData())->maName );
1739 else
1740 aXEdit->SetText( OUString() );
1741 if ( !aTreeListBox->GetEntryCount() )
1742 aRemoveWatchButton->Disable();
1747 IMPL_LINK( WatchWindow, ButtonHdl, Button *, pButton, void )
1749 if (pButton == aRemoveWatchButton.get())
1750 if (SfxDispatcher* pDispatcher = GetDispatcher())
1751 pDispatcher->Execute(SID_BASICIDE_REMOVEWATCH);
1754 IMPL_LINK_NOARG(WatchWindow, TreeListHdl, SvTreeListBox*, void)
1756 SvTreeListEntry* pCurEntry = aTreeListBox->GetCurEntry();
1757 if ( pCurEntry && pCurEntry->GetUserData() )
1758 aXEdit->SetText( static_cast<WatchItem*>(pCurEntry->GetUserData())->maName );
1761 IMPL_LINK_NOARG( WatchWindow, implEndDragHdl, HeaderBar *, void )
1763 const sal_Int32 TAB_WIDTH_MIN = 10;
1764 sal_Int32 nMaxWidth =
1765 aHeaderBar->GetSizePixel().getWidth() - 2 * TAB_WIDTH_MIN;
1767 sal_Int32 nVariableWith = aHeaderBar->GetItemSize( ITEM_ID_VARIABLE );
1768 if( nVariableWith < TAB_WIDTH_MIN )
1769 aHeaderBar->SetItemSize( ITEM_ID_VARIABLE, TAB_WIDTH_MIN );
1770 else if( nVariableWith > nMaxWidth )
1771 aHeaderBar->SetItemSize( ITEM_ID_VARIABLE, nMaxWidth );
1773 sal_Int32 nValueWith = aHeaderBar->GetItemSize( ITEM_ID_VALUE );
1774 if( nValueWith < TAB_WIDTH_MIN )
1775 aHeaderBar->SetItemSize( ITEM_ID_VALUE, TAB_WIDTH_MIN );
1776 else if( nValueWith > nMaxWidth )
1777 aHeaderBar->SetItemSize( ITEM_ID_VALUE, nMaxWidth );
1779 if (aHeaderBar->GetItemSize( ITEM_ID_TYPE ) < TAB_WIDTH_MIN)
1780 aHeaderBar->SetItemSize( ITEM_ID_TYPE, TAB_WIDTH_MIN );
1782 sal_Int32 nPos = 0;
1783 sal_uInt16 nTabs = aHeaderBar->GetItemCount();
1784 for( sal_uInt16 i = 1 ; i < nTabs ; ++i )
1786 nPos += aHeaderBar->GetItemSize( i );
1787 aTreeListBox->SetTab( i, nPos, MapUnit::MapPixel );
1791 IMPL_LINK( WatchWindow, EditAccHdl, Accelerator&, rAcc, void )
1793 switch ( rAcc.GetCurKeyCode().GetCode() )
1795 case KEY_RETURN:
1797 OUString aCurText( aXEdit->GetText() );
1798 if ( !aCurText.isEmpty() )
1800 AddWatch( aCurText );
1801 aXEdit->SetSelection( Selection( 0, 0xFFFF ) );
1804 break;
1805 case KEY_ESCAPE:
1807 aXEdit->SetText( OUString() );
1809 break;
1813 void WatchWindow::UpdateWatches( bool bBasicStopped )
1815 aTreeListBox->UpdateWatches( bBasicStopped );
1819 // StackWindow
1822 StackWindow::StackWindow (Layout* pParent) :
1823 DockingWindow(pParent),
1824 aTreeListBox( VclPtr<SvTreeListBox>::Create(this, WB_BORDER | WB_3DLOOK | WB_HSCROLL | WB_TABSTOP) ),
1825 aStackStr( IDEResId( RID_STR_STACK ) )
1827 aTreeListBox->SetHelpId(HID_BASICIDE_STACKWINDOW_LIST);
1828 aTreeListBox->SetAccessibleName(IDEResId(RID_STR_STACKNAME));
1829 aTreeListBox->SetPosPixel( Point( DWBORDER, nVirtToolBoxHeight ) );
1830 aTreeListBox->SetHighlightRange();
1831 aTreeListBox->SetSelectionMode( SelectionMode::NONE );
1832 aTreeListBox->InsertEntry( OUString() );
1833 aTreeListBox->Show();
1835 SetText(IDEResId(RID_STR_STACKNAME));
1837 SetHelpId( HID_BASICIDE_STACKWINDOW );
1839 // make stack window keyboard accessible
1840 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1844 StackWindow::~StackWindow()
1846 disposeOnce();
1849 void StackWindow::dispose()
1851 if (!IsDisposed())
1852 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1853 aTreeListBox.disposeAndClear();
1854 DockingWindow::dispose();
1857 void StackWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1859 rRenderContext.DrawText(Point(DWBORDER, 7), aStackStr);
1860 lcl_DrawIDEWindowFrame(this, rRenderContext);
1863 void StackWindow::Resize()
1865 Size aSz = GetOutputSizePixel();
1866 Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - nVirtToolBoxHeight - DWBORDER);
1868 if ( aBoxSz.Width() < 4 )
1869 aBoxSz.setWidth( 0 );
1870 if ( aBoxSz.Height() < 4 )
1871 aBoxSz.setHeight( 0 );
1873 aTreeListBox->SetSizePixel( aBoxSz );
1875 Invalidate();
1878 void StackWindow::UpdateCalls()
1880 aTreeListBox->SetUpdateMode(false);
1881 aTreeListBox->Clear();
1883 if (StarBASIC::IsRunning())
1885 ErrCode eOld = SbxBase::GetError();
1886 aTreeListBox->SetSelectionMode( SelectionMode::Single );
1888 sal_Int32 nScope = 0;
1889 SbMethod* pMethod = StarBASIC::GetActiveMethod( nScope );
1890 while ( pMethod )
1892 OUString aEntry( OUString::number(nScope ));
1893 if ( aEntry.getLength() < 2 )
1894 aEntry = " " + aEntry;
1895 aEntry += ": " + pMethod->GetName();
1896 SbxArray* pParams = pMethod->GetParameters();
1897 SbxInfo* pInfo = pMethod->GetInfo();
1898 if ( pParams )
1900 aEntry += "(";
1901 // 0 is the sub's name...
1902 for ( sal_uInt16 nParam = 1; nParam < pParams->Count(); nParam++ )
1904 SbxVariable* pVar = pParams->Get( nParam );
1905 assert(pVar && "Parameter?!");
1906 if ( !pVar->GetName().isEmpty() )
1908 aEntry += pVar->GetName();
1910 else if ( pInfo )
1912 const SbxParamInfo* pParam = pInfo->GetParam( nParam );
1913 if ( pParam )
1915 aEntry += pParam->aName;
1918 aEntry += "=";
1919 SbxDataType eType = pVar->GetType();
1920 if( eType & SbxARRAY )
1922 aEntry += "..." ;
1924 else if( eType != SbxOBJECT )
1926 aEntry += pVar->GetOUString();
1928 if ( nParam < ( pParams->Count() - 1 ) )
1930 aEntry += ", ";
1933 aEntry += ")";
1935 aTreeListBox->InsertEntry( aEntry );
1936 nScope++;
1937 pMethod = StarBASIC::GetActiveMethod( nScope );
1940 SbxBase::ResetError();
1941 if( eOld != ERRCODE_NONE )
1942 SbxBase::SetError( eOld );
1944 else
1946 aTreeListBox->SetSelectionMode( SelectionMode::NONE );
1947 aTreeListBox->InsertEntry( OUString() );
1950 aTreeListBox->SetUpdateMode(true);
1953 ComplexEditorWindow::ComplexEditorWindow( ModulWindow* pParent ) :
1954 Window( pParent, WB_3DLOOK | WB_CLIPCHILDREN ),
1955 aBrkWindow(VclPtr<BreakPointWindow>::Create(this, pParent)),
1956 aLineNumberWindow(VclPtr<LineNumberWindow>::Create(this, pParent)),
1957 aEdtWindow(VclPtr<EditorWindow>::Create(this, pParent)),
1958 aEWVScrollBar( VclPtr<ScrollBar>::Create(this, WB_VSCROLL | WB_DRAG) )
1960 aEdtWindow->Show();
1961 aBrkWindow->Show();
1963 aEWVScrollBar->SetLineSize(nScrollLine);
1964 aEWVScrollBar->SetPageSize(nScrollPage);
1965 aEWVScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) );
1966 aEWVScrollBar->Show();
1969 ComplexEditorWindow::~ComplexEditorWindow()
1971 disposeOnce();
1974 void ComplexEditorWindow::dispose()
1976 aBrkWindow.disposeAndClear();
1977 aLineNumberWindow.disposeAndClear();
1978 aEdtWindow.disposeAndClear();
1979 aEWVScrollBar.disposeAndClear();
1980 vcl::Window::dispose();
1983 void ComplexEditorWindow::Resize()
1985 Size aOutSz = GetOutputSizePixel();
1986 Size aSz(aOutSz);
1987 aSz.AdjustWidth( -(2*DWBORDER) );
1988 aSz.AdjustHeight( -(2*DWBORDER) );
1989 long nBrkWidth = 20;
1990 long nSBWidth = aEWVScrollBar->GetSizePixel().Width();
1992 Size aBrkSz(nBrkWidth, aSz.Height());
1994 Size aLnSz(aLineNumberWindow->GetWidth(), aSz.Height());
1996 if (aLineNumberWindow->IsVisible())
1998 aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz );
1999 aLineNumberWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aLnSz);
2000 Size aEWSz(aSz.Width() - nBrkWidth - aLineNumberWindow->GetWidth() - nSBWidth + 2, aSz.Height());
2001 aEdtWindow->SetPosSizePixel( Point( DWBORDER + aBrkSz.Width() + aLnSz.Width() - 1, DWBORDER ), aEWSz );
2003 else
2005 aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz );
2006 Size aEWSz(aSz.Width() - nBrkWidth - nSBWidth + 2, aSz.Height());
2007 aEdtWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aEWSz);
2010 aEWVScrollBar->SetPosSizePixel( Point( aOutSz.Width() - DWBORDER - nSBWidth, DWBORDER ), Size( nSBWidth, aSz.Height() ) );
2013 IMPL_LINK(ComplexEditorWindow, ScrollHdl, ScrollBar *, pCurScrollBar, void )
2015 if (aEdtWindow->GetEditView())
2017 DBG_ASSERT( pCurScrollBar == aEWVScrollBar.get(), "Who is scrolling?" );
2018 long nDiff = aEdtWindow->GetEditView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos();
2019 aEdtWindow->GetEditView()->Scroll( 0, nDiff );
2020 aBrkWindow->DoScroll( nDiff );
2021 aLineNumberWindow->DoScroll( nDiff );
2022 aEdtWindow->GetEditView()->ShowCursor(false);
2023 pCurScrollBar->SetThumbPos( aEdtWindow->GetEditView()->GetStartDocPos().Y() );
2027 void ComplexEditorWindow::DataChanged(DataChangedEvent const & rDCEvt)
2029 Window::DataChanged(rDCEvt);
2030 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
2031 && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
2033 Color aColor(GetSettings().GetStyleSettings().GetFaceColor());
2034 const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
2035 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFaceColor())
2037 SetBackground(Wallpaper(aColor));
2038 Invalidate();
2043 void ComplexEditorWindow::SetLineNumberDisplay(bool b)
2045 aLineNumberWindow->Show(b);
2046 Resize();
2049 uno::Reference< awt::XWindowPeer >
2050 EditorWindow::GetComponentInterface(bool bCreate)
2052 uno::Reference< awt::XWindowPeer > xPeer(
2053 Window::GetComponentInterface(false));
2054 if (!xPeer.is() && bCreate)
2056 // Make sure edit engine and view are available:
2057 if (!pEditEngine)
2058 CreateEditEngine();
2060 xPeer = svt::createTextWindowPeer(*GetEditView());
2061 SetComponentInterface(xPeer);
2063 return xPeer;
2067 // WatchTreeListBox
2070 WatchTreeListBox::WatchTreeListBox( vcl::Window* pParent, WinBits nWinBits )
2071 : SvHeaderTabListBox( pParent, nWinBits )
2074 WatchTreeListBox::~WatchTreeListBox()
2076 disposeOnce();
2079 void WatchTreeListBox::dispose()
2081 // Destroy user data
2082 SvTreeListEntry* pEntry = First();
2083 while ( pEntry )
2085 delete static_cast<WatchItem*>(pEntry->GetUserData());
2086 pEntry->SetUserData(nullptr);
2087 pEntry = Next( pEntry );
2089 SvHeaderTabListBox::dispose();
2092 void WatchTreeListBox::SetTabs()
2094 SvHeaderTabListBox::SetTabs();
2095 sal_uInt16 nTabCount_ = aTabs.size();
2096 for( sal_uInt16 i = 0 ; i < nTabCount_ ; i++ )
2098 SvLBoxTab* pTab = aTabs[i];
2099 if( i == 2 )
2100 pTab->nFlags |= SvLBoxTabFlags::EDITABLE;
2101 else
2102 pTab->nFlags &= ~SvLBoxTabFlags::EDITABLE;
2106 void WatchTreeListBox::RequestingChildren( SvTreeListEntry * pParent )
2108 if( !StarBASIC::IsRunning() )
2109 return;
2111 if( GetChildCount( pParent ) > 0 )
2112 return;
2114 SvTreeListEntry* pEntry = pParent;
2115 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2117 SbxDimArray* pArray = pItem->mpArray.get();
2118 SbxDimArray* pRootArray = pItem->GetRootArray();
2119 bool bArrayIsRootArray = false;
2120 if( !pArray && pRootArray )
2122 pArray = pRootArray;
2123 bArrayIsRootArray = true;
2126 SbxObject* pObj = pItem->mpObject.get();
2127 if( pObj )
2129 createAllObjectProperties( pObj );
2130 SbxArray* pProps = pObj->GetProperties();
2131 sal_uInt16 nPropCount = pProps->Count();
2132 if ( nPropCount >= 3 &&
2133 pProps->Get( nPropCount -1 )->GetName().equalsIgnoreAsciiCase( "Dbg_Methods" ) &&
2134 pProps->Get( nPropCount -2 )->GetName().equalsIgnoreAsciiCase( "Dbg_Properties" ) &&
2135 pProps->Get( nPropCount -3 )->GetName().equalsIgnoreAsciiCase( "Dbg_SupportedInterfaces" ) )
2137 nPropCount -= 3;
2139 pItem->maMemberList.reserve(nPropCount);
2141 for( sal_uInt16 i = 0 ; i < nPropCount ; ++i )
2143 SbxVariable* pVar = pProps->Get( i );
2145 pItem->maMemberList.push_back(pVar->GetName());
2146 OUString const& rName = pItem->maMemberList.back();
2147 SvTreeListEntry* pChildEntry = SvTreeListBox::InsertEntry( rName, pEntry );
2148 pChildEntry->SetUserData(new WatchItem(rName));
2150 if( nPropCount > 0 )
2152 UpdateWatches();
2155 else if( pArray )
2157 sal_uInt16 nElementCount = 0;
2159 // Loop through indices of current level
2160 int nParentLevel = bArrayIsRootArray ? pItem->nDimLevel : 0;
2161 int nThisLevel = nParentLevel + 1;
2162 sal_Int32 nMin, nMax;
2163 pArray->GetDim32( nThisLevel, nMin, nMax );
2164 for( sal_Int32 i = nMin ; i <= nMax ; i++ )
2166 WatchItem* pChildItem = new WatchItem(pItem->maName);
2168 // Copy data and create name
2170 OUString aIndexStr = "(";
2171 pChildItem->mpArrayParentItem = pItem;
2172 pChildItem->nDimLevel = nThisLevel;
2173 pChildItem->nDimCount = pItem->nDimCount;
2174 pChildItem->vIndices.resize(pChildItem->nDimCount);
2175 sal_Int32 j;
2176 for( j = 0 ; j < nParentLevel ; j++ )
2178 short n = pChildItem->vIndices[j] = pItem->vIndices[j];
2179 aIndexStr += OUString::number( n ) + ",";
2181 pChildItem->vIndices[nParentLevel] = sal::static_int_cast<short>( i );
2182 aIndexStr += OUString::number( i ) + ")";
2184 OUString aDisplayName;
2185 WatchItem* pArrayRootItem = pChildItem->GetRootItem();
2186 if( pArrayRootItem && pArrayRootItem->mpArrayParentItem )
2187 aDisplayName = pItem->maDisplayName;
2188 else
2189 aDisplayName = pItem->maName;
2190 aDisplayName += aIndexStr;
2191 pChildItem->maDisplayName = aDisplayName;
2193 SvTreeListEntry* pChildEntry = SvTreeListBox::InsertEntry( aDisplayName, pEntry );
2194 nElementCount++;
2195 pChildEntry->SetUserData( pChildItem );
2197 if( nElementCount > 0 )
2199 UpdateWatches();
2204 SbxBase* WatchTreeListBox::ImplGetSBXForEntry( SvTreeListEntry* pEntry, bool& rbArrayElement )
2206 SbxBase* pSBX = nullptr;
2207 rbArrayElement = false;
2209 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2210 OUString aVName( pItem->maName );
2212 SvTreeListEntry* pParentEntry = GetParent( pEntry );
2213 WatchItem* pParentItem = pParentEntry ? static_cast<WatchItem*>(pParentEntry->GetUserData()) : nullptr;
2214 if( pParentItem )
2216 SbxObject* pObj = pParentItem->mpObject.get();
2217 SbxDimArray* pArray;
2218 if( pObj )
2220 pSBX = pObj->Find( aVName, SbxClassType::DontCare );
2221 if (SbxVariable const* pVar = IsSbxVariable(pSBX))
2223 // Force getting value
2224 SbxValues aRes;
2225 aRes.eType = SbxVOID;
2226 pVar->Get( aRes );
2229 // Array?
2230 else if( (pArray = pItem->GetRootArray()) != nullptr )
2232 rbArrayElement = true;
2233 if( pParentItem->nDimLevel + 1 == pParentItem->nDimCount )
2234 pSBX = pArray->Get(pItem->vIndices.empty() ? nullptr : &*pItem->vIndices.begin());
2237 else
2239 pSBX = StarBASIC::FindSBXInCurrentScope( aVName );
2241 return pSBX;
2244 bool WatchTreeListBox::EditingEntry( SvTreeListEntry* pEntry, Selection& )
2246 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2248 bool bEdit = false;
2249 if ( StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError() )
2251 // No out of scope entries
2252 bool bArrayElement;
2253 SbxBase* pSbx = ImplGetSBXForEntry( pEntry, bArrayElement );
2254 if (IsSbxVariable(pSbx) || bArrayElement)
2256 // Accept no objects and only end nodes of arrays for editing
2257 if( !pItem->mpObject.is() && ( !pItem->mpArray.is() || pItem->nDimLevel == pItem->nDimCount ) )
2259 aEditingRes = SvHeaderTabListBox::GetEntryText( pEntry, ITEM_ID_VALUE-1 );
2260 aEditingRes = comphelper::string::strip(aEditingRes, ' ');
2261 bEdit = true;
2266 return bEdit;
2269 bool WatchTreeListBox::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText )
2271 OUString aResult = comphelper::string::strip(rNewText, ' ');
2273 sal_uInt16 nResultLen = aResult.getLength();
2274 sal_Unicode cFirst = aResult[0];
2275 sal_Unicode cLast = aResult[ nResultLen - 1 ];
2276 if( cFirst == '\"' && cLast == '\"' )
2277 aResult = aResult.copy( 1, nResultLen - 2 );
2279 return aResult != aEditingRes && ImplBasicEntryEdited(pEntry, aResult);
2282 bool WatchTreeListBox::ImplBasicEntryEdited( SvTreeListEntry* pEntry, const OUString& rResult )
2284 bool bArrayElement;
2285 SbxBase* pSBX = ImplGetSBXForEntry( pEntry, bArrayElement );
2287 if (SbxVariable* pVar = IsSbxVariable(pSBX))
2289 SbxDataType eType = pVar->GetType();
2290 if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxOBJECT)
2291 && ( eType & SbxARRAY ) == 0 )
2293 // If the type is variable, the conversion of the SBX does not matter,
2294 // else the string is converted.
2295 pVar->PutStringExt( rResult );
2299 if ( SbxBase::IsError() )
2301 SbxBase::ResetError();
2304 UpdateWatches();
2306 // The text should never be taken/copied 1:1,
2307 // as the UpdateWatches will be lost
2308 return false;
2312 namespace
2315 void implCollapseModifiedObjectEntry( SvTreeListEntry* pParent, WatchTreeListBox* pThis )
2317 pThis->Collapse( pParent );
2319 SvTreeList* pModel = pThis->GetModel();
2320 SvTreeListEntry* pDeleteEntry;
2321 while( (pDeleteEntry = pThis->SvTreeListBox::GetEntry( pParent, 0 )) != nullptr )
2323 implCollapseModifiedObjectEntry( pDeleteEntry, pThis );
2325 delete static_cast<WatchItem*>(pDeleteEntry->GetUserData());
2326 pModel->Remove( pDeleteEntry );
2330 OUString implCreateTypeStringForDimArray( WatchItem* pItem, SbxDataType eType )
2332 OUString aRetStr = getBasicTypeName( eType );
2334 SbxDimArray* pArray = pItem->mpArray.get();
2335 if( !pArray )
2336 pArray = pItem->GetRootArray();
2337 if( pArray )
2339 int nDimLevel = pItem->nDimLevel;
2340 int nDims = pItem->nDimCount;
2341 if( nDimLevel < nDims )
2343 aRetStr += "(";
2344 for( int i = nDimLevel ; i < nDims ; i++ )
2346 short nMin, nMax;
2347 pArray->GetDim( sal::static_int_cast<short>( i+1 ), nMin, nMax );
2348 aRetStr += OUString::number(nMin) + " to " + OUString::number(nMax);
2349 if( i < nDims - 1 )
2350 aRetStr += ", ";
2352 aRetStr += ")";
2355 return aRetStr;
2358 void implEnableChildren( SvTreeListEntry* pEntry, bool bEnable )
2360 if( bEnable )
2362 pEntry->SetFlags(
2363 (pEntry->GetFlags() & ~SvTLEntryFlags(SvTLEntryFlags::NO_NODEBMP | SvTLEntryFlags::HAD_CHILDREN))
2364 | SvTLEntryFlags::CHILDREN_ON_DEMAND );
2366 else
2368 pEntry->SetFlags( pEntry->GetFlags() & ~SvTLEntryFlags::CHILDREN_ON_DEMAND );
2372 } // namespace
2374 void WatchTreeListBox::UpdateWatches( bool bBasicStopped )
2376 SbMethod* pCurMethod = StarBASIC::GetActiveMethod();
2378 ErrCode eOld = SbxBase::GetError();
2379 setBasicWatchMode( true );
2381 SvTreeListEntry* pEntry = First();
2382 while ( pEntry )
2384 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2385 DBG_ASSERT( !pItem->maName.isEmpty(), "Var? - Must not be empty!" );
2386 OUString aWatchStr;
2387 OUString aTypeStr;
2388 if ( pCurMethod )
2390 bool bArrayElement;
2391 SbxBase* pSBX = ImplGetSBXForEntry( pEntry, bArrayElement );
2393 // Array? If no end node create type string
2394 if( bArrayElement && pItem->nDimLevel < pItem->nDimCount )
2396 SbxDimArray* pRootArray = pItem->GetRootArray();
2397 SbxDataType eType = pRootArray->GetType();
2398 aTypeStr = implCreateTypeStringForDimArray( pItem, eType );
2399 implEnableChildren( pEntry, true );
2402 bool bCollapse = false;
2403 if (SbxVariable const* pVar = IsSbxVariable(pSBX))
2405 // extra treatment of arrays
2406 SbxDataType eType = pVar->GetType();
2407 if ( eType & SbxARRAY )
2409 // consider multidimensional arrays!
2410 if (SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>(pVar->GetObject()))
2412 SbxDimArray* pOldArray = pItem->mpArray.get();
2414 bool bArrayChanged = false;
2415 if( pNewArray != nullptr && pOldArray != nullptr )
2417 // Compare Array dimensions to see if array has changed
2418 // Can be a copy, so comparing pointers does not work
2419 sal_uInt16 nOldDims = pOldArray->GetDims();
2420 sal_uInt16 nNewDims = pNewArray->GetDims();
2421 if( nOldDims != nNewDims )
2423 bArrayChanged = true;
2425 else
2427 for( int i = 0 ; i < nOldDims ; i++ )
2429 short nOldMin, nOldMax;
2430 short nNewMin, nNewMax;
2432 pOldArray->GetDim( sal::static_int_cast<short>( i+1 ), nOldMin, nOldMax );
2433 pNewArray->GetDim( sal::static_int_cast<short>( i+1 ), nNewMin, nNewMax );
2434 if( nOldMin != nNewMin || nOldMax != nNewMax )
2436 bArrayChanged = true;
2437 break;
2442 else if( pNewArray == nullptr || pOldArray == nullptr )
2444 bArrayChanged = true;
2446 if( pNewArray )
2448 implEnableChildren( pEntry, true );
2450 // #i37227 Clear always and replace array
2451 if( pNewArray != pOldArray )
2453 pItem->clearWatchItem();
2454 if( pNewArray )
2456 implEnableChildren( pEntry, true );
2458 pItem->mpArray = pNewArray;
2459 sal_uInt16 nDims = pNewArray->GetDims();
2460 pItem->nDimLevel = 0;
2461 pItem->nDimCount = nDims;
2464 if( bArrayChanged && pOldArray != nullptr )
2466 bCollapse = true;
2468 aTypeStr = implCreateTypeStringForDimArray( pItem, eType );
2470 else
2472 aWatchStr += "<?>";
2475 else if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) )
2477 if (SbxObject* pObj = dynamic_cast<SbxObject*>(pVar->GetObject()))
2479 if ( pItem->mpObject.is() && !pItem->maMemberList.empty() )
2481 bool bObjChanged = false; // Check if member list has changed
2482 SbxArray* pProps = pObj->GetProperties();
2483 sal_uInt16 nPropCount = pProps->Count();
2484 for( sal_uInt16 i = 0 ; i < nPropCount - 3 ; i++ )
2486 SbxVariable* pVar_ = pProps->Get( i );
2487 OUString aName( pVar_->GetName() );
2488 if( pItem->maMemberList[i] != aName )
2490 bObjChanged = true;
2491 break;
2494 if( bObjChanged )
2496 bCollapse = true;
2500 pItem->mpObject = pObj;
2501 implEnableChildren( pEntry, true );
2502 aTypeStr = getBasicObjectTypeName( pObj );
2504 else
2506 aWatchStr = "Null";
2507 if( pItem->mpObject.is() )
2509 bCollapse = true;
2510 pItem->clearWatchItem();
2512 implEnableChildren( pEntry, false );
2516 else
2518 if( pItem->mpObject.is() )
2520 bCollapse = true;
2521 pItem->clearWatchItem();
2523 implEnableChildren( pEntry, false );
2526 bool bString = (static_cast<sal_uInt8>(eType) == sal_uInt8(SbxSTRING));
2527 OUString aStrStr( "\"" );
2528 if( bString )
2530 aWatchStr += aStrStr;
2532 aWatchStr += pVar->GetOUString();
2533 if( bString )
2535 aWatchStr += aStrStr;
2538 if( aTypeStr.isEmpty() )
2540 if( !pVar->IsFixed() )
2542 aTypeStr = "Variant/";
2544 aTypeStr += getBasicTypeName( pVar->GetType() );
2547 else if( !bArrayElement )
2549 aWatchStr += "<Out of Scope>";
2552 if( bCollapse )
2554 implCollapseModifiedObjectEntry( pEntry, this );
2558 else if( bBasicStopped )
2560 if( pItem->mpObject.is() || pItem->mpArray.is() )
2562 implCollapseModifiedObjectEntry( pEntry, this );
2563 pItem->mpObject = nullptr;
2567 SvHeaderTabListBox::SetEntryText( aWatchStr, pEntry, ITEM_ID_VALUE-1 );
2568 SvHeaderTabListBox::SetEntryText( aTypeStr, pEntry, ITEM_ID_TYPE-1 );
2570 pEntry = Next( pEntry );
2573 // Force redraw
2574 Invalidate();
2576 SbxBase::ResetError();
2577 if( eOld != ERRCODE_NONE )
2578 SbxBase::SetError( eOld );
2579 setBasicWatchMode( false );
2582 CodeCompleteListBox::CodeCompleteListBox( CodeCompleteWindow* pPar )
2583 : ListBox(pPar, WB_SORT | WB_BORDER ),
2584 pCodeCompleteWindow( pPar )
2586 SetDoubleClickHdl(LINK(this, CodeCompleteListBox, ImplDoubleClickHdl));
2587 SetSelectHdl(LINK(this, CodeCompleteListBox, ImplSelectHdl));
2590 CodeCompleteListBox::~CodeCompleteListBox()
2592 disposeOnce();
2595 void CodeCompleteListBox::dispose()
2597 pCodeCompleteWindow.clear();
2598 ListBox::dispose();
2601 IMPL_LINK_NOARG(CodeCompleteListBox, ImplDoubleClickHdl, ListBox&, void)
2603 InsertSelectedEntry();
2606 IMPL_LINK_NOARG(CodeCompleteListBox, ImplSelectHdl, ListBox&, void)
2607 {//give back the focus to the parent
2608 pCodeCompleteWindow->pParent->GrabFocus();
2611 TextView* CodeCompleteListBox::GetParentEditView()
2613 return pCodeCompleteWindow->pParent->GetEditView();
2616 void CodeCompleteListBox::InsertSelectedEntry()
2618 if( !aFuncBuffer.isEmpty() )
2620 // if the user typed in something: remove, and insert
2621 GetParentEditView()->SetSelection( pCodeCompleteWindow->pParent->GetLastHighlightPortionTextSelection() );
2622 GetParentEditView()->DeleteSelected();
2624 if( !GetSelectedEntry().isEmpty() )
2625 {//if the user selected something
2626 GetParentEditView()->InsertText( GetSelectedEntry() );
2629 else
2631 if( !GetSelectedEntry().isEmpty() )
2632 {//if the user selected something
2633 GetParentEditView()->InsertText( GetSelectedEntry() );
2636 HideAndRestoreFocus();
2639 void CodeCompleteListBox::SetMatchingEntries()
2641 for(sal_Int32 i=0; i< GetEntryCount(); ++i)
2643 OUString sEntry = GetEntry(i);
2644 if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer.toString() ) )
2646 SelectEntry(sEntry);
2647 break;
2652 void CodeCompleteListBox::KeyInput( const KeyEvent& rKeyEvt )
2654 sal_Unicode aChar = rKeyEvt.GetKeyCode().GetCode();
2655 if( (( aChar >= KEY_A ) && ( aChar <= KEY_Z ))
2656 || ((aChar >= KEY_0) && (aChar <= KEY_9)) )
2658 aFuncBuffer.append(rKeyEvt.GetCharCode());
2659 SetMatchingEntries();
2661 else
2663 switch( aChar )
2665 case KEY_ESCAPE: // hide, do nothing
2666 HideAndRestoreFocus();
2667 break;
2668 case KEY_RIGHT:
2670 TextSelection aTextSelection( GetParentEditView()->GetSelection() );
2671 if( aTextSelection.GetEnd().GetPara() != pCodeCompleteWindow->GetTextSelection().GetEnd().GetPara()-1 )
2673 HideAndRestoreFocus();
2675 break;
2677 case KEY_LEFT:
2679 TextSelection aTextSelection( GetParentEditView()->GetSelection() );
2680 if( aTextSelection.GetStart().GetIndex()-1 < pCodeCompleteWindow->GetTextSelection().GetStart().GetIndex() )
2681 {//leave the cursor where it is
2682 HideAndRestoreFocus();
2684 break;
2686 case KEY_TAB:
2688 TextSelection aTextSelection = pCodeCompleteWindow->pParent->GetLastHighlightPortionTextSelection();
2689 OUString sTypedText = pCodeCompleteWindow->pParent->GetEditEngine()->GetText(aTextSelection);
2690 if( !aFuncBuffer.isEmpty() )
2692 sal_Int32 nInd = GetSelectedEntryPos();
2693 if( nInd != LISTBOX_ENTRY_NOTFOUND )
2694 {//if there is something selected
2695 bool bFound = false;
2696 if( nInd == GetEntryCount() )
2697 nInd = 0;
2698 for( sal_Int32 i = nInd; i != GetEntryCount(); ++i )
2700 OUString sEntry = GetEntry(i);
2701 if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer.toString() )
2702 && (aFuncBuffer.toString() != sTypedText) && (i != nInd) )
2704 SelectEntry( sEntry );
2705 bFound = true;
2706 break;
2709 if( !bFound )
2710 SetMatchingEntries();
2712 GetParentEditView()->SetSelection( aTextSelection );
2713 GetParentEditView()->DeleteSelected();
2714 GetParentEditView()->InsertText( GetSelectedEntry() );
2717 break;
2719 case KEY_SPACE:
2720 HideAndRestoreFocus();
2721 break;
2722 case KEY_BACKSPACE: case KEY_DELETE:
2723 if( !aFuncBuffer.isEmpty() )
2725 //if there was something inserted by tab: add it to aFuncBuffer
2726 TextSelection aSel( GetParentEditView()->GetSelection() );
2727 TextPaM aEnd( GetParentEditView()->CursorEndOfLine(pCodeCompleteWindow->GetTextSelection().GetEnd()) );
2728 GetParentEditView()->SetSelection(TextSelection(pCodeCompleteWindow->GetTextSelection().GetStart(), aEnd ) );
2729 OUString aTabInsertedStr( GetParentEditView()->GetSelected() );
2730 GetParentEditView()->SetSelection( aSel );
2732 if( !aTabInsertedStr.isEmpty() && aTabInsertedStr != aFuncBuffer.toString() )
2734 aFuncBuffer = aTabInsertedStr;
2736 aFuncBuffer.remove(aFuncBuffer.getLength()-1, 1);
2737 SetMatchingEntries();
2739 else
2740 pCodeCompleteWindow->ClearAndHide();
2741 break;
2742 case KEY_RETURN:
2743 InsertSelectedEntry();
2744 break;
2745 case KEY_UP: case KEY_DOWN:
2746 NotifyEvent nEvt( MouseNotifyEvent::KEYINPUT, nullptr, &rKeyEvt );
2747 PreNotify(nEvt);
2748 break;
2751 ListBox::KeyInput(rKeyEvt);
2754 void CodeCompleteListBox::HideAndRestoreFocus()
2756 pCodeCompleteWindow->Hide();
2757 pCodeCompleteWindow->pParent->GrabFocus();
2760 CodeCompleteWindow::CodeCompleteWindow( EditorWindow* pPar )
2761 : Window( pPar ),
2762 pParent( pPar ),
2763 pListBox( VclPtr<CodeCompleteListBox>::Create(this) )
2765 SetSizePixel( Size(151,151) ); //default, later it changes
2766 InitListBox();
2769 CodeCompleteWindow::~CodeCompleteWindow()
2771 disposeOnce();
2774 void CodeCompleteWindow::dispose()
2776 pListBox.disposeAndClear();
2777 pParent.clear();
2778 vcl::Window::dispose();
2781 void CodeCompleteWindow::InitListBox()
2783 pListBox->SetSizePixel( Size(150,150) ); //default, this will adopt the line length
2784 pListBox->Show();
2785 pListBox->EnableQuickSelection( false );
2788 void CodeCompleteWindow::InsertEntry( const OUString& aStr )
2790 pListBox->InsertEntry( aStr );
2793 void CodeCompleteWindow::ClearListBox()
2795 pListBox->Clear();
2796 pListBox->aFuncBuffer.setLength(0);
2799 void CodeCompleteWindow::SetTextSelection( const TextSelection& aSel )
2801 aTextSelection = aSel;
2805 void CodeCompleteWindow::ResizeAndPositionListBox()
2807 if( pListBox->GetEntryCount() >= 1 )
2808 {// if there is at least one element inside
2809 // calculate basic position: under the current line
2810 tools::Rectangle aRect = static_cast<TextEngine*>(pParent->GetEditEngine())->PaMtoEditCursor( pParent->GetEditView()->GetSelection().GetEnd() );
2811 long nViewYOffset = pParent->GetEditView()->GetStartDocPos().Y();
2812 Point aPos = aRect.BottomRight();// this variable will be used later (if needed)
2813 aPos.setY( (aPos.Y() - nViewYOffset) + nBasePad );
2815 OUString aLongestEntry = pListBox->GetEntry( 0 );// grab the longest one: max search
2816 for( sal_Int32 i=1; i< pListBox->GetEntryCount(); ++i )
2818 if( pListBox->GetEntry( i ).getLength() > aLongestEntry.getLength() )
2819 aLongestEntry = pListBox->GetEntry( i );
2821 // get column/line count
2822 const sal_uInt16& nColumns = aLongestEntry.getLength();
2823 const sal_uInt16 nLines = static_cast<sal_uInt16>( std::min( sal_Int32(6), pListBox->GetEntryCount() ));
2825 Size aSize = pListBox->CalcBlockSize( nColumns, nLines );
2826 //set the size
2827 SetSizePixel( aSize );
2828 //1 px smaller, to see the border
2829 aSize.setWidth( aSize.getWidth() - 1 );
2830 aSize.setHeight( aSize.getHeight() - 1 );
2831 pListBox->SetSizePixel( aSize );
2833 //calculate position
2834 const tools::Rectangle aVisArea( pParent->GetEditView()->GetStartDocPos(), pParent->GetOutputSizePixel() ); //the visible area
2835 const Point& aBottomPoint = aVisArea.BottomRight();
2837 if( aVisArea.TopRight().getY() + aPos.getY() + aSize.getHeight() > aBottomPoint.getY() )
2838 {//clipped at the bottom: move it up
2839 const long& nParentFontHeight = pParent->GetEditEngine()->GetFont().GetFontHeight(); //parent's font (in the IDE): needed for height
2840 aPos.AdjustY( -(aSize.getHeight() + nParentFontHeight + nCursorPad) );
2843 if( aVisArea.TopLeft().getX() + aPos.getX() + aSize.getWidth() > aBottomPoint.getX() )
2844 {//clipped at the right side, move it a bit left
2845 aPos.AdjustX( -(aSize.getWidth() + aVisArea.TopLeft().getX()) );
2847 //set the position
2848 SetPosPixel( aPos );
2852 void CodeCompleteWindow::SelectFirstEntry()
2854 if( pListBox->GetEntryCount() > 0 )
2856 pListBox->SelectEntryPos( 0 );
2860 void CodeCompleteWindow::ClearAndHide()
2862 ClearListBox();
2863 pListBox->HideAndRestoreFocus();
2866 UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector< OUString >& aVect, const OUString& sVarType )
2867 : bCanComplete( true )
2869 if( aVect.empty() || sVarType.isEmpty() )
2871 bCanComplete = false;//invalid parameters, nothing to code complete
2872 return;
2877 // Get the base class for reflection:
2878 xClass = css::reflection::theCoreReflection::get(
2879 comphelper::getProcessComponentContext())->forName(sVarType);
2881 catch( const Exception& )
2883 bCanComplete = false;
2884 return;
2887 auto j = aVect.begin() + 1;//start from aVect[1]: aVect[0] is the variable name
2888 OUString sMethName;
2890 while( j != aVect.end() )
2892 sMethName = *j;
2894 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
2896 if( !CheckMethod(sMethName) && !CheckField(sMethName) )
2898 bCanComplete = false;
2899 break;
2902 else
2904 if( !CheckField(sMethName) )
2906 bCanComplete = false;
2907 break;
2911 ++j;
2915 std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassMethods() const
2917 std::vector< OUString > aRetVect;
2918 if( bCanComplete && ( xClass != nullptr ) )
2920 Sequence< Reference< reflection::XIdlMethod > > aMethods = xClass->getMethods();
2921 if( aMethods.getLength() != 0 )
2923 for(sal_Int32 l = 0; l < aMethods.getLength(); ++l)
2925 aRetVect.push_back( aMethods[l]->getName() );
2929 return aRetVect;//this is empty when cannot code complete
2932 std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassFields() const
2934 std::vector< OUString > aRetVect;
2935 if( bCanComplete && ( xClass != nullptr ) )
2937 Sequence< Reference< reflection::XIdlField > > aFields = xClass->getFields();
2938 if( aFields.getLength() != 0 )
2940 for(sal_Int32 l = 0; l < aFields.getLength(); ++l)
2942 aRetVect.push_back( aFields[l]->getName() );
2946 return aRetVect;//this is empty when cannot code complete
2950 bool UnoTypeCodeCompletetor::CheckField( const OUString& sFieldName )
2951 {// modifies xClass!!!
2953 if ( xClass == nullptr )
2954 return false;
2956 Reference< reflection::XIdlField> xField = xClass->getField( sFieldName );
2957 if( xField != nullptr )
2959 xClass = xField->getType();
2960 if( xClass != nullptr )
2962 return true;
2965 return false;
2968 bool UnoTypeCodeCompletetor::CheckMethod( const OUString& sMethName )
2969 {// modifies xClass!!!
2972 if ( xClass == nullptr )
2973 return false;
2975 Reference< reflection::XIdlMethod> xMethod = xClass->getMethod( sMethName );
2976 if( xMethod != nullptr ) //method OK, check return type
2978 xClass = xMethod->getReturnType();
2979 if( xClass != nullptr )
2981 return true;
2984 return false;
2987 } // namespace basctl
2989 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */