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>
46 #include <vcl/commandevent.hxx>
47 #include <vcl/event.hxx>
48 #include <vcl/svapp.hxx>
49 #include <vcl/weld.hxx>
50 #include <tools/stream.hxx>
51 #include <o3tl/hash_combine.hxx>
56 // ID used for the read-only infobar
57 constexpr OUStringLiteral BASIC_IDE_READONLY_INFOBAR
= u
"readonly";
59 using namespace ::com::sun::star::uno
;
60 using namespace ::com::sun::star
;
62 BaseWindow::BaseWindow( vcl::Window
* pParent
, ScriptDocument aDocument
, OUString aLibName
, OUString aName
)
63 :Window( pParent
, WinBits( WB_3DLOOK
) )
64 ,pShellHScrollBar( nullptr)
65 ,pShellVScrollBar( nullptr)
67 ,m_aDocument(std::move( aDocument
))
68 ,m_aLibName(std::move( aLibName
))
69 ,m_aName(std::move( aName
))
73 BaseWindow::~BaseWindow()
78 void BaseWindow::dispose()
80 if (pShellVScrollBar
&& !pShellVScrollBar
->isDisposed())
81 pShellVScrollBar
->SetScrollHdl( Link
<weld::Scrollbar
&,void>() );
82 if (pShellHScrollBar
&& !pShellHScrollBar
->isDisposed())
83 pShellHScrollBar
->SetScrollHdl( Link
<weld::Scrollbar
&,void>() );
84 pShellVScrollBar
.clear();
85 pShellHScrollBar
.clear();
86 vcl::Window::dispose();
89 void BaseWindow::Init()
91 if ( pShellVScrollBar
)
92 pShellVScrollBar
->SetScrollHdl( LINK( this, BaseWindow
, VertScrollHdl
) );
93 if ( pShellHScrollBar
)
94 pShellHScrollBar
->SetScrollHdl( LINK( this, BaseWindow
, HorzScrollHdl
) );
96 // Show the read-only infobar if the module/dialog is read-only
97 GetShell()->GetViewFrame().RemoveInfoBar(BASIC_IDE_READONLY_INFOBAR
);
99 ShowReadOnlyInfoBar();
101 DoInit(); // virtual...
104 void BaseWindow::DoInit()
108 void BaseWindow::GrabScrollBars(ScrollAdaptor
* pHScroll
, ScrollAdaptor
* pVScroll
)
110 pShellHScrollBar
= pHScroll
;
111 pShellVScrollBar
= pVScroll
;
114 IMPL_LINK_NOARG(BaseWindow
, VertScrollHdl
, weld::Scrollbar
&, void)
116 DoScroll(pShellVScrollBar
);
119 IMPL_LINK_NOARG(BaseWindow
, HorzScrollHdl
, weld::Scrollbar
&, void)
121 DoScroll(pShellHScrollBar
);
124 void BaseWindow::ExecuteCommand (SfxRequest
&)
128 void BaseWindow::ExecuteGlobal (SfxRequest
&)
132 bool BaseWindow::EventNotify( NotifyEvent
& rNEvt
)
136 if ( rNEvt
.GetType() == NotifyEventType::KEYINPUT
)
138 KeyEvent aKEvt
= *rNEvt
.GetKeyEvent();
139 vcl::KeyCode aCode
= aKEvt
.GetKeyCode();
140 sal_uInt16 nCode
= aCode
.GetCode();
147 if ( aCode
.IsMod1() )
149 if (Shell
* pShell
= GetShell())
150 pShell
->NextPage( nCode
== KEY_PAGEUP
);
158 return bDone
|| Window::EventNotify( rNEvt
);
161 void BaseWindow::ShowShellScrollBars(bool bVisible
)
165 if (pShellHScrollBar
)
167 pShellHScrollBar
->Enable();
168 pShellHScrollBar
->Show();
170 if (pShellVScrollBar
)
172 pShellVScrollBar
->Enable();
173 pShellVScrollBar
->Show();
178 if (pShellHScrollBar
)
180 pShellHScrollBar
->Disable();
181 pShellHScrollBar
->Hide();
183 if (pShellVScrollBar
)
185 pShellVScrollBar
->Disable();
186 pShellVScrollBar
->Hide();
191 void BaseWindow::DoScroll( Scrollable
* )
195 void BaseWindow::StoreData()
199 bool BaseWindow::AllowUndo()
204 void BaseWindow::UpdateData()
208 OUString
BaseWindow::GetTitle()
213 OUString
BaseWindow::CreateQualifiedName()
216 if ( !m_aLibName
.isEmpty() )
218 LibraryLocation eLocation
= m_aDocument
.getLibraryLocation( m_aLibName
);
219 aName
= m_aDocument
.getTitle(eLocation
) + "." + m_aLibName
+ "." +
225 void BaseWindow::SetReadOnly (bool)
229 bool BaseWindow::IsReadOnly ()
234 // Show the read-only warning messages for module and dialog windows
235 void BaseWindow::ShowReadOnlyInfoBar()
238 if (dynamic_cast<ModulWindow
*>(this))
239 aMsg
= IDEResId(RID_STR_MODULE_READONLY
);
241 aMsg
= IDEResId(RID_STR_DIALOG_READONLY
);
243 GetShell()->GetViewFrame().AppendInfoBar(BASIC_IDE_READONLY_INFOBAR
, OUString(),
244 aMsg
, InfobarType::INFO
, true);
247 void BaseWindow::BasicStarted()
251 void BaseWindow::BasicStopped()
255 bool BaseWindow::IsModified ()
260 SfxUndoManager
* BaseWindow::GetUndoManager()
265 SearchOptionFlags
BaseWindow::GetSearchOptions()
267 return SearchOptionFlags::NONE
;
270 sal_uInt16
BaseWindow::StartSearchAndReplace (SvxSearchItem
const&, bool)
275 void BaseWindow::OnNewDocument ()
278 void BaseWindow::InsertLibInfo () const
280 if (ExtraData
* pData
= GetExtraData())
281 pData
->GetLibInfo().InsertInfo(m_aDocument
, m_aLibName
, m_aName
, GetType());
284 bool BaseWindow::Is (
285 ScriptDocument
const& rDocument
,
286 std::u16string_view rLibName
, std::u16string_view rName
,
287 ItemType eType
, bool bFindSuspended
290 if (bFindSuspended
|| !IsSuspended())
292 // any non-suspended window is ok
293 if (rLibName
.empty() || rName
.empty() || eType
== TYPE_UNKNOWN
)
295 // ok if the parameters match
296 if (m_aDocument
== rDocument
&& m_aLibName
== rLibName
&& m_aName
== rName
&& GetType() == eType
)
302 bool BaseWindow::HasActiveEditor () const
311 // style bits for DockingWindow
312 WinBits
const DockingWindow::StyleBits
=
313 WB_BORDER
| WB_3DLOOK
| WB_CLIPCHILDREN
|
314 WB_MOVEABLE
| WB_SIZEABLE
| WB_DOCKABLE
;
316 DockingWindow::DockingWindow(vcl::Window
* pParent
, const OUString
& rUIXMLDescription
, const OUString
& rID
)
317 : ResizableDockingWindow(pParent
)
318 , m_xBuilder(Application::CreateInterimBuilder(m_xBox
.get(), rUIXMLDescription
, true))
322 m_xContainer
= m_xBuilder
->weld_container(rID
);
325 DockingWindow::DockingWindow (Layout
* pParent
)
326 : ResizableDockingWindow(pParent
, StyleBits
)
331 DockingWindow::~DockingWindow()
336 void DockingWindow::dispose()
338 m_xContainer
.reset();
341 ResizableDockingWindow::dispose();
344 // Sets the position and the size of the docking window. This property is saved
345 // when the window is floating. Called by Layout.
346 void DockingWindow::ResizeIfDocking (Point
const& rPos
, Size
const& rSize
)
348 tools::Rectangle
const rRect(rPos
, rSize
);
349 if (rRect
!= aDockingRect
)
351 // saving the position and the size
352 aDockingRect
= rRect
;
353 // resizing if actually docking
354 if (!IsFloatingMode())
355 SetPosSizePixel(rPos
, rSize
);
358 void DockingWindow::ResizeIfDocking (Size
const& rSize
)
360 ResizeIfDocking(aDockingRect
.TopLeft(), rSize
);
363 // Sets the parent Layout window.
364 // The physical parent is set only when the window is docking.
365 void DockingWindow::SetLayoutWindow (Layout
* pLayout_
)
368 if (!IsFloatingMode())
373 // Increases the "show" reference count.
374 // The window is shown when the reference count is positive.
375 void DockingWindow::Show (bool bShow
) // = true
379 if (++nShowCount
== 1)
380 ResizableDockingWindow::Show();
384 if (--nShowCount
== 0)
385 ResizableDockingWindow::Hide();
389 // Decreases the "show" reference count.
390 // The window is hidden when the reference count reaches zero.
391 void DockingWindow::Hide ()
396 bool DockingWindow::Docking( const Point
& rPos
, tools::Rectangle
& rRect
)
398 if (aDockingRect
.Contains(rPos
))
400 rRect
.SetSize(aDockingRect
.GetSize());
401 return false; // dock
403 else // adjust old size
405 if (!aFloatingRect
.IsEmpty())
406 rRect
.SetSize(aFloatingRect
.GetSize());
407 return true; // float
411 void DockingWindow::EndDocking( const tools::Rectangle
& rRect
, bool bFloatMode
)
414 ResizableDockingWindow::EndDocking( rRect
, bFloatMode
);
417 SetFloatingMode(false);
422 void DockingWindow::ToggleFloatingMode()
424 if (IsFloatingMode())
426 if (!aFloatingRect
.IsEmpty())
428 GetParent()->ScreenToOutputPixel(aFloatingRect
.TopLeft()),
429 aFloatingRect
.GetSize()
435 bool DockingWindow::PrepareToggleFloatingMode()
437 if (IsFloatingMode())
439 // memorize position and size on the desktop...
440 aFloatingRect
= tools::Rectangle(
441 GetParent()->OutputToScreenPixel(GetPosPixel()),
448 void DockingWindow::StartDocking()
450 if (IsFloatingMode())
452 aFloatingRect
= tools::Rectangle(
453 GetParent()->OutputToScreenPixel(GetPosPixel()),
459 void DockingWindow::DockThis ()
461 // resizing when floating -> docking
462 if (!IsFloatingMode())
464 Point
const aPos
= aDockingRect
.TopLeft();
465 Size
const aSize
= aDockingRect
.GetSize();
466 if (aSize
!= GetSizePixel() || aPos
!= GetPosPixel())
467 SetPosSizePixel(aPos
, aSize
);
472 if (!IsFloatingMode() && GetParent() != pLayout
)
474 pLayout
->ArrangeWindows();
478 TabBar::TabBar( vcl::Window
* pParent
) :
479 ::TabBar( pParent
, WinBits( WB_3DLOOK
| WB_SCROLL
| WB_BORDER
| WB_DRAG
) )
483 SetHelpId( HID_BASICIDE_TABBAR
);
486 void TabBar::MouseButtonDown( const MouseEvent
& rMEvt
)
488 if ( rMEvt
.IsLeft() && ( rMEvt
.GetClicks() == 2 ) && !IsInEditMode() )
490 if (SfxDispatcher
* pDispatcher
= GetDispatcher())
491 pDispatcher
->Execute( SID_BASICIDE_MODULEDLG
);
495 ::TabBar::MouseButtonDown( rMEvt
); // base class version
499 void TabBar::Command( const CommandEvent
& rCEvt
)
501 if ( ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
) && !IsInEditMode() )
503 Point
aPos( rCEvt
.IsMouseEvent() ? rCEvt
.GetMousePosPixel() : Point(1,1) );
504 if ( rCEvt
.IsMouseEvent() ) // select right tab
506 Point aP
= PixelToLogic( aPos
);
507 MouseEvent
aMouseEvent( aP
, 1, MouseEventModifiers::SIMPLECLICK
, MOUSE_LEFT
);
508 ::TabBar::MouseButtonDown( aMouseEvent
); // base class
510 if (SfxDispatcher
* pDispatcher
= GetDispatcher())
511 pDispatcher
->ExecutePopup("tabbar", this, &aPos
);
515 TabBarAllowRenamingReturnCode
TabBar::AllowRenaming()
517 bool const bValid
= IsValidSbxName(GetEditText());
521 std::unique_ptr
<weld::MessageDialog
> xError(Application::CreateMessageDialog(GetFrameWeld(),
522 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_BADSBXNAME
)));
526 return bValid
? TABBAR_RENAMING_YES
: TABBAR_RENAMING_NO
;
530 void TabBar::EndRenaming()
532 if ( !IsEditModeCanceled() )
534 SfxUInt16Item
aID( SID_BASICIDE_ARG_TABID
, GetEditPageId() );
535 SfxStringItem
aNewName( SID_BASICIDE_ARG_MODULENAME
, GetEditText() );
536 if (SfxDispatcher
* pDispatcher
= GetDispatcher())
537 pDispatcher
->ExecuteList( SID_BASICIDE_NAMECHANGEDONTAB
,
538 SfxCallMode::SYNCHRON
, { &aID
, &aNewName
});
546 // helper class for sorting TabBar
547 struct TabBarSortHelper
552 bool operator < (TabBarSortHelper
const& rComp
) const
554 return aPageText
.compareToIgnoreAsciiCase(rComp
.aPageText
) < 0;
562 Shell
* pShell
= GetShell();
566 Shell::WindowTable
& aWindowTable
= pShell
->GetWindowTable();
567 TabBarSortHelper aTabBarSortHelper
;
568 std::vector
<TabBarSortHelper
> aModuleList
;
569 std::vector
<TabBarSortHelper
> aDialogList
;
570 sal_uInt16 nPageCount
= GetPageCount();
573 // create module and dialog lists for sorting
574 for ( i
= 0; i
< nPageCount
; i
++)
576 sal_uInt16 nId
= GetPageId( i
);
577 aTabBarSortHelper
.nPageId
= nId
;
578 aTabBarSortHelper
.aPageText
= GetPageText( nId
);
579 BaseWindow
* pWin
= aWindowTable
[ nId
].get();
581 if (dynamic_cast<ModulWindow
*>(pWin
))
583 aModuleList
.push_back( aTabBarSortHelper
);
585 else if (dynamic_cast<DialogWindow
*>(pWin
))
587 aDialogList
.push_back( aTabBarSortHelper
);
591 // sort module and dialog lists by page text
592 std::sort( aModuleList
.begin() , aModuleList
.end() );
593 std::sort( aDialogList
.begin() , aDialogList
.end() );
596 sal_uInt16 nModules
= sal::static_int_cast
<sal_uInt16
>( aModuleList
.size() );
597 sal_uInt16 nDialogs
= sal::static_int_cast
<sal_uInt16
>( aDialogList
.size() );
599 // move module pages to new positions
600 for (i
= 0; i
< nModules
; i
++)
602 MovePage( aModuleList
[i
].nPageId
, i
);
605 // move dialog pages to new positions
606 for (i
= 0; i
< nDialogs
; i
++)
608 MovePage( aDialogList
[i
].nPageId
, nModules
+ i
);
612 void CutLines( OUString
& rStr
, sal_Int32 nStartLine
, sal_Int32 nLines
)
614 sal_Int32 nStartPos
= 0;
616 while ( nLine
< nStartLine
)
618 nStartPos
= searchEOL( rStr
, nStartPos
);
619 if( nStartPos
== -1 )
621 nStartPos
++; // not the \n.
625 SAL_WARN_IF( nStartPos
== -1, "basctl.basicide", "CutLines: Start line not found!" );
627 if ( nStartPos
== -1 )
630 sal_Int32 nEndPos
= nStartPos
;
632 for ( sal_Int32 i
= 0; i
< nLines
; i
++ )
633 nEndPos
= searchEOL( rStr
, nEndPos
+1 );
635 if ( nEndPos
== -1 ) // might happen at the last line
636 nEndPos
= rStr
.getLength();
640 rStr
= OUString::Concat(rStr
.subView( 0, nStartPos
)) + rStr
.subView( nEndPos
);
642 // erase trailing empty lines
644 sal_Int32 n
= nStartPos
;
645 sal_Int32 nLen
= rStr
.getLength();
646 while ( ( n
< nLen
) && ( rStr
[ n
] == LINE_SEP
||
647 rStr
[ n
] == LINE_SEP_CR
) )
654 rStr
= OUString::Concat(rStr
.subView( 0, nStartPos
)) + rStr
.subView( n
);
659 sal_uInt32
CalcLineCount( SvStream
& rStream
)
666 rStream
.ReadChar( c
);
667 while ( !rStream
.eof() )
671 else if ( c
== '\r' )
673 rStream
.ReadChar( c
);
692 void LibInfo::InsertInfo (
693 ScriptDocument
const& rDocument
,
694 OUString
const& rLibName
,
695 OUString
const& rCurrentName
,
696 ItemType eCurrentType
699 Key
aKey(rDocument
, rLibName
);
701 m_aMap
.emplace(aKey
, Item(rCurrentName
, eCurrentType
));
704 void LibInfo::RemoveInfoFor (ScriptDocument
const& rDocument
)
706 Map::iterator it
= std::find_if(m_aMap
.begin(), m_aMap
.end(),
707 [&rDocument
](Map::reference rEntry
) { return rEntry
.first
.GetDocument() == rDocument
; });
708 if (it
!= m_aMap
.end())
712 LibInfo::Item
const* LibInfo::GetInfo (
713 ScriptDocument
const& rDocument
, OUString
const& rLibName
716 Map::iterator it
= m_aMap
.find(Key(rDocument
, rLibName
));
717 return it
!= m_aMap
.end() ? &it
->second
: nullptr;
720 LibInfo::Key::Key (ScriptDocument aDocument
, OUString aLibName
) :
721 m_aDocument(std::move(aDocument
)), m_aLibName(std::move(aLibName
))
724 bool LibInfo::Key::operator == (Key
const& rKey
) const
726 return m_aDocument
== rKey
.m_aDocument
&& m_aLibName
== rKey
.m_aLibName
;
729 size_t LibInfo::Key::Hash::operator () (Key
const& rKey
) const
731 std::size_t seed
= 0;
732 o3tl::hash_combine(seed
, rKey
.m_aDocument
.hashCode());
733 o3tl::hash_combine(seed
, rKey
.m_aLibName
.hashCode());
737 LibInfo::Item::Item (
738 OUString aCurrentName
,
739 ItemType eCurrentType
741 m_aCurrentName(std::move(aCurrentName
)),
742 m_eCurrentType(eCurrentType
)
745 static bool QueryDel(std::u16string_view rName
, const OUString
&rStr
, weld::Widget
* pParent
)
747 OUString aName
= OUString::Concat("\'") + rName
+ "\'";
748 OUString aQuery
= rStr
.replaceAll("XX", aName
);
749 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(pParent
,
750 VclMessageType::Question
, VclButtonsType::YesNo
, aQuery
));
751 return (xQueryBox
->run() == RET_YES
);
754 bool QueryDelMacro( std::u16string_view rName
, weld::Widget
* pParent
)
756 return QueryDel( rName
, IDEResId( RID_STR_QUERYDELMACRO
), pParent
);
759 bool QueryReplaceMacro( std::u16string_view rName
, weld::Widget
* pParent
)
761 return QueryDel( rName
, IDEResId( RID_STR_QUERYREPLACEMACRO
), pParent
);
764 bool QueryDelDialog( std::u16string_view rName
, weld::Widget
* pParent
)
766 return QueryDel( rName
, IDEResId( RID_STR_QUERYDELDIALOG
), pParent
);
769 bool QueryDelLib( std::u16string_view rName
, bool bRef
, weld::Widget
* pParent
)
771 return QueryDel( rName
, IDEResId( bRef
? RID_STR_QUERYDELLIBREF
: RID_STR_QUERYDELLIB
), pParent
);
774 bool QueryDelModule( std::u16string_view rName
, weld::Widget
* pParent
)
776 return QueryDel( rName
, IDEResId( RID_STR_QUERYDELMODULE
), pParent
);
779 bool QueryPassword(weld::Widget
* pDialogParent
, const Reference
< script::XLibraryContainer
>& xLibContainer
, const OUString
& rLibName
, OUString
& rPassword
, bool bRepeat
, bool bNewTitle
)
787 SfxPasswordDialog
aDlg(pDialogParent
);
793 OUString
aTitle(IDEResId(RID_STR_ENTERPASSWORD
));
794 aTitle
= aTitle
.replaceAll("XX", rLibName
);
795 aDlg
.set_title(aTitle
);
802 if ( nRet
== RET_OK
)
804 if ( xLibContainer
.is() && xLibContainer
->hasByName( rLibName
) )
806 Reference
< script::XLibraryContainerPassword
> xPasswd( xLibContainer
, UNO_QUERY
);
807 if ( xPasswd
.is() && xPasswd
->isLibraryPasswordProtected( rLibName
) && !xPasswd
->isLibraryPasswordVerified( rLibName
) )
809 rPassword
= aDlg
.GetPassword();
810 bOK
= xPasswd
->verifyLibraryPassword( rLibName
, rPassword
);
814 std::unique_ptr
<weld::MessageDialog
> xErrorBox(Application::CreateMessageDialog(pDialogParent
,
815 VclMessageType::Warning
, VclButtonsType::Ok
, IDEResId(RID_STR_WRONGPASSWORD
)));
822 while ( bRepeat
&& !bOK
&& nRet
== RET_OK
);
828 } // namespace basctl
830 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */