Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name baside2b.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/basctl/inc -I /home/maarten/src/libreoffice/core/basctl/sdi -I /home/maarten/src/libreoffice/core/basctl/source/inc -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/basctl/sdi -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/basctl/source/basicide/baside2b.cxx

/home/maarten/src/libreoffice/core/basctl/source/basicide/baside2b.cxx

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

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
2
Calling copy constructor for 'Reference<ScrollBar>'
5
Returning from copy constructor for 'Reference<ScrollBar>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
6
Calling 'Reference::clear'
13
Returning; memory was released
205 if (aTmp.get()) {
14
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
3
Assuming field 'm_pBody' is non-null
4
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
)
7
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
8
Calling 'VclReferenceBase::release'
12
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
15
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
9
Assuming the condition is true
10
Taking true branch
40 delete this;
11
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif