nss: upgrade to release 3.73
[LibreOffice.git] / sfx2 / source / dialog / tabdlg.cxx
blob484b431a690e3e269879962bcdeb12f62ceca13e
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>
24 #include <sfx2/tabdlg.hxx>
25 #include <sfx2/app.hxx>
26 #include <sfx2/sfxresid.hxx>
27 #include <sfx2/sfxdlg.hxx>
28 #include <unotools/viewoptions.hxx>
29 #include <vcl/virdev.hxx>
30 #include <sal/log.hxx>
31 #include <tools/debug.hxx>
32 #include <comphelper/lok.hxx>
33 #include <sfx2/lokhelper.hxx>
35 #include <sfx2/strings.hrc>
36 #include <helpids.h>
38 using namespace ::com::sun::star::uno;
40 #define USERITEM_NAME "UserItem"
43 struct TabPageImpl
45 bool mbStandard;
46 SfxOkDialogController* mpSfxDialogController;
47 css::uno::Reference< css::frame::XFrame > mxFrame;
49 TabPageImpl() : mbStandard(false), mpSfxDialogController(nullptr) {}
52 namespace {
54 struct Data_Impl
56 OString sId; // The ID
57 CreateTabPage fnCreatePage; // Pointer to Factory
58 GetTabPageRanges fnGetRanges; // Pointer to Ranges-Function
59 std::unique_ptr<SfxTabPage> xTabPage; // The TabPage itself
60 bool bRefresh; // Flag: Page must be re-initialized
62 // Constructor
63 Data_Impl( const OString& rId, CreateTabPage fnPage,
64 GetTabPageRanges fnRanges ) :
66 sId ( rId ),
67 fnCreatePage( fnPage ),
68 fnGetRanges ( fnRanges ),
69 bRefresh ( false )
76 SfxTabDialogItem::SfxTabDialogItem( const SfxTabDialogItem& rAttr, SfxItemPool* pItemPool )
77 : SfxSetItem( rAttr, pItemPool )
81 SfxTabDialogItem::SfxTabDialogItem( sal_uInt16 nId, const SfxItemSet& rItemSet )
82 : SfxSetItem( nId, rItemSet )
86 SfxTabDialogItem* SfxTabDialogItem::Clone(SfxItemPool* pToPool) const
88 return new SfxTabDialogItem( *this, pToPool );
91 typedef std::vector<Data_Impl*> SfxTabDlgData_Impl;
93 struct TabDlg_Impl
95 bool bHideResetBtn : 1;
96 bool bStarted : 1;
97 SfxTabDlgData_Impl aData;
99 explicit TabDlg_Impl(sal_uInt8 nCnt)
100 : bHideResetBtn(false)
101 , bStarted(false)
103 aData.reserve( nCnt );
107 static Data_Impl* Find( const SfxTabDlgData_Impl& rArr, const OString& rId, sal_uInt16* pPos = nullptr)
109 const sal_uInt16 nCount = rArr.size();
111 for ( sal_uInt16 i = 0; i < nCount; ++i )
113 Data_Impl* pObj = rArr[i];
115 if ( pObj->sId == rId )
117 if ( pPos )
118 *pPos = i;
119 return pObj;
122 return nullptr;
125 void SfxTabPage::SetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame)
127 if (pImpl)
128 pImpl->mxFrame = xFrame;
131 css::uno::Reference< css::frame::XFrame > SfxTabPage::GetFrame() const
133 if (pImpl)
134 return pImpl->mxFrame;
135 return css::uno::Reference< css::frame::XFrame >();
138 SfxTabPage::SfxTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rID, const SfxItemSet *rAttrSet)
139 : BuilderPage(pPage, pController, rUIXMLDescription, rID,
140 comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current()
141 && SfxViewShell::Current()->isLOKMobilePhone())
142 , pSet ( rAttrSet )
143 , bHasExchangeSupport ( false )
144 , pImpl ( new TabPageImpl )
146 pImpl->mpSfxDialogController = dynamic_cast<SfxOkDialogController*>(m_pDialogController);
149 SfxTabPage::~SfxTabPage()
151 if (m_xContainer)
153 std::unique_ptr<weld::Container> xParent(m_xContainer->weld_parent());
154 if (xParent)
155 xParent->move(m_xContainer.get(), nullptr);
157 m_xContainer.reset();
158 pImpl.reset();
159 m_xBuilder.reset();
162 bool SfxTabPage::FillItemSet( SfxItemSet* )
164 return false;
167 void SfxTabPage::Reset( const SfxItemSet* )
171 bool SfxTabPage::DeferResetToFirstActivation() { return false; }
173 void SfxTabPage::ActivatePage( const SfxItemSet& )
174 /* [Description]
176 Default implementation of the virtual ActivatePage method. This method is
177 called when a page of dialogue supports the exchange of data between pages.
178 <SfxTabPage::DeactivatePage(SfxItemSet *)>
183 DeactivateRC SfxTabPage::DeactivatePage( SfxItemSet* )
185 /* [Description]
187 Default implementation of the virtual DeactivatePage method. This method is
188 called by Sfx when leaving a page; the application can, through the return
189 value, control whether to leave the page. If the page is displayed through
190 bHasExchangeSupport which supports data exchange between pages, then a
191 pointer to the exchange set is passed as parameter. This takes on data for
192 the exchange, then the set is available as a parameter in
193 <SfxTabPage::ActivatePage(const SfxItemSet &)>.
195 [Return value]
197 DeactivateRC::LeavePage; Allow leaving the page
201 return DeactivateRC::LeavePage;
205 void SfxTabPage::FillUserData()
207 /* [Description]
209 Virtual method is called by the base class in the destructor to save
210 specific information of the TabPage in the ini-file. When overriding a
211 string must be compiled, which is then flushed with the <SetUserData()>.
218 bool SfxTabPage::IsReadOnly() const
220 return false;
224 const SfxPoolItem* SfxTabPage::GetItem( const SfxItemSet& rSet, sal_uInt16 nSlot, bool bDeep )
226 /* [Description]
228 static Method: hereby are the implementations of the TabPage code
229 being simplified.
233 const SfxItemPool* pPool = rSet.GetPool();
234 sal_uInt16 nWh = pPool->GetWhich( nSlot, bDeep );
235 const SfxPoolItem* pItem = nullptr;
236 rSet.GetItemState( nWh, true, &pItem );
238 if ( !pItem && nWh != nSlot )
239 pItem = &pPool->GetDefaultItem( nWh );
240 return pItem;
244 const SfxPoolItem* SfxTabPage::GetOldItem( const SfxItemSet& rSet,
245 sal_uInt16 nSlot, bool bDeep )
247 /* [Description]
249 This method returns an attribute for comparison of the old value.
253 const SfxItemSet& rOldSet = GetItemSet();
254 sal_uInt16 nWh = GetWhich( nSlot, bDeep );
255 const SfxPoolItem* pItem = nullptr;
257 if ( pImpl->mbStandard && rOldSet.GetParent() )
258 pItem = GetItem( *rOldSet.GetParent(), nSlot );
259 else if ( rSet.GetParent() &&
260 SfxItemState::DONTCARE == rSet.GetItemState( nWh ) )
261 pItem = GetItem( *rSet.GetParent(), nSlot );
262 else
263 pItem = GetItem( rOldSet, nSlot );
264 return pItem;
267 void SfxTabPage::PageCreated( const SfxAllItemSet& /*aSet*/ )
269 SAL_WARN( "sfx.dialog", "SfxTabPage::PageCreated should not be called");
272 void SfxTabPage::ChangesApplied()
276 void SfxTabPage::SetDialogController(SfxOkDialogController* pDialog)
278 pImpl->mpSfxDialogController = pDialog;
279 m_pDialogController = pImpl->mpSfxDialogController;
282 SfxOkDialogController* SfxTabPage::GetDialogController() const
284 return pImpl->mpSfxDialogController;
287 OString SfxTabPage::GetHelpId() const
289 if (m_xContainer)
290 return m_xContainer->get_help_id();
291 return OString();
294 weld::Window* SfxTabPage::GetFrameWeld() const
296 if (m_pDialogController)
297 return m_pDialogController->getDialog();
298 return nullptr;
301 const SfxItemSet* SfxTabPage::GetDialogExampleSet() const
303 if (pImpl->mpSfxDialogController)
304 return pImpl->mpSfxDialogController->GetExampleSet();
305 return nullptr;
308 SfxTabDialogController::SfxTabDialogController
310 weld::Widget* pParent, // Parent Window
311 const OUString& rUIXMLDescription, const OString& rID, // Dialog .ui path, Dialog Name
312 const SfxItemSet* pItemSet, // Itemset with the data;
313 // can be NULL, when Pages are onDemand
314 bool bEditFmt // when yes -> additional Button for standard
316 : SfxOkDialogController(pParent, rUIXMLDescription, rID)
317 , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol"))
318 , m_xOKBtn(m_xBuilder->weld_button("ok"))
319 , m_xApplyBtn(m_xBuilder->weld_button("apply"))
320 , m_xUserBtn(m_xBuilder->weld_button("user"))
321 , m_xCancelBtn(m_xBuilder->weld_button("cancel"))
322 , m_xResetBtn(m_xBuilder->weld_button("reset"))
323 , m_xBaseFmtBtn(m_xBuilder->weld_button("standard"))
324 , m_pSet(pItemSet ? new SfxItemSet(*pItemSet) : nullptr)
325 , m_bStandardPushed(false)
327 m_pImpl.reset(new TabDlg_Impl(m_xTabCtrl->get_n_pages()));
328 m_pImpl->bHideResetBtn = !m_xResetBtn->get_visible();
329 m_xOKBtn->connect_clicked(LINK(this, SfxTabDialogController, OkHdl));
330 m_xCancelBtn->connect_clicked(LINK(this, SfxTabDialogController, CancelHdl));
331 m_xResetBtn->connect_clicked(LINK(this, SfxTabDialogController, ResetHdl));
332 m_xResetBtn->set_label(SfxResId(STR_RESET));
333 m_xTabCtrl->connect_enter_page(LINK(this, SfxTabDialogController, ActivatePageHdl));
334 m_xTabCtrl->connect_leave_page(LINK(this, SfxTabDialogController, DeactivatePageHdl));
335 m_xResetBtn->set_help_id(HID_TABDLG_RESET_BTN);
337 if (bEditFmt)
339 m_xBaseFmtBtn->set_label(SfxResId(STR_STANDARD_SHORTCUT));
340 m_xBaseFmtBtn->connect_clicked(LINK(this, SfxTabDialogController, BaseFmtHdl));
341 m_xBaseFmtBtn->set_help_id(HID_TABDLG_STANDARD_BTN);
342 m_xBaseFmtBtn->show();
345 if (m_xUserBtn)
346 m_xUserBtn->connect_clicked(LINK(this, SfxTabDialogController, UserHdl));
348 if (m_pSet)
350 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
351 m_pOutSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
354 // The reset functionality seems to be confusing to many; disable in LOK.
355 if (comphelper::LibreOfficeKit::isActive())
356 RemoveResetButton();
359 IMPL_LINK_NOARG(SfxTabDialogController, OkHdl, weld::Button&, void)
361 /* [Description]
363 Handler of the Ok-Buttons
364 This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
365 Returns <DeactivateRC::LeavePage>, <SfxTabDialog::Ok()> is called
366 and the Dialog is ended.
370 if (PrepareLeaveCurrentPage())
371 m_xDialog->response(Ok());
374 IMPL_LINK_NOARG(SfxTabDialogController, UserHdl, weld::Button&, void)
376 /* [Description]
378 Handler of the User-Buttons
379 This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
380 returns this <DeactivateRC::LeavePage> and <SfxTabDialog::Ok()> is called.
381 Then the Dialog is ended with the Return value <SfxTabDialog::Ok()>
385 if (PrepareLeaveCurrentPage())
387 short nRet = Ok();
388 if (RET_OK == nRet)
389 nRet = RET_USER;
390 else
391 nRet = RET_CANCEL;
392 m_xDialog->response(nRet);
396 IMPL_LINK_NOARG(SfxTabDialogController, CancelHdl, weld::Button&, void)
398 m_xDialog->response(RET_CANCEL);
401 IMPL_LINK_NOARG(SfxTabDialogController, ResetHdl, weld::Button&, void)
403 /* [Description]
405 Handler behind the reset button.
406 The Current Page is new initialized with their initial data, all the
407 settings that the user has made on this page are repealed.
411 Data_Impl* pDataObject = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
412 assert(pDataObject && "Id not known");
414 pDataObject->xTabPage->Reset(m_pSet.get());
415 // Also reset relevant items of ExampleSet and OutSet to initial state
416 if (!pDataObject->fnGetRanges)
417 return;
419 if (!m_xExampleSet)
420 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
422 const SfxItemPool* pPool = m_pSet->GetPool();
423 const sal_uInt16* pTmpRanges = (pDataObject->fnGetRanges)();
425 while (*pTmpRanges)
427 const sal_uInt16* pU = pTmpRanges + 1;
429 // Correct Range with multiple values
430 sal_uInt16 nTmp = *pTmpRanges, nTmpEnd = *pU;
431 DBG_ASSERT(nTmp <= nTmpEnd, "Range is sorted the wrong way");
433 if (nTmp > nTmpEnd)
435 // If really sorted wrongly, then set new
436 std::swap(nTmp, nTmpEnd);
439 while (nTmp && nTmp <= nTmpEnd)
441 // Iterate over the Range and set the Items
442 sal_uInt16 nWh = pPool->GetWhich(nTmp);
443 const SfxPoolItem* pItem;
444 if (SfxItemState::SET == m_pSet->GetItemState(nWh, false, &pItem))
446 m_xExampleSet->Put(*pItem);
447 m_pOutSet->Put(*pItem);
449 else
451 m_xExampleSet->ClearItem(nWh);
452 m_pOutSet->ClearItem(nWh);
454 nTmp++;
456 // Go to the next pair
457 pTmpRanges += 2;
461 /* [Description]
463 Handler behind the Standard-Button.
464 This button is available when editing style sheets. All the set attributes
465 in the edited stylesheet are deleted.
467 IMPL_LINK_NOARG(SfxTabDialogController, BaseFmtHdl, weld::Button&, void)
469 m_bStandardPushed = true;
471 Data_Impl* pDataObject = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
472 assert(pDataObject && "Id not known");
474 if (!pDataObject->fnGetRanges)
475 return;
477 if (!m_xExampleSet)
478 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
480 const SfxItemPool* pPool = m_pSet->GetPool();
481 const sal_uInt16* pTmpRanges = (pDataObject->fnGetRanges)();
482 SfxItemSet aTmpSet(*m_xExampleSet);
484 while (*pTmpRanges)
486 const sal_uInt16* pU = pTmpRanges + 1;
488 // Correct Range with multiple values
489 sal_uInt16 nTmp = *pTmpRanges, nTmpEnd = *pU;
490 DBG_ASSERT( nTmp <= nTmpEnd, "Range is sorted the wrong way" );
492 if ( nTmp > nTmpEnd )
494 // If really sorted wrongly, then set new
495 std::swap(nTmp, nTmpEnd);
498 while ( nTmp && nTmp <= nTmpEnd ) // guard against overflow
500 // Iterate over the Range and set the Items
501 sal_uInt16 nWh = pPool->GetWhich(nTmp);
502 m_xExampleSet->ClearItem(nWh);
503 aTmpSet.ClearItem(nWh);
504 // At the Outset of InvalidateItem,
505 // so that the change takes effect
506 m_pOutSet->InvalidateItem(nWh);
507 nTmp++;
509 // Go to the next pair
510 pTmpRanges += 2;
512 // Set all Items as new -> the call the current Page Reset()
513 assert(pDataObject->xTabPage && "the Page is gone");
514 pDataObject->xTabPage->Reset( &aTmpSet );
515 pDataObject->xTabPage->pImpl->mbStandard = true;
518 IMPL_LINK(SfxTabDialogController, ActivatePageHdl, const OString&, rPage, void)
520 /* [Description]
522 Handler that is called by StarView for switching to a different page.
523 If possible the <SfxTabPage::Reset(const SfxItemSet &)> or
524 <SfxTabPage::ActivatePage(const SfxItemSet &)> is called on the new page
528 assert(!m_pImpl->aData.empty() && "no Pages registered");
529 Data_Impl* pDataObject = Find(m_pImpl->aData, rPage);
530 if (!pDataObject)
532 SAL_WARN("sfx.dialog", "Tab Page ID not known, this is pretty serious and needs investigation");
533 return;
536 SfxTabPage* pTabPage = pDataObject->xTabPage.get();
537 if (!pTabPage)
538 return;
540 if (pDataObject->bRefresh)
541 pTabPage->Reset(m_pSet.get());
542 pDataObject->bRefresh = false;
544 if (m_xExampleSet)
545 pTabPage->ActivatePage(*m_xExampleSet);
547 if (pTabPage->IsReadOnly() || m_pImpl->bHideResetBtn)
548 m_xResetBtn->hide();
549 else
550 m_xResetBtn->show();
553 IMPL_LINK(SfxTabDialogController, DeactivatePageHdl, const OString&, rPage, bool)
555 /* [Description]
557 Handler that is called by StarView before leaving a page.
559 [Cross-reference]
561 <SfxTabPage::DeactivatePage(SfxItemSet *)>
565 assert(!m_pImpl->aData.empty() && "no Pages registered");
566 Data_Impl* pDataObject = Find(m_pImpl->aData, rPage);
567 if (!pDataObject)
569 SAL_WARN("sfx.dialog", "Tab Page ID not known, this is pretty serious and needs investigation");
570 return false;
573 SfxTabPage* pPage = pDataObject->xTabPage.get();
574 if (!pPage)
575 return true;
577 DeactivateRC nRet = DeactivateRC::LeavePage;
579 if (!m_xExampleSet && pPage->HasExchangeSupport() && m_pSet)
580 m_xExampleSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
582 if (m_pSet)
584 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
586 if (pPage->HasExchangeSupport())
587 nRet = pPage->DeactivatePage(&aTmp);
588 else
589 nRet = pPage->DeactivatePage(nullptr);
590 if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage &&
591 aTmp.Count() && m_xExampleSet)
593 m_xExampleSet->Put( aTmp );
594 m_pOutSet->Put( aTmp );
597 else
599 if ( pPage->HasExchangeSupport() ) //!!!
601 if (!m_xExampleSet)
603 SfxItemPool* pPool = pPage->GetItemSet().GetPool();
604 m_xExampleSet.reset(new SfxItemSet(*pPool, GetInputRanges(*pPool)));
606 nRet = pPage->DeactivatePage(m_xExampleSet.get());
608 else
609 nRet = pPage->DeactivatePage( nullptr );
612 if ( nRet & DeactivateRC::RefreshSet )
614 RefreshInputSet();
615 // Flag all Pages as to be initialized as new
617 for (auto const& elem : m_pImpl->aData)
619 elem->bRefresh = ( elem->xTabPage.get() != pPage ); // Do not refresh own Page anymore
622 return static_cast<bool>(nRet & DeactivateRC::LeavePage);
625 bool SfxTabDialogController::PrepareLeaveCurrentPage()
627 const OString sId = m_xTabCtrl->get_current_page_ident();
628 Data_Impl* pDataObject = Find(m_pImpl->aData, sId);
629 DBG_ASSERT( pDataObject, "Id not known" );
630 SfxTabPage* pPage = pDataObject ? pDataObject->xTabPage.get() : nullptr;
632 bool bEnd = !pPage;
634 if ( pPage )
636 DeactivateRC nRet = DeactivateRC::LeavePage;
637 if ( m_pSet )
639 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
641 if ( pPage->HasExchangeSupport() )
642 nRet = pPage->DeactivatePage( &aTmp );
643 else
644 nRet = pPage->DeactivatePage( nullptr );
646 if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage
647 && aTmp.Count() )
649 m_xExampleSet->Put( aTmp );
650 m_pOutSet->Put( aTmp );
653 else
654 nRet = pPage->DeactivatePage( nullptr );
655 bEnd = nRet != DeactivateRC::KeepPage;
658 return bEnd;
661 const sal_uInt16* SfxTabDialogController::GetInputRanges(const SfxItemPool& rPool)
663 /* [Description]
665 Makes the set over the range of all pages of the dialogue. Pages have the
666 static method for querying their range in AddTabPage, ie deliver their
667 sets onDemand.
669 [Return value]
671 Pointer to a null-terminated array of sal_uInt16. This array belongs to the
672 dialog and is deleted when the dialogue is destroy.
674 [Cross-reference]
676 <SfxTabDialog::AddTabPage(sal_uInt16, CreateTabPage, GetTabPageRanges, bool)>
677 <SfxTabDialog::AddTabPage(sal_uInt16, const String &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
678 <SfxTabDialog::AddTabPage(sal_uInt16, const Bitmap &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
682 if ( m_pSet )
684 SAL_WARN( "sfx.dialog", "Set already exists!" );
685 return m_pSet->GetRanges();
688 if ( m_pRanges )
689 return m_pRanges.get();
690 std::vector<sal_uInt16> aUS;
692 for (auto const& elem : m_pImpl->aData)
695 if ( elem->fnGetRanges )
697 const sal_uInt16* pTmpRanges = (elem->fnGetRanges)();
698 const sal_uInt16* pIter = pTmpRanges;
700 sal_uInt16 nLen;
701 for( nLen = 0; *pIter; ++nLen, ++pIter )
703 aUS.insert( aUS.end(), pTmpRanges, pTmpRanges + nLen );
707 //! Remove duplicated Ids?
709 for (auto & elem : aUS)
710 elem = rPool.GetWhich(elem);
713 // sort
714 if ( aUS.size() > 1 )
716 std::sort( aUS.begin(), aUS.end() );
719 m_pRanges.reset(new sal_uInt16[aUS.size() + 1]);
720 std::copy( aUS.begin(), aUS.end(), m_pRanges.get() );
721 m_pRanges[aUS.size()] = 0;
722 return m_pRanges.get();
725 SfxTabDialogController::~SfxTabDialogController()
727 SavePosAndId();
729 for (auto & elem : m_pImpl->aData)
731 if ( elem->xTabPage )
733 // save settings of all pages (user data)
734 elem->xTabPage->FillUserData();
735 OUString aPageData( elem->xTabPage->GetUserData() );
736 if ( !aPageData.isEmpty() )
738 // save settings of all pages (user data)
739 OUString sConfigId = OStringToOUString(elem->xTabPage->GetConfigId(),
740 RTL_TEXTENCODING_UTF8);
741 SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
742 aPageOpt.SetUserItem( USERITEM_NAME, makeAny( aPageData ) );
745 elem->xTabPage.reset();
747 delete elem;
748 elem = nullptr;
752 short SfxTabDialogController::Ok()
754 /* [Description]
756 Ok handler for the Dialogue.
758 Dialog's current location and current page are saved for the next time
759 the dialog is shown.
761 The OutputSet is created and for each page this or the special OutputSet
762 is set by calling the method <SfxTabPage::FillItemSet(SfxItemSet &)>, to
763 insert the entered data by the user into the set.
765 [Return value]
767 RET_OK: if at least one page has returned from FillItemSet,
768 otherwise RET_CANCEL.
771 SavePosAndId(); //See fdo#38828 "Apply" resetting window position
773 if ( !m_pOutSet )
775 if ( m_xExampleSet )
776 m_pOutSet.reset(new SfxItemSet( *m_xExampleSet ));
777 else if ( m_pSet )
778 m_pOutSet = m_pSet->Clone( false ); // without Items
780 bool bModified = false;
782 for (auto const& elem : m_pImpl->aData)
784 SfxTabPage* pTabPage = elem->xTabPage.get();
786 if ( pTabPage )
788 if ( m_pSet && !pTabPage->HasExchangeSupport() )
790 SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
792 if ( pTabPage->FillItemSet( &aTmp ) )
794 bModified = true;
795 if (m_xExampleSet)
796 m_xExampleSet->Put( aTmp );
797 m_pOutSet->Put( aTmp );
803 if (m_pOutSet && m_pOutSet->Count() > 0)
804 bModified = true;
806 if (m_bStandardPushed)
807 bModified = true;
809 return bModified ? RET_OK : RET_CANCEL;
812 void SfxTabDialogController::RefreshInputSet()
814 /* [Description]
816 Default implementation of the virtual Method.
817 This is called, when <SfxTabPage::DeactivatePage(SfxItemSet *)>
818 returns <DeactivateRC::RefreshSet>.
822 SAL_INFO ( "sfx.dialog", "RefreshInputSet not implemented" );
825 void SfxTabDialogController::PageCreated
827 /* [Description]
829 Default implementation of the virtual method. This is called immediately
830 after creating a page. Here the dialogue can call the TabPage Method
831 directly.
835 const OString&, // Id of the created page
836 SfxTabPage& // Reference to the created page
841 void SfxTabDialogController::SavePosAndId()
843 // save settings (screen position and current page)
844 SvtViewOptions aDlgOpt(EViewType::TabDialog, OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8));
845 aDlgOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
849 Adds a page to the dialog. The Name must correspond to an entry in the
850 TabControl in the dialog .ui
852 void SfxTabDialogController::AddTabPage(const OString &rName /* Page ID */,
853 CreateTabPage pCreateFunc /* Pointer to the Factory Method */,
854 GetTabPageRanges pRangesFunc /* Pointer to the Method for querying Ranges onDemand */)
856 m_pImpl->aData.push_back(new Data_Impl(rName, pCreateFunc, pRangesFunc));
859 void SfxTabDialogController::AddTabPage(const OString &rName /* Page ID */,
860 sal_uInt16 nPageCreateId /* Identifier of the Factory Method to create the page */)
862 SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
863 CreateTabPage pCreateFunc = pFact->GetTabPageCreatorFunc(nPageCreateId);
864 GetTabPageRanges pRangesFunc = pFact->GetTabPageRangesFunc(nPageCreateId);
865 AddTabPage(rName, pCreateFunc, pRangesFunc);
868 /* [Description]
870 Add a page to the dialog. The Rider text is passed on, the page has no
871 counterpart in the TabControl in the resource of the dialogue.
874 void SfxTabDialogController::AddTabPage(const OString &rName, /* Page ID */
875 const OUString& rRiderText,
876 CreateTabPage pCreateFunc /* Pointer to the Factory Method */)
878 assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
879 m_xTabCtrl->append_page(rName, rRiderText);
880 AddTabPage(rName, pCreateFunc, nullptr);
883 void SfxTabDialogController::AddTabPage(const OString &rName, const OUString& rRiderText,
884 sal_uInt16 nPageCreateId /* Identifier of the Factory Method to create the page */)
886 assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
887 m_xTabCtrl->append_page(rName, rRiderText);
888 AddTabPage(rName, nPageCreateId);
891 /* [Description]
893 Default implementation of the virtual Method.
894 This is called when pages create their sets onDemand.
896 SfxItemSet* SfxTabDialogController::CreateInputItemSet(const OString&)
898 SAL_WARN( "sfx.dialog", "CreateInputItemSet not implemented" );
899 return new SfxAllItemSet(SfxGetpApp()->GetPool());
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 OUString sConfigId = OStringToOUString(pDataObject->xTabPage->GetConfigId(), RTL_TEXTENCODING_UTF8);
915 SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
916 OUString sUserData;
917 Any aUserItem = aPageOpt.GetUserItem(USERITEM_NAME);
918 OUString aTemp;
919 if ( aUserItem >>= aTemp )
920 sUserData = aTemp;
921 pDataObject->xTabPage->SetUserData(sUserData);
923 PageCreated(pDataObject->sId, *pDataObject->xTabPage);
924 if (pDataObject->xTabPage->DeferResetToFirstActivation())
925 pDataObject->bRefresh = true; // Reset will be called in ActivatePageHdl
926 else
927 pDataObject->xTabPage->Reset(m_pSet.get());
931 void SfxTabDialogController::setPreviewsToSamePlace()
933 //where tab pages have the same basic layout with a preview on the right,
934 //get both of their non-preview areas to request the same size so that the
935 //preview appears in the same place in each one so flipping between tabs
936 //isn't distracting as it jumps around
937 std::vector<std::unique_ptr<weld::Widget>> aGrids;
938 for (auto pDataObject : m_pImpl->aData)
940 if (!pDataObject->xTabPage)
941 continue;
942 if (!pDataObject->xTabPage->m_xBuilder)
943 continue;
944 std::unique_ptr<weld::Widget> pGrid = pDataObject->xTabPage->m_xBuilder->weld_widget("maingrid");
945 if (!pGrid)
946 continue;
947 aGrids.emplace_back(std::move(pGrid));
950 m_xSizeGroup.reset();
952 if (aGrids.size() <= 1)
953 return;
955 m_xSizeGroup = m_xBuilder->create_size_group();
956 m_xSizeGroup->set_mode(VclSizeGroupMode::Both);
957 for (auto& rGrid : aGrids)
958 m_xSizeGroup->add_widget(rGrid.get());
961 void SfxTabDialogController::RemoveTabPage(const OString& rId)
963 /* [Description]
965 Delete the TabPage with ID nId
969 sal_uInt16 nPos = 0;
970 m_xTabCtrl->remove_page(rId);
971 Data_Impl* pDataObject = Find( m_pImpl->aData, rId, &nPos );
973 if ( pDataObject )
975 if ( pDataObject->xTabPage )
977 pDataObject->xTabPage->FillUserData();
978 OUString aPageData( pDataObject->xTabPage->GetUserData() );
979 if ( !aPageData.isEmpty() )
981 // save settings of this page (user data)
982 OUString sConfigId = OStringToOUString(pDataObject->xTabPage->GetConfigId(),
983 RTL_TEXTENCODING_UTF8);
984 SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
985 aPageOpt.SetUserItem( USERITEM_NAME, makeAny( aPageData ) );
988 pDataObject->xTabPage.reset();
991 delete pDataObject;
992 m_pImpl->aData.erase( m_pImpl->aData.begin() + nPos );
994 else
996 SAL_INFO( "sfx.dialog", "TabPage-Id not known" );
1000 void SfxTabDialogController::Start_Impl()
1002 CreatePages();
1004 setPreviewsToSamePlace();
1006 assert(m_pImpl->aData.size() == static_cast<size_t>(m_xTabCtrl->get_n_pages())
1007 && "not all pages registered");
1009 // load old settings, when exists, setting SetCurPageId will override the settings,
1010 // something that the sort dialog in calc depends on
1011 if (m_sAppPageId.isEmpty())
1013 SvtViewOptions aDlgOpt(EViewType::TabDialog, OStringToOUString(m_xDialog->get_help_id(), RTL_TEXTENCODING_UTF8));
1014 if (aDlgOpt.Exists())
1015 m_xTabCtrl->set_current_page(aDlgOpt.GetPageID());
1018 ActivatePageHdl(m_xTabCtrl->get_current_page_ident());
1020 m_pImpl->bStarted = true;
1023 void SfxTabDialogController::SetCurPageId(const OString& rIdent)
1025 m_sAppPageId = rIdent;
1026 m_xTabCtrl->set_current_page(m_sAppPageId);
1029 /* [Description]
1031 The TabPage is activated with the specified Id.
1033 void SfxTabDialogController::ShowPage(const OString& rIdent)
1035 SetCurPageId(rIdent);
1036 ActivatePageHdl(rIdent);
1039 OString SfxTabDialogController::GetCurPageId() const
1041 return m_xTabCtrl->get_current_page_ident();
1044 short SfxTabDialogController::run()
1046 Start_Impl();
1047 return SfxDialogController::run();
1050 bool SfxTabDialogController::runAsync(const std::shared_ptr<SfxTabDialogController>& rController,
1051 const std::function<void(sal_Int32)>& rFunc)
1053 rController->Start_Impl();
1054 return weld::DialogController::runAsync(rController, rFunc);
1057 void SfxTabDialogController::SetInputSet( const SfxItemSet* pInSet )
1059 /* [Description]
1061 With this method the Input-Set can subsequently be set initially or re-set.
1065 bool bSet = ( m_pSet != nullptr );
1066 m_pSet.reset(pInSet ? new SfxItemSet(*pInSet) : nullptr);
1068 if (!bSet && !m_xExampleSet && !m_pOutSet && m_pSet)
1070 m_xExampleSet.reset(new SfxItemSet(*m_pSet));
1071 m_pOutSet.reset(new SfxItemSet( *m_pSet->GetPool(), m_pSet->GetRanges() ));
1075 SfxItemSet* SfxTabDialogController::GetInputSetImpl()
1077 /* [Description]
1079 Derived classes may create new storage for the InputSet. This has to be
1080 released in the Destructor. To do this, this method must be called.
1084 return m_pSet.get();
1087 void SfxTabDialogController::RemoveResetButton()
1089 m_xResetBtn->hide();
1090 m_pImpl->bHideResetBtn = true;
1093 void SfxTabDialogController::RemoveStandardButton()
1095 m_xBaseFmtBtn->hide();
1098 SfxTabPage* SfxTabDialogController::GetTabPage(const OString& rPageId) const
1100 /* [Description]
1102 Return TabPage with the specified Id.
1106 Data_Impl* pDataObject = Find(m_pImpl->aData, rPageId);
1107 if (pDataObject)
1108 return pDataObject->xTabPage.get();
1109 return nullptr;
1112 void SfxTabDialogController::SetApplyHandler(const Link<weld::Button&, void>& _rHdl)
1114 DBG_ASSERT( m_xApplyBtn, "SfxTabDialog::GetApplyHandler: no apply button enabled!" );
1115 if (m_xApplyBtn)
1116 m_xApplyBtn->connect_clicked(_rHdl);
1119 bool SfxTabDialogController::Apply()
1121 bool bApplied = false;
1122 if (PrepareLeaveCurrentPage())
1124 bApplied = (Ok() == RET_OK);
1125 //let the pages update their saved values
1126 GetInputSetImpl()->Put(*GetOutputItemSet());
1127 for (auto pDataObject : m_pImpl->aData)
1129 if (!pDataObject->xTabPage)
1130 continue;
1131 pDataObject->xTabPage->ChangesApplied();
1134 return bApplied;
1137 std::vector<OString> SfxTabDialogController::getAllPageUIXMLDescriptions() const
1139 int nPages = m_xTabCtrl->get_n_pages();
1140 std::vector<OString> aRet;
1141 aRet.reserve(nPages);
1142 for (int i = 0; i < nPages; ++i)
1143 aRet.push_back(m_xTabCtrl->get_page_ident(i));
1144 return aRet;
1147 bool SfxTabDialogController::selectPageByUIXMLDescription(const OString& rUIXMLDescription)
1149 ShowPage(rUIXMLDescription);
1150 return m_xTabCtrl->get_current_page_ident() == rUIXMLDescription;
1153 BitmapEx SfxTabDialogController::createScreenshot() const
1155 // if we haven't run Start_Impl yet, do so now to create the initial pages
1156 if (!m_pImpl->bStarted)
1158 const_cast<SfxTabDialogController*>(this)->Start_Impl();
1161 VclPtr<VirtualDevice> xDialogSurface(m_xDialog->screenshot());
1162 return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
1165 OString SfxTabDialogController::GetScreenshotId() const
1167 const OString sId = m_xTabCtrl->get_current_page_ident();
1168 Data_Impl* pDataObject = Find(m_pImpl->aData, sId);
1169 SfxTabPage* pPage = pDataObject ? pDataObject->xTabPage.get() : nullptr;
1170 if (pPage)
1172 OString sHelpId(pPage->GetHelpId());
1173 if (!sHelpId.isEmpty())
1174 return sHelpId;
1176 return m_xDialog->get_help_id();
1179 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */