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