lok: Don't attempt to select the exact text after a failed search.
[LibreOffice.git] / basctl / source / basicide / baside2b.cxx
blob68592f41a18095e894c596307b019c24a3279beb
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 .
22 #include "helpid.hrc"
23 #include "baside2.hrc"
25 #include "baside2.hxx"
26 #include "brkdlg.hxx"
27 #include "iderdll.hxx"
29 #include <basic/sbmeth.hxx>
30 #include <basic/sbuno.hxx>
31 #include <com/sun/star/beans/XMultiPropertySet.hpp>
32 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
33 #include <com/sun/star/script/XLibraryContainer2.hpp>
34 #include <comphelper/string.hxx>
35 #include <officecfg/Office/Common.hxx>
36 #include <sfx2/dispatch.hxx>
37 #include <vcl/msgbox.hxx>
38 #include <svl/urihelper.hxx>
39 #include <vcl/xtextedt.hxx>
40 #include <vcl/txtattr.hxx>
41 #include <vcl/settings.hxx>
42 #include <svtools/textwindowpeer.hxx>
43 #include <svtools/treelistentry.hxx>
44 #include <vcl/taskpanelist.hxx>
45 #include <vcl/help.hxx>
47 #include <vector>
48 #include <com/sun/star/reflection/theCoreReflection.hpp>
50 namespace basctl
53 using namespace ::com::sun::star;
54 using namespace ::com::sun::star::uno;
56 namespace
59 sal_uInt16 const NoMarker = 0xFFFF;
60 long const nBasePad = 2;
61 long const nCursorPad = 5;
63 long nVirtToolBoxHeight; // inited in WatchWindow, used in Stackwindow
64 long nHeaderBarHeight;
66 // Returns pBase converted to SbxVariable if valid and is not an SbxMethod.
67 SbxVariable* IsSbxVariable (SbxBase* pBase)
69 if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pBase))
70 if (!dynamic_cast<SbxMethod*>(pVar))
71 return pVar;
72 return 0;
75 Image GetImage (unsigned nId)
77 static ImageList const aImagesNormal(IDEResId(RID_IMGLST_LAYOUT));
78 return aImagesNormal.GetImage(nId);
81 int const nScrollLine = 12;
82 int const nScrollPage = 60;
83 int const DWBORDER = 3;
85 char const cSuffixes[] = "%&!#@$";
87 } // namespace
90 /**
91 * Helper functions to get/set text in TextEngine using
92 * the stream interface.
94 * get/setText() only supports tools Strings limited to 64K).
96 OUString getTextEngineText (ExtTextEngine& rEngine)
98 SvMemoryStream aMemStream;
99 aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
100 aMemStream.SetLineDelimiter( LINEEND_LF );
101 rEngine.Write( aMemStream );
102 sal_Size nSize = aMemStream.Tell();
103 OUString aText( static_cast<const sal_Char*>(aMemStream.GetData()),
104 nSize, RTL_TEXTENCODING_UTF8 );
105 return aText;
108 void setTextEngineText (ExtTextEngine& rEngine, OUString const& aStr)
110 rEngine.SetText(OUString());
111 OString aUTF8Str = OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 );
112 SvMemoryStream aMemStream( (void*)aUTF8Str.getStr(), aUTF8Str.getLength(),
113 StreamMode::READ );
114 aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 );
115 aMemStream.SetLineDelimiter( LINEEND_LF );
116 rEngine.Read(aMemStream);
119 namespace
122 void lcl_DrawIDEWindowFrame(DockingWindow* pWin, vcl::RenderContext& rRenderContext)
124 if (pWin->IsFloatingMode())
125 return;
127 Size aSz = rRenderContext.GetOutputSizePixel();
128 const Color aOldLineColor(rRenderContext.GetLineColor());
129 rRenderContext.SetLineColor(Color(COL_WHITE));
130 // White line on top
131 rRenderContext.DrawLine(Point(0, 0), Point(aSz.Width(), 0));
132 // Black line at bottom
133 rRenderContext.SetLineColor(Color(COL_BLACK));
134 rRenderContext.DrawLine(Point(0, aSz.Height() - 1),
135 Point(aSz.Width(), aSz.Height() - 1));
136 rRenderContext.SetLineColor(aOldLineColor);
139 void lcl_SeparateNameAndIndex( const OUString& rVName, OUString& rVar, OUString& rIndex )
141 rVar = rVName;
142 rIndex.clear();
143 sal_Int32 nIndexStart = rVar.indexOf( '(' );
144 if ( nIndexStart != -1 )
146 sal_Int32 nIndexEnd = rVar.indexOf( ')', nIndexStart );
147 if ( nIndexStart != -1 )
149 rIndex = rVar.copy( nIndexStart+1, nIndexEnd-nIndexStart-1 );
150 rVar = rVar.copy( 0, nIndexStart );
151 rVar = comphelper::string::stripEnd(rVar, ' ');
152 rIndex = comphelper::string::strip(rIndex, ' ');
156 if ( !rVar.isEmpty() )
158 sal_uInt16 nLastChar = rVar.getLength()-1;
159 if ( strchr( cSuffixes, rVar[ nLastChar ] ) )
160 rVar = rVar.replaceAt( nLastChar, 1, "" );
162 if ( !rIndex.isEmpty() )
164 sal_uInt16 nLastChar = rIndex.getLength()-1;
165 if ( strchr( cSuffixes, rIndex[ nLastChar ] ) )
166 rIndex = rIndex.replaceAt( nLastChar, 1, "" );
170 } // namespace
174 // EditorWindow
178 class EditorWindow::ChangesListener:
179 public cppu::WeakImplHelper1< beans::XPropertiesChangeListener >
181 public:
182 explicit ChangesListener(EditorWindow & editor): editor_(editor) {}
184 private:
185 virtual ~ChangesListener() {}
187 virtual void SAL_CALL disposing(lang::EventObject const &) throw (RuntimeException, std::exception) SAL_OVERRIDE
189 osl::MutexGuard g(editor_.mutex_);
190 editor_.notifier_.clear();
193 virtual void SAL_CALL propertiesChange(
194 Sequence< beans::PropertyChangeEvent > const &) throw (RuntimeException, std::exception) SAL_OVERRIDE
196 SolarMutexGuard g;
197 editor_.ImplSetFont();
200 EditorWindow & editor_;
203 class EditorWindow::ProgressInfo : public SfxProgress
205 public:
206 ProgressInfo (SfxObjectShell* pObjSh, OUString const& rText, sal_uLong nRange) :
207 SfxProgress(pObjSh, rText, nRange),
208 nCurState(0)
211 void StepProgress ()
213 SetState(++nCurState);
216 private:
217 sal_uLong nCurState;
220 EditorWindow::EditorWindow (vcl::Window* pParent, ModulWindow* pModulWindow) :
221 Window(pParent, WB_BORDER),
222 pEditView(0),
223 pEditEngine(0),
224 rModulWindow(*pModulWindow),
225 nCurTextWidth(0),
226 aHighlighter(HIGHLIGHT_BASIC),
227 bHighlightning(false),
228 bDoSyntaxHighlight(true),
229 bDelayHighlight(true),
230 pCodeCompleteWnd(VclPtr<CodeCompleteWindow>::Create(this))
232 SetBackground(Wallpaper(GetSettings().GetStyleSettings().GetFieldColor()));
233 SetPointer( Pointer( PointerStyle::Text ) );
234 SetHelpId( HID_BASICIDE_EDITORWINDOW );
236 listener_ = new ChangesListener(*this);
237 Reference< beans::XMultiPropertySet > n(
238 officecfg::Office::Common::Font::SourceViewFont::get(),
239 UNO_QUERY_THROW);
241 osl::MutexGuard g(mutex_);
242 notifier_ = n;
244 Sequence< OUString > s(2);
245 s[0] = "FontHeight";
246 s[1] = "FontName";
247 n->addPropertiesChangeListener(s, listener_.get());
251 EditorWindow::~EditorWindow()
253 disposeOnce();
256 void EditorWindow::dispose()
258 Reference< beans::XMultiPropertySet > n;
260 osl::MutexGuard g(mutex_);
261 n = notifier_;
263 if (n.is()) {
264 n->removePropertiesChangeListener(listener_.get());
267 aSyntaxIdle.Stop();
269 if ( pEditEngine )
271 EndListening( *pEditEngine );
272 pEditEngine->RemoveView(pEditView.get());
274 pCodeCompleteWnd.disposeAndClear();
275 vcl::Window::dispose();
278 OUString EditorWindow::GetWordAtCursor()
280 OUString aWord;
282 if ( pEditView )
284 TextEngine* pTextEngine = pEditView->GetTextEngine();
285 if ( pTextEngine )
287 // check first, if the cursor is at a help URL
288 const TextSelection& rSelection = pEditView->GetSelection();
289 const TextPaM& rSelStart = rSelection.GetStart();
290 const TextPaM& rSelEnd = rSelection.GetEnd();
291 OUString aText = pTextEngine->GetText( rSelEnd.GetPara() );
292 CharClass aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() );
293 sal_Int32 nSelStart = rSelStart.GetIndex();
294 sal_Int32 nSelEnd = rSelEnd.GetIndex();
295 sal_Int32 nLength = aText.getLength();
296 sal_Int32 nStart = 0;
297 sal_Int32 nEnd = nLength;
298 while ( nStart < nLength )
300 OUString aURL( URIHelper::FindFirstURLInText( aText, nStart, nEnd, aClass ) );
301 INetURLObject aURLObj( aURL );
302 if ( aURLObj.GetProtocol() == INetProtocol::VndSunStarHelp
303 && nSelStart >= nStart && nSelStart <= nEnd && nSelEnd >= nStart && nSelEnd <= nEnd )
305 aWord = aURL;
306 break;
308 nStart = nEnd;
309 nEnd = nLength;
312 // Not the selected range, but at the CursorPosition,
313 // if a word is partially selected.
314 if ( aWord.isEmpty() )
315 aWord = pTextEngine->GetWord( rSelEnd );
317 // Can be empty when full word selected, as Cursor behing it
318 if ( aWord.isEmpty() && pEditView->HasSelection() )
319 aWord = pTextEngine->GetWord( rSelStart );
323 return aWord;
326 void EditorWindow::RequestHelp( const HelpEvent& rHEvt )
328 bool bDone = false;
330 // Should have been activated at some point
331 if ( pEditEngine )
333 if ( rHEvt.GetMode() & HelpEventMode::CONTEXT )
335 OUString aKeyword = GetWordAtCursor();
336 Application::GetHelp()->SearchKeyword( aKeyword );
337 bDone = true;
339 else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
341 OUString aHelpText;
342 Point aTopLeft;
343 if ( StarBASIC::IsRunning() )
345 Point aWindowPos = rHEvt.GetMousePosPixel();
346 aWindowPos = ScreenToOutputPixel( aWindowPos );
347 Point aDocPos = GetEditView()->GetDocPos( aWindowPos );
348 TextPaM aCursor = GetEditView()->GetTextEngine()->GetPaM(aDocPos, false);
349 TextPaM aStartOfWord;
350 OUString aWord = GetEditView()->GetTextEngine()->GetWord( aCursor, &aStartOfWord );
351 if ( !aWord.isEmpty() && !comphelper::string::isdigitAsciiString(aWord) )
353 sal_uInt16 nLastChar = aWord.getLength() - 1;
354 if ( strchr( cSuffixes, aWord[ nLastChar ] ) )
355 aWord = aWord.replaceAt( nLastChar, 1, "" );
356 SbxBase* pSBX = StarBASIC::FindSBXInCurrentScope( aWord );
357 if (SbxVariable const* pVar = IsSbxVariable(pSBX))
359 SbxDataType eType = pVar->GetType();
360 if ( (sal_uInt8)eType == (sal_uInt8)SbxOBJECT )
361 // might cause a crash e. g. at the selections-object
362 // Type == Object does not mean pVar == Object!
363 ; // aHelpText = ((SbxObject*)pVar)->GetClassName();
364 else if ( eType & SbxARRAY )
365 ; // aHelpText = "{...}";
366 else if ( (sal_uInt8)eType != (sal_uInt8)SbxEMPTY )
368 aHelpText = pVar->GetName();
369 if ( aHelpText.isEmpty() ) // name is not copied with the passed parameters
370 aHelpText = aWord;
371 aHelpText += "=";
372 aHelpText += pVar->GetOUString();
375 if ( !aHelpText.isEmpty() )
377 aTopLeft = GetEditView()->GetTextEngine()->PaMtoEditCursor( aStartOfWord ).BottomLeft();
378 aTopLeft = GetEditView()->GetWindowPos( aTopLeft );
379 aTopLeft.X() += 5;
380 aTopLeft.Y() += 5;
381 aTopLeft = OutputToScreenPixel( aTopLeft );
385 Help::ShowQuickHelp( this, Rectangle( aTopLeft, Size( 1, 1 ) ), aHelpText, QuickHelpFlags::Top|QuickHelpFlags::Left);
386 bDone = true;
390 if ( !bDone )
391 Window::RequestHelp( rHEvt );
395 void EditorWindow::Resize()
397 // ScrollBars, etc. happens in Adjust...
398 if ( pEditView )
400 long nVisY = pEditView->GetStartDocPos().Y();
402 pEditView->ShowCursor();
403 Size aOutSz( GetOutputSizePixel() );
404 long nMaxVisAreaStart = pEditView->GetTextEngine()->GetTextHeight() - aOutSz.Height();
405 if ( nMaxVisAreaStart < 0 )
406 nMaxVisAreaStart = 0;
407 if ( pEditView->GetStartDocPos().Y() > nMaxVisAreaStart )
409 Point aStartDocPos( pEditView->GetStartDocPos() );
410 aStartDocPos.Y() = nMaxVisAreaStart;
411 pEditView->SetStartDocPos( aStartDocPos );
412 pEditView->ShowCursor();
413 rModulWindow.GetBreakPointWindow().GetCurYOffset() = aStartDocPos.Y();
414 rModulWindow.GetLineNumberWindow().GetCurYOffset() = aStartDocPos.Y();
416 InitScrollBars();
417 if ( nVisY != pEditView->GetStartDocPos().Y() )
418 Invalidate();
423 void EditorWindow::MouseMove( const MouseEvent &rEvt )
425 if ( pEditView )
426 pEditView->MouseMove( rEvt );
430 void EditorWindow::MouseButtonUp( const MouseEvent &rEvt )
432 if ( pEditView )
434 pEditView->MouseButtonUp( rEvt );
435 if (SfxBindings* pBindings = GetBindingsPtr())
437 pBindings->Invalidate( SID_BASICIDE_STAT_POS );
438 pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
443 void EditorWindow::MouseButtonDown( const MouseEvent &rEvt )
445 GrabFocus();
446 if ( pEditView )
447 pEditView->MouseButtonDown( rEvt );
448 if( pCodeCompleteWnd->IsVisible() )
450 if( pEditView->GetSelection() != pCodeCompleteWnd->GetTextSelection() )
451 {//selection changed, code complete window should be hidden
452 pCodeCompleteWnd->GetListBox()->HideAndRestoreFocus();
457 void EditorWindow::Command( const CommandEvent& rCEvt )
459 if ( pEditView )
461 pEditView->Command( rCEvt );
462 if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) ||
463 ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) ||
464 ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) )
466 HandleScrollCommand( rCEvt, rModulWindow.GetHScrollBar(), &rModulWindow.GetEditVScrollBar() );
467 } else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) {
468 SfxDispatcher* pDispatcher = GetDispatcher();
469 if ( pDispatcher )
471 SfxDispatcher::ExecutePopup();
473 if( pCodeCompleteWnd->IsVisible() ) // hide the code complete window
474 pCodeCompleteWnd->ClearAndHide();
479 bool EditorWindow::ImpCanModify()
481 bool bCanModify = true;
482 if ( StarBASIC::IsRunning() && rModulWindow.GetBasicStatus().bIsRunning )
484 // If in Trace-mode, abort the trace or refuse input
485 // Remove markers in the modules in Notify at Basic::Stoped
486 if ( QueryBox( 0, WB_OK_CANCEL, IDEResId(RID_STR_WILLSTOPPRG).toString() ).Execute() == RET_OK )
488 rModulWindow.GetBasicStatus().bIsRunning = false;
489 StopBasic();
491 else
492 bCanModify = false;
494 return bCanModify;
497 void EditorWindow::KeyInput( const KeyEvent& rKEvt )
499 if ( !pEditView ) // Happens in Win95
500 return;
502 #if OSL_DEBUG_LEVEL > 1
503 Range aRange = rModulWindow.GetHScrollBar()->GetRange(); (void)aRange;
504 long nVisSz = rModulWindow.GetHScrollBar()->GetVisibleSize(); (void)nVisSz;
505 long nPapSz = rModulWindow.GetHScrollBar()->GetPageSize(); (void)nPapSz;
506 long nLinSz = rModulWindow.GetHScrollBar()->GetLineSize(); (void)nLinSz;
507 long nThumb = rModulWindow.GetHScrollBar()->GetThumbPos(); (void)nThumb;
508 #endif
509 bool const bWasModified = pEditEngine->IsModified();
510 // see if there is an accelerator to be processed first
511 bool bDone = SfxViewShell::Current()->KeyInput( rKEvt );
513 if( pCodeCompleteWnd->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn() )
515 pCodeCompleteWnd->GetListBox()->KeyInput(rKEvt);
516 if( rKEvt.GetKeyCode().GetCode() == KEY_UP
517 || rKEvt.GetKeyCode().GetCode() == KEY_DOWN
518 || rKEvt.GetKeyCode().GetCode() == KEY_TAB
519 || rKEvt.GetKeyCode().GetCode() == KEY_POINT)
520 return;
523 if( (rKEvt.GetKeyCode().GetCode() == KEY_SPACE ||
524 rKEvt.GetKeyCode().GetCode() == KEY_TAB ||
525 rKEvt.GetKeyCode().GetCode() == KEY_RETURN ) && CodeCompleteOptions::IsAutoCorrectOn() )
527 HandleAutoCorrect();
530 if( rKEvt.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() )
531 {//autoclose double quotes
532 HandleAutoCloseDoubleQuotes();
535 if( rKEvt.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() )
536 {//autoclose parenthesis
537 HandleAutoCloseParen();
540 if( rKEvt.GetKeyCode().GetCode() == KEY_RETURN && CodeCompleteOptions::IsProcedureAutoCompleteOn() )
541 {//autoclose implementation
542 HandleProcedureCompletion();
545 if( rKEvt.GetKeyCode().GetCode() == KEY_POINT && CodeCompleteOptions::IsCodeCompleteOn() )
547 HandleCodeCompletion();
549 if ( !bDone && ( !TextEngine::DoesKeyChangeText( rKEvt ) || ImpCanModify() ) )
551 if ( ( rKEvt.GetKeyCode().GetCode() == KEY_TAB ) && !rKEvt.GetKeyCode().IsMod1() &&
552 !rKEvt.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() )
554 TextSelection aSel( pEditView->GetSelection() );
555 if ( aSel.GetStart().GetPara() != aSel.GetEnd().GetPara() )
557 bDelayHighlight = false;
558 if ( !rKEvt.GetKeyCode().IsShift() )
559 pEditView->IndentBlock();
560 else
561 pEditView->UnindentBlock();
562 bDelayHighlight = true;
563 bDone = true;
566 if ( !bDone )
567 bDone = pEditView->KeyInput( rKEvt );
569 if ( !bDone )
571 Window::KeyInput( rKEvt );
573 else
575 if (SfxBindings* pBindings = GetBindingsPtr())
577 pBindings->Invalidate( SID_BASICIDE_STAT_POS );
578 pBindings->Invalidate( SID_BASICIDE_STAT_TITLE );
579 if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR )
581 pBindings->Update( SID_BASICIDE_STAT_POS );
582 pBindings->Update( SID_BASICIDE_STAT_TITLE );
584 if ( !bWasModified && pEditEngine->IsModified() )
586 pBindings->Invalidate( SID_SAVEDOC );
587 pBindings->Invalidate( SID_DOC_MODIFIED );
588 pBindings->Invalidate( SID_UNDO );
590 if ( rKEvt.GetKeyCode().GetCode() == KEY_INSERT )
591 pBindings->Invalidate( SID_ATTR_INSERT );
596 void EditorWindow::HandleAutoCorrect()
598 TextSelection aSel = GetEditView()->GetSelection();
599 sal_uLong nLine = aSel.GetStart().GetPara();
600 sal_uInt16 nIndex = aSel.GetStart().GetIndex();
601 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
602 const OUString& sActSubName = GetActualSubName( nLine ); // the actual procedure
604 std::vector<HighlightPortion> aPortions;
605 aHighlighter.getHighlightPortions( aLine, aPortions );
607 if( aPortions.empty() )
608 return;
610 HighlightPortion& r = aPortions.back();
611 if( nIndex != aPortions.size()-1 )
612 {//cursor is not standing at the end of the line
613 for (std::vector<HighlightPortion>::iterator i(aPortions.begin());
614 i != aPortions.end(); ++i)
616 if( i->nEnd == nIndex )
618 r = *i;
619 break;
624 OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin );
625 //if WS or empty string: stop, nothing to do
626 if( ( r.tokenType == TT_WHITESPACE ) || sStr.isEmpty() )
627 return;
628 //create the appropriate TextSelection, and update the cache
629 TextPaM aStart( nLine, r.nBegin );
630 TextPaM aEnd( nLine, r.nBegin + sStr.getLength() );
631 TextSelection sTextSelection( aStart, aEnd );
632 rModulWindow.UpdateModule();
633 rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache );
634 // correct the last entered keyword
635 if( r.tokenType == TT_KEYWORDS )
637 sStr = sStr.toAsciiLowerCase();
638 if( !SbModule::GetKeywordCase(sStr).isEmpty() )
639 // if it is a keyword, get its correct case
640 sStr = SbModule::GetKeywordCase(sStr);
641 else
642 // else capitalize first letter/select the correct one, and replace
643 sStr = sStr.replaceAt( 0, 1, OUString(sStr[0]).toAsciiUpperCase() );
645 pEditEngine->ReplaceText( sTextSelection, sStr );
646 pEditView->SetSelection( aSel );
648 if( r.tokenType == TT_IDENTIFIER )
649 {// correct variables
650 if( !aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ).isEmpty() )
652 sStr = aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName );
653 pEditEngine->ReplaceText( sTextSelection, sStr );
654 pEditView->SetSelection( aSel );
656 else
658 //autocorrect procedures
659 SbxArray* pArr = rModulWindow.GetSbModule()->GetMethods();
660 for( sal_uInt32 i=0; i < pArr->Count32(); ++i )
662 if( pArr->Get32(i)->GetName().equalsIgnoreAsciiCase( sStr ) )
664 sStr = pArr->Get32(i)->GetName(); //if found, get the correct case
665 pEditEngine->ReplaceText( sTextSelection, sStr );
666 pEditView->SetSelection( aSel );
667 return;
674 TextSelection EditorWindow::GetLastHighlightPortionTextSelection()
675 {//creates a text selection from the highlight portion on the cursor
676 sal_uLong nLine = GetEditView()->GetSelection().GetStart().GetPara();
677 sal_uInt16 nIndex = GetEditView()->GetSelection().GetStart().GetIndex();
678 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
679 std::vector<HighlightPortion> aPortions;
680 aHighlighter.getHighlightPortions( aLine, aPortions );
682 assert(!aPortions.empty());
683 HighlightPortion& r = aPortions.back();
684 if( nIndex != aPortions.size()-1 )
685 {//cursor is not standing at the end of the line
686 for (std::vector<HighlightPortion>::iterator i(aPortions.begin());
687 i != aPortions.end(); ++i)
689 if( i->nEnd == nIndex )
691 r = *i;
692 break;
697 if( aPortions.size() == 0 )
698 return TextSelection();
700 OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin );
701 TextPaM aStart( nLine, r.nBegin );
702 TextPaM aEnd( nLine, r.nBegin + sStr.getLength() );
703 return TextSelection( aStart, aEnd );
706 void EditorWindow::HandleAutoCloseParen()
708 TextSelection aSel = GetEditView()->GetSelection();
709 sal_uLong nLine = aSel.GetStart().GetPara();
710 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
712 if( aLine.getLength() > 0 && aLine[aSel.GetEnd().GetIndex()-1] != '(' )
714 GetEditView()->InsertText(OUString(")"));
715 //leave the cursor on it's place: inside the parenthesis
716 TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
717 GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
721 void EditorWindow::HandleAutoCloseDoubleQuotes()
723 TextSelection aSel = GetEditView()->GetSelection();
724 sal_uLong nLine = aSel.GetStart().GetPara();
725 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
727 std::vector<HighlightPortion> aPortions;
728 aHighlighter.getHighlightPortions( aLine, aPortions );
730 if( aPortions.empty() )
731 return;
733 if( aLine.getLength() > 0 && !aLine.endsWith("\"") && (aPortions.back().tokenType != TT_STRING) )
735 GetEditView()->InsertText(OUString("\""));
736 //leave the cursor on it's place: inside the two double quotes
737 TextPaM aEnd(nLine, aSel.GetEnd().GetIndex());
738 GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) );
742 void EditorWindow::HandleProcedureCompletion()
745 TextSelection aSel = GetEditView()->GetSelection();
746 sal_uLong nLine = aSel.GetStart().GetPara();
747 OUString aLine( pEditEngine->GetText( nLine ) );
749 bool bFoundName = false;
750 OUString sProcType;
751 OUString sProcName;
753 bFoundName = GetProcedureName(aLine, sProcType, sProcName);
755 if (!bFoundName)
756 return;
758 OUString sText("\nEnd ");
759 aSel = GetEditView()->GetSelection();
760 if( sProcType.equalsIgnoreAsciiCase("function") )
761 sText += "Function\n";
762 if( sProcType.equalsIgnoreAsciiCase("sub") )
763 sText += "Sub\n";
765 if( nLine+1 == pEditEngine->GetParagraphCount() )
767 pEditView->InsertText( sText );//append to the end
768 GetEditView()->SetSelection(aSel);
770 else
772 for( sal_uLong i = nLine+1; i < pEditEngine->GetParagraphCount(); ++i )
773 {//searching forward for end token, or another sub/function definition
774 OUString aCurrLine = pEditEngine->GetText( i );
775 std::vector<HighlightPortion> aCurrPortions;
776 aHighlighter.getHighlightPortions( aCurrLine, aCurrPortions );
778 if( aCurrPortions.size() >= 3 )
779 {//at least 3 tokens: (sub|function) whitespace idetifier ....
780 HighlightPortion& r = aCurrPortions.front();
781 OUString sStr = aCurrLine.copy(r.nBegin, r.nEnd - r.nBegin);
783 if( r.tokenType == 9 )
785 if( sStr.equalsIgnoreAsciiCase("sub") || sStr.equalsIgnoreAsciiCase("function") )
787 pEditView->InsertText( sText );//append to the end
788 GetEditView()->SetSelection(aSel);
789 break;
791 if( sStr.equalsIgnoreAsciiCase("end") )
792 break;
799 bool EditorWindow::GetProcedureName(OUString& rLine, OUString& rProcType, OUString& rProcName) const
801 std::vector<HighlightPortion> aPortions;
802 aHighlighter.getHighlightPortions(rLine, aPortions);
804 if( aPortions.empty() )
805 return false;
807 bool bFoundType = false;
808 bool bFoundName = false;
810 for (std::vector<HighlightPortion>::iterator i(aPortions.begin());
811 i != aPortions.end(); ++i)
813 OUString sTokStr = rLine.copy(i->nBegin, i->nEnd - i->nBegin);
815 if( i->tokenType == 9 && ( sTokStr.equalsIgnoreAsciiCase("sub")
816 || sTokStr.equalsIgnoreAsciiCase("function")) )
818 rProcType = sTokStr;
819 bFoundType = true;
821 if( i->tokenType == 1 && bFoundType )
823 rProcName = sTokStr;
824 bFoundName = true;
825 break;
829 if( !bFoundType || !bFoundName )
830 return false;// no sub/function keyword or there is no identifier
832 return true;
836 void EditorWindow::HandleCodeCompletion()
838 rModulWindow.UpdateModule();
839 rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache);
840 TextSelection aSel = GetEditView()->GetSelection();
841 sal_uLong nLine = aSel.GetStart().GetPara();
842 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified
843 std::vector< OUString > aVect; //vector to hold the base variable+methods for the nested reflection
845 std::vector<HighlightPortion> aPortions;
846 aLine = aLine.copy(0, aSel.GetEnd().GetIndex());
847 aHighlighter.getHighlightPortions( aLine, aPortions );
848 if( !aPortions.empty() )
849 {//use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod ..
850 for( std::vector<HighlightPortion>::reverse_iterator i(
851 aPortions.rbegin());
852 i != aPortions.rend(); ++i)
854 if( i->tokenType == TT_WHITESPACE ) // a whitespace: stop; if there is no ws, it goes to the beginning of the line
855 break;
856 if( i->tokenType == TT_IDENTIFIER || i->tokenType == TT_KEYWORDS ) // extract the identifiers(methods, base variable)
857 /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue
858 * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!)
859 * */
860 aVect.insert( aVect.begin(), aLine.copy(i->nBegin, i->nEnd - i->nBegin) );
863 if( aVect.size() == 0 )//nothing to do
864 return;
865 OUString sBaseName = aVect[0];//variable name
866 OUString sVarType = aCodeCompleteCache.GetVarType( sBaseName );
867 if( !sVarType.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() )
868 {//correct variable name, if autocorrection on
869 const OUString& sStr = aCodeCompleteCache.GetCorrectCaseVarName( sBaseName, GetActualSubName(nLine) );
870 if( !sStr.isEmpty() )
872 TextPaM aStart(nLine, aSel.GetStart().GetIndex() - sStr.getLength() );
873 TextSelection sTextSelection(aStart, TextPaM(nLine, aSel.GetStart().GetIndex()));
874 pEditEngine->ReplaceText( sTextSelection, sStr );
875 pEditView->SetSelection( aSel );
879 UnoTypeCodeCompletetor aTypeCompletor( aVect, sVarType );
881 if( aTypeCompletor.CanCodeComplete() )
883 std::vector< OUString > aEntryVect;//entries to be inserted into the list
884 std::vector< OUString > aFieldVect = aTypeCompletor.GetXIdlClassFields();//fields
885 aEntryVect.insert(aEntryVect.end(), aFieldVect.begin(), aFieldVect.end() );
886 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
887 {// if extended types on, reflect classes, else just the structs (XIdlClass without methods)
888 std::vector< OUString > aMethVect = aTypeCompletor.GetXIdlClassMethods();//methods
889 aEntryVect.insert(aEntryVect.end(), aMethVect.begin(), aMethVect.end() );
891 if( aEntryVect.size() > 0 )
892 SetupAndShowCodeCompleteWnd( aEntryVect, aSel );
897 void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector< OUString >& aEntryVect, TextSelection aSel )
899 // clear the listbox
900 pCodeCompleteWnd->ClearListBox();
901 // fill the listbox
902 for(unsigned int l = 0; l < aEntryVect.size(); ++l)
904 pCodeCompleteWnd->InsertEntry( aEntryVect[l] );
906 // show it
907 pCodeCompleteWnd->Show();
908 pCodeCompleteWnd->ResizeAndPositionListBox();
909 pCodeCompleteWnd->SelectFirstEntry();
910 // correct text selection, and set it
911 aSel.GetStart().GetIndex() += 1;
912 aSel.GetEnd().GetIndex() += 1;
913 pCodeCompleteWnd->SetTextSelection( aSel );
914 //give the focus to the EditView
915 pEditView->GetWindow()->GrabFocus();
918 void EditorWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
920 if (!pEditEngine) // We need it now at latest
921 CreateEditEngine();
923 pEditView->Paint(rRenderContext, rRect);
926 void EditorWindow::LoseFocus()
928 SetSourceInBasic();
929 Window::LoseFocus();
932 bool EditorWindow::SetSourceInBasic()
934 bool bChanged = false;
935 if ( pEditEngine && pEditEngine->IsModified()
936 && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise
937 // any read only bug in the text engine could lead to a crash later
939 if ( !StarBASIC::IsRunning() ) // Not at runtime!
941 rModulWindow.UpdateModule();
942 bChanged = true;
945 return bChanged;
948 // Returns the position of the last character of any of the following
949 // EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found
950 sal_Int32 searchEOL( const OUString& rStr, sal_Int32 fromIndex )
952 sal_Int32 iRetPos = -1;
954 sal_Int32 iLF = rStr.indexOf( LINE_SEP, fromIndex );
955 if( iLF != -1 )
957 iRetPos = iLF;
959 else
961 iRetPos = rStr.indexOf( LINE_SEP_CR, fromIndex );
963 return iRetPos;
966 void EditorWindow::CreateEditEngine()
968 if (pEditEngine)
969 return;
971 pEditEngine.reset(new ExtTextEngine);
972 pEditView.reset(new ExtTextView(pEditEngine.get(), this));
973 pEditView->SetAutoIndentMode(true);
974 pEditEngine->SetUpdateMode(false);
975 pEditEngine->InsertView(pEditView.get());
977 ImplSetFont();
979 aSyntaxIdle.SetPriority( SchedulerPriority::LOWER );
980 aSyntaxIdle.SetIdleHdl( LINK( this, EditorWindow, SyntaxTimerHdl ) );
982 bool bWasDoSyntaxHighlight = bDoSyntaxHighlight;
983 bDoSyntaxHighlight = false; // too slow for large texts...
984 OUString aOUSource(rModulWindow.GetModule());
985 sal_Int32 nLines = 0;
986 sal_Int32 nIndex = -1;
989 nLines++;
990 nIndex = searchEOL( aOUSource, nIndex+1 );
992 while (nIndex >= 0);
994 // nLines*4: SetText+Formatting+DoHighlight+Formatting
995 // it could be cut down on one formatting but you would wait even longer
996 // for the text then if the source code is long...
997 pProgress.reset(new ProgressInfo(GetShell()->GetViewFrame()->GetObjectShell(),
998 IDEResId(RID_STR_GENERATESOURCE).toString(),
999 nLines * 4));
1000 setTextEngineText(*pEditEngine, aOUSource);
1002 pEditView->SetStartDocPos(Point(0, 0));
1003 pEditView->SetSelection(TextSelection());
1004 rModulWindow.GetBreakPointWindow().GetCurYOffset() = 0;
1005 rModulWindow.GetLineNumberWindow().GetCurYOffset() = 0;
1006 pEditEngine->SetUpdateMode(true);
1007 rModulWindow.Update(); // has only been invalidated at UpdateMode = true
1009 pEditView->ShowCursor(true, true);
1011 StartListening(*pEditEngine);
1013 aSyntaxIdle.Stop();
1014 bDoSyntaxHighlight = bWasDoSyntaxHighlight;
1016 for (sal_uInt16 nLine = 0; nLine < nLines; nLine++)
1017 aSyntaxLineTable.insert(nLine);
1018 ForceSyntaxTimeout();
1020 pProgress.reset();
1022 pEditView->EraseVirtualDevice();
1023 pEditEngine->SetModified( false );
1024 pEditEngine->EnableUndo( true );
1026 InitScrollBars();
1028 if (SfxBindings* pBindings = GetBindingsPtr())
1030 pBindings->Invalidate(SID_BASICIDE_STAT_POS);
1031 pBindings->Invalidate(SID_BASICIDE_STAT_TITLE);
1034 DBG_ASSERT(rModulWindow.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: Brechpunkte verschoben?");
1036 // set readonly mode for readonly libraries
1037 ScriptDocument aDocument(rModulWindow.GetDocument());
1038 OUString aOULibName(rModulWindow.GetLibName());
1039 Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY );
1040 if (xModLibContainer.is()
1041 && xModLibContainer->hasByName(aOULibName)
1042 && xModLibContainer->isLibraryReadOnly(aOULibName))
1044 rModulWindow.SetReadOnly(true);
1047 if (aDocument.isDocument() && aDocument.isReadOnly())
1048 rModulWindow.SetReadOnly(true);
1051 // virtual
1052 void EditorWindow::DataChanged(DataChangedEvent const & rDCEvt)
1054 Window::DataChanged(rDCEvt);
1055 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
1056 && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
1058 Color aColor(GetSettings().GetStyleSettings().GetFieldColor());
1059 const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
1060 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor())
1062 SetBackground(Wallpaper(aColor));
1063 Invalidate();
1065 if (pEditEngine != 0)
1067 aColor = GetSettings().GetStyleSettings().GetFieldTextColor();
1068 if (!pOldSettings || aColor !=
1069 pOldSettings-> GetStyleSettings().GetFieldTextColor())
1071 vcl::Font aFont(pEditEngine->GetFont());
1072 aFont.SetColor(aColor);
1073 pEditEngine->SetFont(aFont);
1079 void EditorWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1081 if (TextHint const* pTextHint = dynamic_cast<TextHint const*>(&rHint))
1083 TextHint const& rTextHint = *pTextHint;
1084 if( rTextHint.GetId() == TEXT_HINT_VIEWSCROLLED )
1086 if ( rModulWindow.GetHScrollBar() )
1087 rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() );
1088 rModulWindow.GetEditVScrollBar().SetThumbPos( pEditView->GetStartDocPos().Y() );
1089 rModulWindow.GetBreakPointWindow().DoScroll
1090 ( 0, rModulWindow.GetBreakPointWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
1091 rModulWindow.GetLineNumberWindow().DoScroll
1092 ( 0, rModulWindow.GetLineNumberWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() );
1094 else if( rTextHint.GetId() == TEXT_HINT_TEXTHEIGHTCHANGED )
1096 if ( pEditView->GetStartDocPos().Y() )
1098 long nOutHeight = GetOutputSizePixel().Height();
1099 long nTextHeight = pEditEngine->GetTextHeight();
1100 if ( nTextHeight < nOutHeight )
1101 pEditView->Scroll( 0, pEditView->GetStartDocPos().Y() );
1103 rModulWindow.GetLineNumberWindow().Invalidate();
1106 SetScrollBarRanges();
1108 else if( rTextHint.GetId() == TEXT_HINT_TEXTFORMATTED )
1110 if ( rModulWindow.GetHScrollBar() )
1112 sal_uLong nWidth = pEditEngine->CalcTextWidth();
1113 if ( (long)nWidth != nCurTextWidth )
1115 nCurTextWidth = nWidth;
1116 rModulWindow.GetHScrollBar()->SetRange( Range( 0, (long)nCurTextWidth-1) );
1117 rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() );
1120 long nPrevTextWidth = nCurTextWidth;
1121 nCurTextWidth = pEditEngine->CalcTextWidth();
1122 if ( nCurTextWidth != nPrevTextWidth )
1123 SetScrollBarRanges();
1125 else if( rTextHint.GetId() == TEXT_HINT_PARAINSERTED )
1127 ParagraphInsertedDeleted( rTextHint.GetValue(), true );
1128 DoDelayedSyntaxHighlight( rTextHint.GetValue() );
1130 else if( rTextHint.GetId() == TEXT_HINT_PARAREMOVED )
1132 ParagraphInsertedDeleted( rTextHint.GetValue(), false );
1134 else if( rTextHint.GetId() == TEXT_HINT_PARACONTENTCHANGED )
1136 DoDelayedSyntaxHighlight( rTextHint.GetValue() );
1138 else if( rTextHint.GetId() == TEXT_HINT_VIEWSELECTIONCHANGED )
1140 if (SfxBindings* pBindings = GetBindingsPtr())
1142 pBindings->Invalidate( SID_CUT );
1143 pBindings->Invalidate( SID_COPY );
1149 OUString EditorWindow::GetActualSubName( sal_uLong nLine )
1151 SbxArrayRef pMethods = rModulWindow.GetSbModule()->GetMethods();
1152 for( sal_uInt16 i=0; i < pMethods->Count(); i++ )
1154 SbxVariable* p = PTR_CAST( SbMethod, pMethods->Get( i ) );
1155 SbMethod* pMeth = PTR_CAST( SbMethod, p );
1156 if( pMeth )
1158 sal_uInt16 l1,l2;
1159 pMeth->GetLineRange(l1,l2);
1160 if( (l1 <= nLine+1) && (nLine+1 <= l2) )
1162 return pMeth->GetName();
1166 return OUString("");
1169 void EditorWindow::SetScrollBarRanges()
1171 // extra method, not InitScrollBars, because for EditEngine events too
1172 if ( !pEditEngine )
1173 return;
1175 if ( rModulWindow.GetHScrollBar() )
1176 rModulWindow.GetHScrollBar()->SetRange( Range( 0, nCurTextWidth-1 ) );
1178 rModulWindow.GetEditVScrollBar().SetRange( Range( 0, pEditEngine->GetTextHeight()-1 ) );
1181 void EditorWindow::InitScrollBars()
1183 if (!pEditEngine)
1184 return;
1186 SetScrollBarRanges();
1187 Size aOutSz(GetOutputSizePixel());
1188 rModulWindow.GetEditVScrollBar().SetVisibleSize(aOutSz.Height());
1189 rModulWindow.GetEditVScrollBar().SetPageSize(aOutSz.Height() * 8 / 10);
1190 rModulWindow.GetEditVScrollBar().SetLineSize(GetTextHeight());
1191 rModulWindow.GetEditVScrollBar().SetThumbPos(pEditView->GetStartDocPos().Y());
1192 rModulWindow.GetEditVScrollBar().Show();
1194 if (rModulWindow.GetHScrollBar())
1196 rModulWindow.GetHScrollBar()->SetVisibleSize(aOutSz.Width());
1197 rModulWindow.GetHScrollBar()->SetPageSize(aOutSz.Width() * 8 / 10);
1198 rModulWindow.GetHScrollBar()->SetLineSize(GetTextWidth( "x" ) );
1199 rModulWindow.GetHScrollBar()->SetThumbPos(pEditView->GetStartDocPos().X());
1200 rModulWindow.GetHScrollBar()->Show();
1204 void EditorWindow::ImpDoHighlight( sal_uLong nLine )
1206 if ( bDoSyntaxHighlight )
1208 OUString aLine( pEditEngine->GetText( nLine ) );
1209 bool const bWasModified = pEditEngine->IsModified();
1210 pEditEngine->RemoveAttribs( nLine, true );
1211 std::vector<HighlightPortion> aPortions;
1212 aHighlighter.getHighlightPortions( aLine, aPortions );
1214 for (std::vector<HighlightPortion>::iterator i(aPortions.begin());
1215 i != aPortions.end(); ++i)
1217 Color const aColor = rModulWindow.GetLayout().GetSyntaxColor(i->tokenType);
1218 pEditEngine->SetAttrib(TextAttribFontColor(aColor), nLine, i->nBegin, i->nEnd, true);
1221 pEditEngine->SetModified(bWasModified);
1225 void EditorWindow::UpdateSyntaxHighlighting ()
1227 unsigned nCount = pEditEngine->GetParagraphCount();
1228 for (unsigned i = 0; i < nCount; ++i)
1229 DoDelayedSyntaxHighlight(i);
1232 void EditorWindow::ImplSetFont()
1234 OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().get_value_or(OUString()));
1235 if (sFontName.isEmpty())
1237 vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED,
1238 Application::GetSettings().GetUILanguageTag().getLanguageType(),
1239 GetDefaultFontFlags::NONE, this));
1240 sFontName = aTmpFont.GetName();
1242 Size aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get());
1243 vcl::Font aFont(sFontName, aFontSize);
1244 aFont.SetColor(Application::GetSettings().GetStyleSettings().GetFieldTextColor());
1245 SetPointFont(*this, aFont); // FIXME RenderContext
1246 aFont = GetFont();
1248 rModulWindow.GetBreakPointWindow().SetFont(aFont);
1249 rModulWindow.GetLineNumberWindow().SetFont(aFont);
1251 if (pEditEngine)
1253 bool const bModified = pEditEngine->IsModified();
1254 pEditEngine->SetFont(aFont);
1255 pEditEngine->SetModified(bModified);
1259 void EditorWindow::DoSyntaxHighlight( sal_uLong nPara )
1261 // because of the DelayedSyntaxHighlight it's possible
1262 // that this line does not exist anymore!
1263 if ( nPara < pEditEngine->GetParagraphCount() )
1265 // unfortunately I'm not sure that excactly this line does Modified() ...
1266 if ( pProgress )
1267 pProgress->StepProgress();
1268 ImpDoHighlight( nPara );
1272 void EditorWindow::DoDelayedSyntaxHighlight( sal_uLong nPara )
1274 // line is only added to 'Liste' (list), processed in TimerHdl
1275 // => don't manipulate breaks while EditEngine is formatting
1276 if ( pProgress )
1277 pProgress->StepProgress();
1279 if ( !bHighlightning && bDoSyntaxHighlight )
1281 if ( bDelayHighlight )
1283 aSyntaxLineTable.insert( nPara );
1284 aSyntaxIdle.Start();
1286 else
1287 DoSyntaxHighlight( nPara );
1291 IMPL_LINK_NOARG_TYPED(EditorWindow, SyntaxTimerHdl, Idle *, void)
1293 DBG_ASSERT( pEditView, "Noch keine View, aber Syntax-Highlight ?!" );
1295 bool const bWasModified = pEditEngine->IsModified();
1296 //pEditEngine->SetUpdateMode(false);
1298 bHighlightning = true;
1299 for ( SyntaxLineSet::const_iterator it = aSyntaxLineTable.begin();
1300 it != aSyntaxLineTable.end(); ++it )
1302 sal_uInt16 nLine = *it;
1303 DoSyntaxHighlight( nLine );
1306 // #i45572#
1307 if ( pEditView )
1308 pEditView->ShowCursor( false, true );
1310 pEditEngine->SetModified( bWasModified );
1312 aSyntaxLineTable.clear();
1313 bHighlightning = false;
1316 void EditorWindow::ParagraphInsertedDeleted( sal_uLong nPara, bool bInserted )
1318 if ( pProgress )
1319 pProgress->StepProgress();
1321 if ( !bInserted && ( nPara == TEXT_PARA_ALL ) )
1323 rModulWindow.GetBreakPoints().reset();
1324 rModulWindow.GetBreakPointWindow().Invalidate();
1325 rModulWindow.GetLineNumberWindow().Invalidate();
1327 else
1329 rModulWindow.GetBreakPoints().AdjustBreakPoints( (sal_uInt16)nPara+1, bInserted );
1331 long nLineHeight = GetTextHeight();
1332 Size aSz = rModulWindow.GetBreakPointWindow().GetOutputSize();
1333 Rectangle aInvRect( Point( 0, 0 ), aSz );
1334 long nY = nPara*nLineHeight - rModulWindow.GetBreakPointWindow().GetCurYOffset();
1335 aInvRect.Top() = nY;
1336 rModulWindow.GetBreakPointWindow().Invalidate( aInvRect );
1338 Size aLnSz(rModulWindow.GetLineNumberWindow().GetWidth(),
1339 GetOutputSizePixel().Height() - 2 * DWBORDER);
1340 rModulWindow.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER + 19, DWBORDER), aLnSz);
1341 rModulWindow.GetLineNumberWindow().Invalidate();
1345 void EditorWindow::CreateProgress( const OUString& rText, sal_uLong nRange )
1347 DBG_ASSERT( !pProgress, "ProgressInfo existiert schon" );
1348 pProgress.reset(new ProgressInfo(
1349 GetShell()->GetViewFrame()->GetObjectShell(),
1350 rText,
1351 nRange
1355 void EditorWindow::DestroyProgress()
1357 pProgress.reset();
1360 void EditorWindow::ForceSyntaxTimeout()
1362 aSyntaxIdle.Stop();
1363 aSyntaxIdle.GetIdleHdl().Call(&aSyntaxIdle);
1366 // BreakPointWindow
1368 BreakPointWindow::BreakPointWindow (vcl::Window* pParent, ModulWindow* pModulWindow)
1369 : Window(pParent, WB_BORDER)
1370 , rModulWindow(*pModulWindow)
1371 , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine
1372 , nMarkerPos(NoMarker)
1373 , bErrorMarker(false)
1375 setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor());
1376 SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW);
1379 void BreakPointWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle&)
1381 if (SyncYOffset())
1382 return;
1384 Size const aOutSz = rRenderContext.GetOutputSize();
1385 long const nLineHeight = rRenderContext.GetTextHeight();
1387 Image const aBrk[2] =
1389 GetImage(IMGID_BRKDISABLED),
1390 GetImage(IMGID_BRKENABLED)
1393 Size const aBmpSz = rRenderContext.PixelToLogic(aBrk[1].GetSizePixel());
1394 Point const aBmpOff((aOutSz.Width() - aBmpSz.Width()) / 2,
1395 (nLineHeight - aBmpSz.Height()) / 2);
1397 for (size_t i = 0, n = GetBreakPoints().size(); i < n; ++i)
1399 BreakPoint& rBrk = *GetBreakPoints().at(i);
1400 size_t const nLine = rBrk.nLine - 1;
1401 size_t const nY = nLine*nLineHeight - nCurYOffset;
1402 rRenderContext.DrawImage(Point(0, nY) + aBmpOff, aBrk[rBrk.bEnabled]);
1405 ShowMarker(rRenderContext);
1408 void BreakPointWindow::ShowMarker(vcl::RenderContext& rRenderContext)
1410 if (nMarkerPos == NoMarker)
1411 return;
1413 Size const aOutSz = GetOutputSize();
1414 long const nLineHeight = GetTextHeight();
1416 Image aMarker = GetImage(bErrorMarker ? IMGID_ERRORMARKER : IMGID_STEPMARKER);
1418 Size aMarkerSz(aMarker.GetSizePixel());
1419 aMarkerSz = rRenderContext.PixelToLogic(aMarkerSz);
1420 Point aMarkerOff(0, 0);
1421 aMarkerOff.X() = (aOutSz.Width() - aMarkerSz.Width()) / 2;
1422 aMarkerOff.Y() = (nLineHeight - aMarkerSz.Height()) / 2;
1424 sal_uLong nY = nMarkerPos * nLineHeight - nCurYOffset;
1425 Point aPos(0, nY);
1426 aPos += aMarkerOff;
1428 rRenderContext.DrawImage(aPos, aMarker);
1431 void BreakPointWindow::DoScroll( long nHorzScroll, long nVertScroll )
1433 nCurYOffset -= nVertScroll;
1434 Window::Scroll( nHorzScroll, nVertScroll );
1437 void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine, bool bError )
1439 if ( SyncYOffset() )
1440 Update();
1442 nMarkerPos = nLine;
1443 bErrorMarker = bError;
1444 Invalidate();
1447 void BreakPointWindow::SetNoMarker ()
1449 SetMarkerPos(NoMarker);
1452 BreakPoint* BreakPointWindow::FindBreakPoint( const Point& rMousePos )
1454 size_t nLineHeight = GetTextHeight();
1455 nLineHeight = nLineHeight > 0 ? nLineHeight : 1;
1456 size_t nYPos = rMousePos.Y() + nCurYOffset;
1458 for ( size_t i = 0, n = GetBreakPoints().size(); i < n ; ++i )
1460 BreakPoint* pBrk = GetBreakPoints().at( i );
1461 size_t nLine = pBrk->nLine-1;
1462 size_t nY = nLine*nLineHeight;
1463 if ( ( nYPos > nY ) && ( nYPos < ( nY + nLineHeight ) ) )
1464 return pBrk;
1466 return 0;
1469 void BreakPointWindow::MouseButtonDown( const MouseEvent& rMEvt )
1471 if ( rMEvt.GetClicks() == 2 )
1473 Point aMousePos( PixelToLogic( rMEvt.GetPosPixel() ) );
1474 long nLineHeight = GetTextHeight();
1475 if(nLineHeight)
1477 long nYPos = aMousePos.Y() + nCurYOffset;
1478 long nLine = nYPos / nLineHeight + 1;
1479 rModulWindow.ToggleBreakPoint( (sal_uLong)nLine );
1480 Invalidate();
1485 void BreakPointWindow::Command( const CommandEvent& rCEvt )
1487 if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
1489 Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) );
1490 Point aEventPos( PixelToLogic( aPos ) );
1491 BreakPoint* pBrk = rCEvt.IsMouseEvent() ? FindBreakPoint( aEventPos ) : 0;
1492 if ( pBrk )
1494 // test if break point is enabled...
1495 PopupMenu aBrkPropMenu( IDEResId( RID_POPUP_BRKPROPS ) );
1496 aBrkPropMenu.CheckItem( RID_ACTIV, pBrk->bEnabled );
1497 switch ( aBrkPropMenu.Execute( this, aPos ) )
1499 case RID_ACTIV:
1501 pBrk->bEnabled = !pBrk->bEnabled;
1502 rModulWindow.UpdateBreakPoint( *pBrk );
1503 Invalidate();
1505 break;
1506 case RID_BRKPROPS:
1508 ScopedVclPtrInstance< BreakPointDialog > aBrkDlg( this, GetBreakPoints() );
1509 aBrkDlg->SetCurrentBreakPoint( pBrk );
1510 aBrkDlg->Execute();
1511 Invalidate();
1513 break;
1516 else
1518 PopupMenu aBrkListMenu( IDEResId( RID_POPUP_BRKDLG ) );
1519 switch ( aBrkListMenu.Execute( this, aPos ) )
1521 case RID_BRKDLG:
1523 ScopedVclPtrInstance< BreakPointDialog > aBrkDlg( this, GetBreakPoints() );
1524 aBrkDlg->Execute();
1525 Invalidate();
1527 break;
1533 bool BreakPointWindow::SyncYOffset()
1535 TextView* pView = rModulWindow.GetEditView();
1536 if ( pView )
1538 long nViewYOffset = pView->GetStartDocPos().Y();
1539 if ( nCurYOffset != nViewYOffset )
1541 nCurYOffset = nViewYOffset;
1542 Invalidate();
1543 return true;
1546 return false;
1549 // virtual
1550 void BreakPointWindow::DataChanged(DataChangedEvent const & rDCEvt)
1552 Window::DataChanged(rDCEvt);
1553 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
1554 && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
1556 Color aColor(GetSettings().GetStyleSettings().GetFieldColor());
1557 const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
1558 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor())
1560 setBackgroundColor(aColor);
1561 Invalidate();
1566 void BreakPointWindow::setBackgroundColor(Color aColor)
1568 SetBackground(Wallpaper(aColor));
1571 namespace
1573 const sal_uInt16 ITEM_ID_VARIABLE = 1;
1574 const sal_uInt16 ITEM_ID_VALUE = 2;
1575 const sal_uInt16 ITEM_ID_TYPE = 3;
1578 WatchWindow::WatchWindow (Layout* pParent) :
1579 DockingWindow(pParent),
1580 aWatchStr( IDEResId( RID_STR_REMOVEWATCH ) ),
1581 aXEdit( VclPtr<ExtendedEdit>::Create(this, IDEResId( RID_EDT_WATCHEDIT )) ),
1582 aRemoveWatchButton( VclPtr<ImageButton>::Create(this, IDEResId( RID_IMGBTN_REMOVEWATCH )) ),
1583 aTreeListBox( VclPtr<WatchTreeListBox>::Create(this, WB_BORDER | WB_3DLOOK | WB_HASBUTTONS | WB_HASLINES | WB_HSCROLL | WB_TABSTOP
1584 | WB_HASLINESATROOT | WB_HASBUTTONSATROOT) ),
1585 aHeaderBar( VclPtr<HeaderBar>::Create( this, WB_BUTTONSTYLE | WB_BORDER ) )
1587 aXEdit->SetAccessibleName(IDEResId(RID_STR_WATCHNAME).toString());
1588 aTreeListBox->SetAccessibleName(IDEResId(RID_STR_WATCHNAME).toString());
1590 long nTextLen = GetTextWidth( aWatchStr ) + DWBORDER + 3;
1591 aXEdit->SetPosPixel( Point( nTextLen, 3 ) );
1592 aXEdit->SetAccHdl( LINK( this, WatchWindow, EditAccHdl ) );
1593 aXEdit->GetAccelerator().InsertItem( 1, vcl::KeyCode( KEY_RETURN ) );
1594 aXEdit->GetAccelerator().InsertItem( 2, vcl::KeyCode( KEY_ESCAPE ) );
1595 aXEdit->Show();
1597 aRemoveWatchButton->Disable();
1598 aRemoveWatchButton->SetClickHdl( LINK( this, WatchWindow, ButtonHdl ) );
1599 aRemoveWatchButton->SetPosPixel( Point( nTextLen + aXEdit->GetSizePixel().Width() + 4, 2 ) );
1600 Size aSz( aRemoveWatchButton->GetModeImage().GetSizePixel() );
1601 aSz.Width() += 6;
1602 aSz.Height() += 6;
1603 aRemoveWatchButton->SetSizePixel( aSz );
1604 aRemoveWatchButton->Show();
1606 long nRWBtnSize = aRemoveWatchButton->GetModeImage().GetSizePixel().Height() + 10;
1607 nVirtToolBoxHeight = aXEdit->GetSizePixel().Height() + 7;
1609 if ( nRWBtnSize > nVirtToolBoxHeight )
1610 nVirtToolBoxHeight = nRWBtnSize;
1612 nHeaderBarHeight = 16;
1614 aTreeListBox->SetHelpId(HID_BASICIDE_WATCHWINDOW_LIST);
1615 aTreeListBox->EnableInplaceEditing(true);
1616 aTreeListBox->SetSelectHdl( LINK( this, WatchWindow, TreeListHdl ) );
1617 aTreeListBox->SetPosPixel( Point( DWBORDER, nVirtToolBoxHeight + nHeaderBarHeight ) );
1618 aTreeListBox->SetHighlightRange( 1, 5 );
1620 Point aPnt( DWBORDER, nVirtToolBoxHeight + 1 );
1621 aHeaderBar->SetPosPixel( aPnt );
1622 aHeaderBar->SetEndDragHdl( LINK( this, WatchWindow, implEndDragHdl ) );
1624 long nVarTabWidth = 220;
1625 long nValueTabWidth = 100;
1626 long nTypeTabWidth = 1250;
1627 aHeaderBar->InsertItem( ITEM_ID_VARIABLE, IDEResId(RID_STR_WATCHVARIABLE).toString(), nVarTabWidth );
1628 aHeaderBar->InsertItem( ITEM_ID_VALUE, IDEResId(RID_STR_WATCHVALUE).toString(), nValueTabWidth );
1629 aHeaderBar->InsertItem( ITEM_ID_TYPE, IDEResId(RID_STR_WATCHTYPE).toString(), nTypeTabWidth );
1631 long tabs[ 4 ];
1632 tabs[ 0 ] = 3; // two tabs
1633 tabs[ 1 ] = 0;
1634 tabs[ 2 ] = nVarTabWidth;
1635 tabs[ 3 ] = nVarTabWidth + nValueTabWidth;
1636 aTreeListBox->SvHeaderTabListBox::SetTabs( tabs, MAP_PIXEL );
1637 aTreeListBox->InitHeaderBar( aHeaderBar.get() );
1639 aTreeListBox->SetNodeDefaultImages( );
1641 aHeaderBar->Show();
1643 aTreeListBox->Show();
1645 SetText(IDEResId(RID_STR_WATCHNAME).toString());
1647 SetHelpId( HID_BASICIDE_WATCHWINDOW );
1649 // make watch window keyboard accessible
1650 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1655 WatchWindow::~WatchWindow()
1657 disposeOnce();
1660 void WatchWindow::dispose()
1662 aXEdit.disposeAndClear();
1663 aRemoveWatchButton.disposeAndClear();
1664 aHeaderBar.disposeAndClear();
1665 aTreeListBox.disposeAndClear();
1666 if (!IsDisposed())
1667 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1668 DockingWindow::dispose();
1671 void WatchWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle&)
1673 rRenderContext.DrawText(Point(DWBORDER, 7), aWatchStr);
1674 lcl_DrawIDEWindowFrame(this, rRenderContext);
1677 void WatchWindow::Resize()
1679 Size aSz = GetOutputSizePixel();
1680 Size aBoxSz( aSz.Width() - 2*DWBORDER, aSz.Height() - nVirtToolBoxHeight - DWBORDER );
1682 if ( aBoxSz.Width() < 4 )
1683 aBoxSz.Width() = 0;
1684 if ( aBoxSz.Height() < 4 )
1685 aBoxSz.Height() = 0;
1687 aBoxSz.Height() -= nHeaderBarHeight;
1688 aTreeListBox->SetSizePixel( aBoxSz );
1689 aTreeListBox->GetHScroll()->SetPageSize( aTreeListBox->GetHScroll()->GetVisibleSize() );
1691 aBoxSz.Height() = nHeaderBarHeight;
1692 aHeaderBar->SetSizePixel( aBoxSz );
1694 Invalidate();
1697 struct WatchItem
1699 OUString maName;
1700 OUString maDisplayName;
1701 SbxObjectRef mpObject;
1702 std::vector<OUString> maMemberList;
1704 SbxDimArrayRef mpArray;
1705 int nDimLevel; // 0 = Root
1706 int nDimCount;
1707 std::vector<short> vIndices;
1709 WatchItem* mpArrayParentItem;
1711 explicit WatchItem (OUString const& rName):
1712 maName(rName),
1713 nDimLevel(0),
1714 nDimCount(0),
1715 mpArrayParentItem(0)
1718 void clearWatchItem ()
1720 maMemberList.clear();
1723 WatchItem* GetRootItem();
1724 SbxDimArray* GetRootArray();
1727 WatchItem* WatchItem::GetRootItem()
1729 WatchItem* pItem = mpArrayParentItem;
1730 while( pItem )
1732 if( pItem->mpArray.Is() )
1733 break;
1734 pItem = pItem->mpArrayParentItem;
1736 return pItem;
1739 SbxDimArray* WatchItem::GetRootArray()
1741 WatchItem* pRootItem = GetRootItem();
1742 SbxDimArray* pRet = NULL;
1743 if( pRootItem )
1744 pRet = pRootItem->mpArray;
1745 return pRet;
1748 void WatchWindow::AddWatch( const OUString& rVName )
1750 OUString aVar, aIndex;
1751 lcl_SeparateNameAndIndex( rVName, aVar, aIndex );
1752 WatchItem* pWatchItem = new WatchItem(aVar);
1754 OUString aWatchStr_( aVar );
1755 aWatchStr_ += "\t\t";
1756 SvTreeListEntry* pNewEntry = aTreeListBox->InsertEntry( aWatchStr_, 0, true, TREELIST_APPEND );
1757 pNewEntry->SetUserData( pWatchItem );
1759 aTreeListBox->Select(pNewEntry, true);
1760 aTreeListBox->MakeVisible(pNewEntry);
1761 aRemoveWatchButton->Enable();
1763 UpdateWatches();
1766 bool WatchWindow::RemoveSelectedWatch()
1768 SvTreeListEntry* pEntry = aTreeListBox->GetCurEntry();
1769 if ( pEntry )
1771 aTreeListBox->GetModel()->Remove( pEntry );
1772 pEntry = aTreeListBox->GetCurEntry();
1773 if ( pEntry )
1774 aXEdit->SetText( static_cast<WatchItem*>(pEntry->GetUserData())->maName );
1775 else
1776 aXEdit->SetText( OUString() );
1777 if ( !aTreeListBox->GetEntryCount() )
1778 aRemoveWatchButton->Disable();
1779 return true;
1781 else
1782 return false;
1786 IMPL_LINK( WatchWindow, ButtonHdl, ImageButton *, pButton )
1788 if (pButton == aRemoveWatchButton.get())
1789 if (SfxDispatcher* pDispatcher = GetDispatcher())
1790 pDispatcher->Execute(SID_BASICIDE_REMOVEWATCH);
1791 return 0;
1794 IMPL_LINK_NOARG(WatchWindow, TreeListHdl)
1796 SvTreeListEntry* pCurEntry = aTreeListBox->GetCurEntry();
1797 if ( pCurEntry && pCurEntry->GetUserData() )
1798 aXEdit->SetText( static_cast<WatchItem*>(pCurEntry->GetUserData())->maName );
1800 return 0;
1803 IMPL_LINK( WatchWindow, implEndDragHdl, HeaderBar *, pBar )
1805 (void)pBar;
1807 const sal_Int32 TAB_WIDTH_MIN = 10;
1808 sal_Int32 nMaxWidth =
1809 aHeaderBar->GetSizePixel().getWidth() - 2 * TAB_WIDTH_MIN;
1811 sal_Int32 nVariableWith = aHeaderBar->GetItemSize( ITEM_ID_VARIABLE );
1812 if( nVariableWith < TAB_WIDTH_MIN )
1813 aHeaderBar->SetItemSize( ITEM_ID_VARIABLE, TAB_WIDTH_MIN );
1814 else if( nVariableWith > nMaxWidth )
1815 aHeaderBar->SetItemSize( ITEM_ID_VARIABLE, nMaxWidth );
1817 sal_Int32 nValueWith = aHeaderBar->GetItemSize( ITEM_ID_VALUE );
1818 if( nValueWith < TAB_WIDTH_MIN )
1819 aHeaderBar->SetItemSize( ITEM_ID_VALUE, TAB_WIDTH_MIN );
1820 else if( nValueWith > nMaxWidth )
1821 aHeaderBar->SetItemSize( ITEM_ID_VALUE, nMaxWidth );
1823 if (aHeaderBar->GetItemSize( ITEM_ID_TYPE ) < TAB_WIDTH_MIN)
1824 aHeaderBar->SetItemSize( ITEM_ID_TYPE, TAB_WIDTH_MIN );
1826 sal_Int32 nPos = 0;
1827 sal_uInt16 nTabs = aHeaderBar->GetItemCount();
1828 for( sal_uInt16 i = 1 ; i < nTabs ; ++i )
1830 nPos += aHeaderBar->GetItemSize( i );
1831 aTreeListBox->SetTab( i, nPos, MAP_PIXEL );
1833 return 0;
1836 IMPL_LINK_TYPED( WatchWindow, EditAccHdl, Accelerator *, pAcc, void )
1838 switch ( pAcc->GetCurKeyCode().GetCode() )
1840 case KEY_RETURN:
1842 OUString aCurText( aXEdit->GetText() );
1843 if ( !aCurText.isEmpty() )
1845 AddWatch( aCurText );
1846 aXEdit->SetSelection( Selection( 0, 0xFFFF ) );
1849 break;
1850 case KEY_ESCAPE:
1852 aXEdit->SetText( OUString() );
1854 break;
1858 void WatchWindow::UpdateWatches( bool bBasicStopped )
1860 aTreeListBox->UpdateWatches( bBasicStopped );
1865 // StackWindow
1869 StackWindow::StackWindow (Layout* pParent) :
1870 DockingWindow(pParent),
1871 aTreeListBox( VclPtr<SvTreeListBox>::Create(this, WB_BORDER | WB_3DLOOK | WB_HSCROLL | WB_TABSTOP) ),
1872 aStackStr( IDEResId( RID_STR_STACK ) )
1874 aTreeListBox->SetHelpId(HID_BASICIDE_STACKWINDOW_LIST);
1875 aTreeListBox->SetAccessibleName(IDEResId(RID_STR_STACKNAME).toString());
1876 aTreeListBox->SetPosPixel( Point( DWBORDER, nVirtToolBoxHeight ) );
1877 aTreeListBox->SetHighlightRange();
1878 aTreeListBox->SetSelectionMode( NO_SELECTION );
1879 aTreeListBox->InsertEntry( OUString(), 0, false, TREELIST_APPEND );
1880 aTreeListBox->Show();
1882 SetText(IDEResId(RID_STR_STACKNAME).toString());
1884 SetHelpId( HID_BASICIDE_STACKWINDOW );
1886 // make stack window keyboard accessible
1887 GetSystemWindow()->GetTaskPaneList()->AddWindow( this );
1892 StackWindow::~StackWindow()
1894 disposeOnce();
1897 void StackWindow::dispose()
1899 if (!IsDisposed())
1900 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this );
1901 aTreeListBox.disposeAndClear();
1902 DockingWindow::dispose();
1905 void StackWindow::Paint(vcl::RenderContext& rRenderContext, const Rectangle&)
1907 rRenderContext.DrawText(Point(DWBORDER, 7), aStackStr);
1908 lcl_DrawIDEWindowFrame(this, rRenderContext);
1911 void StackWindow::Resize()
1913 Size aSz = GetOutputSizePixel();
1914 Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - nVirtToolBoxHeight - DWBORDER);
1916 if ( aBoxSz.Width() < 4 )
1917 aBoxSz.Width() = 0;
1918 if ( aBoxSz.Height() < 4 )
1919 aBoxSz.Height() = 0;
1921 aTreeListBox->SetSizePixel( aBoxSz );
1923 Invalidate();
1926 void StackWindow::UpdateCalls()
1928 aTreeListBox->SetUpdateMode(false);
1929 aTreeListBox->Clear();
1931 if (StarBASIC::IsRunning())
1933 SbxError eOld = SbxBase::GetError();
1934 aTreeListBox->SetSelectionMode( SINGLE_SELECTION );
1936 sal_Int32 nScope = 0;
1937 SbMethod* pMethod = StarBASIC::GetActiveMethod( nScope );
1938 while ( pMethod )
1940 OUString aEntry( OUString::number(nScope ));
1941 if ( aEntry.getLength() < 2 )
1942 aEntry = " " + aEntry;
1943 aEntry += ": " + pMethod->GetName();
1944 SbxArray* pParams = pMethod->GetParameters();
1945 SbxInfo* pInfo = pMethod->GetInfo();
1946 if ( pParams )
1948 aEntry += "(";
1949 // 0 is the sub's name...
1950 for ( sal_uInt16 nParam = 1; nParam < pParams->Count(); nParam++ )
1952 SbxVariable* pVar = pParams->Get( nParam );
1953 assert(pVar && "Parameter?!");
1954 if ( !pVar->GetName().isEmpty() )
1956 aEntry += pVar->GetName();
1958 else if ( pInfo )
1960 const SbxParamInfo* pParam = pInfo->GetParam( nParam );
1961 if ( pParam )
1963 aEntry += pParam->aName;
1966 aEntry += "=";
1967 SbxDataType eType = pVar->GetType();
1968 if( eType & SbxARRAY )
1970 aEntry += "..." ;
1972 else if( eType != SbxOBJECT )
1974 aEntry += pVar->GetOUString();
1976 if ( nParam < ( pParams->Count() - 1 ) )
1978 aEntry += ", ";
1981 aEntry += ")";
1983 aTreeListBox->InsertEntry( aEntry, 0, false, TREELIST_APPEND );
1984 nScope++;
1985 pMethod = StarBASIC::GetActiveMethod( nScope );
1988 SbxBase::ResetError();
1989 if( eOld != SbxERR_OK )
1990 SbxBase::SetError( eOld );
1992 else
1994 aTreeListBox->SetSelectionMode( NO_SELECTION );
1995 aTreeListBox->InsertEntry( OUString(), 0, false, TREELIST_APPEND );
1998 aTreeListBox->SetUpdateMode(true);
2001 ComplexEditorWindow::ComplexEditorWindow( ModulWindow* pParent ) :
2002 Window( pParent, WB_3DLOOK | WB_CLIPCHILDREN ),
2003 aBrkWindow(VclPtr<BreakPointWindow>::Create(this, pParent)),
2004 aLineNumberWindow(VclPtr<LineNumberWindow>::Create(this, pParent)),
2005 aEdtWindow(VclPtr<EditorWindow>::Create(this, pParent)),
2006 aEWVScrollBar( VclPtr<ScrollBar>::Create(this, WB_VSCROLL | WB_DRAG) )
2008 aEdtWindow->Show();
2009 aBrkWindow->Show();
2011 aEWVScrollBar->SetLineSize(nScrollLine);
2012 aEWVScrollBar->SetPageSize(nScrollPage);
2013 aEWVScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) );
2014 aEWVScrollBar->Show();
2017 ComplexEditorWindow::~ComplexEditorWindow()
2019 disposeOnce();
2022 void ComplexEditorWindow::dispose()
2024 aBrkWindow.disposeAndClear();
2025 aLineNumberWindow.disposeAndClear();
2026 aEdtWindow.disposeAndClear();
2027 aEWVScrollBar.disposeAndClear();
2028 vcl::Window::dispose();
2031 void ComplexEditorWindow::Resize()
2033 Size aOutSz = GetOutputSizePixel();
2034 Size aSz(aOutSz);
2035 aSz.Width() -= 2*DWBORDER;
2036 aSz.Height() -= 2*DWBORDER;
2037 long nBrkWidth = 20;
2038 long nSBWidth = aEWVScrollBar->GetSizePixel().Width();
2040 Size aBrkSz(nBrkWidth, aSz.Height());
2042 Size aLnSz(aLineNumberWindow->GetWidth(), aSz.Height());
2044 if (aLineNumberWindow->IsVisible())
2046 aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz );
2047 aLineNumberWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aLnSz);
2048 Size aEWSz(aSz.Width() - nBrkWidth - aLineNumberWindow->GetWidth() - nSBWidth + 2, aSz.Height());
2049 aEdtWindow->SetPosSizePixel( Point( DWBORDER + aBrkSz.Width() + aLnSz.Width() - 1, DWBORDER ), aEWSz );
2051 else
2053 aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz );
2054 Size aEWSz(aSz.Width() - nBrkWidth - nSBWidth + 2, aSz.Height());
2055 aEdtWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aEWSz);
2058 aEWVScrollBar->SetPosSizePixel( Point( aOutSz.Width() - DWBORDER - nSBWidth, DWBORDER ), Size( nSBWidth, aSz.Height() ) );
2061 IMPL_LINK(ComplexEditorWindow, ScrollHdl, ScrollBar *, pCurScrollBar )
2063 if (aEdtWindow->GetEditView())
2065 DBG_ASSERT( pCurScrollBar == aEWVScrollBar.get(), "Wer scrollt hier ?" );
2066 long nDiff = aEdtWindow->GetEditView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos();
2067 aEdtWindow->GetEditView()->Scroll( 0, nDiff );
2068 aBrkWindow->DoScroll( 0, nDiff );
2069 aLineNumberWindow->DoScroll(0, nDiff);
2070 aEdtWindow->GetEditView()->ShowCursor(false, true);
2071 pCurScrollBar->SetThumbPos( aEdtWindow->GetEditView()->GetStartDocPos().Y() );
2074 return 0;
2077 void ComplexEditorWindow::DataChanged(DataChangedEvent const & rDCEvt)
2079 Window::DataChanged(rDCEvt);
2080 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS
2081 && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
2083 Color aColor(GetSettings().GetStyleSettings().GetFaceColor());
2084 const AllSettings* pOldSettings = rDCEvt.GetOldSettings();
2085 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFaceColor())
2087 SetBackground(Wallpaper(aColor));
2088 Invalidate();
2093 void ComplexEditorWindow::SetLineNumberDisplay(bool b)
2095 aLineNumberWindow->Show(b);
2096 Resize();
2099 uno::Reference< awt::XWindowPeer >
2100 EditorWindow::GetComponentInterface(bool bCreate)
2102 uno::Reference< awt::XWindowPeer > xPeer(
2103 Window::GetComponentInterface(false));
2104 if (!xPeer.is() && bCreate)
2106 // Make sure edit engine and view are available:
2107 if (!pEditEngine)
2108 CreateEditEngine();
2110 xPeer = svt::createTextWindowPeer(*GetEditView());
2111 SetComponentInterface(xPeer);
2113 return xPeer;
2118 // WatchTreeListBox
2122 WatchTreeListBox::WatchTreeListBox( vcl::Window* pParent, WinBits nWinBits )
2123 : SvHeaderTabListBox( pParent, nWinBits )
2126 WatchTreeListBox::~WatchTreeListBox()
2128 disposeOnce();
2131 void WatchTreeListBox::dispose()
2133 // Destroy user data
2134 SvTreeListEntry* pEntry = First();
2135 while ( pEntry )
2137 delete static_cast<WatchItem*>(pEntry->GetUserData());
2138 pEntry->SetUserData(NULL);
2139 pEntry = Next( pEntry );
2141 SvHeaderTabListBox::dispose();
2144 void WatchTreeListBox::SetTabs()
2146 SvHeaderTabListBox::SetTabs();
2147 sal_uInt16 nTabCount_ = aTabs.size();
2148 for( sal_uInt16 i = 0 ; i < nTabCount_ ; i++ )
2150 SvLBoxTab* pTab = aTabs[i];
2151 if( i == 2 )
2152 pTab->nFlags |= SvLBoxTabFlags::EDITABLE;
2153 else
2154 pTab->nFlags &= ~SvLBoxTabFlags::EDITABLE;
2158 void WatchTreeListBox::RequestingChildren( SvTreeListEntry * pParent )
2160 if( !StarBASIC::IsRunning() )
2161 return;
2163 if( GetChildCount( pParent ) > 0 )
2164 return;
2166 SvTreeListEntry* pEntry = pParent;
2167 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2169 SbxDimArray* pArray = pItem->mpArray;
2170 SbxDimArray* pRootArray = pItem->GetRootArray();
2171 bool bArrayIsRootArray = false;
2172 if( !pArray && pRootArray )
2174 pArray = pRootArray;
2175 bArrayIsRootArray = true;
2178 SbxObject* pObj = pItem->mpObject;
2179 if( pObj )
2181 createAllObjectProperties( pObj );
2182 SbxArray* pProps = pObj->GetProperties();
2183 sal_uInt16 nPropCount = pProps->Count();
2184 if ( nPropCount >= 3 &&
2185 pProps->Get( nPropCount -1 )->GetName().equalsIgnoreAsciiCase( "Dbg_Methods" ) &&
2186 pProps->Get( nPropCount -2 )->GetName().equalsIgnoreAsciiCase( "Dbg_Properties" ) &&
2187 pProps->Get( nPropCount -3 )->GetName().equalsIgnoreAsciiCase( "Dbg_SupportedInterfaces" ) )
2189 nPropCount -= 3;
2191 pItem->maMemberList.reserve(nPropCount);
2193 for( sal_uInt16 i = 0 ; i < nPropCount ; ++i )
2195 SbxVariable* pVar = pProps->Get( i );
2197 pItem->maMemberList.push_back(pVar->GetName());
2198 OUString const& rName = pItem->maMemberList.back();
2199 SvTreeListEntry* pChildEntry = SvTreeListBox::InsertEntry( rName, pEntry );
2200 pChildEntry->SetUserData(new WatchItem(rName));
2202 if( nPropCount > 0 )
2204 UpdateWatches();
2207 else if( pArray )
2209 sal_uInt16 nElementCount = 0;
2211 // Loop through indices of current level
2212 int nParentLevel = bArrayIsRootArray ? pItem->nDimLevel : 0;
2213 int nThisLevel = nParentLevel + 1;
2214 sal_Int32 nMin, nMax;
2215 pArray->GetDim32( nThisLevel, nMin, nMax );
2216 for( sal_Int32 i = nMin ; i <= nMax ; i++ )
2218 WatchItem* pChildItem = new WatchItem(pItem->maName);
2220 // Copy data and create name
2222 OUString aIndexStr = "(";
2223 pChildItem->mpArrayParentItem = pItem;
2224 pChildItem->nDimLevel = nThisLevel;
2225 pChildItem->nDimCount = pItem->nDimCount;
2226 pChildItem->vIndices.resize(pChildItem->nDimCount);
2227 sal_Int32 j;
2228 for( j = 0 ; j < nParentLevel ; j++ )
2230 short n = pChildItem->vIndices[j] = pItem->vIndices[j];
2231 aIndexStr += OUString::number( n ) + ",";
2233 pChildItem->vIndices[nParentLevel] = sal::static_int_cast<short>( i );
2234 aIndexStr += OUString::number( i ) + ")";
2236 OUString aDisplayName;
2237 WatchItem* pArrayRootItem = pChildItem->GetRootItem();
2238 if( pArrayRootItem && pArrayRootItem->mpArrayParentItem )
2239 aDisplayName = pItem->maDisplayName;
2240 else
2241 aDisplayName = pItem->maName;
2242 aDisplayName += aIndexStr;
2243 pChildItem->maDisplayName = aDisplayName;
2245 SvTreeListEntry* pChildEntry = SvTreeListBox::InsertEntry( aDisplayName, pEntry );
2246 nElementCount++;
2247 pChildEntry->SetUserData( pChildItem );
2249 if( nElementCount > 0 )
2251 UpdateWatches();
2256 SbxBase* WatchTreeListBox::ImplGetSBXForEntry( SvTreeListEntry* pEntry, bool& rbArrayElement )
2258 SbxBase* pSBX = NULL;
2259 rbArrayElement = false;
2261 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2262 OUString aVName( pItem->maName );
2264 SvTreeListEntry* pParentEntry = GetParent( pEntry );
2265 WatchItem* pParentItem = pParentEntry ? static_cast<WatchItem*>(pParentEntry->GetUserData()) : NULL;
2266 if( pParentItem )
2268 SbxObject* pObj = pParentItem->mpObject;
2269 SbxDimArray* pArray;
2270 if( pObj )
2272 pSBX = pObj->Find( aVName, SbxCLASS_DONTCARE );
2273 if (SbxVariable const* pVar = IsSbxVariable(pSBX))
2275 // Force getting value
2276 SbxValues aRes;
2277 aRes.eType = SbxVOID;
2278 pVar->Get( aRes );
2281 // Array?
2282 else if( (pArray = pItem->GetRootArray()) != NULL )
2284 rbArrayElement = true;
2285 if( pParentItem->nDimLevel + 1 == pParentItem->nDimCount )
2286 pSBX = pArray->Get(pItem->vIndices.empty() ? 0 : &*pItem->vIndices.begin());
2289 else
2291 pSBX = StarBASIC::FindSBXInCurrentScope( aVName );
2293 return pSBX;
2296 bool WatchTreeListBox::EditingEntry( SvTreeListEntry* pEntry, Selection& )
2298 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2300 bool bEdit = false;
2301 if ( StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError() )
2303 // No out of scope entries
2304 bool bArrayElement;
2305 SbxBase* pSbx = ImplGetSBXForEntry( pEntry, bArrayElement );
2306 if (IsSbxVariable(pSbx) || bArrayElement)
2308 // Accept no objects and only end nodes of arrays for editing
2309 if( !pItem->mpObject && (pItem->mpArray == NULL || pItem->nDimLevel == pItem->nDimCount) )
2311 aEditingRes = SvHeaderTabListBox::GetEntryText( pEntry, ITEM_ID_VALUE-1 );
2312 aEditingRes = comphelper::string::strip(aEditingRes, ' ');
2313 bEdit = true;
2318 return bEdit;
2321 bool WatchTreeListBox::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText )
2323 OUString aResult = comphelper::string::strip(rNewText, ' ');
2325 sal_uInt16 nResultLen = aResult.getLength();
2326 sal_Unicode cFirst = aResult[0];
2327 sal_Unicode cLast = aResult[ nResultLen - 1 ];
2328 if( cFirst == '\"' && cLast == '\"' )
2329 aResult = aResult.copy( 1, nResultLen - 2 );
2331 return aResult != aEditingRes && ImplBasicEntryEdited(pEntry, aResult);
2334 bool WatchTreeListBox::ImplBasicEntryEdited( SvTreeListEntry* pEntry, const OUString& rResult )
2336 bool bArrayElement;
2337 SbxBase* pSBX = ImplGetSBXForEntry( pEntry, bArrayElement );
2339 if (SbxVariable* pVar = IsSbxVariable(pSBX))
2341 SbxDataType eType = pVar->GetType();
2342 if ( (sal_uInt8)eType != (sal_uInt8)SbxOBJECT
2343 && ( eType & SbxARRAY ) == 0 )
2345 // If the type is variable, the conversion of the SBX does not matter,
2346 // else the string is converted.
2347 pVar->PutStringExt( rResult );
2351 if ( SbxBase::IsError() )
2353 SbxBase::ResetError();
2356 UpdateWatches();
2358 // The text should never be taken/copied 1:1,
2359 // as the UpdateWatches will be lost
2360 return false;
2364 namespace
2367 void implCollapseModifiedObjectEntry( SvTreeListEntry* pParent, WatchTreeListBox* pThis )
2369 pThis->Collapse( pParent );
2371 SvTreeList* pModel = pThis->GetModel();
2372 SvTreeListEntry* pDeleteEntry;
2373 while( (pDeleteEntry = pThis->SvTreeListBox::GetEntry( pParent, 0 )) != NULL )
2375 implCollapseModifiedObjectEntry( pDeleteEntry, pThis );
2377 delete static_cast<WatchItem*>(pDeleteEntry->GetUserData());
2378 pModel->Remove( pDeleteEntry );
2382 OUString implCreateTypeStringForDimArray( WatchItem* pItem, SbxDataType eType )
2384 OUString aRetStr = getBasicTypeName( eType );
2386 SbxDimArray* pArray = pItem->mpArray;
2387 if( !pArray )
2388 pArray = pItem->GetRootArray();
2389 if( pArray )
2391 int nDimLevel = pItem->nDimLevel;
2392 int nDims = pItem->nDimCount;
2393 if( nDimLevel < nDims )
2395 aRetStr += "(";
2396 for( int i = nDimLevel ; i < nDims ; i++ )
2398 short nMin, nMax;
2399 pArray->GetDim( sal::static_int_cast<short>( i+1 ), nMin, nMax );
2400 aRetStr += OUString::number(nMin) + " to " + OUString::number(nMax);
2401 if( i < nDims - 1 )
2402 aRetStr += ", ";
2404 aRetStr += ")";
2407 return aRetStr;
2410 void implEnableChildren( SvTreeListEntry* pEntry, bool bEnable )
2412 if( bEnable )
2414 pEntry->SetFlags(
2415 (pEntry->GetFlags() & ~SvTLEntryFlags(SvTLEntryFlags::NO_NODEBMP | SvTLEntryFlags::HAD_CHILDREN))
2416 | SvTLEntryFlags::CHILDREN_ON_DEMAND );
2418 else
2420 pEntry->SetFlags( pEntry->GetFlags() & ~SvTLEntryFlags::CHILDREN_ON_DEMAND );
2424 } // namespace
2426 void WatchTreeListBox::UpdateWatches( bool bBasicStopped )
2428 SbMethod* pCurMethod = StarBASIC::GetActiveMethod();
2430 SbxError eOld = SbxBase::GetError();
2431 setBasicWatchMode( true );
2433 SvTreeListEntry* pEntry = First();
2434 while ( pEntry )
2436 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData());
2437 DBG_ASSERT( !pItem->maName.isEmpty(), "Var? - Must not be empty!" );
2438 OUString aWatchStr;
2439 OUString aTypeStr;
2440 if ( pCurMethod )
2442 bool bArrayElement;
2443 SbxBase* pSBX = ImplGetSBXForEntry( pEntry, bArrayElement );
2445 // Array? If no end node create type string
2446 if( bArrayElement && pItem->nDimLevel < pItem->nDimCount )
2448 SbxDimArray* pRootArray = pItem->GetRootArray();
2449 SbxDataType eType = pRootArray->GetType();
2450 aTypeStr = implCreateTypeStringForDimArray( pItem, eType );
2451 implEnableChildren( pEntry, true );
2454 bool bCollapse = false;
2455 if (SbxVariable const* pVar = IsSbxVariable(pSBX))
2457 // extra treatment of arrays
2458 SbxDataType eType = pVar->GetType();
2459 if ( eType & SbxARRAY )
2461 // consider multidimensinal arrays!
2462 if (SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>(pVar->GetObject()))
2464 SbxDimArray* pOldArray = pItem->mpArray;
2466 bool bArrayChanged = false;
2467 if( pNewArray != NULL && pOldArray != NULL )
2469 // Compare Array dimensions to see if array has changed
2470 // Can be a copy, so comparing pointers does not work
2471 sal_uInt16 nOldDims = pOldArray->GetDims();
2472 sal_uInt16 nNewDims = pNewArray->GetDims();
2473 if( nOldDims != nNewDims )
2475 bArrayChanged = true;
2477 else
2479 for( int i = 0 ; i < nOldDims ; i++ )
2481 short nOldMin, nOldMax;
2482 short nNewMin, nNewMax;
2484 pOldArray->GetDim( sal::static_int_cast<short>( i+1 ), nOldMin, nOldMax );
2485 pNewArray->GetDim( sal::static_int_cast<short>( i+1 ), nNewMin, nNewMax );
2486 if( nOldMin != nNewMin || nOldMax != nNewMax )
2488 bArrayChanged = true;
2489 break;
2494 else if( pNewArray == NULL || pOldArray == NULL )
2496 bArrayChanged = true;
2498 if( pNewArray )
2500 implEnableChildren( pEntry, true );
2502 // #i37227 Clear always and replace array
2503 if( pNewArray != pOldArray )
2505 pItem->clearWatchItem();
2506 if( pNewArray )
2508 implEnableChildren( pEntry, true );
2510 pItem->mpArray = pNewArray;
2511 sal_uInt16 nDims = pNewArray->GetDims();
2512 pItem->nDimLevel = 0;
2513 pItem->nDimCount = nDims;
2516 if( bArrayChanged && pOldArray != NULL )
2518 bCollapse = true;
2520 aTypeStr = implCreateTypeStringForDimArray( pItem, eType );
2522 else
2524 aWatchStr += "<?>";
2527 else if ( (sal_uInt8)eType == (sal_uInt8)SbxOBJECT )
2529 if (SbxObject* pObj = dynamic_cast<SbxObject*>(pVar->GetObject()))
2531 if (pItem->mpObject && !pItem->maMemberList.empty())
2533 bool bObjChanged = false; // Check if member list has changed
2534 SbxArray* pProps = pObj->GetProperties();
2535 sal_uInt16 nPropCount = pProps->Count();
2536 for( sal_uInt16 i = 0 ; i < nPropCount - 3 ; i++ )
2538 SbxVariable* pVar_ = pProps->Get( i );
2539 OUString aName( pVar_->GetName() );
2540 if( pItem->maMemberList[i] != aName )
2542 bObjChanged = true;
2543 break;
2546 if( bObjChanged )
2548 bCollapse = true;
2552 pItem->mpObject = pObj;
2553 implEnableChildren( pEntry, true );
2554 aTypeStr = getBasicObjectTypeName( pObj );
2556 else
2558 aWatchStr = "Null";
2559 if( pItem->mpObject != NULL )
2561 bCollapse = true;
2562 pItem->clearWatchItem();
2564 implEnableChildren( pEntry, false );
2568 else
2570 if( pItem->mpObject != NULL )
2572 bCollapse = true;
2573 pItem->clearWatchItem();
2575 implEnableChildren( pEntry, false );
2578 bool bString = ((sal_uInt8)eType == (sal_uInt8)SbxSTRING);
2579 OUString aStrStr( "\"" );
2580 if( bString )
2582 aWatchStr += aStrStr;
2584 aWatchStr += pVar->GetOUString();
2585 if( bString )
2587 aWatchStr += aStrStr;
2590 if( aTypeStr.isEmpty() )
2592 if( !pVar->IsFixed() )
2594 aTypeStr = "Variant/";
2596 aTypeStr += getBasicTypeName( pVar->GetType() );
2599 else if( !bArrayElement )
2601 aWatchStr += "<Out of Scope>";
2604 if( bCollapse )
2606 implCollapseModifiedObjectEntry( pEntry, this );
2610 else if( bBasicStopped )
2612 if( pItem->mpObject || pItem->mpArray )
2614 implCollapseModifiedObjectEntry( pEntry, this );
2615 pItem->mpObject = NULL;
2619 SvHeaderTabListBox::SetEntryText( aWatchStr, pEntry, ITEM_ID_VALUE-1 );
2620 SvHeaderTabListBox::SetEntryText( aTypeStr, pEntry, ITEM_ID_TYPE-1 );
2622 pEntry = Next( pEntry );
2625 // Force redraw
2626 Invalidate();
2628 SbxBase::ResetError();
2629 if( eOld != SbxERR_OK )
2630 SbxBase::SetError( eOld );
2631 setBasicWatchMode( false );
2634 CodeCompleteListBox::CodeCompleteListBox( CodeCompleteWindow* pPar )
2635 : ListBox(pPar, WB_SORT | WB_BORDER ),
2636 pCodeCompleteWindow( pPar )
2638 SetDoubleClickHdl(LINK(this, CodeCompleteListBox, ImplDoubleClickHdl));
2639 SetSelectHdl(LINK(this, CodeCompleteListBox, ImplSelectHdl));
2642 CodeCompleteListBox::~CodeCompleteListBox()
2644 disposeOnce();
2647 void CodeCompleteListBox::dispose()
2649 pCodeCompleteWindow.clear();
2650 ListBox::dispose();
2653 IMPL_LINK_NOARG(CodeCompleteListBox, ImplDoubleClickHdl)
2655 InsertSelectedEntry();
2656 return 0;
2659 IMPL_LINK_NOARG(CodeCompleteListBox, ImplSelectHdl)
2660 {//give back the focus to the parent
2661 pCodeCompleteWindow->pParent->GrabFocus();
2662 return 0;
2665 ExtTextView* CodeCompleteListBox::GetParentEditView()
2667 return pCodeCompleteWindow->pParent->GetEditView();
2670 void CodeCompleteListBox::InsertSelectedEntry()
2672 if( !aFuncBuffer.toString().isEmpty() )
2674 // if the user typed in something: remove, and insert
2675 GetParentEditView()->SetSelection( pCodeCompleteWindow->pParent->GetLastHighlightPortionTextSelection() );
2676 GetParentEditView()->DeleteSelected();
2678 if( !GetSelectEntry().isEmpty() )
2679 {//if the user selected something
2680 GetParentEditView()->InsertText( GetSelectEntry(), false );
2683 else
2685 if( !GetSelectEntry().isEmpty() )
2686 {//if the user selected something
2687 GetParentEditView()->InsertText( GetSelectEntry(), false );
2690 HideAndRestoreFocus();
2693 void CodeCompleteListBox::SetMatchingEntries()
2695 for(sal_uInt16 i=0; i< GetEntryCount(); ++i)
2697 OUString sEntry = GetEntry(i);
2698 if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer.toString() ) )
2700 SelectEntry(sEntry);
2701 break;
2706 void CodeCompleteListBox::KeyInput( const KeyEvent& rKeyEvt )
2708 sal_Unicode aChar = rKeyEvt.GetKeyCode().GetCode();
2709 if( (( aChar >= KEY_A ) && ( aChar <= KEY_Z ))
2710 || ((aChar >= KEY_0) && (aChar <= KEY_9)) )
2712 aFuncBuffer.append(rKeyEvt.GetCharCode());
2713 SetMatchingEntries();
2715 else
2717 switch( aChar )
2719 case KEY_ESCAPE: // hide, do nothing
2720 HideAndRestoreFocus();
2721 break;
2722 case KEY_RIGHT:
2724 TextSelection aTextSelection( GetParentEditView()->GetSelection() );
2725 if( aTextSelection.GetEnd().GetPara() != pCodeCompleteWindow->GetTextSelection().GetEnd().GetPara()-1 )
2727 HideAndRestoreFocus();
2729 break;
2731 case KEY_LEFT:
2733 TextSelection aTextSelection( GetParentEditView()->GetSelection() );
2734 if( aTextSelection.GetStart().GetIndex()-1 < pCodeCompleteWindow->GetTextSelection().GetStart().GetIndex() )
2735 {//leave the cursor where it is
2736 HideAndRestoreFocus();
2738 break;
2740 case KEY_TAB:
2742 TextSelection aTextSelection = pCodeCompleteWindow->pParent->GetLastHighlightPortionTextSelection();
2743 OUString sTypedText = pCodeCompleteWindow->pParent->GetEditEngine()->GetText(aTextSelection);
2744 if( !aFuncBuffer.isEmpty() )
2746 sal_Int32 nInd = GetSelectEntryPos();
2747 if( nInd != LISTBOX_ENTRY_NOTFOUND )
2748 {//if there is something selected
2749 bool bFound = false;
2750 if( nInd == GetEntryCount() )
2751 nInd = 0;
2752 for( sal_Int32 i = nInd; i != GetEntryCount(); ++i )
2754 OUString sEntry = GetEntry(i);
2755 if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer.toString() )
2756 && (aFuncBuffer.toString() != sTypedText) && (i != nInd) )
2758 SelectEntry( sEntry );
2759 bFound = true;
2760 break;
2763 if( !bFound )
2764 SetMatchingEntries();
2766 GetParentEditView()->SetSelection( aTextSelection );
2767 GetParentEditView()->DeleteSelected();
2768 GetParentEditView()->InsertText( GetSelectEntry(), false );
2771 break;
2773 case KEY_SPACE:
2774 HideAndRestoreFocus();
2775 break;
2776 case KEY_BACKSPACE: case KEY_DELETE:
2777 if( !aFuncBuffer.toString().isEmpty() )
2779 //if there was something inserted by tab: add it to aFuncBuffer
2780 TextSelection aSel( GetParentEditView()->GetSelection() );
2781 TextPaM aEnd( GetParentEditView()->CursorEndOfLine(pCodeCompleteWindow->GetTextSelection().GetEnd()) );
2782 GetParentEditView()->SetSelection(TextSelection(pCodeCompleteWindow->GetTextSelection().GetStart(), aEnd ) );
2783 OUString aTabInsertedStr( GetParentEditView()->GetSelected() );
2784 GetParentEditView()->SetSelection( aSel );
2786 if( !aTabInsertedStr.isEmpty() && aTabInsertedStr != aFuncBuffer.toString() )
2788 aFuncBuffer.makeStringAndClear();
2789 aFuncBuffer = aFuncBuffer.append(aTabInsertedStr);
2791 aFuncBuffer = aFuncBuffer.remove(aFuncBuffer.getLength()-1, 1);
2792 SetMatchingEntries();
2794 else
2795 pCodeCompleteWindow->ClearAndHide();
2796 break;
2797 case KEY_RETURN:
2798 InsertSelectedEntry();
2799 break;
2800 case KEY_UP: case KEY_DOWN:
2801 NotifyEvent nEvt( MouseNotifyEvent::KEYINPUT, NULL, &rKeyEvt );
2802 PreNotify(nEvt);
2803 break;
2806 ListBox::KeyInput(rKeyEvt);
2809 void CodeCompleteListBox::HideAndRestoreFocus()
2811 pCodeCompleteWindow->Hide();
2812 pCodeCompleteWindow->pParent->GrabFocus();
2815 CodeCompleteWindow::CodeCompleteWindow( EditorWindow* pPar )
2816 : Window( pPar ),
2817 pParent( pPar ),
2818 pListBox( VclPtr<CodeCompleteListBox>::Create(this) )
2820 SetSizePixel( Size(151,151) ); //default, later it changes
2821 InitListBox();
2824 CodeCompleteWindow::~CodeCompleteWindow()
2826 disposeOnce();
2829 void CodeCompleteWindow::dispose()
2831 pListBox.disposeAndClear();
2832 pParent.clear();
2833 vcl::Window::dispose();
2836 void CodeCompleteWindow::InitListBox()
2838 pListBox->SetSizePixel( Size(150,150) ); //default, this will adopt the line length
2839 pListBox->Show();
2840 pListBox->EnableQuickSelection( false );
2843 void CodeCompleteWindow::InsertEntry( const OUString& aStr )
2845 pListBox->InsertEntry( aStr );
2848 void CodeCompleteWindow::ClearListBox()
2850 pListBox->Clear();
2851 pListBox->aFuncBuffer.makeStringAndClear();
2854 void CodeCompleteWindow::SetTextSelection( const TextSelection& aSel )
2856 aTextSelection = aSel;
2860 void CodeCompleteWindow::ResizeAndPositionListBox()
2862 if( pListBox->GetEntryCount() >= 1 )
2863 {// if there is at least one element inside
2864 // calculate basic position: under the current line
2865 Rectangle aRect = ( (TextEngine*) pParent->GetEditEngine() )->PaMtoEditCursor( pParent->GetEditView()->GetSelection().GetEnd() , false );
2866 long nViewYOffset = pParent->GetEditView()->GetStartDocPos().Y();
2867 Point aPos = aRect.BottomRight();// this variable will be used later (if needed)
2868 aPos.Y() = (aPos.Y() - nViewYOffset) + nBasePad;
2870 OUString aLongestEntry = pListBox->GetEntry( 0 );// grab the longest one: max search
2871 for( sal_Int32 i=1; i< pListBox->GetEntryCount(); ++i )
2873 if( pListBox->GetEntry( i ).getLength() > aLongestEntry.getLength() )
2874 aLongestEntry = pListBox->GetEntry( i );
2876 // get column/line count
2877 const sal_uInt16& nColumns = aLongestEntry.getLength();
2878 const sal_uInt16 nLines = static_cast<sal_uInt16>( std::min( (sal_Int32) 6, pListBox->GetEntryCount() ));
2880 Size aSize = pListBox->CalcBlockSize( nColumns, nLines );
2881 //set the size
2882 SetSizePixel( aSize );
2883 //1 px smaller, to see the border
2884 aSize.setWidth( aSize.getWidth() - 1 );
2885 aSize.setHeight( aSize.getHeight() - 1 );
2886 pListBox->SetSizePixel( aSize );
2888 //calculate position
2889 const Rectangle aVisArea( pParent->GetEditView()->GetStartDocPos(), pParent->GetOutputSizePixel() );//the visible area
2890 const Point& aBottomPoint = aVisArea.BottomRight();
2892 if( aVisArea.TopRight().getY() + aPos.getY() + aSize.getHeight() > aBottomPoint.getY() )
2893 {//clipped at the bottom: move it up
2894 const long& nParentFontHeight = pParent->GetEditEngine()->GetFont().GetHeight();//parent's font (in the IDE): needed for height
2895 aPos.Y() -= aSize.getHeight() + nParentFontHeight + nCursorPad;
2898 if( aVisArea.TopLeft().getX() + aPos.getX() + aSize.getWidth() > aBottomPoint.getX() )
2899 {//clipped at the right side, move it a bit left
2900 aPos.X() -= aSize.getWidth() + aVisArea.TopLeft().getX();
2902 //set the position
2903 SetPosPixel( aPos );
2907 void CodeCompleteWindow::SelectFirstEntry()
2909 if( pListBox->GetEntryCount() > 0 )
2911 pListBox->SelectEntryPos( 0 );
2915 void CodeCompleteWindow::ClearAndHide()
2917 ClearListBox();
2918 pListBox->HideAndRestoreFocus();
2921 UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector< OUString >& aVect, const OUString& sVarType )
2922 : bCanComplete( true )
2924 if( aVect.size() == 0 || sVarType.isEmpty() )
2926 bCanComplete = false;//invalid parameters, nothing to code complete
2927 return;
2932 // Get the base class for reflection:
2933 xClass = css::reflection::theCoreReflection::get(
2934 comphelper::getProcessComponentContext())->forName(sVarType);
2936 catch( const Exception& )
2938 bCanComplete = false;
2939 return;
2942 unsigned int j = 1;//start from aVect[1]: aVect[0] is the variable name
2943 OUString sMethName;
2945 while( j != aVect.size() )
2947 sMethName = aVect[j];
2949 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
2951 if( !CheckMethod(sMethName) && !CheckField(sMethName) )
2953 bCanComplete = false;
2954 break;
2957 else
2959 if( !CheckField(sMethName) )
2961 bCanComplete = false;
2962 break;
2966 ++j;
2970 std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassMethods() const
2972 std::vector< OUString > aRetVect;
2973 if( bCanComplete && ( xClass != NULL ) )
2975 Sequence< Reference< reflection::XIdlMethod > > aMethods = xClass->getMethods();
2976 if( aMethods.getLength() != 0 )
2978 for(sal_Int32 l = 0; l < aMethods.getLength(); ++l)
2980 aRetVect.push_back( OUString(aMethods[l]->getName()) );
2984 return aRetVect;//this is empty when cannot code complete
2987 std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassFields() const
2989 std::vector< OUString > aRetVect;
2990 if( bCanComplete && ( xClass != NULL ) )
2992 Sequence< Reference< reflection::XIdlField > > aFields = xClass->getFields();
2993 if( aFields.getLength() != 0 )
2995 for(sal_Int32 l = 0; l < aFields.getLength(); ++l)
2997 aRetVect.push_back( OUString(aFields[l]->getName()) );
3001 return aRetVect;//this is empty when cannot code complete
3005 bool UnoTypeCodeCompletetor::CheckField( const OUString& sFieldName )
3006 {// modifies xClass!!!
3007 Reference< reflection::XIdlField> xField = xClass->getField( sFieldName );
3008 if( xField != NULL )
3010 xClass = xField->getType();
3011 if( xClass != NULL )
3013 return true;
3016 return false;
3019 bool UnoTypeCodeCompletetor::CheckMethod( const OUString& sMethName )
3020 {// modifies xClass!!!
3021 Reference< reflection::XIdlMethod> xMethod = xClass->getMethod( sMethName );
3022 if( xMethod != NULL ) //method OK, check return type
3024 xClass = xMethod->getReturnType();
3025 if( xClass != NULL )
3027 return true;
3030 return false;
3033 } // namespace basctl
3035 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */