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 .
21 #include <comphelper/processfactory.hxx>
22 #include <osl/file.hxx>
23 #include <vcl/fixed.hxx>
24 #include <vcl/help.hxx>
25 #include <vcl/msgbox.hxx>
26 #include <svl/eitem.hxx>
27 #include <unotools/viewoptions.hxx>
28 #include <svtools/controldims.hrc>
29 #include <vcl/idle.hxx>
31 #include <sfx2/basedlgs.hxx>
32 #include <sfx2/viewfrm.hxx>
33 #include <sfx2/tabdlg.hxx>
34 #include <sfx2/app.hxx>
35 #include <sfx2/bindings.hxx>
36 #include <sfx2/dispatch.hxx>
37 #include <sfx2/childwin.hxx>
38 #include <sfx2/viewsh.hxx>
39 #include <sfx2/sfxhelp.hxx>
40 #include "workwin.hxx"
41 #include <sfx2/sfxresid.hxx>
44 using namespace ::com::sun::star::uno
;
46 #define USERITEM_NAME OUString("UserItem")
48 SingleTabDlgImpl::SingleTabDlgImpl()
54 class SfxModelessDialog_Impl
: public SfxListener
60 void Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
) SAL_OVERRIDE
;
65 void SfxModelessDialog_Impl::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
67 const SfxSimpleHint
* pSimpleHint
= dynamic_cast<const SfxSimpleHint
*>(&rHint
);
70 switch( pSimpleHint
->GetId() )
79 class SfxFloatingWindow_Impl
: public SfxListener
87 void Notify( SfxBroadcaster
& rBC
, const SfxHint
& rHint
) SAL_OVERRIDE
;
90 void SfxFloatingWindow_Impl::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
92 const SfxSimpleHint
* pSimpleHint
= dynamic_cast<const SfxSimpleHint
*>(&rHint
);
95 switch( pSimpleHint
->GetId() )
106 void SfxModalDialog::SetDialogData_Impl()
108 // save settings (position and user data)
110 if (isLayoutEnabled())
111 sConfigId
= OStringToOUString(GetHelpId(),RTL_TEXTENCODING_UTF8
);
114 SAL_WARN("sfx.config", "Dialog needs to be converted to .ui format");
115 sConfigId
= OUString::number(nUniqId
);
118 SvtViewOptions
aDlgOpt(E_DIALOG
, sConfigId
);
119 aDlgOpt
.SetWindowState(OStringToOUString(
120 GetWindowState(WINDOWSTATE_MASK_POS
), RTL_TEXTENCODING_ASCII_US
));
121 if ( !aExtraData
.isEmpty() )
122 aDlgOpt
.SetUserItem( USERITEM_NAME
, makeAny( aExtraData
) );
127 void SfxModalDialog::GetDialogData_Impl()
131 Helper function, reads the dialogue position from the ini file and
132 puts them on the transferred window.
137 if (isLayoutEnabled())
138 sConfigId
= OStringToOUString(GetHelpId(),RTL_TEXTENCODING_UTF8
);
141 SAL_WARN("sfx.config", "Dialog needs to be converted to .ui format");
142 sConfigId
= OUString::number(nUniqId
);
145 SvtViewOptions
aDlgOpt(E_DIALOG
, sConfigId
);
146 if ( aDlgOpt
.Exists() )
149 SetWindowState( OUStringToOString( aDlgOpt
.GetWindowState().getStr(), RTL_TEXTENCODING_ASCII_US
) );
150 Any aUserItem
= aDlgOpt
.GetUserItem( USERITEM_NAME
);
152 if ( aUserItem
>>= aTemp
)
157 void SfxModalDialog::init()
159 GetDialogData_Impl();
162 SfxModalDialog::SfxModalDialog(vcl::Window
*pParent
, const OUString
& rID
, const OUString
& rUIXMLDescription
)
163 : ModalDialog(pParent
, rID
, rUIXMLDescription
),
164 nUniqId(0), //todo: remove this member when the ResId using ctor is removed
171 SfxModalDialog::~SfxModalDialog()
176 void SfxModalDialog::dispose()
178 SetDialogData_Impl();
180 ModalDialog::dispose();
183 void SfxModalDialog::CreateOutputItemSet( SfxItemPool
& rPool
)
185 DBG_ASSERT( !pOutputSet
, "Double creation of OutputSet!" );
187 pOutputSet
= new SfxAllItemSet( rPool
);
192 void SfxModalDialog::CreateOutputItemSet( const SfxItemSet
& rSet
)
194 DBG_ASSERT( !pOutputSet
, "Double creation of OutputSet!" );
197 pOutputSet
= new SfxItemSet( rSet
);
198 pOutputSet
->ClearItem();
203 void SfxModelessDialog::StateChanged( StateChangedType nStateChange
)
205 if ( nStateChange
== StateChangedType::InitShow
)
207 if ( !pImp
->aWinState
.isEmpty() )
209 SetWindowState( pImp
->aWinState
);
213 Point aPos
= GetPosPixel();
216 aSize
= GetSizePixel();
218 Size aParentSize
= GetParent()->GetOutputSizePixel();
219 Size aDlgSize
= GetSizePixel();
220 aPos
.X() += ( aParentSize
.Width() - aDlgSize
.Width() ) / 2;
221 aPos
.Y() += ( aParentSize
.Height() - aDlgSize
.Height() ) / 2;
224 Rectangle aRect
= GetDesktopRectPixel();
225 aPoint
.X() = aRect
.Right() - aDlgSize
.Width();
226 aPoint
.Y() = aRect
.Bottom() - aDlgSize
.Height();
228 aPoint
= OutputToScreenPixel( aPoint
);
230 if ( aPos
.X() > aPoint
.X() )
231 aPos
.X() = aPoint
.X() ;
232 if ( aPos
.Y() > aPoint
.Y() )
233 aPos
.Y() = aPoint
.Y();
235 if ( aPos
.X() < 0 ) aPos
.X() = 0;
236 if ( aPos
.Y() < 0 ) aPos
.Y() = 0;
242 pImp
->bConstructed
= true;
245 ModelessDialog::StateChanged( nStateChange
);
248 void SfxModelessDialog::Initialize(SfxChildWinInfo
*pInfo
)
252 Initialization of the class SfxModelessDialog via a SfxChildWinInfo.
253 The initialization is done only in a 2nd step after the constructor, this
254 constructor should be called from the derived class or from the
260 pImp
->aWinState
= pInfo
->aWinState
;
263 void SfxModelessDialog::Resize()
267 This virtual method of the class FloatingWindow keeps track if a change
268 in size has been made. When this method is overridden by a derived class,
269 then the SfxFloatingWindow: Resize() must also be called.
273 ModelessDialog::Resize();
274 if ( pImp
->bConstructed
&& pImp
->pMgr
)
276 // start timer for saving window status information
277 pImp
->aMoveIdle
.Start();
281 void SfxModelessDialog::Move()
283 ModelessDialog::Move();
284 if ( pImp
->bConstructed
&& pImp
->pMgr
&& IsReallyVisible() )
286 // start timer for saving window status information
287 pImp
->aMoveIdle
.Start();
292 Implements a timer event that is triggered by a move or resize of the window
293 This will save config information to Views.xcu with a small delay
295 IMPL_LINK_NOARG_TYPED(SfxModelessDialog
, TimerHdl
, Idle
*, void)
297 pImp
->aMoveIdle
.Stop();
298 if ( pImp
->bConstructed
&& pImp
->pMgr
)
301 aSize
= GetSizePixel();
302 sal_uIntPtr nMask
= WINDOWSTATE_MASK_POS
| WINDOWSTATE_MASK_STATE
;
303 if ( GetStyle() & WB_SIZEABLE
)
304 nMask
|= ( WINDOWSTATE_MASK_WIDTH
| WINDOWSTATE_MASK_HEIGHT
);
305 pImp
->aWinState
= GetWindowState( nMask
);
306 GetBindings().GetWorkWindow_Impl()->ConfigChild_Impl( SfxChildIdentifier::DOCKINGWINDOW
, SfxDockingConfig::ALIGNDOCKINGWINDOW
, pImp
->pMgr
->GetType() );
310 SfxModelessDialog::SfxModelessDialog(SfxBindings
* pBindinx
,
311 SfxChildWindow
*pCW
, vcl::Window
*pParent
, const OUString
& rID
,
312 const OUString
& rUIXMLDescription
)
313 : ModelessDialog(pParent
, rID
, rUIXMLDescription
)
318 void SfxModelessDialog::Init(SfxBindings
*pBindinx
, SfxChildWindow
*pCW
)
320 pBindings
= pBindinx
;
321 pImp
= new SfxModelessDialog_Impl
;
323 pImp
->bConstructed
= false;
324 SetUniqueId( GetHelpId() );
326 pImp
->StartListening( *pBindinx
);
327 pImp
->aMoveIdle
.SetPriority(SchedulerPriority::RESIZE
);
328 pImp
->aMoveIdle
.SetIdleHdl(LINK(this,SfxModelessDialog
,TimerHdl
));
333 If a ModelessDialog is enabled its ViewFrame wil be activated.
334 This is necessary by PluginInFrames.
336 bool SfxModelessDialog::Notify( NotifyEvent
& rEvt
)
340 if ( rEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
342 pBindings
->SetActiveFrame( pImp
->pMgr
->GetFrame() );
343 pImp
->pMgr
->Activate_Impl();
345 else if ( rEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
&& !HasChildPathFocus() )
347 pBindings
->SetActiveFrame( ::com::sun::star::uno::Reference
< ::com::sun::star::frame::XFrame
> () );
348 pImp
->pMgr
->Deactivate_Impl();
350 else if( rEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
352 // First, allow KeyInput for Dialog functions ( TAB etc. )
353 if ( !ModelessDialog::Notify( rEvt
) && SfxViewShell::Current() )
354 // then also for valid global accelerators.
355 return SfxViewShell::Current()->GlobalKeyInput_Impl( *rEvt
.GetKeyEvent() );
360 return ModelessDialog::Notify( rEvt
);
363 SfxModelessDialog::~SfxModelessDialog()
368 void SfxModelessDialog::dispose()
370 if ( pImp
->pMgr
->GetFrame().is() && pImp
->pMgr
->GetFrame() == pBindings
->GetActiveFrame() )
371 pBindings
->SetActiveFrame( NULL
);
374 ModelessDialog::dispose();
379 bool SfxModelessDialog::Close()
383 The window is closed when the ChildWindow is destroyed by running the
384 ChildWindow-slots. If this is method is overridden by a derived class
385 method, then the SfxModelessDialogWindow: Close() must be called afterwards
386 if the Close() was not cancelled with "return sal_False".
390 // Execute with Parameters, since Toggle is ignored by some ChildWindows.
391 SfxBoolItem
aValue( pImp
->pMgr
->GetType(), false);
392 pBindings
->GetDispatcher_Impl()->Execute(
393 pImp
->pMgr
->GetType(),
394 SfxCallMode::RECORD
|SfxCallMode::SYNCHRON
, &aValue
, 0L );
400 void SfxModelessDialog::FillInfo(SfxChildWinInfo
& rInfo
) const
404 Fills a SfxChildWinInfo with specific data from SfxModelessDialog,
405 so that it can be written in the INI file. It is assumed that rinfo
406 receives all other possible relevant data in the ChildWindow class.
407 ModelessDialogs have no specific information, so that the base
408 implementation does nothing and therefore must not be called.
414 rInfo
.nFlags
|= SfxChildWindowFlags::ZOOMIN
;
419 bool SfxFloatingWindow::Notify( NotifyEvent
& rEvt
)
423 If a ModelessDialog is enabled, its ViewFrame will be activated.
424 This necessary for the PluginInFrames.
430 if ( rEvt
.GetType() == MouseNotifyEvent::GETFOCUS
)
432 pBindings
->SetActiveFrame( pImp
->pMgr
->GetFrame() );
433 pImp
->pMgr
->Activate_Impl();
435 else if ( rEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
)
437 if ( !HasChildPathFocus() )
439 pBindings
->SetActiveFrame( NULL
);
440 pImp
->pMgr
->Deactivate_Impl();
443 else if( rEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
445 // First, allow KeyInput for Dialog functions
446 if ( !FloatingWindow::Notify( rEvt
) && SfxViewShell::Current() )
447 // then also for valid global accelerators.
448 return SfxViewShell::Current()->GlobalKeyInput_Impl( *rEvt
.GetKeyEvent() );
453 return FloatingWindow::Notify( rEvt
);
456 SfxFloatingWindow::SfxFloatingWindow( SfxBindings
*pBindinx
,
458 vcl::Window
* pParent
, WinBits nWinBits
) :
459 FloatingWindow (pParent
, nWinBits
),
461 pImp( new SfxFloatingWindow_Impl
)
464 pImp
->bConstructed
= false;
465 SetUniqueId( GetHelpId() );
468 pImp
->StartListening( *pBindinx
);
469 pImp
->aMoveIdle
.SetPriority(SchedulerPriority::RESIZE
);
470 pImp
->aMoveIdle
.SetIdleHdl(LINK(this,SfxFloatingWindow
,TimerHdl
));
473 SfxFloatingWindow::SfxFloatingWindow( SfxBindings
*pBindinx
,
475 vcl::Window
* pParent
,
476 const OString
& rID
, const OUString
& rUIXMLDescription
, const css::uno::Reference
<css::frame::XFrame
> &rFrame
) :
477 FloatingWindow(pParent
, rID
, rUIXMLDescription
, rFrame
),
479 pImp( new SfxFloatingWindow_Impl
)
482 pImp
->bConstructed
= false;
484 //do we really need this odd helpid/uniqueid dance ?
485 SetUniqueId( GetHelpId() );
489 pImp
->StartListening( *pBindinx
);
490 pImp
->aMoveIdle
.SetPriority(SchedulerPriority::RESIZE
);
491 pImp
->aMoveIdle
.SetIdleHdl(LINK(this,SfxFloatingWindow
,TimerHdl
));
494 bool SfxFloatingWindow::Close()
498 The window is closed when the ChildWindow is destroyed by running the
499 ChildWindow-slots. If this is method is overridden by a derived class
500 method, then the SfxModelessDialogWindow: Close) must be called afterwards
501 if the Close() was not cancelled with "return sal_False".
505 // Execute with Parameters, since Toggle is ignored by some ChildWindows.
506 SfxBoolItem
aValue( pImp
->pMgr
->GetType(), false);
507 pBindings
->GetDispatcher_Impl()->Execute(
508 pImp
->pMgr
->GetType(),
509 SfxCallMode::RECORD
|SfxCallMode::SYNCHRON
, &aValue
, 0L );
515 SfxFloatingWindow::~SfxFloatingWindow()
520 void SfxFloatingWindow::dispose()
522 if ( pImp
&& pImp
->pMgr
->GetFrame() == pBindings
->GetActiveFrame() )
523 pBindings
->SetActiveFrame( NULL
);
526 FloatingWindow::dispose();
529 void SfxFloatingWindow::Resize()
533 This virtual method of the class FloatingWindow keeps track if a change
534 in size has been made. When this method is overridden by a derived class,
535 then the SfxFloatingWindow: Resize() must also be called.
539 FloatingWindow::Resize();
540 if ( pImp
->bConstructed
&& pImp
->pMgr
)
542 // start timer for saving window status information
543 pImp
->aMoveIdle
.Start();
547 void SfxFloatingWindow::Move()
549 FloatingWindow::Move();
550 if ( pImp
->bConstructed
&& pImp
->pMgr
)
552 // start timer for saving window status information
553 pImp
->aMoveIdle
.Start();
558 Implements a timer event that is triggered by a move or resize of the window
559 This will save config information to Views.xcu with a small delay
561 IMPL_LINK_NOARG_TYPED(SfxFloatingWindow
, TimerHdl
, Idle
*, void)
563 pImp
->aMoveIdle
.Stop();
564 if ( pImp
->bConstructed
&& pImp
->pMgr
)
567 aSize
= GetSizePixel();
568 sal_uIntPtr nMask
= WINDOWSTATE_MASK_POS
| WINDOWSTATE_MASK_STATE
;
569 if ( GetStyle() & WB_SIZEABLE
)
570 nMask
|= ( WINDOWSTATE_MASK_WIDTH
| WINDOWSTATE_MASK_HEIGHT
);
571 pImp
->aWinState
= GetWindowState( nMask
);
572 GetBindings().GetWorkWindow_Impl()->ConfigChild_Impl( SfxChildIdentifier::DOCKINGWINDOW
, SfxDockingConfig::ALIGNDOCKINGWINDOW
, pImp
->pMgr
->GetType() );
577 void SfxFloatingWindow::StateChanged( StateChangedType nStateChange
)
579 if ( nStateChange
== StateChangedType::InitShow
)
581 // FloatingWindows are not centered by default
582 if ( !pImp
->aWinState
.isEmpty() )
583 SetWindowState( pImp
->aWinState
);
584 pImp
->bConstructed
= true;
587 FloatingWindow::StateChanged( nStateChange
);
591 void SfxFloatingWindow::Initialize(SfxChildWinInfo
*pInfo
)
595 Initialization of a class SfxFloatingWindow through a SfxChildWinInfo.
596 The initialization is done only in a 2nd step after the constructor and
597 should be called by the constructor of the derived class or from the
602 pImp
->aWinState
= pInfo
->aWinState
;
607 void SfxFloatingWindow::FillInfo(SfxChildWinInfo
& rInfo
) const
611 Fills a SfxChildWinInfo with specific data from SfxFloatingWindow,
612 so that it can be written in the INI file. It is assumed that rinfo
613 receives all other possible relevant data in the ChildWindow class.
614 Insertions are marked with size and the ZoomIn flag.
615 If this method is overridden, the base implementation must be called first.
621 rInfo
.nFlags
|= SfxChildWindowFlags::ZOOMIN
;
624 // SfxSingleTabDialog ----------------------------------------------------
626 IMPL_LINK_NOARG(SfxSingleTabDialog
, OKHdl_Impl
)
630 Ok_Handler; FillItemSet() is called for setting of Page.
634 if ( !GetInputItemSet() )
636 // TabPage without ItemSet
641 if ( !GetOutputItemSet() )
643 CreateOutputItemSet( *GetInputItemSet() );
645 bool bModified
= false;
647 if ( pImpl
->m_pSfxPage
->HasExchangeSupport() )
649 int nRet
= pImpl
->m_pSfxPage
->DeactivatePage( GetOutputSetImpl() );
650 if ( nRet
!= SfxTabPage::LEAVE_PAGE
)
653 bModified
= ( GetOutputItemSet()->Count() > 0 );
656 bModified
= pImpl
->m_pSfxPage
->FillItemSet( GetOutputSetImpl() );
660 // Save user data in IniManager.
661 pImpl
->m_pSfxPage
->FillUserData();
662 OUString
sData( pImpl
->m_pSfxPage
->GetUserData() );
664 OUString sConfigId
= OStringToOUString(pImpl
->m_pSfxPage
->GetConfigId(),
665 RTL_TEXTENCODING_UTF8
);
666 if (sConfigId
.isEmpty())
668 SAL_WARN("sfx.config", "Tabpage needs to be converted to .ui format");
669 sConfigId
= OUString::number(GetUniqId());
672 SvtViewOptions
aPageOpt(E_TABPAGE
, sConfigId
);
673 aPageOpt
.SetUserItem( USERITEM_NAME
, makeAny( OUString( sData
) ) );
677 EndDialog( RET_CANCEL
);
683 SfxSingleTabDialog::SfxSingleTabDialog(vcl::Window
*pParent
, const SfxItemSet
& rSet
,
684 const OUString
& rID
, const OUString
& rUIXMLDescription
)
685 : SfxModalDialog(pParent
, rID
, rUIXMLDescription
)
687 , pImpl(new SingleTabDlgImpl
)
690 pOKBtn
->SetClickHdl( LINK( this, SfxSingleTabDialog
, OKHdl_Impl
) );
691 get(pCancelBtn
, "cancel");
692 get(pHelpBtn
, "help");
693 SetInputSet( &rSet
);
696 SfxSingleTabDialog::SfxSingleTabDialog(vcl::Window
* pParent
, const SfxItemSet
* pInSet
,
697 const OUString
& rID
, const OUString
& rUIXMLDescription
)
698 : SfxModalDialog(pParent
, rID
, rUIXMLDescription
)
700 , pImpl(new SingleTabDlgImpl
)
703 pOKBtn
->SetClickHdl( LINK( this, SfxSingleTabDialog
, OKHdl_Impl
) );
704 get(pCancelBtn
, "cancel");
705 get(pHelpBtn
, "help");
706 SetInputSet( pInSet
);
709 SfxSingleTabDialog::~SfxSingleTabDialog()
714 void SfxSingleTabDialog::dispose()
716 pImpl
->m_pSfxPage
.disposeAndClear();
717 pImpl
->m_pLine
.disposeAndClear();
722 SfxModalDialog::dispose();
725 void SfxSingleTabDialog::SetTabPage(SfxTabPage
* pTabPage
,
726 GetTabPageRanges pRangesFunc
, sal_uInt32 nSettingsId
)
729 Insert a (new) TabPage; an existing page is deleted.
730 The passed on page is initialized with the initially given Itemset
731 through calling Reset().
735 SetUniqId(nSettingsId
);
736 pImpl
->m_pSfxPage
.disposeAndClear();
737 pImpl
->m_pSfxPage
= pTabPage
;
738 fnGetRanges
= pRangesFunc
;
740 if ( pImpl
->m_pSfxPage
)
742 // First obtain the user data, only then Reset()
743 OUString sConfigId
= OStringToOUString(pImpl
->m_pSfxPage
->GetConfigId(),
744 RTL_TEXTENCODING_UTF8
);
745 if (sConfigId
.isEmpty())
747 SAL_WARN("sfx.config", "Tabpage needs to be converted to .ui format");
748 sConfigId
= OUString::number(GetUniqId());
751 SvtViewOptions
aPageOpt(E_TABPAGE
, sConfigId
);
752 Any aUserItem
= aPageOpt
.GetUserItem( USERITEM_NAME
);
754 aUserItem
>>= sUserData
;
755 pImpl
->m_pSfxPage
->SetUserData(sUserData
);
756 pImpl
->m_pSfxPage
->Reset( GetInputItemSet() );
757 pImpl
->m_pSfxPage
->Show();
759 pHelpBtn
->Show(Help::IsContextHelpEnabled());
761 // Set TabPage text in the Dialog if there is any
762 OUString
sTitle(pImpl
->m_pSfxPage
->GetText());
763 if (!sTitle
.isEmpty())
766 // Dialog receives the HelpId of TabPage if there is any
767 OString
sHelpId(pImpl
->m_pSfxPage
->GetHelpId());
768 if (!sHelpId
.isEmpty())
770 OString
sUniqueId(pImpl
->m_pSfxPage
->GetUniqueId());
771 if (!sUniqueId
.isEmpty())
772 SetUniqueId(sUniqueId
);
776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */