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