1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
28 #include "baside2.hxx"
29 #include <baside3.hxx>
30 #include <basidesh.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>
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>
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)
68 ,m_aDocument(std::move( aDocument
))
69 ,m_aLibName(std::move( aLibName
))
70 ,m_aName(std::move( aName
))
74 BaseWindow::~BaseWindow()
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
);
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
)
137 if ( rNEvt
.GetType() == NotifyEventType::KEYINPUT
)
139 KeyEvent aKEvt
= *rNEvt
.GetKeyEvent();
140 vcl::KeyCode aCode
= aKEvt
.GetKeyCode();
141 sal_uInt16 nCode
= aCode
.GetCode();
148 if ( aCode
.IsMod1() )
150 if (Shell
* pShell
= GetShell())
151 pShell
->NextPage( nCode
== KEY_PAGEUP
);
159 return bDone
|| Window::EventNotify( rNEvt
);
162 void BaseWindow::ShowShellScrollBars(bool bVisible
)
166 if (pShellHScrollBar
)
168 pShellHScrollBar
->Enable();
169 pShellHScrollBar
->Show();
171 if (pShellVScrollBar
)
173 pShellVScrollBar
->Enable();
174 pShellVScrollBar
->Show();
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()
205 void BaseWindow::UpdateData()
209 OUString
BaseWindow::GetTitle()
214 OUString
BaseWindow::CreateQualifiedName()
217 if ( !m_aLibName
.isEmpty() )
219 LibraryLocation eLocation
= m_aDocument
.getLibraryLocation( m_aLibName
);
220 aName
= m_aDocument
.getTitle(eLocation
) + "." + m_aLibName
+ "." +
226 void BaseWindow::SetReadOnly (bool)
230 bool BaseWindow::IsReadOnly ()
235 // Show the read-only warning messages for module and dialog windows
236 void BaseWindow::ShowReadOnlyInfoBar()
239 if (dynamic_cast<ModulWindow
*>(this))
240 aMsg
= IDEResId(RID_STR_MODULE_READONLY
);
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 ()
261 SfxUndoManager
* BaseWindow::GetUndoManager()
266 SearchOptionFlags
BaseWindow::GetSearchOptions()
268 return SearchOptionFlags::NONE
;
271 sal_uInt16
BaseWindow::StartSearchAndReplace (SvxSearchItem
const&, bool)
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
)
296 // ok if the parameters match
297 if (m_aDocument
== rDocument
&& m_aLibName
== rLibName
&& m_aName
== rName
&& GetType() == eType
)
303 bool BaseWindow::HasActiveEditor () const
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))
323 m_xContainer
= m_xBuilder
->weld_container(rID
);
326 DockingWindow::DockingWindow (Layout
* pParent
)
327 : ResizableDockingWindow(pParent
, StyleBits
)
332 DockingWindow::~DockingWindow()
337 void DockingWindow::dispose()
339 m_xContainer
.reset();
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_
)
369 if (!IsFloatingMode())
374 // Increases the "show" reference count.
375 // The window is shown when the reference count is positive.
376 void DockingWindow::Show (bool bShow
) // = true
380 if (++nShowCount
== 1)
381 ResizableDockingWindow::Show();
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 ()
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
)
415 ResizableDockingWindow::EndDocking( rRect
, bFloatMode
);
418 SetFloatingMode(false);
423 void DockingWindow::ToggleFloatingMode()
425 if (IsFloatingMode())
427 if (!aFloatingRect
.IsEmpty())
429 GetParent()->ScreenToOutputPixel(aFloatingRect
.TopLeft()),
430 aFloatingRect
.GetSize()
436 bool DockingWindow::PrepareToggleFloatingMode()
438 if (IsFloatingMode())
440 // memorize position and size on the desktop...
441 aFloatingRect
= tools::Rectangle(
442 GetParent()->OutputToScreenPixel(GetPosPixel()),
449 void DockingWindow::StartDocking()
451 if (IsFloatingMode())
453 aFloatingRect
= tools::Rectangle(
454 GetParent()->OutputToScreenPixel(GetPosPixel()),
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
);
473 if (!IsFloatingMode() && GetParent() != pLayout
)
475 pLayout
->ArrangeWindows();
479 TabBar::TabBar( vcl::Window
* pParent
) :
480 ::TabBar( pParent
, WinBits( WB_3DLOOK
| WB_SCROLL
| WB_BORDER
| WB_DRAG
) )
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
);
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());
522 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(GetFrameWeld(),
523 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_BADSBXNAME
)));
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
});
547 // helper class for sorting TabBar
548 struct TabBarSortHelper
553 bool operator < (TabBarSortHelper
const& rComp
) const
555 return aPageText
.compareToIgnoreAsciiCase(rComp
.aPageText
) < 0;
563 Shell
* pShell
= GetShell();
567 Shell::WindowTable
& aWindowTable
= pShell
->GetWindowTable();
568 TabBarSortHelper aTabBarSortHelper
;
569 std::vector
<TabBarSortHelper
> aModuleList
;
570 std::vector
<TabBarSortHelper
> aDialogList
;
571 sal_uInt16 nPageCount
= GetPageCount();
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;
617 while ( nLine
< nStartLine
)
619 nStartPos
= searchEOL( rStr
, nStartPos
);
620 if( nStartPos
== -1 )
622 nStartPos
++; // not the \n.
626 SAL_WARN_IF( nStartPos
== -1, "basctl.basicide", "CutLines: Start line not found!" );
628 if ( nStartPos
== -1 )
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();
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
) )
655 rStr
= OUString::Concat(rStr
.subView( 0, nStartPos
)) + rStr
.subView( n
);
660 sal_uInt32
CalcLineCount( SvStream
& rStream
)
667 rStream
.ReadChar( c
);
668 while ( !rStream
.eof() )
672 else if ( c
== '\r' )
674 rStream
.ReadChar( c
);
693 void LibInfo::InsertInfo (
694 ScriptDocument
const& rDocument
,
695 OUString
const& rLibName
,
696 OUString
const& rCurrentName
,
697 ItemType eCurrentType
700 Key
aKey(rDocument
, rLibName
);
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())
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());
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
)
788 SfxPasswordDialog
aDlg(pDialogParent
);
794 OUString
aTitle(IDEResId(RID_STR_ENTERPASSWORD
));
795 aTitle
= aTitle
.replaceAll("XX", rLibName
);
796 aDlg
.set_title(aTitle
);
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
);
815 std::unique_ptr
<weld::MessageDialog
> xErrorBox(Application::CreateMessageDialog(pDialogParent
,
816 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_WRONGPASSWORD
)));
823 while ( bRepeat
&& !bOK
&& nRet
== RET_OK
);
829 } // namespace basctl
831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */