1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <sal/config.h> 21 22 #include <cassert> 23 24 #include <helpids.h> 25 #include <strings.hrc> 26 #include <bitmaps.hlst> 27 28 #include "baside2.hxx" 29 #include "brkdlg.hxx" 30 #include <iderdll.hxx> 31 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/textview.hxx> 45 #include <vcl/txtattr.hxx> 46 #include <vcl/settings.hxx> 47 #include <svtools/textwindowpeer.hxx> 48 #include <vcl/treelistentry.hxx> 49 #include <vcl/taskpanelist.hxx> 50 #include <vcl/help.hxx> 51 #include <cppuhelper/implbase.hxx> 52 #include <vector> 53 #include <com/sun/star/reflection/theCoreReflection.hpp> 54 #include <unotools/charclass.hxx> 55 56 namespace basctl 57 { 58 59 using namespace ::com::sun::star; 60 using namespace ::com::sun::star::uno; 61 62 namespace 63 { 64 65 sal_uInt16 const NoMarker = 0xFFFF; 66 long const nBasePad = 2; 67 long const nCursorPad = 5; 68 69 long nVirtToolBoxHeight; // inited in WatchWindow, used in Stackwindow 70 static const long nHeaderBarHeight = 16; 71 72 // Returns pBase converted to SbxVariable if valid and is not an SbxMethod. 73 SbxVariable* IsSbxVariable (SbxBase* pBase) 74 { 75 if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pBase)) 76 if (!dynamic_cast<SbxMethod*>(pVar)) 77 return pVar; 78 return nullptr; 79 } 80 81 Image GetImage(const OUString& rId) 82 { 83 return Image(StockImage::Yes, rId); 84 } 85 86 int const nScrollLine = 12; 87 int const nScrollPage = 60; 88 int const DWBORDER = 3; 89 90 char const cSuffixes[] = "%&!#@$"; 91 92 } // namespace 93 94 95 /** 96 * Helper functions to get/set text in TextEngine using 97 * the stream interface. 98 * 99 * get/setText() only supports tools Strings limited to 64K). 100 */ 101 OUString getTextEngineText (ExtTextEngine& rEngine) 102 { 103 SvMemoryStream aMemStream; 104 aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); 105 aMemStream.SetLineDelimiter( LINEEND_LF ); 106 rEngine.Write( aMemStream ); 107 std::size_t nSize = aMemStream.Tell(); 108 OUString aText( static_cast<const sal_Char*>(aMemStream.GetData()), 109 nSize, RTL_TEXTENCODING_UTF8 ); 110 return aText; 111 } 112 113 void setTextEngineText (ExtTextEngine& rEngine, OUString const& aStr) 114 { 115 rEngine.SetText(OUString()); 116 OString aUTF8Str = OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ); 117 SvMemoryStream aMemStream( const_cast<char *>(aUTF8Str.getStr()), aUTF8Str.getLength(), 118 StreamMode::READ ); 119 aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); 120 aMemStream.SetLineDelimiter( LINEEND_LF ); 121 rEngine.Read(aMemStream); 122 } 123 124 namespace 125 { 126 127 void lcl_DrawIDEWindowFrame(DockingWindow const * pWin, vcl::RenderContext& rRenderContext) 128 { 129 if (pWin->IsFloatingMode()) 130 return; 131 132 Size aSz(pWin->GetOutputSizePixel()); 133 const Color aOldLineColor(rRenderContext.GetLineColor()); 134 rRenderContext.SetLineColor(COL_WHITE); 135 // White line on top 136 rRenderContext.DrawLine(Point(0, 0), Point(aSz.Width(), 0)); 137 // Black line at bottom 138 rRenderContext.SetLineColor(COL_BLACK); 139 rRenderContext.DrawLine(Point(0, aSz.Height() - 1), 140 Point(aSz.Width(), aSz.Height() - 1)); 141 rRenderContext.SetLineColor(aOldLineColor); 142 } 143 144 void lcl_SeparateNameAndIndex( const OUString& rVName, OUString& rVar, OUString& rIndex ) 145 { 146 rVar = rVName; 147 rIndex.clear(); 148 sal_Int32 nIndexStart = rVar.indexOf( '(' ); 149 if ( nIndexStart != -1 ) 150 { 151 sal_Int32 nIndexEnd = rVar.indexOf( ')', nIndexStart ); 152 if (nIndexEnd != -1) 153 { 154 rIndex = rVar.copy(nIndexStart + 1, nIndexEnd - nIndexStart - 1); 155 rVar = rVar.copy(0, nIndexStart); 156 rVar = comphelper::string::stripEnd(rVar, ' '); 157 rIndex = comphelper::string::strip(rIndex, ' '); 158 } 159 } 160 161 if ( !rVar.isEmpty() ) 162 { 163 sal_uInt16 nLastChar = rVar.getLength()-1; 164 if ( strchr( cSuffixes, rVar[ nLastChar ] ) ) 165 rVar = rVar.replaceAt( nLastChar, 1, "" ); 166 } 167 if ( !rIndex.isEmpty() ) 168 { 169 sal_uInt16 nLastChar = rIndex.getLength()-1; 170 if ( strchr( cSuffixes, rIndex[ nLastChar ] ) ) 171 rIndex = rIndex.replaceAt( nLastChar, 1, "" ); 172 } 173 } 174 175 } // namespace 176 177 178 // EditorWindow 179 180 181 class EditorWindow::ChangesListener: 182 public cppu::WeakImplHelper< beans::XPropertiesChangeListener > 183 { 184 public: 185 explicit ChangesListener(EditorWindow & editor): editor_(editor) {} 186 187 private: 188 virtual ~ChangesListener() override {} 189 190 virtual void SAL_CALL disposing(lang::EventObject const &) override 191 { 192 osl::MutexGuard g(editor_.mutex_); 193 editor_.notifier_.clear(); 194 } 195 196 virtual void SAL_CALL propertiesChange( 197 Sequence< beans::PropertyChangeEvent > const &) override 198 { 199 SolarMutexGuard g; 200 editor_.ImplSetFont(); 201 } 202 203 EditorWindow & editor_; 204 }; 205 206 class EditorWindow::ProgressInfo : public SfxProgress 207 { 208 public: 209 ProgressInfo (SfxObjectShell* pObjSh, OUString const& rText, sal_uInt32 nRange) : 210 SfxProgress(pObjSh, rText, nRange), 211 nCurState(0) 212 { } 213 214 void StepProgress () 215 { 216 SetState(++nCurState); 217 } 218 219 private: 220 sal_uLong nCurState; 221 }; 222 223 EditorWindow::EditorWindow (vcl::Window* pParent, ModulWindow* pModulWindow) : 224 Window(pParent, WB_BORDER), 225 rModulWindow(*pModulWindow), 226 nCurTextWidth(0), 227 aHighlighter(HighlighterLanguage::Basic), 228 bHighlighting(false), 229 bDoSyntaxHighlight(true), 230 bDelayHighlight(true), 231 pCodeCompleteWnd(VclPtr<CodeCompleteWindow>::Create(this)) 232 { 233 SetBackground(Wallpaper(rModulWindow.GetLayout().GetBackgroundColor())); 234 SetPointer( Pointer( PointerStyle::Text ) ); 235 SetHelpId( HID_BASICIDE_EDITORWINDOW ); 236 237 listener_ = new ChangesListener(*this); 238 Reference< beans::XMultiPropertySet > n( 239 officecfg::Office::Common::Font::SourceViewFont::get(), 240 UNO_QUERY_THROW); 241 { 242 osl::MutexGuard g(mutex_); 243 notifier_ = n; 244 } 245 const Sequence<OUString> aPropertyNames{"FontHeight", "FontName"}; 246 n->addPropertiesChangeListener(aPropertyNames, listener_.get()); 247 } 248 249 250 EditorWindow::~EditorWindow() 251 { 252 disposeOnce(); 253 } 254 255 void EditorWindow::dispose() 256 { 257 Reference< beans::XMultiPropertySet > n; 258 { 259 osl::MutexGuard g(mutex_); 260 n = notifier_; 261 } 262 if (n.is()) { 263 n->removePropertiesChangeListener(listener_.get()); 264 } 265 266 aSyntaxIdle.Stop(); 267 268 if ( pEditEngine ) 269 { 270 EndListening( *pEditEngine ); 271 pEditEngine->RemoveView(pEditView.get()); 272 } 273 pCodeCompleteWnd.disposeAndClear(); 274 vcl::Window::dispose(); 275 } 276 277 OUString EditorWindow::GetWordAtCursor() 278 { 279 OUString aWord; 280 281 if ( pEditView ) 282 { 283 TextEngine* pTextEngine = pEditView->GetTextEngine(); 284 if ( pTextEngine ) 285 { 286 // check first, if the cursor is at a help URL 287 const TextSelection& rSelection = pEditView->GetSelection(); 288 const TextPaM& rSelStart = rSelection.GetStart(); 289 const TextPaM& rSelEnd = rSelection.GetEnd(); 290 OUString aText = pTextEngine->GetText( rSelEnd.GetPara() ); 291 CharClass aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() ); 292 sal_Int32 nSelStart = rSelStart.GetIndex(); 293 sal_Int32 nSelEnd = rSelEnd.GetIndex(); 294 sal_Int32 nLength = aText.getLength(); 295 sal_Int32 nStart = 0; 296 sal_Int32 nEnd = nLength; 297 while ( nStart < nLength ) 298 { 299 OUString aURL( URIHelper::FindFirstURLInText( aText, nStart, nEnd, aClass ) ); 300 INetURLObject aURLObj( aURL ); 301 if ( aURLObj.GetProtocol() == INetProtocol::VndSunStarHelp 302 && nSelStart >= nStart && nSelStart <= nEnd && nSelEnd >= nStart && nSelEnd <= nEnd ) 303 { 304 aWord = aURL; 305 break; 306 } 307 nStart = nEnd; 308 nEnd = nLength; 309 } 310 311 // Not the selected range, but at the CursorPosition, 312 // if a word is partially selected. 313 if ( aWord.isEmpty() ) 314 aWord = pTextEngine->GetWord( rSelEnd ); 315 316 // Can be empty when full word selected, as Cursor behind it 317 if ( aWord.isEmpty() && pEditView->HasSelection() ) 318 aWord = pTextEngine->GetWord( rSelStart ); 319 } 320 } 321 322 return aWord; 323 } 324 325 void EditorWindow::RequestHelp( const HelpEvent& rHEvt ) 326 { 327 bool bDone = false; 328 329 // Should have been activated at some point 330 if ( pEditEngine ) 331 { 332 if ( rHEvt.GetMode() & HelpEventMode::CONTEXT ) 333 { 334 OUString aKeyword = GetWordAtCursor(); 335 Application::GetHelp()->SearchKeyword( aKeyword ); 336 bDone = true; 337 } 338 else if ( rHEvt.GetMode() & HelpEventMode::QUICK ) 339 { 340 OUString aHelpText; 341 Point aTopLeft; 342 if ( StarBASIC::IsRunning() ) 343 { 344 Point aWindowPos = rHEvt.GetMousePosPixel(); 345 aWindowPos = ScreenToOutputPixel( aWindowPos ); 346 Point aDocPos = GetEditView()->GetDocPos( aWindowPos ); 347 TextPaM aCursor = GetEditView()->GetTextEngine()->GetPaM(aDocPos); 348 TextPaM aStartOfWord; 349 OUString aWord = GetEditView()->GetTextEngine()->GetWord( aCursor, &aStartOfWord ); 350 if ( !aWord.isEmpty() && !comphelper::string::isdigitAsciiString(aWord) ) 351 { 352 sal_uInt16 nLastChar = aWord.getLength() - 1; 353 if ( strchr( cSuffixes, aWord[ nLastChar ] ) ) 354 aWord = aWord.replaceAt( nLastChar, 1, "" ); 355 SbxBase* pSBX = StarBASIC::FindSBXInCurrentScope( aWord ); 356 if (SbxVariable const* pVar = IsSbxVariable(pSBX)) 357 { 358 SbxDataType eType = pVar->GetType(); 359 if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) ) 360 // might cause a crash e. g. at the selections-object 361 // Type == Object does not mean pVar == Object! 362 ; // aHelpText = ((SbxObject*)pVar)->GetClassName(); 363 else if ( eType & SbxARRAY ) 364 ; // aHelpText = "{...}"; 365 else if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxEMPTY) ) 366 { 367 aHelpText = pVar->GetName(); 368 if ( aHelpText.isEmpty() ) // name is not copied with the passed parameters 369 aHelpText = aWord; 370 aHelpText += "=" + pVar->GetOUString(); 371 } 372 } 373 if ( !aHelpText.isEmpty() ) 374 { 375 aTopLeft = GetEditView()->GetTextEngine()->PaMtoEditCursor( aStartOfWord ).BottomLeft(); 376 aTopLeft = GetEditView()->GetWindowPos( aTopLeft ); 377 aTopLeft.AdjustX(5 ); 378 aTopLeft.AdjustY(5 ); 379 aTopLeft = OutputToScreenPixel( aTopLeft ); 380 } 381 } 382 } 383 Help::ShowQuickHelp( this, tools::Rectangle( aTopLeft, Size( 1, 1 ) ), aHelpText, QuickHelpFlags::Top|QuickHelpFlags::Left); 384 bDone = true; 385 } 386 } 387 388 if ( !bDone ) 389 Window::RequestHelp( rHEvt ); 390 } 391 392 393 void EditorWindow::Resize() 394 { 395 // ScrollBars, etc. happens in Adjust... 396 if ( pEditView ) 397 { 398 long nVisY = pEditView->GetStartDocPos().Y(); 399 400 pEditView->ShowCursor(); 401 Size aOutSz( GetOutputSizePixel() ); 402 long nMaxVisAreaStart = pEditView->GetTextEngine()->GetTextHeight() - aOutSz.Height(); 403 if ( nMaxVisAreaStart < 0 ) 404 nMaxVisAreaStart = 0; 405 if ( pEditView->GetStartDocPos().Y() > nMaxVisAreaStart ) 406 { 407 Point aStartDocPos( pEditView->GetStartDocPos() ); 408 aStartDocPos.setY( nMaxVisAreaStart ); 409 pEditView->SetStartDocPos( aStartDocPos ); 410 pEditView->ShowCursor(); 411 rModulWindow.GetBreakPointWindow().GetCurYOffset() = aStartDocPos.Y(); 412 rModulWindow.GetLineNumberWindow().GetCurYOffset() = aStartDocPos.Y(); 413 } 414 InitScrollBars(); 415 if ( nVisY != pEditView->GetStartDocPos().Y() ) 416 Invalidate(); 417 } 418 } 419 420 421 void EditorWindow::MouseMove( const MouseEvent &rEvt ) 422 { 423 if ( pEditView ) 424 pEditView->MouseMove( rEvt ); 425 } 426 427 428 void EditorWindow::MouseButtonUp( const MouseEvent &rEvt ) 429 { 430 if ( pEditView ) 431 { 432 pEditView->MouseButtonUp( rEvt ); 433 if (SfxBindings* pBindings = GetBindingsPtr()) 434 { 435 pBindings->Invalidate( SID_BASICIDE_STAT_POS ); 436 pBindings->Invalidate( SID_BASICIDE_STAT_TITLE ); 437 } 438 } 439 } 440 441 void EditorWindow::MouseButtonDown( const MouseEvent &rEvt ) 442 { 443 GrabFocus(); 444 if ( pEditView ) 445 pEditView->MouseButtonDown( rEvt ); 446 if( pCodeCompleteWnd->IsVisible() ) 447 { 448 if( pEditView->GetSelection() != pCodeCompleteWnd->GetTextSelection() ) 449 {//selection changed, code complete window should be hidden 450 pCodeCompleteWnd->GetListBox()->HideAndRestoreFocus(); 451 } 452 } 453 } 454 455 void EditorWindow::Command( const CommandEvent& rCEvt ) 456 { 457 if ( pEditView ) 458 { 459 pEditView->Command( rCEvt ); 460 if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) || 461 ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) || 462 ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) ) 463 { 464 HandleScrollCommand( rCEvt, rModulWindow.GetHScrollBar(), &rModulWindow.GetEditVScrollBar() ); 465 } else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) { 466 SfxDispatcher* pDispatcher = GetDispatcher(); 467 if ( pDispatcher ) 468 { 469 SfxDispatcher::ExecutePopup(); 470 } 471 if( pCodeCompleteWnd->IsVisible() ) // hide the code complete window 472 pCodeCompleteWnd->ClearAndHide(); 473 } 474 } 475 } 476 477 bool EditorWindow::ImpCanModify() 478 { 479 bool bCanModify = true; 480 if ( StarBASIC::IsRunning() && rModulWindow.GetBasicStatus().bIsRunning ) 481 { 482 // If in Trace-mode, abort the trace or refuse input 483 // Remove markers in the modules in Notify at Basic::Stopped 484 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr, 485 VclMessageType::Question, VclButtonsType::OkCancel, 486 IDEResId(RID_STR_WILLSTOPPRG))); 487 if (xQueryBox->run() == RET_OK) 488 { 489 rModulWindow.GetBasicStatus().bIsRunning = false; 490 StopBasic(); 491 } 492 else 493 bCanModify = false; 494 } 495 return bCanModify; 496 } 497 498 void EditorWindow::KeyInput( const KeyEvent& rKEvt ) 499 { 500 if ( !pEditView ) // Happens in Win95 501 return; 502 503 bool const bWasModified = pEditEngine->IsModified(); 504 // see if there is an accelerator to be processed first 505 SfxViewShell *pVS( SfxViewShell::Current()); 506 bool bDone = pVS && pVS->KeyInput( rKEvt ); 507 508 if( pCodeCompleteWnd->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn() ) 509 { 510 pCodeCompleteWnd->GetListBox()->KeyInput(rKEvt); 511 if( rKEvt.GetKeyCode().GetCode() == KEY_UP 512 || rKEvt.GetKeyCode().GetCode() == KEY_DOWN 513 || rKEvt.GetKeyCode().GetCode() == KEY_TAB 514 || rKEvt.GetKeyCode().GetCode() == KEY_POINT) 515 return; 516 } 517 518 if( (rKEvt.GetKeyCode().GetCode() == KEY_SPACE || 519 rKEvt.GetKeyCode().GetCode() == KEY_TAB || 520 rKEvt.GetKeyCode().GetCode() == KEY_RETURN ) && CodeCompleteOptions::IsAutoCorrectOn() ) 521 { 522 HandleAutoCorrect(); 523 } 524 525 if( rKEvt.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() ) 526 {//autoclose double quotes 527 HandleAutoCloseDoubleQuotes(); 528 } 529 530 if( rKEvt.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() ) 531 {//autoclose parenthesis 532 HandleAutoCloseParen(); 533 } 534 535 if( rKEvt.GetKeyCode().GetCode() == KEY_RETURN && CodeCompleteOptions::IsProcedureAutoCompleteOn() ) 536 {//autoclose implementation 537 HandleProcedureCompletion(); 538 } 539 540 if( rKEvt.GetKeyCode().GetCode() == KEY_POINT && CodeCompleteOptions::IsCodeCompleteOn() ) 541 { 542 HandleCodeCompletion(); 543 } 544 if ( !bDone && ( !TextEngine::DoesKeyChangeText( rKEvt ) || ImpCanModify() ) ) 545 { 546 if ( ( rKEvt.GetKeyCode().GetCode() == KEY_TAB ) && !rKEvt.GetKeyCode().IsMod1() && 547 !rKEvt.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() ) 548 { 549 TextSelection aSel( pEditView->GetSelection() ); 550 if ( aSel.GetStart().GetPara() != aSel.GetEnd().GetPara() ) 551 { 552 bDelayHighlight = false; 553 if ( !rKEvt.GetKeyCode().IsShift() ) 554 pEditView->IndentBlock(); 555 else 556 pEditView->UnindentBlock(); 557 bDelayHighlight = true; 558 bDone = true; 559 } 560 } 561 if ( !bDone ) 562 bDone = pEditView->KeyInput( rKEvt ); 563 } 564 if ( !bDone ) 565 { 566 Window::KeyInput( rKEvt ); 567 } 568 else 569 { 570 if (SfxBindings* pBindings = GetBindingsPtr()) 571 { 572 pBindings->Invalidate( SID_BASICIDE_STAT_POS ); 573 pBindings->Invalidate( SID_BASICIDE_STAT_TITLE ); 574 if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR ) 575 { 576 pBindings->Update( SID_BASICIDE_STAT_POS ); 577 pBindings->Update( SID_BASICIDE_STAT_TITLE ); 578 } 579 if ( !bWasModified && pEditEngine->IsModified() ) 580 { 581 pBindings->Invalidate( SID_SAVEDOC ); 582 pBindings->Invalidate( SID_DOC_MODIFIED ); 583 pBindings->Invalidate( SID_UNDO ); 584 } 585 if ( rKEvt.GetKeyCode().GetCode() == KEY_INSERT ) 586 pBindings->Invalidate( SID_ATTR_INSERT ); 587 } 588 } 589 } 590 591 void EditorWindow::HandleAutoCorrect() 592 { 593 TextSelection aSel = GetEditView()->GetSelection(); 594 const sal_uInt32 nLine = aSel.GetStart().GetPara(); 595 const sal_Int32 nIndex = aSel.GetStart().GetIndex(); 596 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified 597 const OUString& sActSubName = GetActualSubName( nLine ); // the actual procedure 598 599 std::vector<HighlightPortion> aPortions; 600 aHighlighter.getHighlightPortions( aLine, aPortions ); 601 602 if( aPortions.empty() ) 603 return; 604 605 HighlightPortion& r = aPortions.back(); 606 if( static_cast<size_t>(nIndex) != aPortions.size()-1 ) 607 {//cursor is not standing at the end of the line 608 for (auto const& portion : aPortions) 609 { 610 if( portion.nEnd == nIndex ) 611 { 612 r = portion; 613 break; 614 } 615 } 616 } 617 618 OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin ); 619 //if WS or empty string: stop, nothing to do 620 if( ( r.tokenType == TokenType::Whitespace ) || sStr.isEmpty() ) 621 return; 622 //create the appropriate TextSelection, and update the cache 623 TextPaM aStart( nLine, r.nBegin ); 624 TextPaM aEnd( nLine, r.nBegin + sStr.getLength() ); 625 TextSelection sTextSelection( aStart, aEnd ); 626 rModulWindow.UpdateModule(); 627 rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache ); 628 // correct the last entered keyword 629 if( r.tokenType == TokenType::Keywords ) 630 { 631 sStr = sStr.toAsciiLowerCase(); 632 if( !SbModule::GetKeywordCase(sStr).isEmpty() ) 633 // if it is a keyword, get its correct case 634 sStr = SbModule::GetKeywordCase(sStr); 635 else 636 // else capitalize first letter/select the correct one, and replace 637 sStr = sStr.replaceAt( 0, 1, OUString(sStr[0]).toAsciiUpperCase() ); 638 639 pEditEngine->ReplaceText( sTextSelection, sStr ); 640 pEditView->SetSelection( aSel ); 641 } 642 if( r.tokenType == TokenType::Identifier ) 643 {// correct variables 644 if( !aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ).isEmpty() ) 645 { 646 sStr = aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ); 647 pEditEngine->ReplaceText( sTextSelection, sStr ); 648 pEditView->SetSelection( aSel ); 649 } 650 else 651 { 652 //autocorrect procedures 653 SbxArray* pArr = rModulWindow.GetSbModule()->GetMethods().get(); 654 for( sal_uInt32 i=0; i < pArr->Count32(); ++i ) 655 { 656 if( pArr->Get32(i)->GetName().equalsIgnoreAsciiCase( sStr ) ) 657 { 658 sStr = pArr->Get32(i)->GetName(); //if found, get the correct case 659 pEditEngine->ReplaceText( sTextSelection, sStr ); 660 pEditView->SetSelection( aSel ); 661 return; 662 } 663 } 664 } 665 } 666 } 667 668 TextSelection EditorWindow::GetLastHighlightPortionTextSelection() 669 {//creates a text selection from the highlight portion on the cursor 670 const sal_uInt32 nLine = GetEditView()->GetSelection().GetStart().GetPara(); 671 const sal_Int32 nIndex = GetEditView()->GetSelection().GetStart().GetIndex(); 672 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified 673 std::vector<HighlightPortion> aPortions; 674 aHighlighter.getHighlightPortions( aLine, aPortions ); 675 676 assert(!aPortions.empty()); 677 HighlightPortion& r = aPortions.back(); 678 if( static_cast<size_t>(nIndex) != aPortions.size()-1 ) 679 {//cursor is not standing at the end of the line 680 for (auto const& portion : aPortions) 681 { 682 if( portion.nEnd == nIndex ) 683 { 684 r = portion; 685 break; 686 } 687 } 688 } 689 690 if( aPortions.empty() ) 691 return TextSelection(); 692 693 OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin ); 694 TextPaM aStart( nLine, r.nBegin ); 695 TextPaM aEnd( nLine, r.nBegin + sStr.getLength() ); 696 return TextSelection( aStart, aEnd ); 697 } 698 699 void EditorWindow::HandleAutoCloseParen() 700 { 701 TextSelection aSel = GetEditView()->GetSelection(); 702 const sal_uInt32 nLine = aSel.GetStart().GetPara(); 703 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified 704 705 if( aLine.getLength() > 0 && aLine[aSel.GetEnd().GetIndex()-1] != '(' ) 706 { 707 GetEditView()->InsertText(")"); 708 //leave the cursor on its place: inside the parenthesis 709 TextPaM aEnd(nLine, aSel.GetEnd().GetIndex()); 710 GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) ); 711 } 712 } 713 714 void EditorWindow::HandleAutoCloseDoubleQuotes() 715 { 716 TextSelection aSel = GetEditView()->GetSelection(); 717 const sal_uInt32 nLine = aSel.GetStart().GetPara(); 718 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified 719 720 std::vector<HighlightPortion> aPortions; 721 aHighlighter.getHighlightPortions( aLine, aPortions ); 722 723 if( aPortions.empty() ) 724 return; 725 726 if( aLine.getLength() > 0 && !aLine.endsWith("\"") && (aPortions.back().tokenType != TokenType::String) ) 727 { 728 GetEditView()->InsertText("\""); 729 //leave the cursor on its place: inside the two double quotes 730 TextPaM aEnd(nLine, aSel.GetEnd().GetIndex()); 731 GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) ); 732 } 733 } 734 735 void EditorWindow::HandleProcedureCompletion() 736 { 737 738 TextSelection aSel = GetEditView()->GetSelection(); 739 const sal_uInt32 nLine = aSel.GetStart().GetPara(); 740 OUString aLine( pEditEngine->GetText( nLine ) ); 741 742 OUString sProcType; 743 OUString sProcName; 744 bool bFoundName = GetProcedureName(aLine, sProcType, sProcName); 745 if (!bFoundName) 746 return; 747 748 OUString sText("\nEnd "); 749 aSel = GetEditView()->GetSelection(); 750 if( sProcType.equalsIgnoreAsciiCase("function") ) 751 sText += "Function\n"; 752 if( sProcType.equalsIgnoreAsciiCase("sub") ) 753 sText += "Sub\n"; 754 755 if( nLine+1 == pEditEngine->GetParagraphCount() ) 756 { 757 pEditView->InsertText( sText );//append to the end 758 GetEditView()->SetSelection(aSel); 759 } 760 else 761 { 762 for( sal_uInt32 i = nLine+1; i < pEditEngine->GetParagraphCount(); ++i ) 763 {//searching forward for end token, or another sub/function definition 764 OUString aCurrLine = pEditEngine->GetText( i ); 765 std::vector<HighlightPortion> aCurrPortions; 766 aHighlighter.getHighlightPortions( aCurrLine, aCurrPortions ); 767 768 if( aCurrPortions.size() >= 3 ) 769 {//at least 3 tokens: (sub|function) whitespace identifier... 770 HighlightPortion& r = aCurrPortions.front(); 771 OUString sStr = aCurrLine.copy(r.nBegin, r.nEnd - r.nBegin); 772 773 if( r.tokenType == TokenType::Keywords ) 774 { 775 if( sStr.equalsIgnoreAsciiCase("sub") || sStr.equalsIgnoreAsciiCase("function") ) 776 { 777 pEditView->InsertText( sText );//append to the end 778 GetEditView()->SetSelection(aSel); 779 break; 780 } 781 if( sStr.equalsIgnoreAsciiCase("end") ) 782 break; 783 } 784 } 785 } 786 } 787 } 788 789 bool EditorWindow::GetProcedureName(OUString const & rLine, OUString& rProcType, OUString& rProcName) const 790 { 791 std::vector<HighlightPortion> aPortions; 792 aHighlighter.getHighlightPortions(rLine, aPortions); 793 794 if( aPortions.empty() ) 795 return false; 796 797 bool bFoundType = false; 798 bool bFoundName = false; 799 800 for (auto const& portion : aPortions) 801 { 802 OUString sTokStr = rLine.copy(portion.nBegin, portion.nEnd - portion.nBegin); 803 804 if( portion.tokenType == TokenType::Keywords && ( sTokStr.equalsIgnoreAsciiCase("sub") 805 || sTokStr.equalsIgnoreAsciiCase("function")) ) 806 { 807 rProcType = sTokStr; 808 bFoundType = true; 809 } 810 if( portion.tokenType == TokenType::Identifier && bFoundType ) 811 { 812 rProcName = sTokStr; 813 bFoundName = true; 814 break; 815 } 816 } 817 818 if( !bFoundType || !bFoundName ) 819 return false;// no sub/function keyword or there is no identifier 820 821 return true; 822 823 } 824 825 void EditorWindow::HandleCodeCompletion() 826 { 827 rModulWindow.UpdateModule(); 828 rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache); 829 TextSelection aSel = GetEditView()->GetSelection(); 830 const sal_uInt32 nLine = aSel.GetStart().GetPara(); 831 OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified 832 std::vector< OUString > aVect; //vector to hold the base variable+methods for the nested reflection 833 834 std::vector<HighlightPortion> aPortions; 835 aLine = aLine.copy(0, aSel.GetEnd().GetIndex()); 836 aHighlighter.getHighlightPortions( aLine, aPortions ); 837 if( !aPortions.empty() ) 838 {//use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod .. 839 for( std::vector<HighlightPortion>::reverse_iterator i( 840 aPortions.rbegin()); 841 i != aPortions.rend(); ++i) 842 { 843 if( i->tokenType == TokenType::Whitespace ) // a whitespace: stop; if there is no ws, it goes to the beginning of the line 844 break; 845 if( i->tokenType == TokenType::Identifier || i->tokenType == TokenType::Keywords ) // extract the identifiers(methods, base variable) 846 /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue 847 * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!) 848 * */ 849 aVect.insert( aVect.begin(), aLine.copy(i->nBegin, i->nEnd - i->nBegin) ); 850 } 851 852 if( aVect.empty() )//nothing to do 853 return; 854 855 OUString sBaseName = aVect[aVect.size()-1];//variable name 856 OUString sVarType = aCodeCompleteCache.GetVarType( sBaseName ); 857 858 if( !sVarType.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() ) 859 {//correct variable name, if autocorrection on 860 const OUString& sStr = aCodeCompleteCache.GetCorrectCaseVarName( sBaseName, GetActualSubName(nLine) ); 861 if( !sStr.isEmpty() ) 862 { 863 TextPaM aStart(nLine, aSel.GetStart().GetIndex() - sStr.getLength() ); 864 TextSelection sTextSelection(aStart, TextPaM(nLine, aSel.GetStart().GetIndex())); 865 pEditEngine->ReplaceText( sTextSelection, sStr ); 866 pEditView->SetSelection( aSel ); 867 } 868 } 869 870 UnoTypeCodeCompletetor aTypeCompletor( aVect, sVarType ); 871 872 if( aTypeCompletor.CanCodeComplete() ) 873 { 874 std::vector< OUString > aEntryVect;//entries to be inserted into the list 875 std::vector< OUString > aFieldVect = aTypeCompletor.GetXIdlClassFields();//fields 876 aEntryVect.insert(aEntryVect.end(), aFieldVect.begin(), aFieldVect.end() ); 877 if( CodeCompleteOptions::IsExtendedTypeDeclaration() ) 878 {// if extended types on, reflect classes, else just the structs (XIdlClass without methods) 879 std::vector< OUString > aMethVect = aTypeCompletor.GetXIdlClassMethods();//methods 880 aEntryVect.insert(aEntryVect.end(), aMethVect.begin(), aMethVect.end() ); 881 } 882 if( !aEntryVect.empty() ) 883 SetupAndShowCodeCompleteWnd( aEntryVect, aSel ); 884 } 885 } 886 } 887 888 void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector< OUString >& aEntryVect, TextSelection aSel ) 889 { 890 // clear the listbox 891 pCodeCompleteWnd->ClearListBox(); 892 // fill the listbox 893 for(const auto & l : aEntryVect) 894 { 895 pCodeCompleteWnd->InsertEntry( l ); 896 } 897 // show it 898 pCodeCompleteWnd->Show(); 899 pCodeCompleteWnd->ResizeAndPositionListBox(); 900 pCodeCompleteWnd->SelectFirstEntry(); 901 // correct text selection, and set it 902 ++aSel.GetStart().GetIndex(); 903 ++aSel.GetEnd().GetIndex(); 904 pCodeCompleteWnd->SetTextSelection( aSel ); 905 //give the focus to the EditView 906 pEditView->GetWindow()->GrabFocus(); 907 } 908 909 void EditorWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) 910 { 911 if (!pEditEngine) // We need it now at latest 912 CreateEditEngine(); 913 914 pEditView->Paint(rRenderContext, rRect); 915 } 916 917 void EditorWindow::LoseFocus() 918 { 919 SetSourceInBasic(); 920 Window::LoseFocus(); 921 } 922 923 void EditorWindow::SetSourceInBasic() 924 { 925 if ( pEditEngine && pEditEngine->IsModified() 926 && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise 927 // any read only bug in the text engine could lead to a crash later 928 { 929 if ( !StarBASIC::IsRunning() ) // Not at runtime! 930 { 931 rModulWindow.UpdateModule(); 932 } 933 } 934 } 935 936 // Returns the position of the last character of any of the following 937 // EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found 938 sal_Int32 searchEOL( const OUString& rStr, sal_Int32 fromIndex ) 939 { 940 sal_Int32 iRetPos = -1; 941 942 sal_Int32 iLF = rStr.indexOf( LINE_SEP, fromIndex ); 943 if( iLF != -1 ) 944 { 945 iRetPos = iLF; 946 } 947 else 948 { 949 iRetPos = rStr.indexOf( LINE_SEP_CR, fromIndex ); 950 } 951 return iRetPos; 952 } 953 954 void EditorWindow::CreateEditEngine() 955 { 956 if (pEditEngine) 957 return; 958 959 pEditEngine.reset(new ExtTextEngine); 960 pEditView.reset(new TextView(pEditEngine.get(), this)); 961 pEditView->SetAutoIndentMode(true); 962 pEditEngine->SetUpdateMode(false); 963 pEditEngine->InsertView(pEditView.get()); 964 965 ImplSetFont(); 966 967 aSyntaxIdle.SetInvokeHandler( LINK( this, EditorWindow, SyntaxTimerHdl ) ); 968 aSyntaxIdle.SetDebugName( "basctl EditorWindow aSyntaxIdle" ); 969 970 bool bWasDoSyntaxHighlight = bDoSyntaxHighlight; 971 bDoSyntaxHighlight = false; // too slow for large texts... 972 OUString aOUSource(rModulWindow.GetModule()); 973 sal_Int32 nLines = 0; 974 sal_Int32 nIndex = -1; 975 do 976 { 977 nLines++; 978 nIndex = searchEOL( aOUSource, nIndex+1 ); 979 } 980 while (nIndex >= 0); 981 982 // nLines*4: SetText+Formatting+DoHighlight+Formatting 983 // it could be cut down on one formatting but you would wait even longer 984 // for the text then if the source code is long... 985 pProgress.reset(new ProgressInfo(GetShell()->GetViewFrame()->GetObjectShell(), 986 IDEResId(RID_STR_GENERATESOURCE), 987 nLines * 4)); 988 setTextEngineText(*pEditEngine, aOUSource); 989 990 pEditView->SetStartDocPos(Point(0, 0)); 991 pEditView->SetSelection(TextSelection()); 992 rModulWindow.GetBreakPointWindow().GetCurYOffset() = 0; 993 rModulWindow.GetLineNumberWindow().GetCurYOffset() = 0; 994 pEditEngine->SetUpdateMode(true); 995 rModulWindow.Update(); // has only been invalidated at UpdateMode = true 996 997 pEditView->ShowCursor(); 998 999 StartListening(*pEditEngine); 1000 1001 aSyntaxIdle.Stop(); 1002 bDoSyntaxHighlight = bWasDoSyntaxHighlight; 1003 1004 for (sal_Int32 nLine = 0; nLine < nLines; nLine++) 1005 aSyntaxLineTable.insert(nLine); 1006 ForceSyntaxTimeout(); 1007 1008 pProgress.reset(); 1009 1010 pEditEngine->SetModified( false ); 1011 pEditEngine->EnableUndo( true ); 1012 1013 InitScrollBars(); 1014 1015 if (SfxBindings* pBindings = GetBindingsPtr()) 1016 { 1017 pBindings->Invalidate(SID_BASICIDE_STAT_POS); 1018 pBindings->Invalidate(SID_BASICIDE_STAT_TITLE); 1019 } 1020 1021 DBG_ASSERT(rModulWindow.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?"); 1022 1023 // set readonly mode for readonly libraries 1024 ScriptDocument aDocument(rModulWindow.GetDocument()); 1025 OUString aOULibName(rModulWindow.GetLibName()); 1026 Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); 1027 if (xModLibContainer.is() 1028 && xModLibContainer->hasByName(aOULibName) 1029 && xModLibContainer->isLibraryReadOnly(aOULibName)) 1030 { 1031 rModulWindow.SetReadOnly(true); 1032 } 1033 1034 if (aDocument.isDocument() && aDocument.isReadOnly()) 1035 rModulWindow.SetReadOnly(true); 1036 } 1037 1038 void EditorWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) 1039 { 1040 if (TextHint const* pTextHint = dynamic_cast<TextHint const*>(&rHint)) 1041 { 1042 TextHint const& rTextHint = *pTextHint; 1043 if( rTextHint.GetId() == SfxHintId::TextViewScrolled ) 1044 { 1045 if ( rModulWindow.GetHScrollBar() ) 1046 rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() ); 1047 rModulWindow.GetEditVScrollBar().SetThumbPos( pEditView->GetStartDocPos().Y() ); 1048 rModulWindow.GetBreakPointWindow().DoScroll 1049 ( rModulWindow.GetBreakPointWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() ); 1050 rModulWindow.GetLineNumberWindow().DoScroll 1051 ( rModulWindow.GetLineNumberWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() ); 1052 } 1053 else if( rTextHint.GetId() == SfxHintId::TextHeightChanged ) 1054 { 1055 if ( pEditView->GetStartDocPos().Y() ) 1056 { 1057 long nOutHeight = GetOutputSizePixel().Height(); 1058 long nTextHeight = pEditEngine->GetTextHeight(); 1059 if ( nTextHeight < nOutHeight ) 1060 pEditView->Scroll( 0, pEditView->GetStartDocPos().Y() ); 1061 1062 rModulWindow.GetLineNumberWindow().Invalidate(); 1063 } 1064 1065 SetScrollBarRanges(); 1066 } 1067 else if( rTextHint.GetId() == SfxHintId::TextFormatted ) 1068 { 1069 if ( rModulWindow.GetHScrollBar() ) 1070 { 1071 const long nWidth = pEditEngine->CalcTextWidth(); 1072 if ( nWidth != nCurTextWidth ) 1073 { 1074 nCurTextWidth = nWidth; 1075 rModulWindow.GetHScrollBar()->SetRange( Range( 0, nCurTextWidth-1) ); 1076 rModulWindow.GetHScrollBar()->SetThumbPos( pEditView->GetStartDocPos().X() ); 1077 } 1078 } 1079 long nPrevTextWidth = nCurTextWidth; 1080 nCurTextWidth = pEditEngine->CalcTextWidth(); 1081 if ( nCurTextWidth != nPrevTextWidth ) 1082 SetScrollBarRanges(); 1083 } 1084 else if( rTextHint.GetId() == SfxHintId::TextParaInserted ) 1085 { 1086 ParagraphInsertedDeleted( rTextHint.GetValue(), true ); 1087 DoDelayedSyntaxHighlight( rTextHint.GetValue() ); 1088 } 1089 else if( rTextHint.GetId() == SfxHintId::TextParaRemoved ) 1090 { 1091 ParagraphInsertedDeleted( rTextHint.GetValue(), false ); 1092 } 1093 else if( rTextHint.GetId() == SfxHintId::TextParaContentChanged ) 1094 { 1095 DoDelayedSyntaxHighlight( rTextHint.GetValue() ); 1096 } 1097 else if( rTextHint.GetId() == SfxHintId::TextViewSelectionChanged ) 1098 { 1099 if (SfxBindings* pBindings = GetBindingsPtr()) 1100 { 1101 pBindings->Invalidate( SID_CUT ); 1102 pBindings->Invalidate( SID_COPY ); 1103 } 1104 } 1105 } 1106 } 1107 1108 OUString EditorWindow::GetActualSubName( sal_uLong nLine ) 1109 { 1110 SbxArrayRef pMethods = rModulWindow.GetSbModule()->GetMethods(); 1111 for( sal_uInt16 i=0; i < pMethods->Count(); i++ ) 1112 { 1113 SbMethod* pMeth = dynamic_cast<SbMethod*>( pMethods->Get( i ) ); 1114 if( pMeth ) 1115 { 1116 sal_uInt16 l1,l2; 1117 pMeth->GetLineRange(l1,l2); 1118 if( (l1 <= nLine+1) && (nLine+1 <= l2) ) 1119 { 1120 return pMeth->GetName(); 1121 } 1122 } 1123 } 1124 return OUString(); 1125 } 1126 1127 void EditorWindow::SetScrollBarRanges() 1128 { 1129 // extra method, not InitScrollBars, because for EditEngine events too 1130 if ( !pEditEngine ) 1131 return; 1132 1133 if ( rModulWindow.GetHScrollBar() ) 1134 rModulWindow.GetHScrollBar()->SetRange( Range( 0, nCurTextWidth-1 ) ); 1135 1136 rModulWindow.GetEditVScrollBar().SetRange( Range( 0, pEditEngine->GetTextHeight()-1 ) ); 1137 } 1138 1139 void EditorWindow::InitScrollBars() 1140 { 1141 if (!pEditEngine) 1142 return; 1143 1144 SetScrollBarRanges(); 1145 Size aOutSz(GetOutputSizePixel()); 1146 rModulWindow.GetEditVScrollBar().SetVisibleSize(aOutSz.Height()); 1147 rModulWindow.GetEditVScrollBar().SetPageSize(aOutSz.Height() * 8 / 10); 1148 rModulWindow.GetEditVScrollBar().SetLineSize(GetTextHeight()); 1149 rModulWindow.GetEditVScrollBar().SetThumbPos(pEditView->GetStartDocPos().Y()); 1150 rModulWindow.GetEditVScrollBar().Show(); 1151 1152 if (rModulWindow.GetHScrollBar()) 1153 { 1154 rModulWindow.GetHScrollBar()->SetVisibleSize(aOutSz.Width()); 1155 rModulWindow.GetHScrollBar()->SetPageSize(aOutSz.Width() * 8 / 10); 1156 rModulWindow.GetHScrollBar()->SetLineSize(GetTextWidth( "x" ) ); 1157 rModulWindow.GetHScrollBar()->SetThumbPos(pEditView->GetStartDocPos().X()); 1158 rModulWindow.GetHScrollBar()->Show(); 1159 } 1160 } 1161 1162 void EditorWindow::ImpDoHighlight( sal_uLong nLine ) 1163 { 1164 if ( bDoSyntaxHighlight ) 1165 { 1166 OUString aLine( pEditEngine->GetText( nLine ) ); 1167 bool const bWasModified = pEditEngine->IsModified(); 1168 pEditEngine->RemoveAttribs( nLine ); 1169 std::vector<HighlightPortion> aPortions; 1170 aHighlighter.getHighlightPortions( aLine, aPortions ); 1171 1172 for (auto const& portion : aPortions) 1173 { 1174 Color const aColor = rModulWindow.GetLayout().GetSyntaxColor(portion.tokenType); 1175 pEditEngine->SetAttrib(TextAttribFontColor(aColor), nLine, portion.nBegin, portion.nEnd); 1176 } 1177 1178 pEditEngine->SetModified(bWasModified); 1179 } 1180 } 1181 1182 void EditorWindow::ChangeFontColor( Color aColor ) 1183 { 1184 if (pEditEngine) 1185 { 1186 vcl::Font aFont(pEditEngine->GetFont()); 1187 aFont.SetColor(aColor); 1188 pEditEngine->SetFont(aFont); 1189 } 1190 } 1191 1192 void EditorWindow::UpdateSyntaxHighlighting () 1193 { 1194 const sal_uInt32 nCount = pEditEngine->GetParagraphCount(); 1195 for (sal_uInt32 i = 0; i < nCount; ++i) 1196 DoDelayedSyntaxHighlight(i); 1197 } 1198 1199 void EditorWindow::ImplSetFont() 1200 { 1201 OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().get_value_or(OUString())); 1202 if (sFontName.isEmpty()) 1203 { 1204 vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED, 1205 Application::GetSettings().GetUILanguageTag().getLanguageType(), 1206 GetDefaultFontFlags::NONE, this)); 1207 sFontName = aTmpFont.GetFamilyName(); 1208 } 1209 Size aFontSize(0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get()); 1210 vcl::Font aFont(sFontName, aFontSize); 1211 aFont.SetColor(rModulWindow.GetLayout().GetFontColor()); 1212 SetPointFont(*this, aFont); // FIXME RenderContext 1213 aFont = GetFont(); 1214 1215 rModulWindow.GetBreakPointWindow().SetFont(aFont); 1216 rModulWindow.GetLineNumberWindow().SetFont(aFont); 1217 1218 if (pEditEngine) 1219 { 1220 bool const bModified = pEditEngine->IsModified(); 1221 pEditEngine->SetFont(aFont); 1222 pEditEngine->SetModified(bModified); 1223 } 1224 } 1225 1226 void EditorWindow::DoSyntaxHighlight( sal_uLong nPara ) 1227 { 1228 // because of the DelayedSyntaxHighlight it's possible 1229 // that this line does not exist anymore! 1230 if ( nPara < pEditEngine->GetParagraphCount() ) 1231 { 1232 // unfortunately I'm not sure that exactly this line does Modified()... 1233 if ( pProgress ) 1234 pProgress->StepProgress(); 1235 ImpDoHighlight( nPara ); 1236 } 1237 } 1238 1239 void EditorWindow::DoDelayedSyntaxHighlight( sal_uLong nPara ) 1240 { 1241 // line is only added to list, processed in TimerHdl 1242 // => don't manipulate breaks while EditEngine is formatting 1243 if ( pProgress ) 1244 pProgress->StepProgress(); 1245 1246 if ( !bHighlighting && bDoSyntaxHighlight ) 1247 { 1248 if ( bDelayHighlight ) 1249 { 1250 aSyntaxLineTable.insert( nPara ); 1251 aSyntaxIdle.Start(); 1252 } 1253 else 1254 DoSyntaxHighlight( nPara ); 1255 } 1256 } 1257 1258 IMPL_LINK_NOARG(EditorWindow, SyntaxTimerHdl, Timer *, void) 1259 { 1260 DBG_ASSERT( pEditView, "Not yet a View, but Syntax-Highlight?!" ); 1261 1262 bool const bWasModified = pEditEngine->IsModified(); 1263 //pEditEngine->SetUpdateMode(false); 1264 1265 bHighlighting = true; 1266 for (auto const& syntaxLine : aSyntaxLineTable) 1267 { 1268 DoSyntaxHighlight(syntaxLine); 1269 } 1270 1271 // #i45572# 1272 if ( pEditView ) 1273 pEditView->ShowCursor( false ); 1274 1275 pEditEngine->SetModified( bWasModified ); 1276 1277 aSyntaxLineTable.clear(); 1278 bHighlighting = false; 1279 } 1280 1281 void EditorWindow::ParagraphInsertedDeleted( sal_uLong nPara, bool bInserted ) 1282 { 1283 if ( pProgress ) 1284 pProgress->StepProgress(); 1285 1286 if ( !bInserted && ( nPara == TEXT_PARA_ALL ) ) 1287 { 1288 rModulWindow.GetBreakPoints().reset(); 1289 rModulWindow.GetBreakPointWindow().Invalidate(); 1290 rModulWindow.GetLineNumberWindow().Invalidate(); 1291 } 1292 else 1293 { 1294 rModulWindow.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16>(nPara)+1, bInserted ); 1295 1296 long nLineHeight = GetTextHeight(); 1297 Size aSz = rModulWindow.GetBreakPointWindow().GetOutputSize(); 1298 tools::Rectangle aInvRect( Point( 0, 0 ), aSz ); 1299 long nY = nPara*nLineHeight - rModulWindow.GetBreakPointWindow().GetCurYOffset(); 1300 aInvRect.SetTop( nY ); 1301 rModulWindow.GetBreakPointWindow().Invalidate( aInvRect ); 1302 1303 Size aLnSz(rModulWindow.GetLineNumberWindow().GetWidth(), 1304 GetOutputSizePixel().Height() - 2 * DWBORDER); 1305 rModulWindow.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER + 19, DWBORDER), aLnSz); 1306 rModulWindow.GetLineNumberWindow().Invalidate(); 1307 } 1308 } 1309 1310 void EditorWindow::CreateProgress( const OUString& rText, sal_uInt32 nRange ) 1311 { 1312 DBG_ASSERT( !pProgress, "ProgressInfo exists already" ); 1313 pProgress.reset(new ProgressInfo( 1314 GetShell()->GetViewFrame()->GetObjectShell(), 1315 rText, 1316 nRange 1317 )); 1318 } 1319 1320 void EditorWindow::DestroyProgress() 1321 { 1322 pProgress.reset(); 1323 } 1324 1325 void EditorWindow::ForceSyntaxTimeout() 1326 { 1327 aSyntaxIdle.Stop(); 1328 aSyntaxIdle.Invoke(); 1329 } 1330 1331 // BreakPointWindow 1332 1333 BreakPointWindow::BreakPointWindow (vcl::Window* pParent, ModulWindow* pModulWindow) 1334 : Window(pParent, WB_BORDER) 1335 , rModulWindow(*pModulWindow) 1336 , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine 1337 , nMarkerPos(NoMarker) 1338 , bErrorMarker(false) 1339 { 1340 setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor()); 1341 SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW); 1342 } 1343 1344 void BreakPointWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) 1345 { 1346 if (SyncYOffset()) 1347 return; 1348 1349 Size const aOutSz = rRenderContext.GetOutputSize(); 1350 long const nLineHeight = rRenderContext.GetTextHeight(); 1351 1352 Image const aBrk[2] = 1353 { 1354 GetImage(RID_BMP_BRKDISABLED), 1355 GetImage(RID_BMP_BRKENABLED) 1356 }; 1357 1358 Size const aBmpSz = rRenderContext.PixelToLogic(aBrk[1].GetSizePixel()); 1359 Point const aBmpOff((aOutSz.Width() - aBmpSz.Width()) / 2, 1360 (nLineHeight - aBmpSz.Height()) / 2); 1361 1362 for (size_t i = 0, n = GetBreakPoints().size(); i < n; ++i) 1363 { 1364 BreakPoint& rBrk = GetBreakPoints().at(i); 1365 sal_uInt16 const nLine = rBrk.nLine - 1; 1366 size_t const nY = nLine*nLineHeight - nCurYOffset; 1367 rRenderContext.DrawImage(Point(0, nY) + aBmpOff, aBrk[rBrk.bEnabled]); 1368 } 1369 1370 ShowMarker(rRenderContext); 1371 } 1372 1373 void BreakPointWindow::ShowMarker(vcl::RenderContext& rRenderContext) 1374 { 1375 if (nMarkerPos == NoMarker) 1376 return; 1377 1378 Size const aOutSz = GetOutputSize(); 1379 long const nLineHeight = GetTextHeight(); 1380 1381 Image aMarker = GetImage(bErrorMarker ? OUStringLiteral(RID_BMP_ERRORMARKER) : OUStringLiteral(RID_BMP_STEPMARKER)); 1382 1383 Size aMarkerSz(aMarker.GetSizePixel()); 1384 aMarkerSz = rRenderContext.PixelToLogic(aMarkerSz); 1385 Point aMarkerOff(0, 0); 1386 aMarkerOff.setX( (aOutSz.Width() - aMarkerSz.Width()) / 2 ); 1387 aMarkerOff.setY( (nLineHeight - aMarkerSz.Height()) / 2 ); 1388 1389 sal_uLong nY = nMarkerPos * nLineHeight - nCurYOffset; 1390 Point aPos(0, nY); 1391 aPos += aMarkerOff; 1392 1393 rRenderContext.DrawImage(aPos, aMarker); 1394 } 1395 1396 void BreakPointWindow::DoScroll( long nVertScroll ) 1397 { 1398 nCurYOffset -= nVertScroll; 1399 Window::Scroll( 0, nVertScroll ); 1400 } 1401 1402 void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine, bool bError ) 1403 { 1404 if ( SyncYOffset() ) 1405 Update(); 1406 1407 nMarkerPos = nLine; 1408 bErrorMarker = bError; 1409 Invalidate(); 1410 } 1411 1412 void BreakPointWindow::SetNoMarker () 1413 { 1414 SetMarkerPos(NoMarker); 1415 } 1416 1417 BreakPoint* BreakPointWindow::FindBreakPoint( const Point& rMousePos ) 1418 { 1419 size_t nLineHeight = GetTextHeight(); 1420 nLineHeight = nLineHeight > 0 ? nLineHeight : 1; 1421 size_t nYPos = rMousePos.Y() + nCurYOffset; 1422 1423 for ( size_t i = 0, n = GetBreakPoints().size(); i < n ; ++i ) 1424 { 1425 BreakPoint& rBrk = GetBreakPoints().at( i ); 1426 sal_uInt16 nLine = rBrk.nLine-1; 1427 size_t nY = nLine*nLineHeight; 1428 if ( ( nYPos > nY ) && ( nYPos < ( nY + nLineHeight ) ) ) 1429 return &rBrk; 1430 } 1431 return nullptr; 1432 } 1433 1434 void BreakPointWindow::MouseButtonDown( const MouseEvent& rMEvt ) 1435 { 1436 if ( rMEvt.GetClicks() == 2 ) 1437 { 1438 Point aMousePos( PixelToLogic( rMEvt.GetPosPixel() ) ); 1439 long nLineHeight = GetTextHeight(); 1440 if(nLineHeight) 1441 { 1442 long nYPos = aMousePos.Y() + nCurYOffset; 1443 long nLine = nYPos / nLineHeight + 1; 1444 rModulWindow.ToggleBreakPoint( static_cast<sal_uLong>(nLine) ); 1445 Invalidate(); 1446 } 1447 } 1448 } 1449 1450 void BreakPointWindow::Command( const CommandEvent& rCEvt ) 1451 { 1452 if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) 1453 { 1454 if (!mpUIBuilder) 1455 mpUIBuilder.reset(new VclBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "modules/BasicIDE/ui/breakpointmenus.ui", "")); 1456 1457 Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) ); 1458 Point aEventPos( PixelToLogic( aPos ) ); 1459 BreakPoint* pBrk = rCEvt.IsMouseEvent() ? FindBreakPoint( aEventPos ) : nullptr; 1460 if ( pBrk ) 1461 { 1462 // test if break point is enabled... 1463 VclPtr<PopupMenu> xBrkPropMenu = mpUIBuilder->get_menu("breakmenu"); 1464 xBrkPropMenu->CheckItem("active", pBrk->bEnabled); 1465 OString sCommand = xBrkPropMenu->GetItemIdent(xBrkPropMenu->Execute(this, aPos)); 1466 if (sCommand == "active") 1467 { 1468 pBrk->bEnabled = !pBrk->bEnabled; 1469 rModulWindow.UpdateBreakPoint( *pBrk ); 1470 Invalidate(); 1471 } 1472 else if (sCommand == "properties") 1473 { 1474 BreakPointDialog aBrkDlg(GetFrameWeld(), GetBreakPoints()); 1475 aBrkDlg.SetCurrentBreakPoint( *pBrk ); 1476 aBrkDlg.run(); 1477 Invalidate(); 1478 } 1479 } 1480 else 1481 { 1482 VclPtr<PopupMenu> xBrkListMenu = mpUIBuilder->get_menu("breaklistmenu"); 1483 OString sCommand = xBrkListMenu->GetItemIdent(xBrkListMenu->Execute(this, aPos)); 1484 if (sCommand == "manage") 1485 { 1486 BreakPointDialog aBrkDlg(GetFrameWeld(), GetBreakPoints()); 1487 aBrkDlg.run(); 1488 Invalidate(); 1489 } 1490 } 1491 } 1492 } 1493 1494 bool BreakPointWindow::SyncYOffset() 1495 { 1496 TextView* pView = rModulWindow.GetEditView(); 1497 if ( pView ) 1498 { 1499 long nViewYOffset = pView->GetStartDocPos().Y(); 1500 if ( nCurYOffset != nViewYOffset ) 1501 { 1502 nCurYOffset = nViewYOffset; 1503 Invalidate(); 1504 return true; 1505 } 1506 } 1507 return false; 1508 } 1509 1510 // virtual 1511 void BreakPointWindow::DataChanged(DataChangedEvent const & rDCEvt) 1512 { 1513 Window::DataChanged(rDCEvt); 1514 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS 1515 && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) 1516 { 1517 Color aColor(GetSettings().GetStyleSettings().GetFieldColor()); 1518 const AllSettings* pOldSettings = rDCEvt.GetOldSettings(); 1519 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor()) 1520 { 1521 setBackgroundColor(aColor); 1522 Invalidate(); 1523 } 1524 } 1525 } 1526 1527 void BreakPointWindow::setBackgroundColor(Color aColor) 1528 { 1529 SetBackground(Wallpaper(aColor)); 1530 } 1531 1532 void BreakPointWindow::dispose() 1533 { 1534 mpUIBuilder.reset(); 1535 Window::dispose(); 1536 } 1537 1538 namespace 1539 { 1540 const sal_uInt16 ITEM_ID_VARIABLE = 1; 1541 const sal_uInt16 ITEM_ID_VALUE = 2; 1542 const sal_uInt16 ITEM_ID_TYPE = 3; 1543 } 1544 1545 WatchWindow::WatchWindow (Layout* pParent) 1546 : DockingWindow(pParent) 1547 , aWatchStr(IDEResId( RID_STR_REMOVEWATCH)) 1548 , aXEdit(VclPtr<ExtendedEdit>::Create(this, WB_BORDER | WB_3DLOOK)) 1549 , aRemoveWatchButton(VclPtr<ImageButton>::Create(this, WB_SMALLSTYLE)) 1550 , aTreeListBox(VclPtr<WatchTreeListBox>::Create(this, WB_BORDER | WB_3DLOOK | WB_HASBUTTONS | 1551 WB_HASLINES | WB_HSCROLL | WB_TABSTOP | 1552 WB_HASLINESATROOT | WB_HASBUTTONSATROOT)) 1553 , aHeaderBar(VclPtr<HeaderBar>::Create(this, WB_BUTTONSTYLE | WB_BORDER)) 1554 { 1555 aXEdit->SetAccessibleName(IDEResId(RID_STR_WATCHNAME)); 1556 aXEdit->SetHelpId(HID_BASICIDE_WATCHWINDOW_EDIT); 1557 aXEdit->SetSizePixel(aXEdit->LogicToPixel(Size(80, 12), MapMode(MapUnit::MapAppFont))); 1558 aTreeListBox->SetAccessibleName(IDEResId(RID_STR_WATCHNAME)); 1559 1560 long nTextLen = GetTextWidth( aWatchStr ) + DWBORDER + 3; 1561 aXEdit->SetPosPixel( Point( nTextLen, 3 ) ); 1562 aXEdit->SetAccHdl( LINK( this, WatchWindow, EditAccHdl ) ); 1563 aXEdit->GetAccelerator().InsertItem( 1, vcl::KeyCode( KEY_RETURN ) ); 1564 aXEdit->GetAccelerator().InsertItem( 2, vcl::KeyCode( KEY_ESCAPE ) ); 1565 aXEdit->Show(); 1566 1567 aRemoveWatchButton->Disable(); 1568 aRemoveWatchButton->SetClickHdl( LINK( this, WatchWindow, ButtonHdl ) ); 1569 aRemoveWatchButton->SetPosPixel( Point( nTextLen + aXEdit->GetSizePixel().Width() + 4, 2 ) ); 1570 aRemoveWatchButton->SetHelpId(HID_BASICIDE_REMOVEWATCH); 1571 aRemoveWatchButton->SetModeImage(Image(StockImage::Yes, RID_BMP_REMOVEWATCH)); 1572 aRemoveWatchButton->SetQuickHelpText(IDEResId(RID_STR_REMOVEWATCHTIP)); 1573 Size aSz( aRemoveWatchButton->GetModeImage().GetSizePixel() ); 1574 aSz.AdjustWidth(6 ); 1575 aSz.AdjustHeight(6 ); 1576 aRemoveWatchButton->SetSizePixel( aSz ); 1577 aRemoveWatchButton->Show(); 1578 1579 long nRWBtnSize = aRemoveWatchButton->GetModeImage().GetSizePixel().Height() + 10; 1580 nVirtToolBoxHeight = aXEdit->GetSizePixel().Height() + 7; 1581 1582 if ( nRWBtnSize > nVirtToolBoxHeight ) 1583 nVirtToolBoxHeight = nRWBtnSize; 1584 1585 aTreeListBox->SetHelpId(HID_BASICIDE_WATCHWINDOW_LIST); 1586 aTreeListBox->EnableInplaceEditing(true); 1587 aTreeListBox->SetSelectHdl( LINK( this, WatchWindow, TreeListHdl ) ); 1588 aTreeListBox->SetPosPixel( Point( DWBORDER, nVirtToolBoxHeight + nHeaderBarHeight ) ); 1589 aTreeListBox->SetHighlightRange( 1, 5 ); 1590 1591 Point aPnt( DWBORDER, nVirtToolBoxHeight + 1 ); 1592 aHeaderBar->SetPosPixel( aPnt ); 1593 aHeaderBar->SetEndDragHdl( LINK( this, WatchWindow, implEndDragHdl ) ); 1594 1595 long nVarTabWidth = 220; 1596 long nValueTabWidth = 100; 1597 long const nTypeTabWidth = 1250; 1598 aHeaderBar->InsertItem( ITEM_ID_VARIABLE, IDEResId(RID_STR_WATCHVARIABLE), nVarTabWidth ); 1599 aHeaderBar->InsertItem( ITEM_ID_VALUE, IDEResId(RID_STR_WATCHVALUE), nValueTabWidth ); 1600 aHeaderBar->InsertItem( ITEM_ID_TYPE, IDEResId(RID_STR_WATCHTYPE), nTypeTabWidth ); 1601 1602 long aTabPositions[] = { 0, nVarTabWidth, nVarTabWidth + nValueTabWidth }; 1603 aTreeListBox->SvHeaderTabListBox::SetTabs( SAL_N_ELEMENTS(aTabPositions), aTabPositions, MapUnit::MapPixel ); 1604 aTreeListBox->InitHeaderBar( aHeaderBar.get() ); 1605 1606 aTreeListBox->SetNodeDefaultImages( ); 1607 1608 aHeaderBar->Show(); 1609 1610 aTreeListBox->Show(); 1611 1612 SetText(IDEResId(RID_STR_WATCHNAME)); 1613 1614 SetHelpId( HID_BASICIDE_WATCHWINDOW ); 1615 1616 // make watch window keyboard accessible 1617 GetSystemWindow()->GetTaskPaneList()->AddWindow( this ); 1618 } 1619 1620 1621 WatchWindow::~WatchWindow() 1622 { 1623 disposeOnce(); 1624 } 1625 1626 void WatchWindow::dispose() 1627 { 1628 aXEdit.disposeAndClear(); 1629 aRemoveWatchButton.disposeAndClear(); 1630 aHeaderBar.disposeAndClear(); 1631 aTreeListBox.disposeAndClear(); 1632 if (!IsDisposed()) 1633 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this ); 1634 DockingWindow::dispose(); 1635 } 1636 1637 void WatchWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) 1638 { 1639 rRenderContext.DrawText(Point(DWBORDER, 7), aWatchStr); 1640 lcl_DrawIDEWindowFrame(this, rRenderContext); 1641 } 1642 1643 void WatchWindow::Resize() 1644 { 1645 Size aSz = GetOutputSizePixel(); 1646 Size aBoxSz( aSz.Width() - 2*DWBORDER, aSz.Height() - nVirtToolBoxHeight - DWBORDER ); 1647 1648 if ( aBoxSz.Width() < 4 ) 1649 aBoxSz.setWidth( 0 ); 1650 if ( aBoxSz.Height() < 4 ) 1651 aBoxSz.setHeight( 0 ); 1652 1653 aBoxSz.AdjustHeight( -nHeaderBarHeight ); 1654 aTreeListBox->SetSizePixel( aBoxSz ); 1655 aTreeListBox->GetHScroll()->SetPageSize( aTreeListBox->GetHScroll()->GetVisibleSize() ); 1656 1657 aBoxSz.setHeight( nHeaderBarHeight ); 1658 aHeaderBar->SetSizePixel( aBoxSz ); 1659 1660 Invalidate(); 1661 } 1662 1663 struct WatchItem 1664 { 1665 OUString maName; 1666 OUString maDisplayName; 1667 SbxObjectRef mpObject; 1668 std::vector<OUString> maMemberList; 1669 1670 SbxDimArrayRef mpArray; 1671 int nDimLevel; // 0 = Root 1672 int nDimCount; 1673 std::vector<short> vIndices; 1674 1675 WatchItem* mpArrayParentItem; 1676 1677 explicit WatchItem (OUString const& rName): 1678 maName(rName), 1679 nDimLevel(0), 1680 nDimCount(0), 1681 mpArrayParentItem(nullptr) 1682 { } 1683 1684 void clearWatchItem () 1685 { 1686 maMemberList.clear(); 1687 } 1688 1689 WatchItem* GetRootItem(); 1690 SbxDimArray* GetRootArray(); 1691 }; 1692 1693 WatchItem* WatchItem::GetRootItem() 1694 { 1695 WatchItem* pItem = mpArrayParentItem; 1696 while( pItem ) 1697 { 1698 if( pItem->mpArray.is() ) 1699 break; 1700 pItem = pItem->mpArrayParentItem; 1701 } 1702 return pItem; 1703 } 1704 1705 SbxDimArray* WatchItem::GetRootArray() 1706 { 1707 WatchItem* pRootItem = GetRootItem(); 1708 SbxDimArray* pRet = nullptr; 1709 if( pRootItem ) 1710 pRet = pRootItem->mpArray.get(); 1711 return pRet; 1712 } 1713 1714 void WatchWindow::AddWatch( const OUString& rVName ) 1715 { 1716 OUString aVar, aIndex; 1717 lcl_SeparateNameAndIndex( rVName, aVar, aIndex ); 1718 WatchItem* pWatchItem = new WatchItem(aVar); 1719 1720 OUString aWatchStr_ = aVar + "\t\t"; 1721 SvTreeListEntry* pNewEntry = aTreeListBox->InsertEntry( aWatchStr_, nullptr, true ); 1722 pNewEntry->SetUserData( pWatchItem ); 1723 1724 aTreeListBox->Select(pNewEntry); 1725 aTreeListBox->MakeVisible(pNewEntry); 1726 aRemoveWatchButton->Enable(); 1727 1728 UpdateWatches(false); 1729 } 1730 1731 void WatchWindow::RemoveSelectedWatch() 1732 { 1733 SvTreeListEntry* pEntry = aTreeListBox->GetCurEntry(); 1734 if ( pEntry ) 1735 { 1736 aTreeListBox->GetModel()->Remove( pEntry ); 1737 pEntry = aTreeListBox->GetCurEntry(); 1738 if ( pEntry ) 1739 aXEdit->SetText( static_cast<WatchItem*>(pEntry->GetUserData())->maName ); 1740 else 1741 aXEdit->SetText( OUString() ); 1742 if ( !aTreeListBox->GetEntryCount() ) 1743 aRemoveWatchButton->Disable(); 1744 } 1745 } 1746 1747 1748 IMPL_LINK( WatchWindow, ButtonHdl, Button *, pButton, void ) 1749 { 1750 if (pButton == aRemoveWatchButton.get()) 1751 if (SfxDispatcher* pDispatcher = GetDispatcher()) 1752 pDispatcher->Execute(SID_BASICIDE_REMOVEWATCH); 1753 } 1754 1755 IMPL_LINK_NOARG(WatchWindow, TreeListHdl, SvTreeListBox*, void) 1756 { 1757 SvTreeListEntry* pCurEntry = aTreeListBox->GetCurEntry(); 1758 if ( pCurEntry && pCurEntry->GetUserData() ) 1759 aXEdit->SetText( static_cast<WatchItem*>(pCurEntry->GetUserData())->maName ); 1760 } 1761 1762 IMPL_LINK_NOARG( WatchWindow, implEndDragHdl, HeaderBar *, void ) 1763 { 1764 const sal_Int32 TAB_WIDTH_MIN = 10; 1765 sal_Int32 nMaxWidth = 1766 aHeaderBar->GetSizePixel().getWidth() - 2 * TAB_WIDTH_MIN; 1767 1768 sal_Int32 nVariableWith = aHeaderBar->GetItemSize( ITEM_ID_VARIABLE ); 1769 if( nVariableWith < TAB_WIDTH_MIN ) 1770 aHeaderBar->SetItemSize( ITEM_ID_VARIABLE, TAB_WIDTH_MIN ); 1771 else if( nVariableWith > nMaxWidth ) 1772 aHeaderBar->SetItemSize( ITEM_ID_VARIABLE, nMaxWidth ); 1773 1774 sal_Int32 nValueWith = aHeaderBar->GetItemSize( ITEM_ID_VALUE ); 1775 if( nValueWith < TAB_WIDTH_MIN ) 1776 aHeaderBar->SetItemSize( ITEM_ID_VALUE, TAB_WIDTH_MIN ); 1777 else if( nValueWith > nMaxWidth ) 1778 aHeaderBar->SetItemSize( ITEM_ID_VALUE, nMaxWidth ); 1779 1780 if (aHeaderBar->GetItemSize( ITEM_ID_TYPE ) < TAB_WIDTH_MIN) 1781 aHeaderBar->SetItemSize( ITEM_ID_TYPE, TAB_WIDTH_MIN ); 1782 1783 sal_Int32 nPos = 0; 1784 sal_uInt16 nTabs = aHeaderBar->GetItemCount(); 1785 for( sal_uInt16 i = 1 ; i < nTabs ; ++i ) 1786 { 1787 nPos += aHeaderBar->GetItemSize( i ); 1788 aTreeListBox->SetTab( i, nPos, MapUnit::MapPixel ); 1789 } 1790 } 1791 1792 IMPL_LINK( WatchWindow, EditAccHdl, Accelerator&, rAcc, void ) 1793 { 1794 switch ( rAcc.GetCurKeyCode().GetCode() ) 1795 { 1796 case KEY_RETURN: 1797 { 1798 OUString aCurText( aXEdit->GetText() ); 1799 if ( !aCurText.isEmpty() ) 1800 { 1801 AddWatch( aCurText ); 1802 aXEdit->SetSelection( Selection( 0, 0xFFFF ) ); 1803 } 1804 } 1805 break; 1806 case KEY_ESCAPE: 1807 { 1808 aXEdit->SetText( OUString() ); 1809 } 1810 break; 1811 } 1812 } 1813 1814 void WatchWindow::UpdateWatches( bool bBasicStopped ) 1815 { 1816 aTreeListBox->UpdateWatches( bBasicStopped ); 1817 } 1818 1819 1820 // StackWindow 1821 1822 1823 StackWindow::StackWindow (Layout* pParent) : 1824 DockingWindow(pParent), 1825 aTreeListBox( VclPtr<SvTreeListBox>::Create(this, WB_BORDER | WB_3DLOOK | WB_HSCROLL | WB_TABSTOP) ), 1826 aStackStr( IDEResId( RID_STR_STACK ) ) 1827 { 1828 aTreeListBox->SetHelpId(HID_BASICIDE_STACKWINDOW_LIST); 1829 aTreeListBox->SetAccessibleName(IDEResId(RID_STR_STACKNAME)); 1830 aTreeListBox->SetPosPixel( Point( DWBORDER, nVirtToolBoxHeight ) ); 1831 aTreeListBox->SetHighlightRange(); 1832 aTreeListBox->SetSelectionMode( SelectionMode::NONE ); 1833 aTreeListBox->InsertEntry( OUString() ); 1834 aTreeListBox->Show(); 1835 1836 SetText(IDEResId(RID_STR_STACKNAME)); 1837 1838 SetHelpId( HID_BASICIDE_STACKWINDOW ); 1839 1840 // make stack window keyboard accessible 1841 GetSystemWindow()->GetTaskPaneList()->AddWindow( this ); 1842 } 1843 1844 1845 StackWindow::~StackWindow() 1846 { 1847 disposeOnce(); 1848 } 1849 1850 void StackWindow::dispose() 1851 { 1852 if (!IsDisposed()) 1853 GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this ); 1854 aTreeListBox.disposeAndClear(); 1855 DockingWindow::dispose(); 1856 } 1857 1858 void StackWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) 1859 { 1860 rRenderContext.DrawText(Point(DWBORDER, 7), aStackStr); 1861 lcl_DrawIDEWindowFrame(this, rRenderContext); 1862 } 1863 1864 void StackWindow::Resize() 1865 { 1866 Size aSz = GetOutputSizePixel(); 1867 Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - nVirtToolBoxHeight - DWBORDER); 1868 1869 if ( aBoxSz.Width() < 4 ) 1870 aBoxSz.setWidth( 0 ); 1871 if ( aBoxSz.Height() < 4 ) 1872 aBoxSz.setHeight( 0 ); 1873 1874 aTreeListBox->SetSizePixel( aBoxSz ); 1875 1876 Invalidate(); 1877 } 1878 1879 void StackWindow::UpdateCalls() 1880 { 1881 aTreeListBox->SetUpdateMode(false); 1882 aTreeListBox->Clear(); 1883 1884 if (StarBASIC::IsRunning()) 1885 { 1886 ErrCode eOld = SbxBase::GetError(); 1887 aTreeListBox->SetSelectionMode( SelectionMode::Single ); 1888 1889 sal_Int32 nScope = 0; 1890 SbMethod* pMethod = StarBASIC::GetActiveMethod( nScope ); 1891 while ( pMethod ) 1892 { 1893 OUStringBuffer aEntry( OUString::number(nScope )); 1894 if ( aEntry.getLength() < 2 ) 1895 aEntry.insert(0, " "); 1896 aEntry.append(": ").append(pMethod->GetName()); 1897 SbxArray* pParams = pMethod->GetParameters(); 1898 SbxInfo* pInfo = pMethod->GetInfo(); 1899 if ( pParams ) 1900 { 1901 aEntry.append("("); 1902 // 0 is the sub's name... 1903 for ( sal_uInt16 nParam = 1; nParam < pParams->Count(); nParam++ ) 1904 { 1905 SbxVariable* pVar = pParams->Get( nParam ); 1906 assert(pVar && "Parameter?!"); 1907 if ( !pVar->GetName().isEmpty() ) 1908 { 1909 aEntry.append(pVar->GetName()); 1910 } 1911 else if ( pInfo ) 1912 { 1913 const SbxParamInfo* pParam = pInfo->GetParam( nParam ); 1914 if ( pParam ) 1915 { 1916 aEntry.append(pParam->aName); 1917 } 1918 } 1919 aEntry.append("="); 1920 SbxDataType eType = pVar->GetType(); 1921 if( eType & SbxARRAY ) 1922 { 1923 aEntry.append("..."); 1924 } 1925 else if( eType != SbxOBJECT ) 1926 { 1927 aEntry.append(pVar->GetOUString()); 1928 } 1929 if ( nParam < ( pParams->Count() - 1 ) ) 1930 { 1931 aEntry.append(", "); 1932 } 1933 } 1934 aEntry.append(")"); 1935 } 1936 aTreeListBox->InsertEntry( aEntry.makeStringAndClear() ); 1937 nScope++; 1938 pMethod = StarBASIC::GetActiveMethod( nScope ); 1939 } 1940 1941 SbxBase::ResetError(); 1942 if( eOld != ERRCODE_NONE ) 1943 SbxBase::SetError( eOld ); 1944 } 1945 else 1946 { 1947 aTreeListBox->SetSelectionMode( SelectionMode::NONE ); 1948 aTreeListBox->InsertEntry( OUString() ); 1949 } 1950 1951 aTreeListBox->SetUpdateMode(true); 1952 } 1953 1954 ComplexEditorWindow::ComplexEditorWindow( ModulWindow* pParent ) : 1955 Window( pParent, WB_3DLOOK | WB_CLIPCHILDREN ), 1956 aBrkWindow(VclPtr<BreakPointWindow>::Create(this, pParent)), 1957 aLineNumberWindow(VclPtr<LineNumberWindow>::Create(this, pParent)), 1958 aEdtWindow(VclPtr<EditorWindow>::Create(this, pParent)), 1959 aEWVScrollBar( VclPtr<ScrollBar>::Create(this, WB_VSCROLL | WB_DRAG) ) 1960 { 1961 aEdtWindow->Show(); 1962 aBrkWindow->Show(); 1963 1964 aEWVScrollBar->SetLineSize(nScrollLine); 1965 aEWVScrollBar->SetPageSize(nScrollPage); 1966 aEWVScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) ); 1967 aEWVScrollBar->Show(); 1968 } 1969 1970 ComplexEditorWindow::~ComplexEditorWindow() 1971 { 1972 disposeOnce(); 1973 } 1974 1975 void ComplexEditorWindow::dispose() 1976 { 1977 aBrkWindow.disposeAndClear(); 1978 aLineNumberWindow.disposeAndClear(); 1979 aEdtWindow.disposeAndClear(); 1980 aEWVScrollBar.disposeAndClear(); 1981 vcl::Window::dispose(); 1982 } 1983 1984 void ComplexEditorWindow::Resize() 1985 { 1986 Size aOutSz = GetOutputSizePixel(); 1987 Size aSz(aOutSz); 1988 aSz.AdjustWidth( -(2*DWBORDER) ); 1989 aSz.AdjustHeight( -(2*DWBORDER) ); 1990 long nBrkWidth = 20; 1991 long nSBWidth = aEWVScrollBar->GetSizePixel().Width(); 1992 1993 Size aBrkSz(nBrkWidth, aSz.Height()); 1994 1995 Size aLnSz(aLineNumberWindow->GetWidth(), aSz.Height()); 1996 1997 if (aLineNumberWindow->IsVisible()) 1998 { 1999 aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz ); 2000 aLineNumberWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aLnSz); 2001 Size aEWSz(aSz.Width() - nBrkWidth - aLineNumberWindow->GetWidth() - nSBWidth + 2, aSz.Height()); 2002 aEdtWindow->SetPosSizePixel( Point( DWBORDER + aBrkSz.Width() + aLnSz.Width() - 1, DWBORDER ), aEWSz ); 2003 } 2004 else 2005 { 2006 aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz ); 2007 Size aEWSz(aSz.Width() - nBrkWidth - nSBWidth + 2, aSz.Height()); 2008 aEdtWindow->SetPosSizePixel(Point(DWBORDER + aBrkSz.Width() - 1, DWBORDER), aEWSz); 2009 } 2010 2011 aEWVScrollBar->SetPosSizePixel( Point( aOutSz.Width() - DWBORDER - nSBWidth, DWBORDER ), Size( nSBWidth, aSz.Height() ) ); 2012 } 2013 2014 IMPL_LINK(ComplexEditorWindow, ScrollHdl, ScrollBar *, pCurScrollBar, void ) 2015 { 2016 if (aEdtWindow->GetEditView()) 2017 { 2018 DBG_ASSERT( pCurScrollBar == aEWVScrollBar.get(), "Who is scrolling?" ); 2019 long nDiff = aEdtWindow->GetEditView()->GetStartDocPos().Y() - pCurScrollBar->GetThumbPos(); 2020 aEdtWindow->GetEditView()->Scroll( 0, nDiff ); 2021 aBrkWindow->DoScroll( nDiff ); 2022 aLineNumberWindow->DoScroll( nDiff ); 2023 aEdtWindow->GetEditView()->ShowCursor(false); 2024 pCurScrollBar->SetThumbPos( aEdtWindow->GetEditView()->GetStartDocPos().Y() ); 2025 } 2026 } 2027 2028 void ComplexEditorWindow::DataChanged(DataChangedEvent const & rDCEvt) 2029 { 2030 Window::DataChanged(rDCEvt); 2031 if (rDCEvt.GetType() == DataChangedEventType::SETTINGS 2032 && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) 2033 { 2034 Color aColor(GetSettings().GetStyleSettings().GetFaceColor()); 2035 const AllSettings* pOldSettings = rDCEvt.GetOldSettings(); 2036 if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFaceColor()) 2037 { 2038 SetBackground(Wallpaper(aColor)); 2039 Invalidate(); 2040 } 2041 } 2042 } 2043 2044 void ComplexEditorWindow::SetLineNumberDisplay(bool b) 2045 { 2046 aLineNumberWindow->Show(b); 2047 Resize(); 2048 } 2049 2050 uno::Reference< awt::XWindowPeer > 2051 EditorWindow::GetComponentInterface(bool bCreate) 2052 { 2053 uno::Reference< awt::XWindowPeer > xPeer( 2054 Window::GetComponentInterface(false)); 2055 if (!xPeer.is() && bCreate) 2056 { 2057 // Make sure edit engine and view are available: 2058 if (!pEditEngine) 2059 CreateEditEngine(); 2060 2061 xPeer = svt::createTextWindowPeer(*GetEditView()); 2062 SetComponentInterface(xPeer); 2063 } 2064 return xPeer; 2065 } 2066 2067 2068 // WatchTreeListBox 2069 2070 2071 WatchTreeListBox::WatchTreeListBox( vcl::Window* pParent, WinBits nWinBits ) 2072 : SvHeaderTabListBox( pParent, nWinBits ) 2073 {} 2074 2075 WatchTreeListBox::~WatchTreeListBox() 2076 { 2077 disposeOnce(); 2078 } 2079 2080 void WatchTreeListBox::dispose() 2081 { 2082 // Destroy user data 2083 SvTreeListEntry* pEntry = First(); 2084 while ( pEntry ) 2085 { 2086 delete static_cast<WatchItem*>(pEntry->GetUserData()); 2087 pEntry->SetUserData(nullptr); 2088 pEntry = Next( pEntry ); 2089 } 2090 SvHeaderTabListBox::dispose(); 2091 } 2092 2093 void WatchTreeListBox::SetTabs() 2094 { 2095 SvHeaderTabListBox::SetTabs(); 2096 sal_uInt16 nTabCount_ = aTabs.size(); 2097 for( sal_uInt16 i = 0 ; i < nTabCount_ ; i++ ) 2098 { 2099 SvLBoxTab* pTab = aTabs[i].get(); 2100 if( i == 2 ) 2101 pTab->nFlags |= SvLBoxTabFlags::EDITABLE; 2102 else 2103 pTab->nFlags &= ~SvLBoxTabFlags::EDITABLE; 2104 } 2105 } 2106 2107 void WatchTreeListBox::RequestingChildren( SvTreeListEntry * pParent ) 2108 { 2109 if( !StarBASIC::IsRunning() ) 2110 return; 2111 2112 if( GetChildCount( pParent ) > 0 ) 2113 return; 2114 2115 SvTreeListEntry* pEntry = pParent; 2116 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData()); 2117 2118 SbxDimArray* pArray = pItem->mpArray.get(); 2119 SbxDimArray* pRootArray = pItem->GetRootArray(); 2120 bool bArrayIsRootArray = false; 2121 if( !pArray && pRootArray ) 2122 { 2123 pArray = pRootArray; 2124 bArrayIsRootArray = true; 2125 } 2126 2127 SbxObject* pObj = pItem->mpObject.get(); 2128 if( pObj ) 2129 { 2130 createAllObjectProperties( pObj ); 2131 SbxArray* pProps = pObj->GetProperties(); 2132 sal_uInt16 nPropCount = pProps->Count(); 2133 if ( nPropCount >= 3 && 2134 pProps->Get( nPropCount -1 )->GetName().equalsIgnoreAsciiCase( "Dbg_Methods" ) && 2135 pProps->Get( nPropCount -2 )->GetName().equalsIgnoreAsciiCase( "Dbg_Properties" ) && 2136 pProps->Get( nPropCount -3 )->GetName().equalsIgnoreAsciiCase( "Dbg_SupportedInterfaces" ) ) 2137 { 2138 nPropCount -= 3; 2139 } 2140 pItem->maMemberList.reserve(nPropCount); 2141 2142 for( sal_uInt16 i = 0 ; i < nPropCount ; ++i ) 2143 { 2144 SbxVariable* pVar = pProps->Get( i ); 2145 2146 pItem->maMemberList.push_back(pVar->GetName()); 2147 OUString const& rName = pItem->maMemberList.back(); 2148 SvTreeListEntry* pChildEntry = SvTreeListBox::InsertEntry( rName, pEntry ); 2149 pChildEntry->SetUserData(new WatchItem(rName)); 2150 } 2151 if( nPropCount > 0 ) 2152 { 2153 UpdateWatches(); 2154 } 2155 } 2156 else if( pArray ) 2157 { 2158 sal_uInt16 nElementCount = 0; 2159 2160 // Loop through indices of current level 2161 int nParentLevel = bArrayIsRootArray ? pItem->nDimLevel : 0; 2162 int nThisLevel = nParentLevel + 1; 2163 sal_Int32 nMin, nMax; 2164 pArray->GetDim32( nThisLevel, nMin, nMax ); 2165 for( sal_Int32 i = nMin ; i <= nMax ; i++ ) 2166 { 2167 WatchItem* pChildItem = new WatchItem(pItem->maName); 2168 2169 // Copy data and create name 2170 2171 OUStringBuffer aIndexStr = "("; 2172 pChildItem->mpArrayParentItem = pItem; 2173 pChildItem->nDimLevel = nThisLevel; 2174 pChildItem->nDimCount = pItem->nDimCount; 2175 pChildItem->vIndices.resize(pChildItem->nDimCount); 2176 sal_Int32 j; 2177 for( j = 0 ; j < nParentLevel ; j++ ) 2178 { 2179 short n = pChildItem->vIndices[j] = pItem->vIndices[j]; 2180 aIndexStr.append(OUString::number( n )).append(","); 2181 } 2182 pChildItem->vIndices[nParentLevel] = sal::static_int_cast<short>( i ); 2183 aIndexStr.append(OUString::number( i )).append(")"); 2184 2185 OUString aDisplayName; 2186 WatchItem* pArrayRootItem = pChildItem->GetRootItem(); 2187 if( pArrayRootItem && pArrayRootItem->mpArrayParentItem ) 2188 aDisplayName = pItem->maDisplayName; 2189 else 2190 aDisplayName = pItem->maName; 2191 aDisplayName += aIndexStr; 2192 pChildItem->maDisplayName = aDisplayName; 2193 2194 SvTreeListEntry* pChildEntry = SvTreeListBox::InsertEntry( aDisplayName, pEntry ); 2195 nElementCount++; 2196 pChildEntry->SetUserData( pChildItem ); 2197 } 2198 if( nElementCount > 0 ) 2199 { 2200 UpdateWatches(); 2201 } 2202 } 2203 } 2204 2205 SbxBase* WatchTreeListBox::ImplGetSBXForEntry( SvTreeListEntry* pEntry, bool& rbArrayElement ) 2206 { 2207 SbxBase* pSBX = nullptr; 2208 rbArrayElement = false; 2209 2210 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData()); 2211 OUString aVName( pItem->maName ); 2212 2213 SvTreeListEntry* pParentEntry = GetParent( pEntry ); 2214 WatchItem* pParentItem = pParentEntry ? static_cast<WatchItem*>(pParentEntry->GetUserData()) : nullptr; 2215 if( pParentItem ) 2216 { 2217 SbxObject* pObj = pParentItem->mpObject.get(); 2218 SbxDimArray* pArray; 2219 if( pObj ) 2220 { 2221 pSBX = pObj->Find( aVName, SbxClassType::DontCare ); 2222 if (SbxVariable const* pVar = IsSbxVariable(pSBX)) 2223 { 2224 // Force getting value 2225 SbxValues aRes; 2226 aRes.eType = SbxVOID; 2227 pVar->Get( aRes ); 2228 } 2229 } 2230 // Array? 2231 else if( (pArray = pItem->GetRootArray()) != nullptr ) 2232 { 2233 rbArrayElement = true; 2234 if( pParentItem->nDimLevel + 1 == pParentItem->nDimCount ) 2235 pSBX = pArray->Get(pItem->vIndices.empty() ? nullptr : &*pItem->vIndices.begin()); 2236 } 2237 } 2238 else 2239 { 2240 pSBX = StarBASIC::FindSBXInCurrentScope( aVName ); 2241 } 2242 return pSBX; 2243 } 2244 2245 bool WatchTreeListBox::EditingEntry( SvTreeListEntry* pEntry, Selection& ) 2246 { 2247 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData()); 2248 2249 bool bEdit = false; 2250 if ( StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError() ) 2251 { 2252 // No out of scope entries 2253 bool bArrayElement; 2254 SbxBase* pSbx = ImplGetSBXForEntry( pEntry, bArrayElement ); 2255 if (IsSbxVariable(pSbx) || bArrayElement) 2256 { 2257 // Accept no objects and only end nodes of arrays for editing 2258 if( !pItem->mpObject.is() && ( !pItem->mpArray.is() || pItem->nDimLevel == pItem->nDimCount ) ) 2259 { 2260 aEditingRes = SvHeaderTabListBox::GetEntryText( pEntry, ITEM_ID_VALUE-1 ); 2261 aEditingRes = comphelper::string::strip(aEditingRes, ' '); 2262 bEdit = true; 2263 } 2264 } 2265 } 2266 2267 return bEdit; 2268 } 2269 2270 bool WatchTreeListBox::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) 2271 { 2272 OUString aResult = comphelper::string::strip(rNewText, ' '); 2273 2274 sal_uInt16 nResultLen = aResult.getLength(); 2275 sal_Unicode cFirst = aResult[0]; 2276 sal_Unicode cLast = aResult[ nResultLen - 1 ]; 2277 if( cFirst == '\"' && cLast == '\"' ) 2278 aResult = aResult.copy( 1, nResultLen - 2 ); 2279 2280 if (aResult == aEditingRes) 2281 return false; 2282 2283 bool bArrayElement; 2284 SbxBase* pSBX = ImplGetSBXForEntry( pEntry, bArrayElement ); 2285 2286 if (SbxVariable* pVar = IsSbxVariable(pSBX)) 2287 { 2288 SbxDataType eType = pVar->GetType(); 2289 if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxOBJECT) 2290 && ( eType & SbxARRAY ) == 0 ) 2291 { 2292 // If the type is variable, the conversion of the SBX does not matter, 2293 // else the string is converted. 2294 pVar->PutStringExt( aResult ); 2295 } 2296 } 2297 2298 if ( SbxBase::IsError() ) 2299 { 2300 SbxBase::ResetError(); 2301 } 2302 2303 UpdateWatches(); 2304 2305 // The text should never be taken/copied 1:1, 2306 // as the UpdateWatches will be lost 2307 return false; 2308 } 2309 2310 2311 namespace 2312 { 2313 2314 void implCollapseModifiedObjectEntry( SvTreeListEntry* pParent, WatchTreeListBox* pThis ) 2315 { 2316 pThis->Collapse( pParent ); 2317 2318 SvTreeList* pModel = pThis->GetModel(); 2319 SvTreeListEntry* pDeleteEntry; 2320 while( (pDeleteEntry = pThis->SvTreeListBox::GetEntry( pParent, 0 )) != nullptr ) 2321 { 2322 implCollapseModifiedObjectEntry( pDeleteEntry, pThis ); 2323 2324 delete static_cast<WatchItem*>(pDeleteEntry->GetUserData()); 2325 pModel->Remove( pDeleteEntry ); 2326 } 2327 } 2328 2329 OUString implCreateTypeStringForDimArray( WatchItem* pItem, SbxDataType eType ) 2330 { 2331 OUString aRetStr = getBasicTypeName( eType ); 2332 2333 SbxDimArray* pArray = pItem->mpArray.get(); 2334 if( !pArray ) 2335 pArray = pItem->GetRootArray(); 2336 if( pArray ) 2337 { 2338 int nDimLevel = pItem->nDimLevel; 2339 int nDims = pItem->nDimCount; 2340 if( nDimLevel < nDims ) 2341 { 2342 aRetStr += "("; 2343 for( int i = nDimLevel ; i < nDims ; i++ ) 2344 { 2345 short nMin, nMax; 2346 pArray->GetDim( sal::static_int_cast<short>( i+1 ), nMin, nMax ); 2347 aRetStr += OUString::number(nMin) + " to " + OUString::number(nMax); 2348 if( i < nDims - 1 ) 2349 aRetStr += ", "; 2350 } 2351 aRetStr += ")"; 2352 } 2353 } 2354 return aRetStr; 2355 } 2356 2357 void implEnableChildren( SvTreeListEntry* pEntry, bool bEnable ) 2358 { 2359 if( bEnable ) 2360 { 2361 pEntry->SetFlags( 2362 (pEntry->GetFlags() & ~SvTLEntryFlags(SvTLEntryFlags::NO_NODEBMP | SvTLEntryFlags::HAD_CHILDREN)) 2363 | SvTLEntryFlags::CHILDREN_ON_DEMAND ); 2364 } 2365 else 2366 { 2367 pEntry->SetFlags( pEntry->GetFlags() & ~SvTLEntryFlags::CHILDREN_ON_DEMAND ); 2368 } 2369 } 2370 2371 } // namespace 2372 2373 void WatchTreeListBox::UpdateWatches( bool bBasicStopped ) 2374 { 2375 SbMethod* pCurMethod = StarBASIC::GetActiveMethod(); 2376 2377 ErrCode eOld = SbxBase::GetError(); 2378 setBasicWatchMode( true ); 2379 2380 SvTreeListEntry* pEntry = First(); 2381 while ( pEntry ) 2382 { 2383 WatchItem* pItem = static_cast<WatchItem*>(pEntry->GetUserData()); 2384 DBG_ASSERT( !pItem->maName.isEmpty(), "Var? - Must not be empty!" ); 2385 OUString aWatchStr; 2386 OUString aTypeStr; 2387 if ( pCurMethod ) 2388 { 2389 bool bArrayElement; 2390 SbxBase* pSBX = ImplGetSBXForEntry( pEntry, bArrayElement ); 2391 2392 // Array? If no end node create type string 2393 if( bArrayElement && pItem->nDimLevel < pItem->nDimCount ) 2394 { 2395 SbxDimArray* pRootArray = pItem->GetRootArray(); 2396 SbxDataType eType = pRootArray->GetType(); 2397 aTypeStr = implCreateTypeStringForDimArray( pItem, eType ); 2398 implEnableChildren( pEntry, true ); 2399 } 2400 2401 bool bCollapse = false; 2402 if (SbxVariable const* pVar = IsSbxVariable(pSBX)) 2403 { 2404 // extra treatment of arrays 2405 SbxDataType eType = pVar->GetType(); 2406 if ( eType & SbxARRAY ) 2407 { 2408 // consider multidimensional arrays! 2409 if (SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>(pVar->GetObject())) 2410 { 2411 SbxDimArray* pOldArray = pItem->mpArray.get(); 2412 2413 bool bArrayChanged = false; 2414 if (pOldArray != nullptr) 2415 { 2416 // Compare Array dimensions to see if array has changed 2417 // Can be a copy, so comparing pointers does not work 2418 sal_uInt16 nOldDims = pOldArray->GetDims(); 2419 sal_uInt16 nNewDims = pNewArray->GetDims(); 2420 if( nOldDims != nNewDims ) 2421 { 2422 bArrayChanged = true; 2423 } 2424 else 2425 { 2426 for( int i = 0 ; i < nOldDims ; i++ ) 2427 { 2428 short nOldMin, nOldMax; 2429 short nNewMin, nNewMax; 2430 2431 pOldArray->GetDim( sal::static_int_cast<short>( i+1 ), nOldMin, nOldMax ); 2432 pNewArray->GetDim( sal::static_int_cast<short>( i+1 ), nNewMin, nNewMax ); 2433 if( nOldMin != nNewMin || nOldMax != nNewMax ) 2434 { 2435 bArrayChanged = true; 2436 break; 2437 } 2438 } 2439 } 2440 } 2441 else 2442 { 2443 bArrayChanged = true; 2444 } 2445 implEnableChildren(pEntry, true); 2446 // #i37227 Clear always and replace array 2447 if( pNewArray != pOldArray ) 2448 { 2449 pItem->clearWatchItem(); 2450 implEnableChildren(pEntry, true); 2451 2452 pItem->mpArray = pNewArray; 2453 sal_uInt16 nDims = pNewArray->GetDims(); 2454 pItem->nDimLevel = 0; 2455 pItem->nDimCount = nDims; 2456 } 2457 if( bArrayChanged && pOldArray != nullptr ) 2458 { 2459 bCollapse = true; 2460 } 2461 aTypeStr = implCreateTypeStringForDimArray( pItem, eType ); 2462 } 2463 else 2464 { 2465 aWatchStr += "<?>"; 2466 } 2467 } 2468 else if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) ) 2469 { 2470 if (SbxObject* pObj = dynamic_cast<SbxObject*>(pVar->GetObject())) 2471 { 2472 if ( pItem->mpObject.is() && !pItem->maMemberList.empty() ) 2473 { 2474 bool bObjChanged = false; // Check if member list has changed 2475 SbxArray* pProps = pObj->GetProperties(); 2476 sal_uInt16 nPropCount = pProps->Count(); 2477 for( sal_uInt16 i = 0 ; i < nPropCount - 3 ; i++ ) 2478 { 2479 SbxVariable* pVar_ = pProps->Get( i ); 2480 if( pItem->maMemberList[i] != pVar_->GetName() ) 2481 { 2482 bObjChanged = true; 2483 break; 2484 } 2485 } 2486 if( bObjChanged ) 2487 { 2488 bCollapse = true; 2489 } 2490 } 2491 2492 pItem->mpObject = pObj; 2493 implEnableChildren( pEntry, true ); 2494 aTypeStr = getBasicObjectTypeName( pObj ); 2495 } 2496 else 2497 { 2498 aWatchStr = "Null"; 2499 if( pItem->mpObject.is() ) 2500 { 2501 bCollapse = true; 2502 pItem->clearWatchItem(); 2503 2504 implEnableChildren( pEntry, false ); 2505 } 2506 } 2507 } 2508 else 2509 { 2510 if( pItem->mpObject.is() ) 2511 { 2512 bCollapse = true; 2513 pItem->clearWatchItem(); 2514 2515 implEnableChildren( pEntry, false ); 2516 } 2517 2518 bool bString = (static_cast<sal_uInt8>(eType) == sal_uInt8(SbxSTRING)); 2519 OUString aStrStr( "\"" ); 2520 if( bString ) 2521 { 2522 aWatchStr += aStrStr; 2523 } 2524 aWatchStr += pVar->GetOUString(); 2525 if( bString ) 2526 { 2527 aWatchStr += aStrStr; 2528 } 2529 } 2530 if( aTypeStr.isEmpty() ) 2531 { 2532 if( !pVar->IsFixed() ) 2533 { 2534 aTypeStr = "Variant/"; 2535 } 2536 aTypeStr += getBasicTypeName( pVar->GetType() ); 2537 } 2538 } 2539 else if( !bArrayElement ) 2540 { 2541 aWatchStr += "<Out of Scope>"; 2542 } 2543 2544 if( bCollapse ) 2545 { 2546 implCollapseModifiedObjectEntry( pEntry, this ); 2547 } 2548 2549 } 2550 else if( bBasicStopped ) 2551 { 2552 if( pItem->mpObject.is() || pItem->mpArray.is() ) 2553 { 2554 implCollapseModifiedObjectEntry( pEntry, this ); 2555 pItem->mpObject = nullptr; 2556 } 2557 } 2558 2559 SvHeaderTabListBox::SetEntryText( aWatchStr, pEntry, ITEM_ID_VALUE-1 ); 2560 SvHeaderTabListBox::SetEntryText( aTypeStr, pEntry, ITEM_ID_TYPE-1 ); 2561 2562 pEntry = Next( pEntry ); 2563 } 2564 2565 // Force redraw 2566 Invalidate(); 2567 2568 SbxBase::ResetError(); 2569 if( eOld != ERRCODE_NONE ) 2570 SbxBase::SetError( eOld ); 2571 setBasicWatchMode( false ); 2572 } 2573 2574 CodeCompleteListBox::CodeCompleteListBox( CodeCompleteWindow* pPar ) 2575 : ListBox(pPar, WB_SORT | WB_BORDER ), 2576 pCodeCompleteWindow( pPar ) 2577 { 2578 SetDoubleClickHdl(LINK(this, CodeCompleteListBox, ImplDoubleClickHdl)); 2579 SetSelectHdl(LINK(this, CodeCompleteListBox, ImplSelectHdl)); 2580 } 2581 2582 CodeCompleteListBox::~CodeCompleteListBox() 2583 { 2584 disposeOnce(); 2585 } 2586 2587 void CodeCompleteListBox::dispose() 2588 { 2589 pCodeCompleteWindow.clear(); 2590 ListBox::dispose(); 2591 } 2592 2593 IMPL_LINK_NOARG(CodeCompleteListBox, ImplDoubleClickHdl, ListBox&, void) 2594 { 2595 InsertSelectedEntry(); 2596 } 2597 2598 IMPL_LINK_NOARG(CodeCompleteListBox, ImplSelectHdl, ListBox&, void) 2599 {//give back the focus to the parent 2600 pCodeCompleteWindow->pParent->GrabFocus(); 2601 } 2602 2603 TextView* CodeCompleteListBox::GetParentEditView() 2604 { 2605 return pCodeCompleteWindow->pParent->GetEditView(); 2606 } 2607 2608 void CodeCompleteListBox::InsertSelectedEntry() 2609 { 2610 if( !aFuncBuffer.isEmpty() ) 2611 { 2612 // if the user typed in something: remove, and insert 2613 GetParentEditView()->SetSelection( pCodeCompleteWindow->pParent->GetLastHighlightPortionTextSelection() ); 2614 GetParentEditView()->DeleteSelected(); 2615 2616 if( !GetSelectedEntry().isEmpty() ) 2617 {//if the user selected something 2618 GetParentEditView()->InsertText( GetSelectedEntry() ); 2619 } 2620 } 2621 else 2622 { 2623 if( !GetSelectedEntry().isEmpty() ) 2624 {//if the user selected something 2625 GetParentEditView()->InsertText( GetSelectedEntry() ); 2626 } 2627 } 2628 HideAndRestoreFocus(); 2629 } 2630 2631 void CodeCompleteListBox::SetMatchingEntries() 2632 { 2633 for(sal_Int32 i=0; i< GetEntryCount(); ++i) 2634 { 2635 OUString sEntry = GetEntry(i); 2636 if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer.toString() ) ) 2637 { 2638 SelectEntry(sEntry); 2639 break; 2640 } 2641 } 2642 } 2643 2644 void CodeCompleteListBox::KeyInput( const KeyEvent& rKeyEvt ) 2645 { 2646 sal_Unicode aChar = rKeyEvt.GetKeyCode().GetCode(); 2647 if( (( aChar >= KEY_A ) && ( aChar <= KEY_Z )) 2648 || ((aChar >= KEY_0) && (aChar <= KEY_9)) ) 2649 { 2650 aFuncBuffer.append(rKeyEvt.GetCharCode()); 2651 SetMatchingEntries(); 2652 } 2653 else 2654 { 2655 switch( aChar ) 2656 { 2657 case KEY_ESCAPE: // hide, do nothing 2658 HideAndRestoreFocus(); 2659 break; 2660 case KEY_RIGHT: 2661 { 2662 TextSelection aTextSelection( GetParentEditView()->GetSelection() ); 2663 if( aTextSelection.GetEnd().GetPara() != pCodeCompleteWindow->GetTextSelection().GetEnd().GetPara()-1 ) 2664 { 2665 HideAndRestoreFocus(); 2666 } 2667 break; 2668 } 2669 case KEY_LEFT: 2670 { 2671 TextSelection aTextSelection( GetParentEditView()->GetSelection() ); 2672 if( aTextSelection.GetStart().GetIndex()-1 < pCodeCompleteWindow->GetTextSelection().GetStart().GetIndex() ) 2673 {//leave the cursor where it is 2674 HideAndRestoreFocus(); 2675 } 2676 break; 2677 } 2678 case KEY_TAB: 2679 { 2680 TextSelection aTextSelection = pCodeCompleteWindow->pParent->GetLastHighlightPortionTextSelection(); 2681 OUString sTypedText = pCodeCompleteWindow->pParent->GetEditEngine()->GetText(aTextSelection); 2682 if( !aFuncBuffer.isEmpty() ) 2683 { 2684 sal_Int32 nInd = GetSelectedEntryPos(); 2685 if( nInd != LISTBOX_ENTRY_NOTFOUND ) 2686 {//if there is something selected 2687 bool bFound = false; 2688 if( nInd == GetEntryCount() ) 2689 nInd = 0; 2690 for( sal_Int32 i = nInd; i != GetEntryCount(); ++i ) 2691 { 2692 OUString sEntry = GetEntry(i); 2693 if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer.toString() ) 2694 && (aFuncBuffer.toString() != sTypedText) && (i != nInd) ) 2695 { 2696 SelectEntry( sEntry ); 2697 bFound = true; 2698 break; 2699 } 2700 } 2701 if( !bFound ) 2702 SetMatchingEntries(); 2703 2704 GetParentEditView()->SetSelection( aTextSelection ); 2705 GetParentEditView()->DeleteSelected(); 2706 GetParentEditView()->InsertText( GetSelectedEntry() ); 2707 } 2708 } 2709 break; 2710 } 2711 case KEY_SPACE: 2712 HideAndRestoreFocus(); 2713 break; 2714 case KEY_BACKSPACE: case KEY_DELETE: 2715 if( !aFuncBuffer.isEmpty() ) 2716 { 2717 //if there was something inserted by tab: add it to aFuncBuffer 2718 TextSelection aSel( GetParentEditView()->GetSelection() ); 2719 TextPaM aEnd( GetParentEditView()->CursorEndOfLine(pCodeCompleteWindow->GetTextSelection().GetEnd()) ); 2720 GetParentEditView()->SetSelection(TextSelection(pCodeCompleteWindow->GetTextSelection().GetStart(), aEnd ) ); 2721 OUString aTabInsertedStr( GetParentEditView()->GetSelected() ); 2722 GetParentEditView()->SetSelection( aSel ); 2723 2724 if( !aTabInsertedStr.isEmpty() && aTabInsertedStr != aFuncBuffer.toString() ) 2725 { 2726 aFuncBuffer = aTabInsertedStr; 2727 } 2728 aFuncBuffer.remove(aFuncBuffer.getLength()-1, 1); 2729 SetMatchingEntries(); 2730 } 2731 else 2732 pCodeCompleteWindow->ClearAndHide(); 2733 break; 2734 case KEY_RETURN: 2735 InsertSelectedEntry(); 2736 break; 2737 case KEY_UP: case KEY_DOWN: 2738 NotifyEvent nEvt( MouseNotifyEvent::KEYINPUT, nullptr, &rKeyEvt ); 2739 PreNotify(nEvt); 2740 break; 2741 } 2742 } 2743 ListBox::KeyInput(rKeyEvt); 2744 } 2745 2746 void CodeCompleteListBox::HideAndRestoreFocus() 2747 { 2748 pCodeCompleteWindow->Hide(); 2749 pCodeCompleteWindow->pParent->GrabFocus(); 2750 } 2751 2752 CodeCompleteWindow::CodeCompleteWindow( EditorWindow* pPar ) 2753 : Window( pPar ), 2754 pParent( pPar ), 2755 pListBox( VclPtr<CodeCompleteListBox>::Create(this) ) 2756 { 2757 SetSizePixel( Size(151,151) ); //default, later it changes 2758 InitListBox(); 2759 } 2760 2761 CodeCompleteWindow::~CodeCompleteWindow() 2762 { 2763 disposeOnce(); 2764 } 2765 2766 void CodeCompleteWindow::dispose() 2767 { 2768 pListBox.disposeAndClear(); 2769 pParent.clear(); 2770 vcl::Window::dispose(); 2771 } 2772 2773 void CodeCompleteWindow::InitListBox() 2774 { 2775 pListBox->SetSizePixel( Size(150,150) ); //default, this will adopt the line length 2776 pListBox->Show(); 2777 pListBox->EnableQuickSelection( false ); 2778 } 2779 2780 void CodeCompleteWindow::InsertEntry( const OUString& aStr ) 2781 { 2782 pListBox->InsertEntry( aStr ); 2783 } 2784 2785 void CodeCompleteWindow::ClearListBox() 2786 { 2787 pListBox->Clear(); 2788 pListBox->aFuncBuffer.setLength(0); 2789 } 2790 2791 void CodeCompleteWindow::SetTextSelection( const TextSelection& aSel ) 2792 { 2793 aTextSelection = aSel; 2794 } 2795 2796 2797 void CodeCompleteWindow::ResizeAndPositionListBox() 2798 { 2799 if( pListBox->GetEntryCount() >= 1 ) 2800 {// if there is at least one element inside 2801 // calculate basic position: under the current line 2802 tools::Rectangle aRect = static_cast<TextEngine*>(pParent->GetEditEngine())->PaMtoEditCursor( pParent->GetEditView()->GetSelection().GetEnd() ); 2803 long nViewYOffset = pParent->GetEditView()->GetStartDocPos().Y(); 2804 Point aPos = aRect.BottomRight();// this variable will be used later (if needed) 2805 aPos.setY( (aPos.Y() - nViewYOffset) + nBasePad ); 2806 2807 OUString aLongestEntry = pListBox->GetEntry( 0 );// grab the longest one: max search 2808 for( sal_Int32 i=1; i< pListBox->GetEntryCount(); ++i ) 2809 { 2810 if( pListBox->GetEntry( i ).getLength() > aLongestEntry.getLength() ) 2811 aLongestEntry = pListBox->GetEntry( i ); 2812 } 2813 // get column/line count 2814 const sal_uInt16& nColumns = aLongestEntry.getLength(); 2815 const sal_uInt16 nLines = static_cast<sal_uInt16>( std::min( sal_Int32(6), pListBox->GetEntryCount() )); 2816 2817 Size aSize = pListBox->CalcBlockSize( nColumns, nLines ); 2818 //set the size 2819 SetSizePixel( aSize ); 2820 //1 px smaller, to see the border 2821 aSize.setWidth( aSize.getWidth() - 1 ); 2822 aSize.setHeight( aSize.getHeight() - 1 ); 2823 pListBox->SetSizePixel( aSize ); 2824 2825 //calculate position 2826 const tools::Rectangle aVisArea( pParent->GetEditView()->GetStartDocPos(), pParent->GetOutputSizePixel() ); //the visible area 2827 const Point& aBottomPoint = aVisArea.BottomRight(); 2828 2829 if( aVisArea.TopRight().getY() + aPos.getY() + aSize.getHeight() > aBottomPoint.getY() ) 2830 {//clipped at the bottom: move it up 2831 const long& nParentFontHeight = pParent->GetEditEngine()->GetFont().GetFontHeight(); //parent's font (in the IDE): needed for height 2832 aPos.AdjustY( -(aSize.getHeight() + nParentFontHeight + nCursorPad) ); 2833 } 2834 2835 if( aVisArea.TopLeft().getX() + aPos.getX() + aSize.getWidth() > aBottomPoint.getX() ) 2836 {//clipped at the right side, move it a bit left 2837 aPos.AdjustX( -(aSize.getWidth() + aVisArea.TopLeft().getX()) ); 2838 } 2839 //set the position 2840 SetPosPixel( aPos ); 2841 } 2842 } 2843 2844 void CodeCompleteWindow::SelectFirstEntry() 2845 { 2846 if( pListBox->GetEntryCount() > 0 ) 2847 { 2848 pListBox->SelectEntryPos( 0 ); 2849 } 2850 } 2851 2852 void CodeCompleteWindow::ClearAndHide() 2853 { 2854 ClearListBox(); 2855 pListBox->HideAndRestoreFocus(); 2856 } 2857 2858 UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector< OUString >& aVect, const OUString& sVarType ) 2859 : bCanComplete( true ) 2860 { 2861 if( aVect.empty() || sVarType.isEmpty() ) 2862 { 2863 bCanComplete = false;//invalid parameters, nothing to code complete 2864 return; 2865 } 2866 2867 try 2868 { 2869 // Get the base class for reflection: 2870 xClass = css::reflection::theCoreReflection::get( 2871 comphelper::getProcessComponentContext())->forName(sVarType); 2872 } 2873 catch( const Exception& ) 2874 { 2875 bCanComplete = false; 2876 return; 2877 } 2878 2879 auto j = aVect.begin() + 1;//start from aVect[1]: aVect[0] is the variable name 2880 OUString sMethName; 2881 2882 while( j != aVect.end() ) 2883 { 2884 sMethName = *j; 2885 2886 if( CodeCompleteOptions::IsExtendedTypeDeclaration() ) 2887 { 2888 if( !CheckMethod(sMethName) && !CheckField(sMethName) ) 2889 { 2890 bCanComplete = false; 2891 break; 2892 } 2893 } 2894 else 2895 { 2896 if( !CheckField(sMethName) ) 2897 { 2898 bCanComplete = false; 2899 break; 2900 } 2901 } 2902 2903 ++j; 2904 } 2905 } 2906 2907 std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassMethods() const 2908 { 2909 std::vector< OUString > aRetVect; 2910 if( bCanComplete && ( xClass != nullptr ) ) 2911 { 2912 Sequence< Reference< reflection::XIdlMethod > > aMethods = xClass->getMethods(); 2913 if( aMethods.getLength() != 0 ) 2914 { 2915 for(sal_Int32 l = 0; l < aMethods.getLength(); ++l) 2916 { 2917 aRetVect.push_back( aMethods[l]->getName() ); 2918 } 2919 } 2920 } 2921 return aRetVect;//this is empty when cannot code complete 2922 } 2923 2924 std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassFields() const 2925 { 2926 std::vector< OUString > aRetVect; 2927 if( bCanComplete && ( xClass != nullptr ) ) 2928 { 2929 Sequence< Reference< reflection::XIdlField > > aFields = xClass->getFields(); 2930 if( aFields.getLength() != 0 ) 2931 { 2932 for(sal_Int32 l = 0; l < aFields.getLength(); ++l) 2933 { 2934 aRetVect.push_back( aFields[l]->getName() ); 2935 } 2936 } 2937 } 2938 return aRetVect;//this is empty when cannot code complete 2939 } 2940 2941 2942 bool UnoTypeCodeCompletetor::CheckField( const OUString& sFieldName ) 2943 {// modifies xClass!!! 2944 2945 if ( xClass == nullptr ) 2946 return false; 2947 2948 Reference< reflection::XIdlField> xField = xClass->getField( sFieldName ); 2949 if( xField != nullptr ) 2950 { 2951 xClass = xField->getType(); 2952 if( xClass != nullptr ) 2953 { 2954 return true; 2955 } 2956 } 2957 return false; 2958 } 2959 2960 bool UnoTypeCodeCompletetor::CheckMethod( const OUString& sMethName ) 2961 {// modifies xClass!!! 2962 2963 2964 if ( xClass == nullptr ) 2965 return false; 2966 2967 Reference< reflection::XIdlMethod> xMethod = xClass->getMethod( sMethName ); 2968 if( xMethod != nullptr ) //method OK, check return type 2969 { 2970 xClass = xMethod->getReturnType(); 2971 if( xClass != nullptr ) 2972 { 2973 return true; 2974 } 2975 } 2976 return false; 2977 } 2978 2979 } // namespace basctl 2980 2981 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2982
