lok dialog: enable MessageDialog tunneling
[LibreOffice.git] / sfx2 / source / dialog / tabdlg.cxx
blob4eb7a29d1c49a304c6f66b1ec0d1eac08674a160
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 .
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <algorithm>
25 #include <appdata.hxx>
26 #include <comphelper/lok.hxx>
27 #include <sfxtypes.hxx>
28 #include <sfx2/tabdlg.hxx>
29 #include <sfx2/viewfrm.hxx>
30 #include <sfx2/app.hxx>
31 #include <sfx2/sfxresid.hxx>
32 #include <sfx2/sfxhelp.hxx>
33 #include <sfx2/ctrlitem.hxx>
34 #include <sfx2/bindings.hxx>
35 #include <sfx2/sfxdlg.hxx>
36 #include <sfx2/itemconnect.hxx>
37 #include <sfx2/viewsh.hxx>
38 #include <uitest/sfx_uiobject.hxx>
39 #include <unotools/viewoptions.hxx>
40 #include <vcl/builder.hxx>
41 #include <vcl/msgbox.hxx>
42 #include <vcl/IDialogRenderable.hxx>
44 #include <sfx2/strings.hrc>
45 #include <helpids.h>
47 using namespace ::com::sun::star::uno;
49 #define USERITEM_NAME "UserItem"
52 struct TabPageImpl
54 bool mbStandard;
55 sfx::ItemConnectionArray maItemConn;
56 css::uno::Reference< css::frame::XFrame > mxFrame;
58 TabPageImpl() : mbStandard( false ) {}
61 struct Data_Impl
63 sal_uInt16 nId; // The ID
64 CreateTabPage fnCreatePage; // Pointer to Factory
65 GetTabPageRanges fnGetRanges; // Pointer to Ranges-Function
66 VclPtr<SfxTabPage> pTabPage; // The TabPage itself
67 bool bRefresh; // Flag: Page must be re-initialized
69 // Constructor
70 Data_Impl( sal_uInt16 Id, CreateTabPage fnPage,
71 GetTabPageRanges fnRanges ) :
73 nId ( Id ),
74 fnCreatePage( fnPage ),
75 fnGetRanges ( fnRanges ),
76 pTabPage ( nullptr ),
77 bRefresh ( false )
79 if ( !fnCreatePage )
81 SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
82 if ( pFact )
84 fnCreatePage = pFact->GetTabPageCreatorFunc( nId );
85 fnGetRanges = pFact->GetTabPageRangesFunc( nId );
91 SfxTabDialogItem::SfxTabDialogItem( const SfxTabDialogItem& rAttr, SfxItemPool* pItemPool )
92 : SfxSetItem( rAttr, pItemPool )
96 SfxTabDialogItem::SfxTabDialogItem( sal_uInt16 nId, const SfxItemSet& rItemSet )
97 : SfxSetItem( nId, rItemSet )
101 SfxPoolItem* SfxTabDialogItem::Clone(SfxItemPool* pToPool) const
103 return new SfxTabDialogItem( *this, pToPool );
106 SfxPoolItem* SfxTabDialogItem::Create(SvStream& /*rStream*/, sal_uInt16 /*nVersion*/) const
108 OSL_FAIL( "Use it only in UI!" );
109 return nullptr;
112 typedef std::vector<Data_Impl*> SfxTabDlgData_Impl;
114 struct TabDlg_Impl
116 bool bModal : 1,
117 bHideResetBtn : 1;
118 SfxTabDlgData_Impl aData;
120 explicit TabDlg_Impl( sal_uInt8 nCnt ) :
121 bModal ( true ),
122 bHideResetBtn ( false )
124 aData.reserve( nCnt );
129 static Data_Impl* Find( const SfxTabDlgData_Impl& rArr, sal_uInt16 nId, sal_uInt16* pPos = nullptr)
131 const sal_uInt16 nCount = rArr.size();
133 for ( sal_uInt16 i = 0; i < nCount; ++i )
135 Data_Impl* pObj = rArr[i];
137 if ( pObj->nId == nId )
139 if ( pPos )
140 *pPos = i;
141 return pObj;
144 return nullptr;
147 void SfxTabPage::SetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame)
149 if (pImpl)
150 pImpl->mxFrame = xFrame;
153 css::uno::Reference< css::frame::XFrame > SfxTabPage::GetFrame()
155 if (pImpl)
156 return pImpl->mxFrame;
157 return css::uno::Reference< css::frame::XFrame >();
160 SfxTabPage::SfxTabPage(vcl::Window *pParent, const OString& rID, const OUString& rUIXMLDescription, const SfxItemSet *rAttrSet)
161 : TabPage(pParent, rID, rUIXMLDescription)
162 , pSet ( rAttrSet )
163 , bHasExchangeSupport ( false )
164 , pImpl ( new TabPageImpl )
168 SfxTabPage::~SfxTabPage()
170 disposeOnce();
173 void SfxTabPage::dispose()
175 pImpl.reset();
176 TabPage::dispose();
179 bool SfxTabPage::FillItemSet( SfxItemSet* rSet )
181 return pImpl->maItemConn.DoFillItemSet( *rSet, GetItemSet() );
184 void SfxTabPage::Reset( const SfxItemSet* rSet )
186 pImpl->maItemConn.DoApplyFlags( rSet );
187 pImpl->maItemConn.DoReset( rSet );
190 void SfxTabPage::ActivatePage( const SfxItemSet& )
191 /* [Description]
193 Default implementation of the virtual ActivatePage method. This method is
194 called when a page of dialogue supports the exchange of data between pages.
195 <SfxTabPage::DeactivatePage(SfxItemSet *)>
200 DeactivateRC SfxTabPage::DeactivatePage( SfxItemSet* )
202 /* [Description]
204 Default implementation of the virtual DeactivatePage method. This method is
205 called by Sfx when leaving a page; the application can, through the return
206 value, control whether to leave the page. If the page is displayed through
207 bHasExchangeSupport which supports data exchange between pages, then a
208 pointer to the exchange set is passed as parameter. This takes on data for
209 the exchange, then the set is available as a parameter in
210 <SfxTabPage::ActivatePage(const SfxItemSet &)>.
212 [Return value]
214 DeactivateRC::LeavePage; Allow leaving the page
218 return DeactivateRC::LeavePage;
222 void SfxTabPage::FillUserData()
224 /* [Description]
226 Virtual method is called by the base class in the destructor to save
227 specific information of the TabPage in the ini-file. When overriding a
228 string must be compiled, which is then flushed with the <SetUserData()>.
235 bool SfxTabPage::IsReadOnly() const
237 return false;
241 const SfxPoolItem* SfxTabPage::GetItem( const SfxItemSet& rSet, sal_uInt16 nSlot, bool bDeep )
243 /* [Description]
245 static Method: hereby are the implementations of the TabPage code
246 being simplified.
250 const SfxItemPool* pPool = rSet.GetPool();
251 sal_uInt16 nWh = pPool->GetWhich( nSlot, bDeep );
252 const SfxPoolItem* pItem = nullptr;
253 rSet.GetItemState( nWh, true, &pItem );
255 if ( !pItem && nWh != nSlot )
256 pItem = &pPool->GetDefaultItem( nWh );
257 return pItem;
261 const SfxPoolItem* SfxTabPage::GetOldItem( const SfxItemSet& rSet,
262 sal_uInt16 nSlot, bool bDeep )
264 /* [Description]
266 This method returns an attribute for comparison of the old value.
270 const SfxItemSet& rOldSet = GetItemSet();
271 sal_uInt16 nWh = GetWhich( nSlot, bDeep );
272 const SfxPoolItem* pItem = nullptr;
274 if ( pImpl->mbStandard && rOldSet.GetParent() )
275 pItem = GetItem( *rOldSet.GetParent(), nSlot );
276 else if ( rSet.GetParent() &&
277 SfxItemState::DONTCARE == rSet.GetItemState( nWh ) )
278 pItem = GetItem( *rSet.GetParent(), nSlot );
279 else
280 pItem = GetItem( rOldSet, nSlot );
281 return pItem;
284 void SfxTabPage::PageCreated( const SfxAllItemSet& /*aSet*/ )
286 SAL_WARN( "sfx.dialog", "SfxTabPage::PageCreated should not be called");
289 void SfxTabPage::ChangesApplied()
293 void SfxTabPage::AddItemConnection( sfx::ItemConnectionBase* pConnection )
295 pImpl->maItemConn.AddConnection( pConnection );
298 SfxTabDialog* SfxTabPage::GetTabDialog() const
300 return dynamic_cast<SfxTabDialog*>(GetParentDialog());
304 SfxTabDialog::SfxTabDialog
306 /* [Description]
308 Constructor, temporary without Frame
312 vcl::Window* pParent, // Parent Window
313 const OUString& rID, const OUString& rUIXMLDescription, //Dialog Name, Dialog .ui path
314 const SfxItemSet* pItemSet, // Itemset with the data;
315 // can be NULL, when Pages are onDemand
316 bool bEditFmt // when yes -> additional Button for standard
318 : TabDialog(pParent, rID, rUIXMLDescription)
319 , m_pSet(pItemSet ? new SfxItemSet(*pItemSet) : nullptr)
320 , m_pOutSet(nullptr)
321 , m_pRanges(nullptr)
322 , m_nAppPageId(USHRT_MAX)
323 , m_bStandardPushed(false)
324 , m_pExampleSet(nullptr)
326 Init_Impl(bEditFmt);
328 sal_uInt16 nPageCount = m_pTabCtrl->GetPageCount();
329 for (sal_uInt16 nPage = 0; nPage < nPageCount; ++nPage)
331 sal_uInt16 nPageId = m_pTabCtrl->GetPageId(nPage);
332 m_pTabCtrl->SetTabPage(nPageId, nullptr);
336 SfxTabDialog::~SfxTabDialog()
338 disposeOnce();
341 void SfxTabDialog::dispose()
343 SavePosAndId();
345 for ( SfxTabDlgData_Impl::const_iterator it = m_pImpl->aData.begin(); it != m_pImpl->aData.end(); ++it )
347 Data_Impl* pDataObject = *it;
349 if ( pDataObject->pTabPage )
351 // save settings of all pages (user data)
352 pDataObject->pTabPage->FillUserData();
353 OUString aPageData( pDataObject->pTabPage->GetUserData() );
354 if ( !aPageData.isEmpty() )
356 // save settings of all pages (user data)
357 OUString sConfigId = OStringToOUString(pDataObject->pTabPage->GetConfigId(),
358 RTL_TEXTENCODING_UTF8);
359 if (sConfigId.isEmpty())
361 SAL_WARN("sfx.dialog", "Tabpage needs to be converted to .ui format");
362 sConfigId = OUString::number(pDataObject->nId);
365 SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
366 aPageOpt.SetUserItem( USERITEM_NAME, makeAny( aPageData ) );
369 pDataObject->pTabPage.disposeAndClear();
371 delete pDataObject;
372 pDataObject = nullptr;
375 m_pImpl.reset();
376 delete m_pSet;
377 m_pSet = nullptr;
378 delete m_pOutSet;
379 m_pOutSet = nullptr;
380 delete m_pExampleSet;
381 m_pExampleSet = nullptr;
382 delete [] m_pRanges;
383 m_pRanges = nullptr;
385 if (m_bOwnsBaseFmtBtn)
386 m_pBaseFmtBtn.disposeAndClear();
387 if (m_bOwnsResetBtn)
388 m_pResetBtn.disposeAndClear();
389 if (m_bOwnsHelpBtn)
390 m_pHelpBtn.disposeAndClear();
391 if (m_bOwnsCancelBtn)
392 m_pCancelBtn.disposeAndClear();
393 if (m_bOwnsOKBtn)
394 m_pOKBtn.disposeAndClear();
395 m_pBox.clear();
396 m_pTabCtrl.clear();
397 m_pOKBtn.clear();
398 m_pApplyBtn.clear();
399 m_pUserBtn.clear();
400 m_pCancelBtn.clear();
401 m_pHelpBtn.clear();
402 m_pResetBtn.clear();
403 m_pBaseFmtBtn.clear();
404 m_pActionArea.clear();
406 TabDialog::dispose();
409 void SfxTabDialog::Init_Impl(bool bFmtFlag)
410 /* [Description]
412 internal initialization of the dialogue
415 m_pBox = get_content_area();
416 assert(m_pBox);
417 m_pUIBuilder->get(m_pTabCtrl, "tabcontrol");
419 m_pImpl.reset( new TabDlg_Impl(m_pTabCtrl->GetPageCount()) );
421 m_pActionArea = get_action_area();
422 assert(m_pActionArea);
424 m_pOKBtn = m_pUIBuilder->get<PushButton>("ok");
425 m_bOwnsOKBtn = m_pOKBtn == nullptr;
426 if (m_bOwnsOKBtn)
427 m_pOKBtn = VclPtr<OKButton>::Create(m_pActionArea);
429 m_pApplyBtn = m_pUIBuilder->get<PushButton>("apply");
430 m_pUserBtn = m_pUIBuilder->get<PushButton>("user");
431 m_pCancelBtn = m_pUIBuilder->get<CancelButton>("cancel");
432 m_bOwnsCancelBtn = m_pCancelBtn == nullptr;
433 if (m_bOwnsCancelBtn)
434 m_pCancelBtn = VclPtr<CancelButton>::Create(m_pActionArea);
436 m_pHelpBtn = m_pUIBuilder->get<HelpButton>("help");
437 m_bOwnsHelpBtn = m_pHelpBtn == nullptr;
438 if (m_bOwnsHelpBtn)
439 m_pHelpBtn = VclPtr<HelpButton>::Create(m_pActionArea);
441 m_pResetBtn = m_pUIBuilder->get<PushButton>("reset");
442 m_bOwnsResetBtn = m_pResetBtn == nullptr;
443 if (m_bOwnsResetBtn)
445 m_pResetBtn = VclPtr<PushButton>::Create(m_pActionArea.get());
446 m_pResetBtn->set_id("reset");
448 else
449 m_pImpl->bHideResetBtn = !m_pResetBtn->IsVisible();
451 m_pBaseFmtBtn = m_pUIBuilder->get<PushButton>("standard");
452 m_bOwnsBaseFmtBtn = m_pBaseFmtBtn == nullptr;
453 if (m_bOwnsBaseFmtBtn)
455 m_pBaseFmtBtn = VclPtr<PushButton>::Create(m_pActionArea.get());
456 m_pBaseFmtBtn->set_id("standard");
459 m_pOKBtn->SetClickHdl( LINK( this, SfxTabDialog, OkHdl ) );
460 m_pCancelBtn->SetClickHdl( LINK( this, SfxTabDialog, CancelHdl ) );
461 m_pResetBtn->SetClickHdl( LINK( this, SfxTabDialog, ResetHdl ) );
462 m_pResetBtn->SetText( SfxResId( STR_RESET ) );
463 m_pTabCtrl->SetActivatePageHdl(
464 LINK( this, SfxTabDialog, ActivatePageHdl ) );
465 m_pTabCtrl->SetDeactivatePageHdl(
466 LINK( this, SfxTabDialog, DeactivatePageHdl ) );
467 m_pActionArea->Show();
468 m_pBox->Show();
469 m_pTabCtrl->Show();
470 m_pOKBtn->Show();
471 m_pCancelBtn->Show();
472 m_pHelpBtn->Show();
473 m_pResetBtn->Show();
474 m_pResetBtn->SetHelpId( HID_TABDLG_RESET_BTN );
476 if ( m_pUserBtn )
478 m_pUserBtn->SetClickHdl( LINK( this, SfxTabDialog, UserHdl ) );
479 m_pUserBtn->Show();
482 if ( bFmtFlag )
484 m_pBaseFmtBtn->SetText( SfxResId( STR_STANDARD_SHORTCUT ) );
485 m_pBaseFmtBtn->SetClickHdl( LINK( this, SfxTabDialog, BaseFmtHdl ) );
486 m_pBaseFmtBtn->SetHelpId( HID_TABDLG_STANDARD_BTN );
487 m_pBaseFmtBtn->Show();
490 if ( m_pSet )
492 m_pExampleSet = new SfxItemSet( *m_pSet );
493 m_pOutSet = new SfxItemSet( *m_pSet->GetPool(), m_pSet->GetRanges() );
497 void SfxTabDialog::RemoveResetButton()
499 m_pResetBtn->Hide();
500 m_pImpl->bHideResetBtn = true;
503 void SfxTabDialog::RemoveStandardButton()
505 m_pBaseFmtBtn->Hide();
508 short SfxTabDialog::Execute()
510 if ( !m_pTabCtrl->GetPageCount() )
511 return RET_CANCEL;
512 Start_Impl();
514 return TabDialog::Execute();
517 bool SfxTabDialog::StartExecuteAsync( VclAbstractDialog::AsyncContext &rCtx )
519 if ( !m_pTabCtrl->GetPageCount() )
521 rCtx.mxOwner.disposeAndClear();
522 return false;
524 Start_Impl();
525 return TabDialog::StartExecuteAsync( rCtx );
528 void SfxTabDialog::StartExecuteModal( const Link<Dialog&,void>& rEndDialogHdl )
530 if ( !m_pTabCtrl->GetPageCount() )
531 return;
532 Start_Impl();
533 TabDialog::StartExecuteModal( rEndDialogHdl );
537 void SfxTabDialog::Start()
539 m_pImpl->bModal = false;
540 Start_Impl();
542 Show();
544 if ( IsVisible() && ( !HasChildPathFocus() || HasFocus() ) )
545 GrabFocusToFirstControl();
549 void SfxTabDialog::SetApplyHandler(const Link<Button*, void>& _rHdl)
551 DBG_ASSERT( m_pApplyBtn, "SfxTabDialog::GetApplyHandler: no apply button enabled!" );
552 if ( m_pApplyBtn )
553 m_pApplyBtn->SetClickHdl( _rHdl );
557 void SfxTabDialog::Start_Impl()
559 assert(m_pImpl->aData.size() == m_pTabCtrl->GetPageCount()
560 && "not all pages registered");
561 sal_uInt16 nActPage = m_pTabCtrl->GetPageId( 0 );
563 // load old settings, when exists
564 SvtViewOptions aDlgOpt(EViewType::TabDialog, OStringToOUString(GetHelpId(),RTL_TEXTENCODING_UTF8));
565 if ( aDlgOpt.Exists() )
567 SetWindowState(OUStringToOString(aDlgOpt.GetWindowState(), RTL_TEXTENCODING_ASCII_US));
569 // initial TabPage from Program/Help/config
570 nActPage = static_cast<sal_uInt16>(aDlgOpt.GetPageID());
572 if ( USHRT_MAX != m_nAppPageId )
573 nActPage = m_nAppPageId;
575 if ( TAB_PAGE_NOTFOUND == m_pTabCtrl->GetPagePos( nActPage ) )
576 nActPage = m_pTabCtrl->GetPageId( 0 );
578 else if ( USHRT_MAX != m_nAppPageId && TAB_PAGE_NOTFOUND != m_pTabCtrl->GetPagePos( m_nAppPageId ) )
579 nActPage = m_nAppPageId;
581 m_pTabCtrl->SetCurPageId( nActPage );
582 ActivatePageHdl( m_pTabCtrl );
585 void SfxTabDialog::AddTabPage( sal_uInt16 nId, const OUString &rRiderText )
587 AddTabPage( nId, rRiderText, nullptr, nullptr );
591 Adds a page to the dialog. The Name must correspond to a entry in the
592 TabControl in the dialog .ui
594 sal_uInt16 SfxTabDialog::AddTabPage
596 const OString &rName, // Page ID
597 CreateTabPage pCreateFunc, // Pointer to the Factory Method
598 GetTabPageRanges pRangesFunc // Pointer to the Method for querying
599 // Ranges onDemand
602 sal_uInt16 nId = m_pTabCtrl->GetPageId(rName);
603 m_pImpl->aData.push_back(
604 new Data_Impl( nId, pCreateFunc, pRangesFunc ) );
605 return nId;
609 Adds a page to the dialog. The Name must correspond to a entry in the
610 TabControl in the dialog .ui
612 sal_uInt16 SfxTabDialog::AddTabPage
614 const OString &rName, // Page ID
615 sal_uInt16 nPageCreateId // Identifier of the Factory Method to create the page
618 SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
619 assert(pFact);
620 CreateTabPage pCreateFunc = pFact->GetTabPageCreatorFunc(nPageCreateId);
621 assert(pCreateFunc);
622 GetTabPageRanges pRangesFunc = pFact->GetTabPageRangesFunc(nPageCreateId);
623 sal_uInt16 nPageId = m_pTabCtrl->GetPageId(rName);
624 m_pImpl->aData.push_back(new Data_Impl(nPageId, pCreateFunc, pRangesFunc));
625 return nPageId;
629 void SfxTabDialog::AddTabPage
631 /* [Description]
633 Add a page to the dialog. The Rider text is passed on, the page has no
634 counterpart in the TabControl in the resource of the dialogue.
638 sal_uInt16 nId,
639 const OUString& rRiderText,
640 CreateTabPage pCreateFunc,
641 GetTabPageRanges pRangesFunc,
642 sal_uInt16 nPos
645 DBG_ASSERT( TAB_PAGE_NOTFOUND == m_pTabCtrl->GetPagePos( nId ),
646 "Double Page-Ids in the Tabpage" );
647 m_pTabCtrl->InsertPage( nId, rRiderText, nPos );
648 m_pImpl->aData.push_back( new Data_Impl( nId, pCreateFunc, pRangesFunc ) );
651 void SfxTabDialog::RemoveTabPage( sal_uInt16 nId )
653 /* [Description]
655 Delete the TabPage with ID nId
659 sal_uInt16 nPos = 0;
660 m_pTabCtrl->RemovePage( nId );
661 Data_Impl* pDataObject = Find( m_pImpl->aData, nId, &nPos );
663 if ( pDataObject )
665 if ( pDataObject->pTabPage )
667 pDataObject->pTabPage->FillUserData();
668 OUString aPageData( pDataObject->pTabPage->GetUserData() );
669 if ( !aPageData.isEmpty() )
671 // save settings of this page (user data)
672 OUString sConfigId = OStringToOUString(pDataObject->pTabPage->GetConfigId(),
673 RTL_TEXTENCODING_UTF8);
674 if (sConfigId.isEmpty())
676 SAL_WARN("sfx.dialog", "Tabpage needs to be converted to .ui format");
677 sConfigId = OUString::number(pDataObject->nId);
680 SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
681 aPageOpt.SetUserItem( USERITEM_NAME, makeAny( aPageData ) );
684 pDataObject->pTabPage.disposeAndClear();
687 delete pDataObject;
688 m_pImpl->aData.erase( m_pImpl->aData.begin() + nPos );
690 else
692 SAL_INFO( "sfx.dialog", "TabPage-Id not known" );
696 void SfxTabDialog::RemoveTabPage(const OString &rName)
698 RemoveTabPage(m_pTabCtrl->GetPageId(rName));
702 void SfxTabDialog::PageCreated
704 /* [Description]
706 Default implementation of the virtual method. This is called immediately
707 after creating a page. Here the dialogue can call the TabPage Method
708 directly.
712 sal_uInt16, // Id of the created page
713 SfxTabPage& // Reference to the created page
719 SfxItemSet* SfxTabDialog::GetInputSetImpl()
721 /* [Description]
723 Derived classes may create new storage for the InputSet. This has to be
724 released in the Destructor. To do this, this method must be called.
728 return m_pSet;
732 SfxTabPage* SfxTabDialog::GetTabPage( sal_uInt16 nPageId ) const
734 /* [Description]
736 Return TabPage with the specified Id.
740 sal_uInt16 nPos = 0;
741 Data_Impl* pDataObject = Find( m_pImpl->aData, nPageId, &nPos );
743 if ( pDataObject )
744 return pDataObject->pTabPage;
745 return nullptr;
748 void SfxTabDialog::SavePosAndId()
750 // save settings (screen position and current page)
751 SvtViewOptions aDlgOpt(EViewType::TabDialog, OStringToOUString(GetHelpId(),RTL_TEXTENCODING_UTF8));
752 aDlgOpt.SetWindowState(OStringToOUString(GetWindowState(WindowStateMask::Pos),RTL_TEXTENCODING_ASCII_US));
753 // to-do replace with name of page when all pages are converted to .ui
754 aDlgOpt.SetPageID( m_pTabCtrl->GetCurPageId() );
758 short SfxTabDialog::Ok()
760 /* [Description]
762 Ok handler for the Dialogue.
764 Dialog's current location and current page are saved for the next time
765 the dialog is shown.
767 The OutputSet is created and for each page this or the special OutputSet
768 is set by calling the method <SfxTabPage::FillItemSet(SfxItemSet &)>, to
769 insert the entered data by the user into the set.
771 [Return value]
773 RET_OK: if at least one page has returned from FillItemSet,
774 otherwise RET_CANCEL.
777 SavePosAndId(); //See fdo#38828 "Apply" resetting window position
779 if ( !m_pOutSet )
781 if ( !m_pExampleSet && m_pSet )
782 m_pOutSet = m_pSet->Clone( false ); // without Items
783 else if ( m_pExampleSet )
784 m_pOutSet = new SfxItemSet( *m_pExampleSet );
786 bool bModified = false;
788 for ( SfxTabDlgData_Impl::const_iterator it = m_pImpl->aData.begin(); it != m_pImpl->aData.end(); ++it )
790 Data_Impl* pDataObject = *it;
791 SfxTabPage* pTabPage = pDataObject->pTabPage;
793 if ( pTabPage )
795 if ( m_pSet && !pTabPage->HasExchangeSupport() )
797 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
799 if ( pTabPage->FillItemSet( &aTmp ) )
801 bModified = true;
802 if (m_pExampleSet)
803 m_pExampleSet->Put( aTmp );
804 m_pOutSet->Put( aTmp );
810 if ( m_pOutSet && m_pOutSet->Count() > 0 )
811 bModified = true;
813 if (m_bStandardPushed)
814 bModified = true;
815 return bModified ? RET_OK : RET_CANCEL;
818 IMPL_LINK_NOARG(SfxTabDialog, CancelHdl, Button*, void)
820 EndDialog( RET_USER_CANCEL );
824 SfxItemSet* SfxTabDialog::CreateInputItemSet( sal_uInt16 )
826 /* [Description]
828 Default implementation of the virtual Method.
829 This is called when pages create their sets onDemand.
833 SAL_WARN( "sfx.dialog", "CreateInputItemSet not implemented" );
834 return new SfxAllItemSet( SfxGetpApp()->GetPool() );
838 void SfxTabDialog::RefreshInputSet()
840 /* [Description]
842 Default implementation of the virtual Method.
843 This is called, when <SfxTabPage::DeactivatePage(SfxItemSet *)>
844 returns <DeactivateRC::RefreshSet>.
848 SAL_INFO ( "sfx.dialog", "RefreshInputSet not implemented" );
852 IMPL_LINK_NOARG(SfxTabDialog, OkHdl, Button*, void)
854 /* [Description]
856 Handler of the Ok-Buttons
857 This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
858 Returns <DeactivateRC::LeavePage>, <SfxTabDialog::Ok()> is called
859 and the Dialog is ended.
863 if (PrepareLeaveCurrentPage())
865 if ( m_pImpl->bModal )
866 EndDialog( Ok() );
867 else
869 Ok();
870 Close();
875 bool SfxTabDialog::Apply()
877 bool bApplied = false;
878 if (PrepareLeaveCurrentPage())
880 bApplied = (Ok() == RET_OK);
881 //let the pages update their saved values
882 GetInputSetImpl()->Put(*GetOutputItemSet());
883 sal_uInt16 pageCount = m_pTabCtrl->GetPageCount();
884 for (sal_uInt16 pageIdx = 0; pageIdx < pageCount; ++pageIdx)
886 SfxTabPage* pPage = dynamic_cast<SfxTabPage*> (m_pTabCtrl->GetTabPage(m_pTabCtrl->GetPageId(pageIdx)));
887 if (pPage)
888 pPage->ChangesApplied();
891 return bApplied;
895 bool SfxTabDialog::PrepareLeaveCurrentPage()
897 sal_uInt16 const nId = m_pTabCtrl->GetCurPageId();
898 SfxTabPage* pPage = dynamic_cast<SfxTabPage*> (m_pTabCtrl->GetTabPage( nId ));
899 bool bEnd = !pPage;
901 if ( pPage )
903 DeactivateRC nRet = DeactivateRC::LeavePage;
904 if ( m_pSet )
906 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
908 if ( pPage->HasExchangeSupport() )
909 nRet = pPage->DeactivatePage( &aTmp );
910 else
911 nRet = pPage->DeactivatePage( nullptr );
913 if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage
914 && aTmp.Count() )
916 m_pExampleSet->Put( aTmp );
917 m_pOutSet->Put( aTmp );
920 else
921 nRet = pPage->DeactivatePage( nullptr );
922 bEnd = nRet != DeactivateRC::KeepPage;
925 return bEnd;
929 IMPL_LINK_NOARG(SfxTabDialog, UserHdl, Button*, void)
931 /* [Description]
933 Handler of the User-Buttons
934 This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
935 returns this <DeactivateRC::LeavePage> and <SfxTabDialog::Ok()> is called.
936 Then the Dialog is ended with the Return value <SfxTabDialog::Ok()>
940 if ( PrepareLeaveCurrentPage () )
942 short nRet = Ok();
944 if ( RET_OK == nRet )
945 nRet = RET_USER;
946 else
947 nRet = RET_USER_CANCEL;
948 EndDialog( nRet );
953 IMPL_LINK_NOARG(SfxTabDialog, ResetHdl, Button*, void)
955 /* [Description]
957 Handler behind the reset button.
958 The Current Page is new initialized with their initial data, all the
959 settings that the user has made on this page are repealed.
963 const sal_uInt16 nId = m_pTabCtrl->GetCurPageId();
964 Data_Impl* pDataObject = Find( m_pImpl->aData, nId );
965 DBG_ASSERT( pDataObject, "Id not known" );
967 pDataObject->pTabPage->Reset( m_pSet );
971 IMPL_LINK_NOARG(SfxTabDialog, BaseFmtHdl, Button*, void)
973 /* [Description]
975 Handler behind the Standard-Button.
976 This button is available when editing style sheets. All the set attributes
977 in the edited stylesheet are deleted.
981 m_bStandardPushed = true;
983 const sal_uInt16 nId = m_pTabCtrl->GetCurPageId();
984 Data_Impl* pDataObject = Find( m_pImpl->aData, nId );
985 DBG_ASSERT( pDataObject, "Id not known" );
987 if ( pDataObject->fnGetRanges )
989 if ( !m_pExampleSet )
990 m_pExampleSet = new SfxItemSet( *m_pSet );
992 const SfxItemPool* pPool = m_pSet->GetPool();
993 const sal_uInt16* pTmpRanges = (pDataObject->fnGetRanges)();
994 SfxItemSet aTmpSet( *m_pExampleSet );
996 while ( *pTmpRanges )
998 const sal_uInt16* pU = pTmpRanges + 1;
1000 if ( *pTmpRanges == *pU )
1002 // Range which two identical values -> only set one Item
1003 sal_uInt16 nWh = pPool->GetWhich( *pTmpRanges );
1004 m_pExampleSet->ClearItem( nWh );
1005 aTmpSet.ClearItem( nWh );
1006 // At the Outset of InvalidateItem,
1007 // so that the change takes effect
1008 m_pOutSet->InvalidateItem( nWh );
1010 else
1012 // Correct Range with multiple values
1013 sal_uInt16 nTmp = *pTmpRanges, nTmpEnd = *pU;
1014 DBG_ASSERT( nTmp <= nTmpEnd, "Range is sorted the wrong way" );
1016 if ( nTmp > nTmpEnd )
1018 // If really sorted wrongly, then set new
1019 sal_uInt16 nTmp1 = nTmp;
1020 nTmp = nTmpEnd;
1021 nTmpEnd = nTmp1;
1024 while ( nTmp <= nTmpEnd )
1026 // Iterate over the Range and set the Items
1027 sal_uInt16 nWh = pPool->GetWhich( nTmp );
1028 m_pExampleSet->ClearItem( nWh );
1029 aTmpSet.ClearItem( nWh );
1030 // At the Outset of InvalidateItem,
1031 // so that the change takes effect
1032 m_pOutSet->InvalidateItem( nWh );
1033 nTmp++;
1036 // Go to the next pair
1037 pTmpRanges += 2;
1039 // Set all Items as new -> the call the current Page Reset()
1040 DBG_ASSERT( pDataObject->pTabPage, "the Page is gone" );
1041 pDataObject->pTabPage->Reset( &aTmpSet );
1042 pDataObject->pTabPage->pImpl->mbStandard = true;
1047 IMPL_LINK( SfxTabDialog, ActivatePageHdl, TabControl *, pTabCtrl, void )
1049 /* [Description]
1051 Handler that is called by StarView for switching to a different page.
1052 If the page not exist yet then it is created and the virtual Method
1053 <SfxTabDialog::PageCreated( sal_uInt16, SfxTabPage &)> is called. If the page
1054 exist, then the if possible the <SfxTabPage::Reset(const SfxItemSet &)> or
1055 <SfxTabPage::ActivatePage(const SfxItemSet &)> is called.
1059 sal_uInt16 nId = pTabCtrl->GetCurPageId();
1061 DBG_ASSERT( m_pImpl->aData.size(), "no Pages registered" );
1063 // Tab Page already there?
1064 VclPtr<SfxTabPage> pTabPage = dynamic_cast<SfxTabPage*> (pTabCtrl->GetTabPage( nId ));
1065 Data_Impl* pDataObject = Find( m_pImpl->aData, nId );
1067 // fallback to 1st page when requested one does not exist
1068 if(!pDataObject && pTabCtrl->GetPageCount())
1070 pTabCtrl->SetCurPageId(pTabCtrl->GetPageId(0));
1071 nId = pTabCtrl->GetCurPageId();
1072 pTabPage = dynamic_cast< SfxTabPage* >(pTabCtrl->GetTabPage(nId));
1073 pDataObject = Find(m_pImpl->aData, nId);
1076 if (!pDataObject)
1078 SAL_WARN("sfx.dialog", "Tab Page ID not known, this is pretty serious and needs investigation");
1079 return;
1082 // Create TabPage if possible:
1083 if ( !pTabPage )
1085 if ( m_pSet )
1086 pTabPage = (pDataObject->fnCreatePage)( pTabCtrl, m_pSet );
1087 else
1088 pTabPage = (pDataObject->fnCreatePage)
1089 ( pTabCtrl, CreateInputItemSet( nId ) );
1090 DBG_ASSERT( nullptr == pDataObject->pTabPage, "create TabPage more than once" );
1091 pDataObject->pTabPage = pTabPage;
1093 OUString sConfigId = OStringToOUString(pTabPage->GetConfigId(), RTL_TEXTENCODING_UTF8);
1094 if (sConfigId.isEmpty())
1096 SAL_WARN("sfx.dialog", "Tabpage needs to be converted to .ui format");
1097 sConfigId = OUString::number(pDataObject->nId);
1099 SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
1100 OUString sUserData;
1101 Any aUserItem = aPageOpt.GetUserItem( USERITEM_NAME );
1102 OUString aTemp;
1103 if ( aUserItem >>= aTemp )
1104 sUserData = aTemp;
1105 pTabPage->SetUserData( sUserData );
1106 Size aSiz = pTabPage->GetSizePixel();
1108 Size aCtrlSiz = pTabCtrl->GetTabPageSizePixel();
1109 // Only set Size on TabControl when < as TabPage
1110 if ( aCtrlSiz.Width() < aSiz.Width() ||
1111 aCtrlSiz.Height() < aSiz.Height() )
1113 pTabCtrl->SetTabPageSizePixel( aSiz );
1116 PageCreated( nId, *pTabPage );
1118 pTabPage->Reset( m_pSet );
1120 pTabCtrl->SetTabPage( nId, pTabPage );
1122 else if ( pDataObject->bRefresh )
1123 pTabPage->Reset( m_pSet );
1124 pDataObject->bRefresh = false;
1126 if ( m_pExampleSet )
1127 pTabPage->ActivatePage( *m_pExampleSet );
1129 if ( pTabPage->IsReadOnly() || m_pImpl->bHideResetBtn )
1130 m_pResetBtn->Hide();
1131 else
1132 m_pResetBtn->Show();
1136 IMPL_LINK( SfxTabDialog, DeactivatePageHdl, TabControl *, pTabCtrl, bool )
1138 /* [Description]
1140 Handler that is called by StarView before leaving a page.
1142 [Cross-reference]
1144 <SfxTabPage::DeactivatePage(SfxItemSet *)>
1148 sal_uInt16 nId = pTabCtrl->GetCurPageId();
1149 SfxTabPage *pPage = dynamic_cast<SfxTabPage*> (pTabCtrl->GetTabPage( nId ));
1150 DBG_ASSERT( pPage, "no active Page" );
1151 if (!pPage)
1152 return false;
1153 #ifdef DBG_UTIL
1154 Data_Impl* pDataObject = Find( m_pImpl->aData, pTabCtrl->GetCurPageId() );
1155 DBG_ASSERT( pDataObject, "no Data structure for current page" );
1156 #endif
1158 DeactivateRC nRet = DeactivateRC::LeavePage;
1160 if ( !m_pExampleSet && pPage->HasExchangeSupport() && m_pSet )
1161 m_pExampleSet = new SfxItemSet( *m_pSet->GetPool(), m_pSet->GetRanges() );
1163 if ( m_pSet )
1165 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
1167 if ( pPage->HasExchangeSupport() )
1168 nRet = pPage->DeactivatePage( &aTmp );
1169 else
1170 nRet = pPage->DeactivatePage( nullptr );
1171 if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage &&
1172 aTmp.Count() && m_pExampleSet)
1174 m_pExampleSet->Put( aTmp );
1175 m_pOutSet->Put( aTmp );
1178 else
1180 if ( pPage->HasExchangeSupport() ) //!!!
1182 if ( !m_pExampleSet )
1184 SfxItemPool* pPool = pPage->GetItemSet().GetPool();
1185 m_pExampleSet =
1186 new SfxItemSet( *pPool, GetInputRanges( *pPool ) );
1188 nRet = pPage->DeactivatePage( m_pExampleSet );
1190 else
1191 nRet = pPage->DeactivatePage( nullptr );
1194 if ( nRet & DeactivateRC::RefreshSet )
1196 RefreshInputSet();
1197 // Flag all Pages as to be initialized as new
1199 for ( SfxTabDlgData_Impl::const_iterator it = m_pImpl->aData.begin(); it != m_pImpl->aData.end(); ++it )
1201 Data_Impl* pObj = *it;
1203 if ( pObj->pTabPage.get() != pPage ) // Do not refresh own Page anymore
1204 pObj->bRefresh = true;
1205 else
1206 pObj->bRefresh = false;
1209 return static_cast<bool>(nRet & DeactivateRC::LeavePage);
1213 void SfxTabDialog::ShowPage( sal_uInt16 nId )
1215 /* [Description]
1217 The TabPage is activated with the specified Id.
1221 m_pTabCtrl->SetCurPageId( nId );
1222 ActivatePageHdl( m_pTabCtrl );
1225 OString SfxTabDialog::GetScreenshotId() const
1227 SfxTabPage *pActiveTabPage = GetCurTabPage();
1228 OString aScreenshotId = GetHelpId();
1230 if ( pActiveTabPage )
1232 vcl::Window* pToplevelBox = pActiveTabPage->GetWindow( GetWindowType::FirstChild );
1234 if ( pToplevelBox )
1235 aScreenshotId = pToplevelBox->GetHelpId();
1238 return aScreenshotId;
1241 const sal_uInt16* SfxTabDialog::GetInputRanges( const SfxItemPool& rPool )
1243 /* [Description]
1245 Makes the set over the range of all pages of the dialogue. Pages have the
1246 static method for querying their range in AddTabPage, ie deliver their
1247 sets onDemand.
1249 [Return value]
1251 Pointer to a null-terminated array of sal_uInt16. This array belongs to the
1252 dialog and is deleted when the dialogue is destroy.
1254 [Cross-reference]
1256 <SfxTabDialog::AddTabPage(sal_uInt16, CreateTabPage, GetTabPageRanges, bool)>
1257 <SfxTabDialog::AddTabPage(sal_uInt16, const String &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
1258 <SfxTabDialog::AddTabPage(sal_uInt16, const Bitmap &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
1262 if ( m_pSet )
1264 SAL_WARN( "sfx.dialog", "Set already exists!" );
1265 return m_pSet->GetRanges();
1268 if ( m_pRanges )
1269 return m_pRanges;
1270 std::vector<sal_uInt16> aUS;
1272 for ( SfxTabDlgData_Impl::const_iterator it = m_pImpl->aData.begin(); it != m_pImpl->aData.end(); ++it )
1274 Data_Impl* pDataObject = *it;
1276 if ( pDataObject->fnGetRanges )
1278 const sal_uInt16* pTmpRanges = (pDataObject->fnGetRanges)();
1279 const sal_uInt16* pIter = pTmpRanges;
1281 sal_uInt16 nLen;
1282 for( nLen = 0; *pIter; ++nLen, ++pIter )
1284 aUS.insert( aUS.end(), pTmpRanges, pTmpRanges + nLen );
1288 //! Remove duplicated Ids?
1290 sal_uInt16 nCount = aUS.size();
1291 for ( sal_uInt16 i = 0; i < nCount; ++i )
1292 aUS[i] = rPool.GetWhich( aUS[i] );
1295 // sort
1296 if ( aUS.size() > 1 )
1298 std::sort( aUS.begin(), aUS.end() );
1301 m_pRanges = new sal_uInt16[aUS.size() + 1];
1302 std::copy( aUS.begin(), aUS.end(), m_pRanges );
1303 m_pRanges[aUS.size()] = 0;
1304 return m_pRanges;
1308 void SfxTabDialog::SetInputSet( const SfxItemSet* pInSet )
1310 /* [Description]
1312 With this method the Input-Set can subsequently be set initially or re-set.
1316 bool bSet = ( m_pSet != nullptr );
1317 delete m_pSet;
1318 m_pSet = pInSet ? new SfxItemSet(*pInSet) : nullptr;
1320 if (!bSet && !m_pExampleSet && !m_pOutSet && m_pSet)
1322 m_pExampleSet = new SfxItemSet( *m_pSet );
1323 m_pOutSet = new SfxItemSet( *m_pSet->GetPool(), m_pSet->GetRanges() );
1327 FactoryFunction SfxTabDialog::GetUITestFactory() const
1329 return SfxTabDialogUIObject::create;
1332 std::vector<OString> SfxTabDialog::getAllPageUIXMLDescriptions() const
1334 std::vector<OString> aRetval;
1336 for (SfxTabDlgData_Impl::const_iterator it = m_pImpl->aData.begin(); it != m_pImpl->aData.end(); ++it)
1338 SfxTabPage* pCandidate = GetTabPage((*it)->nId);
1340 if (!pCandidate)
1342 // force SfxTabPage creation
1343 const_cast<SfxTabDialog*>(this)->ShowPage((*it)->nId);
1344 pCandidate = GetTabPage((*it)->nId);
1347 if (pCandidate)
1349 // use UIXMLDescription (without '.ui', with '/')
1350 aRetval.push_back(pCandidate->getUIFile());
1354 return aRetval;
1357 bool SfxTabDialog::selectPageByUIXMLDescription(const OString& rUIXMLDescription)
1359 for (SfxTabDlgData_Impl::const_iterator it = m_pImpl->aData.begin(); it != m_pImpl->aData.end(); ++it)
1361 SfxTabPage* pCandidate = (*it)->pTabPage;
1363 if (!pCandidate)
1365 // force SfxTabPage creation
1366 ShowPage((*it)->nId);
1367 pCandidate = GetTabPage((*it)->nId);
1370 if (pCandidate && pCandidate->getUIFile() == rUIXMLDescription)
1372 ShowPage((*it)->nId);
1373 return true;
1377 return false;
1380 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */