Bump version to 24.04.3.4
[LibreOffice.git] / sfx2 / source / dialog / tabdlg.cxx
blob39d0245637ca69a658d8735449068ce916d216c8
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 <stdlib.h>
22 #include <algorithm>
23 #include <string_view>
25 #include <sfx2/tabdlg.hxx>
26 #include <sfx2/app.hxx>
27 #include <sfx2/sfxresid.hxx>
28 #include <sfx2/sfxdlg.hxx>
29 #include <sfx2/viewsh.hxx>
30 #include <unotools/viewoptions.hxx>
31 #include <utility>
32 #include <vcl/virdev.hxx>
33 #include <sal/log.hxx>
34 #include <tools/debug.hxx>
35 #include <comphelper/lok.hxx>
37 #include <sfx2/strings.hrc>
38 #include <helpids.h>
40 using namespace ::com::sun::star::uno;
42 constexpr OUString USERITEM_NAME = u"UserItem"_ustr;
45 struct TabPageImpl
47 bool mbStandard;
48 SfxOkDialogController* mpSfxDialogController;
49 css::uno::Reference< css::frame::XFrame > mxFrame;
51 TabPageImpl() : mbStandard(false), mpSfxDialogController(nullptr) {}
54 namespace {
56 struct Data_Impl
58 OUString sId; // The ID
59 CreateTabPage fnCreatePage; // Pointer to Factory
60 GetTabPageRanges fnGetRanges; // Pointer to Ranges-Function
61 std::unique_ptr<SfxTabPage> xTabPage; // The TabPage itself
62 bool bRefresh; // Flag: Page must be re-initialized
64 // Constructor
65 Data_Impl( const OUString& rId, CreateTabPage fnPage,
66 GetTabPageRanges fnRanges ) :
68 sId ( rId ),
69 fnCreatePage( fnPage ),
70 fnGetRanges ( fnRanges ),
71 bRefresh ( false )
78 SfxTabDialogItem::SfxTabDialogItem( const SfxTabDialogItem& rAttr, SfxItemPool* pItemPool )
79 : SfxSetItem( rAttr, pItemPool )
83 SfxTabDialogItem::SfxTabDialogItem( sal_uInt16 nId, const SfxItemSet& rItemSet )
84 : SfxSetItem( nId, rItemSet )
88 SfxTabDialogItem* SfxTabDialogItem::Clone(SfxItemPool* pToPool) const
90 return new SfxTabDialogItem( *this, pToPool );
93 typedef std::vector<Data_Impl*> SfxTabDlgData_Impl;
95 struct TabDlg_Impl
97 bool bHideResetBtn : 1;
98 bool bStarted : 1;
99 SfxTabDlgData_Impl aData;
101 explicit TabDlg_Impl(sal_uInt8 nCnt)
102 : bHideResetBtn(false)
103 , bStarted(false)
105 aData.reserve( nCnt );
109 static Data_Impl* Find( const SfxTabDlgData_Impl& rArr, std::u16string_view rId, sal_uInt16* pPos = nullptr)
111 const sal_uInt16 nCount = rArr.size();
113 for ( sal_uInt16 i = 0; i < nCount; ++i )
115 Data_Impl* pObj = rArr[i];
117 if ( pObj->sId == rId )
119 if ( pPos )
120 *pPos = i;
121 return pObj;
124 return nullptr;
127 void SfxTabPage::SetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame)
129 if (mpImpl)
130 mpImpl->mxFrame = xFrame;
133 css::uno::Reference< css::frame::XFrame > SfxTabPage::GetFrame() const
135 if (mpImpl)
136 return mpImpl->mxFrame;
137 return css::uno::Reference< css::frame::XFrame >();
140 SfxTabPage::SfxTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OUString& rID, const SfxItemSet *rAttrSet)
141 : BuilderPage(pPage, pController, rUIXMLDescription, rID,
142 comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current()
143 && SfxViewShell::Current()->isLOKMobilePhone())
144 , mpSet(rAttrSet)
145 , mbHasExchangeSupport(false)
146 , mpImpl(new TabPageImpl)
148 mpImpl->mpSfxDialogController = dynamic_cast<SfxOkDialogController*>(m_pDialogController);
151 SfxTabPage::~SfxTabPage()
153 if (m_xContainer)
155 std::unique_ptr<weld::Container> xParent(m_xContainer->weld_parent());
156 if (xParent)
157 xParent->move(m_xContainer.get(), nullptr);
159 m_xContainer.reset();
160 mpImpl.reset();
161 m_xBuilder.reset();
164 bool SfxTabPage::FillItemSet( SfxItemSet* )
166 return false;
170 Returns the visible strings of a dialog.
172 Supported items:
173 - label
174 - check button
175 - radio button
176 - toggle button
177 - link button
178 - button
180 OUString SfxTabPage::GetAllStrings() { return OUString(); }
182 void SfxTabPage::Reset( const SfxItemSet* )
186 bool SfxTabPage::DeferResetToFirstActivation() { return false; }
188 void SfxTabPage::ActivatePage( const SfxItemSet& )
189 /* [Description]
191 Default implementation of the virtual ActivatePage method. This method is
192 called when a page of dialogue supports the exchange of data between pages.
193 <SfxTabPage::DeactivatePage(SfxItemSet *)>
198 DeactivateRC SfxTabPage::DeactivatePage( SfxItemSet* )
200 /* [Description]
202 Default implementation of the virtual DeactivatePage method. This method is
203 called by Sfx when leaving a page; the application can, through the return
204 value, control whether to leave the page. If the page is displayed through
205 bHasExchangeSupport which supports data exchange between pages, then a
206 pointer to the exchange set is passed as parameter. This takes on data for
207 the exchange, then the set is available as a parameter in
208 <SfxTabPage::ActivatePage(const SfxItemSet &)>.
210 [Return value]
212 DeactivateRC::LeavePage; Allow leaving the page
216 return DeactivateRC::LeavePage;
220 void SfxTabPage::FillUserData()
222 /* [Description]
224 Virtual method is called by the base class in the destructor to save
225 specific information of the TabPage in the ini-file. When overriding a
226 string must be compiled, which is then flushed with the <SetUserData()>.
233 bool SfxTabPage::IsReadOnly() const
235 return false;
239 const SfxPoolItem* SfxTabPage::GetItem( const SfxItemSet& rSet, sal_uInt16 nSlot, bool bDeep )
241 /* [Description]
243 static Method: hereby are the implementations of the TabPage code
244 being simplified.
248 const SfxItemPool* pPool = rSet.GetPool();
249 sal_uInt16 nWh = pPool->GetWhich( nSlot, bDeep );
250 const SfxPoolItem* pItem = nullptr;
251 rSet.GetItemState( nWh, true, &pItem );
253 if ( !pItem && nWh != nSlot )
254 pItem = &pPool->GetDefaultItem( nWh );
255 return pItem;
259 const SfxPoolItem* SfxTabPage::GetOldItem( const SfxItemSet& rSet,
260 sal_uInt16 nSlot, bool bDeep )
262 /* [Description]
264 This method returns an attribute for comparison of the old value.
268 const SfxItemSet& rOldSet = GetItemSet();
269 sal_uInt16 nWh = GetWhich( nSlot, bDeep );
270 const SfxPoolItem* pItem = nullptr;
272 if (mpImpl->mbStandard && rOldSet.GetParent())
273 pItem = GetItem( *rOldSet.GetParent(), nSlot );
274 else if ( rSet.GetParent() &&
275 SfxItemState::DONTCARE == rSet.GetItemState( nWh ) )
276 pItem = GetItem( *rSet.GetParent(), nSlot );
277 else
278 pItem = GetItem( rOldSet, nSlot );
279 return pItem;
282 void SfxTabPage::PageCreated( const SfxAllItemSet& /*aSet*/ )
284 SAL_WARN( "sfx.dialog", "SfxTabPage::PageCreated should not be called");
287 void SfxTabPage::ChangesApplied()
291 void SfxTabPage::SetDialogController(SfxOkDialogController* pDialog)
293 mpImpl->mpSfxDialogController = pDialog;
294 m_pDialogController = mpImpl->mpSfxDialogController;
297 SfxOkDialogController* SfxTabPage::GetDialogController() const
299 return mpImpl->mpSfxDialogController;
302 OUString SfxTabPage::GetHelpId() const
304 if (m_xContainer)
305 return m_xContainer->get_help_id();
306 return {};
309 weld::Window* SfxTabPage::GetFrameWeld() const
311 if (m_pDialogController)
312 return m_pDialogController->getDialog();
313 return nullptr;
316 const SfxItemSet* SfxTabPage::GetDialogExampleSet() const
318 if (mpImpl->mpSfxDialogController)
319 return mpImpl->mpSfxDialogController->GetExampleSet();
320 return nullptr;
323 SfxTabDialogController::SfxTabDialogController
325 weld::Widget* pParent, // Parent Window
326 const OUString& rUIXMLDescription, const OUString& rID, // Dialog .ui path, Dialog Name
327 const SfxItemSet* pItemSet, // Itemset with the data;
328 // can be NULL, when Pages are onDemand
329 bool bEditFmt // when yes -> additional Button for standard
331 : SfxOkDialogController(pParent, rUIXMLDescription, rID)
332 , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
333 , m_xOKBtn(m_xBuilder->weld_button("ok"))
334 , m_xApplyBtn(m_xBuilder->weld_button("apply"))
335 , m_xUserBtn(m_xBuilder->weld_button("user"))
336 , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
337 , m_xResetBtn(m_xBuilder->weld_button("reset"))
338 , m_xBaseFmtBtn(m_xBuilder->weld_button("standard"))
339 , m_pSet(pItemSet ? new SfxItemSet(*pItemSet) : nullptr)
340 , m_bStandardPushed(false)
342 m_pImpl.reset(new TabDlg_Impl(m_xTabCtrl->get_n_pages()));
343 m_pImpl->bHideResetBtn = !m_xResetBtn->get_visible();
344 m_xOKBtn->connect_clicked(LINK(this, SfxTabDialogController, OkHdl));
345 m_xCancelBtn->connect_clicked(LINK(this, SfxTabDialogController, CancelHdl));
346 m_xResetBtn->connect_clicked(LINK(this, SfxTabDialogController, ResetHdl));
347 m_xResetBtn->set_label(SfxResId(STR_RESET));
348 m_xTabCtrl->connect_enter_page(LINK(this, SfxTabDialogController, ActivatePageHdl));
349 m_xTabCtrl->connect_leave_page(LINK(this, SfxTabDialogController, DeactivatePageHdl));
350 m_xResetBtn->set_help_id(HID_TABDLG_RESET_BTN);
352 if (bEditFmt)
354 m_xBaseFmtBtn->set_label(SfxResId(STR_STANDARD_SHORTCUT));
355 m_xBaseFmtBtn->connect_clicked(LINK(this, SfxTabDialogController, BaseFmtHdl));
356 m_xBaseFmtBtn->set_help_id(HID_TABDLG_STANDARD_BTN);
357 m_xBaseFmtBtn->show();
360 if (m_xUserBtn)
361 m_xUserBtn->connect_clicked(LINK(this, SfxTabDialogController, UserHdl));
363 if (m_pSet)
365 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
366 m_pOutSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
369 // The reset functionality seems to be confusing to many; disable in LOK.
370 if (comphelper::LibreOfficeKit::isActive())
371 RemoveResetButton();
374 IMPL_LINK_NOARG(SfxTabDialogController, OkHdl, weld::Button&, void)
376 /* [Description]
378 Handler of the Ok-Buttons
379 This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
380 Returns <DeactivateRC::LeavePage>, <SfxTabDialog::Ok()> is called
381 and the Dialog is ended.
385 if (PrepareLeaveCurrentPage())
386 m_xDialog->response(Ok());
389 IMPL_LINK_NOARG(SfxTabDialogController, UserHdl, weld::Button&, void)
391 /* [Description]
393 Handler of the User-Buttons
394 This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
395 returns this <DeactivateRC::LeavePage> and <SfxTabDialog::Ok()> is called.
396 Then the Dialog is ended with the Return value <SfxTabDialog::Ok()>
400 if (PrepareLeaveCurrentPage())
402 short nRet = Ok();
403 if (RET_OK == nRet)
404 nRet = RET_USER;
405 else
406 nRet = RET_CANCEL;
407 m_xDialog->response(nRet);
411 IMPL_LINK_NOARG(SfxTabDialogController, CancelHdl, weld::Button&, void)
413 m_xDialog->response(RET_CANCEL);
416 IMPL_LINK_NOARG(SfxTabDialogController, ResetHdl, weld::Button&, void)
418 /* [Description]
420 Handler behind the reset button.
421 The Current Page is new initialized with their initial data, all the
422 settings that the user has made on this page are repealed.
426 Data_Impl* pDataObject = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
427 assert(pDataObject && "Id not known");
429 pDataObject->xTabPage->Reset(m_pSet.get());
430 // Also reset relevant items of ExampleSet and OutSet to initial state
431 if (!pDataObject->fnGetRanges)
432 return;
434 if (!m_xExampleSet)
435 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
437 const SfxItemPool* pPool = m_pSet->GetPool();
438 const WhichRangesContainer& pTmpRanges = (pDataObject->fnGetRanges)();
440 for (const auto & rPair : pTmpRanges)
442 // Correct Range with multiple values
443 sal_uInt16 nTmp = rPair.first, nTmpEnd = rPair.second;
444 DBG_ASSERT(nTmp <= nTmpEnd, "Range is sorted the wrong way");
446 if (nTmp > nTmpEnd)
448 // If really sorted wrongly, then set new
449 std::swap(nTmp, nTmpEnd);
452 while (nTmp && nTmp <= nTmpEnd)
454 // Iterate over the Range and set the Items
455 sal_uInt16 nWh = pPool->GetWhich(nTmp);
456 const SfxPoolItem* pItem;
457 if (SfxItemState::SET == m_pSet->GetItemState(nWh, false, &pItem))
459 m_xExampleSet->Put(*pItem);
461 else
463 m_xExampleSet->ClearItem(nWh);
465 m_pOutSet->ClearItem(nWh);
466 nTmp++;
471 /* [Description]
473 Handler behind the Standard-Button.
474 This button is available when editing style sheets. All the set attributes
475 in the edited stylesheet are deleted.
477 IMPL_LINK_NOARG(SfxTabDialogController, BaseFmtHdl, weld::Button&, void)
479 m_bStandardPushed = true;
481 Data_Impl* pDataObject = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
482 assert(pDataObject && "Id not known");
484 if (!pDataObject->fnGetRanges)
485 return;
487 if (!m_xExampleSet)
488 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
490 const SfxItemPool* pPool = m_pSet->GetPool();
491 const WhichRangesContainer& pTmpRanges = (pDataObject->fnGetRanges)();
492 SfxItemSet aTmpSet(*m_xExampleSet);
494 for (const auto& rPair : pTmpRanges)
496 // Correct Range with multiple values
497 sal_uInt16 nTmp = rPair.first, nTmpEnd = rPair.second;
498 DBG_ASSERT( nTmp <= nTmpEnd, "Range is sorted the wrong way" );
500 if ( nTmp > nTmpEnd )
502 // If really sorted wrongly, then set new
503 std::swap(nTmp, nTmpEnd);
506 while ( nTmp && nTmp <= nTmpEnd ) // guard against overflow
508 // Iterate over the Range and set the Items
509 sal_uInt16 nWh = pPool->GetWhich(nTmp);
510 m_xExampleSet->ClearItem(nWh);
511 aTmpSet.ClearItem(nWh);
512 // At the Outset of InvalidateItem,
513 // so that the change takes effect
514 m_pOutSet->InvalidateItem(nWh);
515 nTmp++;
518 // Set all Items as new -> the call the current Page Reset()
519 assert(pDataObject->xTabPage && "the Page is gone");
520 pDataObject->xTabPage->Reset( &aTmpSet );
521 pDataObject->xTabPage->mpImpl->mbStandard = true;
524 IMPL_LINK(SfxTabDialogController, ActivatePageHdl, const OUString&, rPage, void)
526 ActivatePage(rPage);
529 void SfxTabDialogController::ActivatePage(const OUString& rPage)
530 /* [Description]
532 Handler that is called by StarView for switching to a different page.
533 If possible the <SfxTabPage::Reset(const SfxItemSet &)> or
534 <SfxTabPage::ActivatePage(const SfxItemSet &)> is called on the new page
538 assert(!m_pImpl->aData.empty() && "no Pages registered");
539 Data_Impl* pDataObject = Find(m_pImpl->aData, rPage);
540 if (!pDataObject)
542 SAL_WARN("sfx.dialog", "Tab Page ID '" << rPage << "' not known, this is pretty serious and needs investigation");
543 return;
546 SfxTabPage* pTabPage = pDataObject->xTabPage.get();
547 if (!pTabPage)
548 return;
550 if (pDataObject->bRefresh)
551 pTabPage->Reset(m_pSet.get());
552 pDataObject->bRefresh = false;
554 if (m_xExampleSet)
555 pTabPage->ActivatePage(*m_xExampleSet);
557 if (pTabPage->IsReadOnly() || m_pImpl->bHideResetBtn)
558 m_xResetBtn->hide();
559 else
560 m_xResetBtn->show();
563 IMPL_LINK(SfxTabDialogController, DeactivatePageHdl, const OUString&, rPage, bool)
565 return DeactivatePage(rPage);
568 bool SfxTabDialogController::DeactivatePage(std::u16string_view aPage)
569 /* [Description]
571 Handler that is called by StarView before leaving a page.
573 [Cross-reference]
575 <SfxTabPage::DeactivatePage(SfxItemSet *)>
579 assert(!m_pImpl->aData.empty() && "no Pages registered");
580 Data_Impl* pDataObject = Find(m_pImpl->aData, aPage);
581 if (!pDataObject)
583 SAL_WARN("sfx.dialog", "Tab Page ID not known, this is pretty serious and needs investigation");
584 return false;
587 SfxTabPage* pPage = pDataObject->xTabPage.get();
588 if (!pPage)
589 return true;
591 DeactivateRC nRet = DeactivateRC::LeavePage;
593 if (!m_xExampleSet && pPage->HasExchangeSupport() && m_pSet)
594 m_xExampleSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
596 if (m_pSet)
598 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
600 if (pPage->HasExchangeSupport())
601 nRet = pPage->DeactivatePage(&aTmp);
602 else
603 nRet = pPage->DeactivatePage(nullptr);
604 if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage &&
605 aTmp.Count() && m_xExampleSet)
607 m_xExampleSet->Put( aTmp );
608 m_pOutSet->Put( aTmp );
611 else
613 if ( pPage->HasExchangeSupport() ) //!!!
615 if (!m_xExampleSet)
617 SfxItemPool* pPool = pPage->GetItemSet().GetPool();
618 m_xExampleSet.reset(new SfxItemSet(*pPool, GetInputRanges(*pPool)));
620 nRet = pPage->DeactivatePage(m_xExampleSet.get());
622 else
623 nRet = pPage->DeactivatePage( nullptr );
626 if ( nRet & DeactivateRC::RefreshSet )
628 RefreshInputSet();
629 // Flag all Pages as to be initialized as new
631 for (auto const& elem : m_pImpl->aData)
633 elem->bRefresh = ( elem->xTabPage.get() != pPage ); // Do not refresh own Page anymore
636 return static_cast<bool>(nRet & DeactivateRC::LeavePage);
639 bool SfxTabDialogController::PrepareLeaveCurrentPage()
641 const OUString sId = m_xTabCtrl->get_current_page_ident();
642 Data_Impl* pDataObject = Find(m_pImpl->aData, sId);
643 DBG_ASSERT( pDataObject, "Id not known" );
644 SfxTabPage* pPage = pDataObject ? pDataObject->xTabPage.get() : nullptr;
646 bool bEnd = !pPage;
648 if ( pPage )
650 DeactivateRC nRet = DeactivateRC::LeavePage;
651 if ( m_pSet )
653 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
655 if ( pPage->HasExchangeSupport() )
656 nRet = pPage->DeactivatePage( &aTmp );
657 else
658 nRet = pPage->DeactivatePage( nullptr );
660 if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage
661 && aTmp.Count() )
663 m_xExampleSet->Put( aTmp );
664 m_pOutSet->Put( aTmp );
667 else
668 nRet = pPage->DeactivatePage( nullptr );
669 bEnd = nRet != DeactivateRC::KeepPage;
672 return bEnd;
675 const WhichRangesContainer & SfxTabDialogController::GetInputRanges(const SfxItemPool& rPool)
677 /* [Description]
679 Makes the set over the range of all pages of the dialogue. Pages have the
680 static method for querying their range in AddTabPage, ie deliver their
681 sets onDemand.
683 [Return value]
685 Pointer to a null-terminated array of sal_uInt16. This array belongs to the
686 dialog and is deleted when the dialogue is destroy.
688 [Cross-reference]
690 <SfxTabDialog::AddTabPage(sal_uInt16, CreateTabPage, GetTabPageRanges, bool)>
691 <SfxTabDialog::AddTabPage(sal_uInt16, const String &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
692 <SfxTabDialog::AddTabPage(sal_uInt16, const Bitmap &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
696 if ( m_pSet )
698 SAL_WARN( "sfx.dialog", "Set already exists!" );
699 return m_pSet->GetRanges();
702 if ( !m_pRanges.empty() )
703 return m_pRanges;
704 SfxItemSet aUS(const_cast<SfxItemPool&>(rPool));
706 for (auto const& elem : m_pImpl->aData)
709 if ( elem->fnGetRanges )
711 const WhichRangesContainer& pTmpRanges = (elem->fnGetRanges)();
713 for (const auto & rPair : pTmpRanges)
715 sal_uInt16 nWidFrom = rPool.GetWhich(rPair.first);
716 sal_uInt16 nWidTo = rPool.GetWhich(rPair.second);
717 aUS.MergeRange(nWidFrom, nWidTo); // Keep it valid
722 m_pRanges = aUS.GetRanges();
723 return m_pRanges;
726 SfxTabDialogController::~SfxTabDialogController()
728 SavePosAndId();
730 for (auto & elem : m_pImpl->aData)
732 if ( elem->xTabPage )
734 // save settings of all pages (user data)
735 elem->xTabPage->FillUserData();
736 OUString aPageData( elem->xTabPage->GetUserData() );
737 if ( !aPageData.isEmpty() )
739 // save settings of all pages (user data)
740 SvtViewOptions aPageOpt(EViewType::TabPage, elem->xTabPage->GetConfigId());
741 aPageOpt.SetUserItem( USERITEM_NAME, Any( aPageData ) );
744 elem->xTabPage.reset();
746 delete elem;
747 elem = nullptr;
751 short SfxTabDialogController::Ok()
753 /* [Description]
755 Ok handler for the Dialogue.
757 Dialog's current location and current page are saved for the next time
758 the dialog is shown.
760 The OutputSet is created and for each page this or the special OutputSet
761 is set by calling the method <SfxTabPage::FillItemSet(SfxItemSet &)>, to
762 insert the entered data by the user into the set.
764 [Return value]
766 RET_OK: if at least one page has returned from FillItemSet,
767 otherwise RET_CANCEL.
770 SavePosAndId(); //See fdo#38828 "Apply" resetting window position
772 if ( !m_pOutSet )
774 if ( m_xExampleSet )
775 m_pOutSet.reset(new SfxItemSet( *m_xExampleSet ));
776 else if ( m_pSet )
777 m_pOutSet = m_pSet->Clone( false ); // without Items
779 bool bModified = false;
781 for (auto const& elem : m_pImpl->aData)
783 SfxTabPage* pTabPage = elem->xTabPage.get();
785 if ( pTabPage )
787 if ( m_pSet && !pTabPage->HasExchangeSupport() )
789 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
791 if ( pTabPage->FillItemSet( &aTmp ) )
793 bModified = true;
794 if (m_xExampleSet)
795 m_xExampleSet->Put( aTmp );
796 m_pOutSet->Put( aTmp );
802 if (m_pOutSet && m_pOutSet->Count() > 0)
803 bModified = true;
805 if (m_bStandardPushed)
806 bModified = true;
808 return bModified ? RET_OK : RET_CANCEL;
811 void SfxTabDialogController::RefreshInputSet()
813 /* [Description]
815 Default implementation of the virtual Method.
816 This is called, when <SfxTabPage::DeactivatePage(SfxItemSet *)>
817 returns <DeactivateRC::RefreshSet>.
821 SAL_INFO ( "sfx.dialog", "RefreshInputSet not implemented" );
824 void SfxTabDialogController::PageCreated
826 /* [Description]
828 Default implementation of the virtual method. This is called immediately
829 after creating a page. Here the dialogue can call the TabPage Method
830 directly.
834 const OUString&, // Id of the created page
835 SfxTabPage& // Reference to the created page
840 void SfxTabDialogController::SavePosAndId()
842 // save settings (screen position and current page)
843 SvtViewOptions aDlgOpt(EViewType::TabDialog, m_xDialog->get_help_id());
844 aDlgOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
848 Adds a page to the dialog. The Name must correspond to an entry in the
849 TabControl in the dialog .ui
851 void SfxTabDialogController::AddTabPage(const OUString &rName /* Page ID */,
852 CreateTabPage pCreateFunc /* Pointer to the Factory Method */,
853 GetTabPageRanges pRangesFunc /* Pointer to the Method for querying Ranges onDemand */)
855 m_pImpl->aData.push_back(new Data_Impl(rName, pCreateFunc, pRangesFunc));
858 void SfxTabDialogController::AddTabPage(const OUString &rName /* Page ID */,
859 sal_uInt16 nPageCreateId /* Identifier of the Factory Method to create the page */)
861 SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
862 CreateTabPage pCreateFunc = pFact->GetTabPageCreatorFunc(nPageCreateId);
863 GetTabPageRanges pRangesFunc = pFact->GetTabPageRangesFunc(nPageCreateId);
864 AddTabPage(rName, pCreateFunc, pRangesFunc);
867 /* [Description]
869 Add a page to the dialog. The Rider text is passed on, the page has no
870 counterpart in the TabControl in the resource of the dialogue.
873 void SfxTabDialogController::AddTabPage(const OUString &rName, /* Page ID */
874 const OUString& rRiderText,
875 CreateTabPage pCreateFunc /* Pointer to the Factory Method */)
877 assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
878 m_xTabCtrl->append_page(rName, rRiderText);
879 AddTabPage(rName, pCreateFunc, nullptr);
882 void SfxTabDialogController::AddTabPage(const OUString &rName, const OUString& rRiderText,
883 sal_uInt16 nPageCreateId /* Identifier of the Factory Method to create the page */)
885 assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
886 m_xTabCtrl->append_page(rName, rRiderText);
887 AddTabPage(rName, nPageCreateId);
890 /* [Description]
892 Default implementation of the virtual Method.
893 This is called when pages create their sets onDemand.
895 SfxItemSet* SfxTabDialogController::CreateInputItemSet(const OUString&)
897 SAL_WARN( "sfx.dialog", "CreateInputItemSet not implemented" );
898 m_xItemSet = std::make_unique<SfxAllItemSet>(SfxGetpApp()->GetPool());
899 return m_xItemSet.get();
902 void SfxTabDialogController::CreatePages()
904 for (auto pDataObject : m_pImpl->aData)
906 if (pDataObject->xTabPage)
907 continue;
908 weld::Container* pPage = m_xTabCtrl->get_page(pDataObject->sId);
909 if (m_pSet)
910 pDataObject->xTabPage = (pDataObject->fnCreatePage)(pPage, this, m_pSet.get());
911 else
912 pDataObject->xTabPage = (pDataObject->fnCreatePage)(pPage, this, CreateInputItemSet(pDataObject->sId));
913 pDataObject->xTabPage->SetDialogController(this);
914 SvtViewOptions aPageOpt(EViewType::TabPage, pDataObject->xTabPage->GetConfigId());
915 OUString sUserData;
916 Any aUserItem = aPageOpt.GetUserItem(USERITEM_NAME);
917 OUString aTemp;
918 if ( aUserItem >>= aTemp )
919 sUserData = aTemp;
920 pDataObject->xTabPage->SetUserData(sUserData);
922 PageCreated(pDataObject->sId, *pDataObject->xTabPage);
923 if (pDataObject->xTabPage->DeferResetToFirstActivation())
924 pDataObject->bRefresh = true; // Reset will be called in ActivatePageHdl
925 else
926 pDataObject->xTabPage->Reset(m_pSet.get());
930 void SfxTabDialogController::setPreviewsToSamePlace()
932 //where tab pages have the same basic layout with a preview on the right,
933 //get both of their non-preview areas to request the same size so that the
934 //preview appears in the same place in each one so flipping between tabs
935 //isn't distracting as it jumps around
936 std::vector<std::unique_ptr<weld::Widget>> aGrids;
937 for (auto pDataObject : m_pImpl->aData)
939 if (!pDataObject->xTabPage)
940 continue;
941 if (!pDataObject->xTabPage->m_xBuilder)
942 continue;
943 std::unique_ptr<weld::Widget> pGrid = pDataObject->xTabPage->m_xBuilder->weld_widget("maingrid");
944 if (!pGrid)
945 continue;
946 aGrids.emplace_back(std::move(pGrid));
949 m_xSizeGroup.reset();
951 if (aGrids.size() <= 1)
952 return;
954 m_xSizeGroup = m_xBuilder->create_size_group();
955 m_xSizeGroup->set_mode(VclSizeGroupMode::Both);
956 for (auto& rGrid : aGrids)
957 m_xSizeGroup->add_widget(rGrid.get());
960 void SfxTabDialogController::RemoveTabPage(const OUString& rId)
962 /* [Description]
964 Delete the TabPage with ID nId
968 sal_uInt16 nPos = 0;
969 m_xTabCtrl->remove_page(rId);
970 Data_Impl* pDataObject = Find( m_pImpl->aData, rId, &nPos );
972 if ( pDataObject )
974 if ( pDataObject->xTabPage )
976 pDataObject->xTabPage->FillUserData();
977 OUString aPageData( pDataObject->xTabPage->GetUserData() );
978 if ( !aPageData.isEmpty() )
980 // save settings of this page (user data)
981 SvtViewOptions aPageOpt(EViewType::TabPage, pDataObject->xTabPage->GetConfigId());
982 aPageOpt.SetUserItem( USERITEM_NAME, Any( aPageData ) );
985 pDataObject->xTabPage.reset();
988 delete pDataObject;
989 m_pImpl->aData.erase( m_pImpl->aData.begin() + nPos );
991 else
993 SAL_INFO( "sfx.dialog", "TabPage-Id not known" );
997 void SfxTabDialogController::Start_Impl()
999 CreatePages();
1001 setPreviewsToSamePlace();
1003 assert(m_pImpl->aData.size() == static_cast<size_t>(m_xTabCtrl->get_n_pages())
1004 && "not all pages registered");
1006 // load old settings, when exists, setting SetCurPageId will override the settings,
1007 // something that the sort dialog in calc depends on
1008 if (m_sAppPageId.isEmpty())
1010 SvtViewOptions aDlgOpt(EViewType::TabDialog, m_xDialog->get_help_id());
1011 if (aDlgOpt.Exists())
1012 m_xTabCtrl->set_current_page(aDlgOpt.GetPageID());
1015 ActivatePage(m_xTabCtrl->get_current_page_ident());
1017 m_pImpl->bStarted = true;
1020 void SfxTabDialogController::SetCurPageId(const OUString& rIdent)
1022 m_sAppPageId = rIdent;
1023 m_xTabCtrl->set_current_page(m_sAppPageId);
1026 /* [Description]
1028 The TabPage is activated with the specified Id.
1030 void SfxTabDialogController::ShowPage(const OUString& rIdent)
1032 SetCurPageId(rIdent);
1033 ActivatePage(rIdent);
1036 OUString SfxTabDialogController::GetCurPageId() const
1038 return m_xTabCtrl->get_current_page_ident();
1041 short SfxTabDialogController::run()
1043 Start_Impl();
1044 return SfxDialogController::run();
1047 bool SfxTabDialogController::runAsync(const std::shared_ptr<SfxTabDialogController>& rController,
1048 const std::function<void(sal_Int32)>& rFunc)
1050 rController->Start_Impl();
1051 return weld::DialogController::runAsync(rController, rFunc);
1054 void SfxTabDialogController::SetInputSet( const SfxItemSet* pInSet )
1056 /* [Description]
1058 With this method the Input-Set can subsequently be set initially or re-set.
1062 bool bSet = ( m_pSet != nullptr );
1063 m_pSet.reset(pInSet ? new SfxItemSet(*pInSet) : nullptr);
1065 if (!bSet && !m_xExampleSet && !m_pOutSet && m_pSet)
1067 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
1068 m_pOutSet.reset(new SfxItemSet( *m_pSet->GetPool(), m_pSet->GetRanges() ));
1072 SfxItemSet* SfxTabDialogController::GetInputSetImpl()
1074 /* [Description]
1076 Derived classes may create new storage for the InputSet. This has to be
1077 released in the Destructor. To do this, this method must be called.
1081 return m_pSet.get();
1084 void SfxTabDialogController::RemoveResetButton()
1086 m_xResetBtn->hide();
1087 m_pImpl->bHideResetBtn = true;
1090 void SfxTabDialogController::RemoveStandardButton()
1092 m_xBaseFmtBtn->hide();
1095 SfxTabPage* SfxTabDialogController::GetTabPage(std::u16string_view rPageId) const
1097 /* [Description]
1099 Return TabPage with the specified Id.
1103 Data_Impl* pDataObject = Find(m_pImpl->aData, rPageId);
1104 if (pDataObject)
1105 return pDataObject->xTabPage.get();
1106 return nullptr;
1109 void SfxTabDialogController::SetApplyHandler(const Link<weld::Button&, void>& _rHdl)
1111 DBG_ASSERT( m_xApplyBtn, "SfxTabDialog::GetApplyHandler: no apply button enabled!" );
1112 if (m_xApplyBtn)
1113 m_xApplyBtn->connect_clicked(_rHdl);
1116 bool SfxTabDialogController::Apply()
1118 bool bApplied = false;
1119 if (PrepareLeaveCurrentPage())
1121 bApplied = (Ok() == RET_OK);
1122 //let the pages update their saved values
1123 GetInputSetImpl()->Put(*GetOutputItemSet());
1124 for (auto pDataObject : m_pImpl->aData)
1126 if (!pDataObject->xTabPage)
1127 continue;
1128 pDataObject->xTabPage->ChangesApplied();
1131 return bApplied;
1134 std::vector<OUString> SfxTabDialogController::getAllPageUIXMLDescriptions() const
1136 int nPages = m_xTabCtrl->get_n_pages();
1137 std::vector<OUString> aRet;
1138 aRet.reserve(nPages);
1139 for (int i = 0; i < nPages; ++i)
1140 aRet.push_back(m_xTabCtrl->get_page_ident(i));
1141 return aRet;
1144 bool SfxTabDialogController::selectPageByUIXMLDescription(const OUString& rUIXMLDescription)
1146 ShowPage(rUIXMLDescription);
1147 return m_xTabCtrl->get_current_page_ident() == rUIXMLDescription;
1150 BitmapEx SfxTabDialogController::createScreenshot() const
1152 // if we haven't run Start_Impl yet, do so now to create the initial pages
1153 if (!m_pImpl->bStarted)
1155 const_cast<SfxTabDialogController*>(this)->Start_Impl();
1158 VclPtr<VirtualDevice> xDialogSurface(m_xDialog->screenshot());
1159 return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
1162 OUString SfxTabDialogController::GetScreenshotId() const
1164 const OUString sId = m_xTabCtrl->get_current_page_ident();
1165 Data_Impl* pDataObject = Find(m_pImpl->aData, sId);
1166 SfxTabPage* pPage = pDataObject ? pDataObject->xTabPage.get() : nullptr;
1167 if (pPage)
1169 OUString sHelpId(pPage->GetHelpId());
1170 if (!sHelpId.isEmpty())
1171 return sHelpId;
1173 return m_xDialog->get_help_id();
1176 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */