Bump version to 24.04.3.4
[LibreOffice.git] / basctl / source / basicide / bastypes.cxx
blobe436bc9f7e0ae6a2c9df4415f799b9554298cf1a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <strings.hrc>
25 #include <helpids.h>
26 #include <iderid.hxx>
28 #include "baside2.hxx"
29 #include <baside3.hxx>
30 #include <basidesh.hxx>
31 #include <basobj.hxx>
32 #include <iderdll.hxx>
33 #include "iderdll2.hxx"
35 #include <com/sun/star/script/XLibraryContainerPassword.hpp>
36 #include <sal/log.hxx>
37 #include <sfx2/dispatch.hxx>
38 #include <sfx2/infobar.hxx>
39 #include <sfx2/passwd.hxx>
40 #include <sfx2/sfxsids.hrc>
41 #include <sfx2/viewfrm.hxx>
42 #include <svl/intitem.hxx>
43 #include <svl/stritem.hxx>
44 #include <svl/srchdefs.hxx>
45 #include <svl/itemset.hxx>
46 #include <utility>
47 #include <vcl/commandevent.hxx>
48 #include <vcl/event.hxx>
49 #include <vcl/svapp.hxx>
50 #include <vcl/weld.hxx>
51 #include <tools/stream.hxx>
52 #include <o3tl/hash_combine.hxx>
54 namespace basctl
57 // ID used for the read-only infobar
58 constexpr OUString BASIC_IDE_READONLY_INFOBAR = u"readonly"_ustr;
60 using namespace ::com::sun::star::uno;
61 using namespace ::com::sun::star;
63 BaseWindow::BaseWindow( vcl::Window* pParent, ScriptDocument aDocument, OUString aLibName, OUString aName )
64 :Window( pParent, WinBits( WB_3DLOOK ) )
65 ,pShellHScrollBar( nullptr)
66 ,pShellVScrollBar( nullptr)
67 ,nStatus( 0)
68 ,m_aDocument(std::move( aDocument ))
69 ,m_aLibName(std::move( aLibName ))
70 ,m_aName(std::move( aName ))
74 BaseWindow::~BaseWindow()
76 disposeOnce();
79 void BaseWindow::dispose()
81 if (pShellVScrollBar && !pShellVScrollBar->isDisposed())
82 pShellVScrollBar->SetScrollHdl( Link<weld::Scrollbar&,void>() );
83 if (pShellHScrollBar && !pShellHScrollBar->isDisposed())
84 pShellHScrollBar->SetScrollHdl( Link<weld::Scrollbar&,void>() );
85 pShellVScrollBar.clear();
86 pShellHScrollBar.clear();
87 vcl::Window::dispose();
90 void BaseWindow::Init()
92 if ( pShellVScrollBar )
93 pShellVScrollBar->SetScrollHdl( LINK( this, BaseWindow, VertScrollHdl ) );
94 if ( pShellHScrollBar )
95 pShellHScrollBar->SetScrollHdl( LINK( this, BaseWindow, HorzScrollHdl ) );
97 // Show the read-only infobar if the module/dialog is read-only
98 GetShell()->GetViewFrame().RemoveInfoBar(BASIC_IDE_READONLY_INFOBAR);
99 if (IsReadOnly())
100 ShowReadOnlyInfoBar();
102 DoInit(); // virtual...
105 void BaseWindow::DoInit()
109 void BaseWindow::GrabScrollBars(ScrollAdaptor* pHScroll, ScrollAdaptor* pVScroll)
111 pShellHScrollBar = pHScroll;
112 pShellVScrollBar = pVScroll;
115 IMPL_LINK_NOARG(BaseWindow, VertScrollHdl, weld::Scrollbar&, void)
117 DoScroll(pShellVScrollBar);
120 IMPL_LINK_NOARG(BaseWindow, HorzScrollHdl, weld::Scrollbar&, void)
122 DoScroll(pShellHScrollBar);
125 void BaseWindow::ExecuteCommand (SfxRequest&)
129 void BaseWindow::ExecuteGlobal (SfxRequest&)
133 bool BaseWindow::EventNotify( NotifyEvent& rNEvt )
135 bool bDone = false;
137 if ( rNEvt.GetType() == NotifyEventType::KEYINPUT )
139 KeyEvent aKEvt = *rNEvt.GetKeyEvent();
140 vcl::KeyCode aCode = aKEvt.GetKeyCode();
141 sal_uInt16 nCode = aCode.GetCode();
143 switch ( nCode )
145 case KEY_PAGEUP:
146 case KEY_PAGEDOWN:
148 if ( aCode.IsMod1() )
150 if (Shell* pShell = GetShell())
151 pShell->NextPage( nCode == KEY_PAGEUP );
152 bDone = true;
155 break;
159 return bDone || Window::EventNotify( rNEvt );
162 void BaseWindow::ShowShellScrollBars(bool bVisible)
164 if (bVisible)
166 if (pShellHScrollBar)
168 pShellHScrollBar->Enable();
169 pShellHScrollBar->Show();
171 if (pShellVScrollBar)
173 pShellVScrollBar->Enable();
174 pShellVScrollBar->Show();
177 else
179 if (pShellHScrollBar)
181 pShellHScrollBar->Disable();
182 pShellHScrollBar->Hide();
184 if (pShellVScrollBar)
186 pShellVScrollBar->Disable();
187 pShellVScrollBar->Hide();
192 void BaseWindow::DoScroll( Scrollable* )
196 void BaseWindow::StoreData()
200 bool BaseWindow::AllowUndo()
202 return true;
205 void BaseWindow::UpdateData()
209 OUString BaseWindow::GetTitle()
211 return OUString();
214 OUString BaseWindow::CreateQualifiedName()
216 OUString aName;
217 if ( !m_aLibName.isEmpty() )
219 LibraryLocation eLocation = m_aDocument.getLibraryLocation( m_aLibName );
220 aName = m_aDocument.getTitle(eLocation) + "." + m_aLibName + "." +
221 GetTitle();
223 return aName;
226 void BaseWindow::SetReadOnly (bool)
230 bool BaseWindow::IsReadOnly ()
232 return false;
235 // Show the read-only warning messages for module and dialog windows
236 void BaseWindow::ShowReadOnlyInfoBar()
238 OUString aMsg;
239 if (dynamic_cast<ModulWindow*>(this))
240 aMsg = IDEResId(RID_STR_MODULE_READONLY);
241 else
242 aMsg = IDEResId(RID_STR_DIALOG_READONLY);
244 GetShell()->GetViewFrame().AppendInfoBar(BASIC_IDE_READONLY_INFOBAR, OUString(),
245 aMsg, InfobarType::INFO, true);
248 void BaseWindow::BasicStarted()
252 void BaseWindow::BasicStopped()
256 bool BaseWindow::IsModified ()
258 return true;
261 SfxUndoManager* BaseWindow::GetUndoManager()
263 return nullptr;
266 SearchOptionFlags BaseWindow::GetSearchOptions()
268 return SearchOptionFlags::NONE;
271 sal_uInt16 BaseWindow::StartSearchAndReplace (SvxSearchItem const&, bool)
273 return 0;
276 void BaseWindow::OnNewDocument ()
279 void BaseWindow::InsertLibInfo () const
281 if (ExtraData* pData = GetExtraData())
282 pData->GetLibInfo().InsertInfo(m_aDocument, m_aLibName, m_aName, GetType());
285 bool BaseWindow::Is (
286 ScriptDocument const& rDocument,
287 std::u16string_view rLibName, std::u16string_view rName,
288 ItemType eType, bool bFindSuspended
291 if (bFindSuspended || !IsSuspended())
293 // any non-suspended window is ok
294 if (rLibName.empty() || rName.empty() || eType == TYPE_UNKNOWN)
295 return true;
296 // ok if the parameters match
297 if (m_aDocument == rDocument && m_aLibName == rLibName && m_aName == rName && GetType() == eType)
298 return true;
300 return false;
303 bool BaseWindow::HasActiveEditor () const
305 return false;
309 // DockingWindow
312 // style bits for DockingWindow
313 WinBits const DockingWindow::StyleBits =
314 WB_BORDER | WB_3DLOOK | WB_CLIPCHILDREN |
315 WB_MOVEABLE | WB_SIZEABLE | WB_DOCKABLE;
317 DockingWindow::DockingWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, const OUString& rID)
318 : ResizableDockingWindow(pParent)
319 , m_xBuilder(Application::CreateInterimBuilder(m_xBox.get(), rUIXMLDescription, true))
320 , pLayout(nullptr)
321 , nShowCount(0)
323 m_xContainer = m_xBuilder->weld_container(rID);
326 DockingWindow::DockingWindow (Layout* pParent)
327 : ResizableDockingWindow(pParent, StyleBits)
328 , pLayout(pParent)
329 , nShowCount(0)
332 DockingWindow::~DockingWindow()
334 disposeOnce();
337 void DockingWindow::dispose()
339 m_xContainer.reset();
340 m_xBuilder.reset();
341 pLayout.clear();
342 ResizableDockingWindow::dispose();
345 // Sets the position and the size of the docking window. This property is saved
346 // when the window is floating. Called by Layout.
347 void DockingWindow::ResizeIfDocking (Point const& rPos, Size const& rSize)
349 tools::Rectangle const rRect(rPos, rSize);
350 if (rRect != aDockingRect)
352 // saving the position and the size
353 aDockingRect = rRect;
354 // resizing if actually docking
355 if (!IsFloatingMode())
356 SetPosSizePixel(rPos, rSize);
359 void DockingWindow::ResizeIfDocking (Size const& rSize)
361 ResizeIfDocking(aDockingRect.TopLeft(), rSize);
364 // Sets the parent Layout window.
365 // The physical parent is set only when the window is docking.
366 void DockingWindow::SetLayoutWindow (Layout* pLayout_)
368 pLayout = pLayout_;
369 if (!IsFloatingMode())
370 SetParent(pLayout);
374 // Increases the "show" reference count.
375 // The window is shown when the reference count is positive.
376 void DockingWindow::Show (bool bShow) // = true
378 if (bShow)
380 if (++nShowCount == 1)
381 ResizableDockingWindow::Show();
383 else
385 if (--nShowCount == 0)
386 ResizableDockingWindow::Hide();
390 // Decreases the "show" reference count.
391 // The window is hidden when the reference count reaches zero.
392 void DockingWindow::Hide ()
394 Show(false);
397 bool DockingWindow::Docking( const Point& rPos, tools::Rectangle& rRect )
399 if (aDockingRect.Contains(rPos))
401 rRect.SetSize(aDockingRect.GetSize());
402 return false; // dock
404 else // adjust old size
406 if (!aFloatingRect.IsEmpty())
407 rRect.SetSize(aFloatingRect.GetSize());
408 return true; // float
412 void DockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode )
414 if ( bFloatMode )
415 ResizableDockingWindow::EndDocking( rRect, bFloatMode );
416 else
418 SetFloatingMode(false);
419 DockThis();
423 void DockingWindow::ToggleFloatingMode()
425 if (IsFloatingMode())
427 if (!aFloatingRect.IsEmpty())
428 SetPosSizePixel(
429 GetParent()->ScreenToOutputPixel(aFloatingRect.TopLeft()),
430 aFloatingRect.GetSize()
433 DockThis();
436 bool DockingWindow::PrepareToggleFloatingMode()
438 if (IsFloatingMode())
440 // memorize position and size on the desktop...
441 aFloatingRect = tools::Rectangle(
442 GetParent()->OutputToScreenPixel(GetPosPixel()),
443 GetSizePixel()
446 return true;
449 void DockingWindow::StartDocking()
451 if (IsFloatingMode())
453 aFloatingRect = tools::Rectangle(
454 GetParent()->OutputToScreenPixel(GetPosPixel()),
455 GetSizePixel()
460 void DockingWindow::DockThis ()
462 // resizing when floating -> docking
463 if (!IsFloatingMode())
465 Point const aPos = aDockingRect.TopLeft();
466 Size const aSize = aDockingRect.GetSize();
467 if (aSize != GetSizePixel() || aPos != GetPosPixel())
468 SetPosSizePixel(aPos, aSize);
471 if (pLayout)
473 if (!IsFloatingMode() && GetParent() != pLayout)
474 SetParent(pLayout);
475 pLayout->ArrangeWindows();
479 TabBar::TabBar( vcl::Window* pParent ) :
480 ::TabBar( pParent, WinBits( WB_3DLOOK | WB_SCROLL | WB_BORDER | WB_DRAG ) )
482 EnableEditMode();
484 SetHelpId( HID_BASICIDE_TABBAR );
487 void TabBar::MouseButtonDown( const MouseEvent& rMEvt )
489 if ( rMEvt.IsLeft() && ( rMEvt.GetClicks() == 2 ) && !IsInEditMode() )
491 if (SfxDispatcher* pDispatcher = GetDispatcher())
492 pDispatcher->Execute( SID_BASICIDE_MODULEDLG );
494 else
496 ::TabBar::MouseButtonDown( rMEvt ); // base class version
500 void TabBar::Command( const CommandEvent& rCEvt )
502 if ( ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) && !IsInEditMode() )
504 Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) );
505 if ( rCEvt.IsMouseEvent() ) // select right tab
507 Point aP = PixelToLogic( aPos );
508 MouseEvent aMouseEvent( aP, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT );
509 ::TabBar::MouseButtonDown( aMouseEvent ); // base class
511 if (SfxDispatcher* pDispatcher = GetDispatcher())
512 pDispatcher->ExecutePopup("tabbar", this, &aPos);
516 TabBarAllowRenamingReturnCode TabBar::AllowRenaming()
518 bool const bValid = IsValidSbxName(GetEditText());
520 if ( !bValid )
522 std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(GetFrameWeld(),
523 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME)));
524 xError->run();
527 return bValid ? TABBAR_RENAMING_YES : TABBAR_RENAMING_NO;
531 void TabBar::EndRenaming()
533 if ( !IsEditModeCanceled() )
535 SfxUInt16Item aID( SID_BASICIDE_ARG_TABID, GetEditPageId() );
536 SfxStringItem aNewName( SID_BASICIDE_ARG_MODULENAME, GetEditText() );
537 if (SfxDispatcher* pDispatcher = GetDispatcher())
538 pDispatcher->ExecuteList( SID_BASICIDE_NAMECHANGEDONTAB,
539 SfxCallMode::SYNCHRON, { &aID, &aNewName });
544 namespace
547 // helper class for sorting TabBar
548 struct TabBarSortHelper
550 sal_uInt16 nPageId;
551 OUString aPageText;
553 bool operator < (TabBarSortHelper const& rComp) const
555 return aPageText.compareToIgnoreAsciiCase(rComp.aPageText) < 0;
559 } // namespace
561 void TabBar::Sort()
563 Shell* pShell = GetShell();
564 if (!pShell)
565 return;
567 Shell::WindowTable& aWindowTable = pShell->GetWindowTable();
568 TabBarSortHelper aTabBarSortHelper;
569 std::vector<TabBarSortHelper> aModuleList;
570 std::vector<TabBarSortHelper> aDialogList;
571 sal_uInt16 nPageCount = GetPageCount();
572 sal_uInt16 i;
574 // create module and dialog lists for sorting
575 for ( i = 0; i < nPageCount; i++)
577 sal_uInt16 nId = GetPageId( i );
578 aTabBarSortHelper.nPageId = nId;
579 aTabBarSortHelper.aPageText = GetPageText( nId );
580 BaseWindow* pWin = aWindowTable[ nId ].get();
582 if (dynamic_cast<ModulWindow*>(pWin))
584 aModuleList.push_back( aTabBarSortHelper );
586 else if (dynamic_cast<DialogWindow*>(pWin))
588 aDialogList.push_back( aTabBarSortHelper );
592 // sort module and dialog lists by page text
593 std::sort( aModuleList.begin() , aModuleList.end() );
594 std::sort( aDialogList.begin() , aDialogList.end() );
597 sal_uInt16 nModules = sal::static_int_cast<sal_uInt16>( aModuleList.size() );
598 sal_uInt16 nDialogs = sal::static_int_cast<sal_uInt16>( aDialogList.size() );
600 // move module pages to new positions
601 for (i = 0; i < nModules; i++)
603 MovePage( aModuleList[i].nPageId , i );
606 // move dialog pages to new positions
607 for (i = 0; i < nDialogs; i++)
609 MovePage( aDialogList[i].nPageId , nModules + i );
613 void CutLines( OUString& rStr, sal_Int32 nStartLine, sal_Int32 nLines )
615 sal_Int32 nStartPos = 0;
616 sal_Int32 nLine = 0;
617 while ( nLine < nStartLine )
619 nStartPos = searchEOL( rStr, nStartPos );
620 if( nStartPos == -1 )
621 break;
622 nStartPos++; // not the \n.
623 nLine++;
626 SAL_WARN_IF( nStartPos == -1, "basctl.basicide", "CutLines: Start line not found!" );
628 if ( nStartPos == -1 )
629 return;
631 sal_Int32 nEndPos = nStartPos;
633 for ( sal_Int32 i = 0; i < nLines; i++ )
634 nEndPos = searchEOL( rStr, nEndPos+1 );
636 if ( nEndPos == -1 ) // might happen at the last line
637 nEndPos = rStr.getLength();
638 else
639 nEndPos++;
641 rStr = OUString::Concat(rStr.subView( 0, nStartPos )) + rStr.subView( nEndPos );
643 // erase trailing empty lines
645 sal_Int32 n = nStartPos;
646 sal_Int32 nLen = rStr.getLength();
647 while ( ( n < nLen ) && ( rStr[ n ] == LINE_SEP ||
648 rStr[ n ] == LINE_SEP_CR ) )
650 n++;
653 if ( n > nStartPos )
655 rStr = OUString::Concat(rStr.subView( 0, nStartPos )) + rStr.subView( n );
660 sal_uInt32 CalcLineCount( SvStream& rStream )
662 sal_uInt32 nLFs = 0;
663 sal_uInt32 nCRs = 0;
664 char c;
666 rStream.Seek( 0 );
667 rStream.ReadChar( c );
668 while ( !rStream.eof() )
670 if ( c == '\n' )
671 nLFs++;
672 else if ( c == '\r' )
673 nCRs++;
674 rStream.ReadChar( c );
677 rStream.Seek( 0 );
678 if ( nLFs > nCRs )
679 return nLFs;
680 return nCRs;
684 // LibInfo
687 LibInfo::LibInfo ()
690 LibInfo::~LibInfo ()
693 void LibInfo::InsertInfo (
694 ScriptDocument const& rDocument,
695 OUString const& rLibName,
696 OUString const& rCurrentName,
697 ItemType eCurrentType
700 Key aKey(rDocument, rLibName);
701 m_aMap.erase(aKey);
702 m_aMap.emplace(aKey, Item(rCurrentName, eCurrentType));
705 void LibInfo::RemoveInfoFor (ScriptDocument const& rDocument)
707 Map::iterator it = std::find_if(m_aMap.begin(), m_aMap.end(),
708 [&rDocument](Map::reference rEntry) { return rEntry.first.GetDocument() == rDocument; });
709 if (it != m_aMap.end())
710 m_aMap.erase(it);
713 LibInfo::Item const* LibInfo::GetInfo (
714 ScriptDocument const& rDocument, OUString const& rLibName
717 Map::iterator it = m_aMap.find(Key(rDocument, rLibName));
718 return it != m_aMap.end() ? &it->second : nullptr;
721 LibInfo::Key::Key (ScriptDocument aDocument, OUString aLibName) :
722 m_aDocument(std::move(aDocument)), m_aLibName(std::move(aLibName))
725 bool LibInfo::Key::operator == (Key const& rKey) const
727 return m_aDocument == rKey.m_aDocument && m_aLibName == rKey.m_aLibName;
730 size_t LibInfo::Key::Hash::operator () (Key const& rKey) const
732 std::size_t seed = 0;
733 o3tl::hash_combine(seed, rKey.m_aDocument.hashCode());
734 o3tl::hash_combine(seed, rKey.m_aLibName.hashCode());
735 return seed;
738 LibInfo::Item::Item (
739 OUString aCurrentName,
740 ItemType eCurrentType
742 m_aCurrentName(std::move(aCurrentName)),
743 m_eCurrentType(eCurrentType)
746 static bool QueryDel(std::u16string_view rName, const OUString &rStr, weld::Widget* pParent)
748 OUString aName = OUString::Concat("\'") + rName + "\'";
749 OUString aQuery = rStr.replaceAll("XX", aName);
750 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParent,
751 VclMessageType::Question, VclButtonsType::YesNo, aQuery));
752 return (xQueryBox->run() == RET_YES);
755 bool QueryDelMacro( std::u16string_view rName, weld::Widget* pParent )
757 return QueryDel( rName, IDEResId( RID_STR_QUERYDELMACRO ), pParent );
760 bool QueryReplaceMacro( std::u16string_view rName, weld::Widget* pParent )
762 return QueryDel( rName, IDEResId( RID_STR_QUERYREPLACEMACRO ), pParent );
765 bool QueryDelDialog( std::u16string_view rName, weld::Widget* pParent )
767 return QueryDel( rName, IDEResId( RID_STR_QUERYDELDIALOG ), pParent );
770 bool QueryDelLib( std::u16string_view rName, bool bRef, weld::Widget* pParent )
772 return QueryDel( rName, IDEResId( bRef ? RID_STR_QUERYDELLIBREF : RID_STR_QUERYDELLIB ), pParent );
775 bool QueryDelModule( std::u16string_view rName, weld::Widget* pParent )
777 return QueryDel( rName, IDEResId( RID_STR_QUERYDELMODULE ), pParent );
780 bool QueryPassword(weld::Widget* pDialogParent, const Reference< script::XLibraryContainer >& xLibContainer, const OUString& rLibName, OUString& rPassword, bool bRepeat, bool bNewTitle)
782 bool bOK = false;
783 sal_uInt16 nRet = 0;
787 // password dialog
788 SfxPasswordDialog aDlg(pDialogParent);
789 aDlg.SetMinLen(1);
791 // set new title
792 if ( bNewTitle )
794 OUString aTitle(IDEResId(RID_STR_ENTERPASSWORD));
795 aTitle = aTitle.replaceAll("XX", rLibName);
796 aDlg.set_title(aTitle);
799 // execute dialog
800 nRet = aDlg.run();
802 // verify password
803 if ( nRet == RET_OK )
805 if ( xLibContainer.is() && xLibContainer->hasByName( rLibName ) )
807 Reference< script::XLibraryContainerPassword > xPasswd( xLibContainer, UNO_QUERY );
808 if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( rLibName ) && !xPasswd->isLibraryPasswordVerified( rLibName ) )
810 rPassword = aDlg.GetPassword();
811 bOK = xPasswd->verifyLibraryPassword( rLibName, rPassword );
813 if ( !bOK )
815 std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pDialogParent,
816 VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_WRONGPASSWORD)));
817 xErrorBox->run();
823 while ( bRepeat && !bOK && nRet == RET_OK );
825 return bOK;
829 } // namespace basctl
831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */