1183 lines
34 KiB
C++
1183 lines
34 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <algorithm>
|
|
#include <string_view>
|
|
|
|
#include <sfx2/tabdlg.hxx>
|
|
#include <sfx2/app.hxx>
|
|
#include <sfx2/sfxresid.hxx>
|
|
#include <sfx2/sfxdlg.hxx>
|
|
#include <sfx2/viewsh.hxx>
|
|
#include <unotools/viewoptions.hxx>
|
|
#include <utility>
|
|
#include <vcl/virdev.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <tools/debug.hxx>
|
|
#include <comphelper/lok.hxx>
|
|
|
|
#include <sfx2/strings.hrc>
|
|
#include <helpids.h>
|
|
|
|
using namespace ::com::sun::star::uno;
|
|
|
|
constexpr OUString USERITEM_NAME = u"UserItem"_ustr;
|
|
|
|
|
|
struct TabPageImpl
|
|
{
|
|
bool mbStandard;
|
|
SfxOkDialogController* mpSfxDialogController;
|
|
css::uno::Reference< css::frame::XFrame > mxFrame;
|
|
|
|
TabPageImpl() : mbStandard(false), mpSfxDialogController(nullptr) {}
|
|
};
|
|
|
|
namespace {
|
|
|
|
struct Data_Impl
|
|
{
|
|
OUString sId; // The ID
|
|
CreateTabPage fnCreatePage; // Pointer to Factory
|
|
GetTabPageRanges fnGetRanges; // Pointer to Ranges-Function
|
|
std::unique_ptr<SfxTabPage> xTabPage; // The TabPage itself
|
|
bool bRefresh; // Flag: Page must be re-initialized
|
|
|
|
// Constructor
|
|
Data_Impl( const OUString& rId, CreateTabPage fnPage,
|
|
GetTabPageRanges fnRanges ) :
|
|
|
|
sId ( rId ),
|
|
fnCreatePage( fnPage ),
|
|
fnGetRanges ( fnRanges ),
|
|
bRefresh ( false )
|
|
{
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
SfxTabDialogItem::SfxTabDialogItem( const SfxTabDialogItem& rAttr, SfxItemPool* pItemPool )
|
|
: SfxSetItem( rAttr, pItemPool )
|
|
{
|
|
}
|
|
|
|
SfxTabDialogItem::SfxTabDialogItem( sal_uInt16 nId, const SfxItemSet& rItemSet )
|
|
: SfxSetItem( nId, rItemSet )
|
|
{
|
|
}
|
|
|
|
SfxTabDialogItem* SfxTabDialogItem::Clone(SfxItemPool* pToPool) const
|
|
{
|
|
return new SfxTabDialogItem( *this, pToPool );
|
|
}
|
|
|
|
typedef std::vector<Data_Impl*> SfxTabDlgData_Impl;
|
|
|
|
struct TabDlg_Impl
|
|
{
|
|
bool bHideResetBtn : 1;
|
|
bool bStarted : 1;
|
|
SfxTabDlgData_Impl aData;
|
|
|
|
explicit TabDlg_Impl(sal_uInt8 nCnt)
|
|
: bHideResetBtn(false)
|
|
, bStarted(false)
|
|
{
|
|
aData.reserve( nCnt );
|
|
}
|
|
};
|
|
|
|
static auto Find(const SfxTabDlgData_Impl& rArr, std::u16string_view rId)
|
|
{
|
|
return std::find_if(rArr.begin(), rArr.end(),
|
|
[rId](const auto& item) { return item->sId == rId; });
|
|
}
|
|
|
|
void SfxTabPage::SetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame)
|
|
{
|
|
if (mpImpl)
|
|
mpImpl->mxFrame = xFrame;
|
|
}
|
|
|
|
css::uno::Reference< css::frame::XFrame > SfxTabPage::GetFrame() const
|
|
{
|
|
if (mpImpl)
|
|
return mpImpl->mxFrame;
|
|
return css::uno::Reference< css::frame::XFrame >();
|
|
}
|
|
|
|
static bool isLOKMobilePhone()
|
|
{
|
|
if (!comphelper::LibreOfficeKit::isActive())
|
|
return false;
|
|
const SfxViewShell* pCurrentShell = SfxViewShell::Current();
|
|
return pCurrentShell && pCurrentShell->isLOKMobilePhone();
|
|
}
|
|
|
|
SfxTabPage::SfxTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OUString& rID, const SfxItemSet *rAttrSet)
|
|
: BuilderPage(pPage, pController, rUIXMLDescription, rID, isLOKMobilePhone())
|
|
, mpSet(rAttrSet)
|
|
, mbHasExchangeSupport(false)
|
|
, mbCancel(false)
|
|
, mpImpl(new TabPageImpl)
|
|
{
|
|
mpImpl->mpSfxDialogController = dynamic_cast<SfxOkDialogController*>(m_pDialogController);
|
|
}
|
|
|
|
SfxTabPage::~SfxTabPage()
|
|
{
|
|
if (m_xContainer)
|
|
{
|
|
std::unique_ptr<weld::Container> xParent(m_xContainer->weld_parent());
|
|
if (xParent)
|
|
xParent->move(m_xContainer.get(), nullptr);
|
|
}
|
|
m_xContainer.reset();
|
|
mpImpl.reset();
|
|
m_xBuilder.reset();
|
|
}
|
|
|
|
bool SfxTabPage::FillItemSet( SfxItemSet* )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
Returns the visible strings of a dialog.
|
|
|
|
Supported items:
|
|
- label
|
|
- check button
|
|
- radio button
|
|
- toggle button
|
|
- link button
|
|
- button
|
|
*/
|
|
OUString SfxTabPage::GetAllStrings() { return OUString(); }
|
|
|
|
void SfxTabPage::Reset( const SfxItemSet* )
|
|
{
|
|
}
|
|
|
|
bool SfxTabPage::DeferResetToFirstActivation() { return false; }
|
|
|
|
void SfxTabPage::ActivatePage( const SfxItemSet& )
|
|
/* [Description]
|
|
|
|
Default implementation of the virtual ActivatePage method. This method is
|
|
called when a page of dialogue supports the exchange of data between pages.
|
|
<SfxTabPage::DeactivatePage(SfxItemSet *)>
|
|
*/
|
|
{
|
|
}
|
|
|
|
DeactivateRC SfxTabPage::DeactivatePage( SfxItemSet* )
|
|
|
|
/* [Description]
|
|
|
|
Default implementation of the virtual DeactivatePage method. This method is
|
|
called by Sfx when leaving a page; the application can, through the return
|
|
value, control whether to leave the page. If the page is displayed through
|
|
bHasExchangeSupport which supports data exchange between pages, then a
|
|
pointer to the exchange set is passed as parameter. This takes on data for
|
|
the exchange, then the set is available as a parameter in
|
|
<SfxTabPage::ActivatePage(const SfxItemSet &)>.
|
|
|
|
[Return value]
|
|
|
|
DeactivateRC::LeavePage; Allow leaving the page
|
|
*/
|
|
|
|
{
|
|
return DeactivateRC::LeavePage;
|
|
}
|
|
|
|
|
|
void SfxTabPage::FillUserData()
|
|
|
|
/* [Description]
|
|
|
|
Virtual method is called by the base class in the destructor to save
|
|
specific information of the TabPage in the ini-file. When overriding a
|
|
string must be compiled, which is then flushed with the <SetUserData()>.
|
|
*/
|
|
|
|
{
|
|
}
|
|
|
|
|
|
bool SfxTabPage::IsReadOnly() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
const SfxPoolItem* SfxTabPage::GetItem( const SfxItemSet& rSet, sal_uInt16 nSlot, bool bDeep )
|
|
|
|
/* [Description]
|
|
|
|
static Method: hereby are the implementations of the TabPage code
|
|
being simplified.
|
|
*/
|
|
|
|
{
|
|
const SfxItemPool* pPool = rSet.GetPool();
|
|
sal_uInt16 nWh = pPool->GetWhichIDFromSlotID( nSlot, bDeep );
|
|
const SfxPoolItem* pItem = nullptr;
|
|
rSet.GetItemState( nWh, true, &pItem );
|
|
|
|
if ( !pItem && nWh != nSlot )
|
|
pItem = &pPool->GetUserOrPoolDefaultItem( nWh );
|
|
return pItem;
|
|
}
|
|
|
|
|
|
const SfxPoolItem* SfxTabPage::GetOldItem( const SfxItemSet& rSet,
|
|
sal_uInt16 nSlot, bool bDeep )
|
|
|
|
/* [Description]
|
|
|
|
This method returns an attribute for comparison of the old value.
|
|
*/
|
|
|
|
{
|
|
const SfxItemSet& rOldSet = GetItemSet();
|
|
sal_uInt16 nWh = GetWhich( nSlot, bDeep );
|
|
const SfxPoolItem* pItem = nullptr;
|
|
|
|
if (mpImpl->mbStandard && rOldSet.GetParent())
|
|
pItem = GetItem( *rOldSet.GetParent(), nSlot );
|
|
else if ( rSet.GetParent() &&
|
|
SfxItemState::INVALID == rSet.GetItemState( nWh ) )
|
|
pItem = GetItem( *rSet.GetParent(), nSlot );
|
|
else
|
|
pItem = GetItem( rOldSet, nSlot );
|
|
return pItem;
|
|
}
|
|
|
|
void SfxTabPage::PageCreated( const SfxAllItemSet& /*aSet*/ )
|
|
{
|
|
SAL_WARN( "sfx.dialog", "SfxTabPage::PageCreated should not be called");
|
|
}
|
|
|
|
void SfxTabPage::ChangesApplied()
|
|
{
|
|
}
|
|
|
|
void SfxTabPage::SetDialogController(SfxOkDialogController* pDialog)
|
|
{
|
|
mpImpl->mpSfxDialogController = pDialog;
|
|
m_pDialogController = mpImpl->mpSfxDialogController;
|
|
}
|
|
|
|
SfxOkDialogController* SfxTabPage::GetDialogController() const
|
|
{
|
|
return mpImpl->mpSfxDialogController;
|
|
}
|
|
|
|
OUString SfxTabPage::GetHelpId() const
|
|
{
|
|
if (m_xContainer)
|
|
return m_xContainer->get_help_id();
|
|
return {};
|
|
}
|
|
|
|
weld::Window* SfxTabPage::GetFrameWeld() const
|
|
{
|
|
if (m_pDialogController)
|
|
return m_pDialogController->getDialog();
|
|
return nullptr;
|
|
}
|
|
|
|
const SfxItemSet* SfxTabPage::GetDialogExampleSet() const
|
|
{
|
|
if (mpImpl->mpSfxDialogController)
|
|
return mpImpl->mpSfxDialogController->GetExampleSet();
|
|
return nullptr;
|
|
}
|
|
|
|
SfxTabDialogController::SfxTabDialogController
|
|
(
|
|
weld::Widget* pParent, // Parent Window
|
|
const OUString& rUIXMLDescription, const OUString& rID, // Dialog .ui path, Dialog Name
|
|
const SfxItemSet* pItemSet, // Itemset with the data;
|
|
// can be NULL, when Pages are onDemand
|
|
bool bEditFmt // when yes -> additional Button for standard
|
|
)
|
|
: SfxOkDialogController(pParent, rUIXMLDescription, rID)
|
|
, m_xTabCtrl(m_xBuilder->weld_notebook(u"tabcontrol"_ustr))
|
|
, m_xOKBtn(m_xBuilder->weld_button(u"ok"_ustr))
|
|
, m_xApplyBtn(m_xBuilder->weld_button(u"apply"_ustr))
|
|
, m_xUserBtn(m_xBuilder->weld_button(u"user"_ustr))
|
|
, m_xCancelBtn(m_xBuilder->weld_button(u"cancel"_ustr))
|
|
, m_xResetBtn(m_xBuilder->weld_button(u"reset"_ustr))
|
|
, m_xBaseFmtBtn(m_xBuilder->weld_button(u"standard"_ustr))
|
|
, m_pSet(pItemSet ? new SfxItemSet(*pItemSet) : nullptr)
|
|
, m_bStandardPushed(false)
|
|
{
|
|
m_pImpl.reset(new TabDlg_Impl(m_xTabCtrl->get_n_pages()));
|
|
m_pImpl->bHideResetBtn = !m_xResetBtn->get_visible();
|
|
m_xOKBtn->connect_clicked(LINK(this, SfxTabDialogController, OkHdl));
|
|
m_xCancelBtn->connect_clicked(LINK(this, SfxTabDialogController, CancelHdl));
|
|
m_xResetBtn->connect_clicked(LINK(this, SfxTabDialogController, ResetHdl));
|
|
m_xResetBtn->set_label(SfxResId(STR_RESET));
|
|
m_xTabCtrl->connect_enter_page(LINK(this, SfxTabDialogController, ActivatePageHdl));
|
|
m_xTabCtrl->connect_leave_page(LINK(this, SfxTabDialogController, DeactivatePageHdl));
|
|
m_xResetBtn->set_help_id(HID_TABDLG_RESET_BTN);
|
|
|
|
if (bEditFmt)
|
|
{
|
|
m_xBaseFmtBtn->set_label(SfxResId(STR_STANDARD_SHORTCUT));
|
|
m_xBaseFmtBtn->connect_clicked(LINK(this, SfxTabDialogController, BaseFmtHdl));
|
|
m_xBaseFmtBtn->set_help_id(HID_TABDLG_STANDARD_BTN);
|
|
m_xBaseFmtBtn->show();
|
|
}
|
|
|
|
if (m_xUserBtn)
|
|
m_xUserBtn->connect_clicked(LINK(this, SfxTabDialogController, UserHdl));
|
|
|
|
if (m_pSet)
|
|
{
|
|
m_xExampleSet.reset(new SfxItemSet(*m_pSet));
|
|
m_pOutSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
|
|
}
|
|
|
|
// The reset functionality seems to be confusing to many; disable in LOK.
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
RemoveResetButton();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SfxTabDialogController, OkHdl, weld::Button&, void)
|
|
|
|
/* [Description]
|
|
|
|
Handler of the Ok-Buttons
|
|
This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
|
|
Returns <DeactivateRC::LeavePage>, <SfxTabDialog::Ok()> is called
|
|
and the Dialog is ended.
|
|
*/
|
|
|
|
{
|
|
if (PrepareLeaveCurrentPage())
|
|
m_xDialog->response(Ok());
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SfxTabDialogController, UserHdl, weld::Button&, void)
|
|
|
|
/* [Description]
|
|
|
|
Handler of the User-Buttons
|
|
This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
|
|
returns this <DeactivateRC::LeavePage> and <SfxTabDialog::Ok()> is called.
|
|
Then the Dialog is ended with the Return value <SfxTabDialog::Ok()>
|
|
*/
|
|
|
|
{
|
|
if (PrepareLeaveCurrentPage())
|
|
{
|
|
short nRet = Ok();
|
|
if (RET_OK == nRet)
|
|
nRet = RET_USER;
|
|
else
|
|
nRet = RET_CANCEL;
|
|
m_xDialog->response(nRet);
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SfxTabDialogController, CancelHdl, weld::Button&, void)
|
|
{
|
|
m_xDialog->response(RET_CANCEL);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SfxTabDialogController, ResetHdl, weld::Button&, void)
|
|
|
|
/* [Description]
|
|
|
|
Handler behind the reset button.
|
|
The Current Page is new initialized with their initial data, all the
|
|
settings that the user has made on this page are repealed.
|
|
*/
|
|
|
|
{
|
|
auto it = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
|
|
assert(it != m_pImpl->aData.end() && "Id not known");
|
|
|
|
(*it)->xTabPage->Reset(m_pSet.get());
|
|
// Also reset relevant items of ExampleSet and OutSet to initial state
|
|
if (!(*it)->fnGetRanges)
|
|
return;
|
|
|
|
if (!m_xExampleSet)
|
|
m_xExampleSet.reset(new SfxItemSet(*m_pSet));
|
|
|
|
const SfxItemPool* pPool = m_pSet->GetPool();
|
|
const WhichRangesContainer aTmpRanges = ((*it)->fnGetRanges)();
|
|
|
|
for (const auto & rPair : aTmpRanges)
|
|
{
|
|
// Correct Range with multiple values
|
|
sal_uInt16 nTmp = rPair.first, nTmpEnd = rPair.second;
|
|
DBG_ASSERT(nTmp <= nTmpEnd, "Range is sorted the wrong way");
|
|
|
|
if (nTmp > nTmpEnd)
|
|
{
|
|
// If really sorted wrongly, then set new
|
|
std::swap(nTmp, nTmpEnd);
|
|
}
|
|
|
|
while (nTmp && nTmp <= nTmpEnd)
|
|
{
|
|
// Iterate over the Range and set the Items
|
|
sal_uInt16 nWh = pPool->GetWhichIDFromSlotID(nTmp);
|
|
const SfxPoolItem* pItem;
|
|
if (SfxItemState::SET == m_pSet->GetItemState(nWh, false, &pItem))
|
|
{
|
|
m_xExampleSet->Put(*pItem);
|
|
}
|
|
else
|
|
{
|
|
m_xExampleSet->ClearItem(nWh);
|
|
}
|
|
m_pOutSet->ClearItem(nWh);
|
|
nTmp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* [Description]
|
|
|
|
Handler behind the Standard-Button.
|
|
This button is available when editing style sheets. All the set attributes
|
|
in the edited stylesheet are deleted.
|
|
*/
|
|
IMPL_LINK_NOARG(SfxTabDialogController, BaseFmtHdl, weld::Button&, void)
|
|
{
|
|
m_bStandardPushed = true;
|
|
|
|
auto it = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
|
|
assert(it != m_pImpl->aData.end() && "Id not known");
|
|
|
|
if (!(*it)->fnGetRanges)
|
|
return;
|
|
|
|
if (!m_xExampleSet)
|
|
m_xExampleSet.reset(new SfxItemSet(*m_pSet));
|
|
|
|
const SfxItemPool* pPool = m_pSet->GetPool();
|
|
const WhichRangesContainer aTmpRanges = ((*it)->fnGetRanges)();
|
|
SfxItemSet aTmpSet(*m_xExampleSet);
|
|
|
|
for (const auto& rPair : aTmpRanges)
|
|
{
|
|
// Correct Range with multiple values
|
|
sal_uInt16 nTmp = rPair.first, nTmpEnd = rPair.second;
|
|
DBG_ASSERT( nTmp <= nTmpEnd, "Range is sorted the wrong way" );
|
|
|
|
if ( nTmp > nTmpEnd )
|
|
{
|
|
// If really sorted wrongly, then set new
|
|
std::swap(nTmp, nTmpEnd);
|
|
}
|
|
|
|
while ( nTmp && nTmp <= nTmpEnd ) // guard against overflow
|
|
{
|
|
// Iterate over the Range and set the Items
|
|
sal_uInt16 nWh = pPool->GetWhichIDFromSlotID(nTmp);
|
|
m_xExampleSet->ClearItem(nWh);
|
|
aTmpSet.ClearItem(nWh);
|
|
// At the Outset of InvalidateItem,
|
|
// so that the change takes effect
|
|
m_pOutSet->InvalidateItem(nWh);
|
|
nTmp++;
|
|
}
|
|
}
|
|
// Set all Items as new -> the call the current Page Reset()
|
|
assert((*it)->xTabPage && "the Page is gone");
|
|
(*it)->xTabPage->Reset(&aTmpSet);
|
|
(*it)->xTabPage->mpImpl->mbStandard = true;
|
|
}
|
|
|
|
IMPL_LINK(SfxTabDialogController, ActivatePageHdl, const OUString&, rPage, void)
|
|
{
|
|
ActivatePage(rPage);
|
|
}
|
|
|
|
void SfxTabDialogController::ActivatePage(const OUString& rPage)
|
|
/* [Description]
|
|
|
|
Handler that is called by StarView for switching to a different page.
|
|
If possible the <SfxTabPage::Reset(const SfxItemSet &)> or
|
|
<SfxTabPage::ActivatePage(const SfxItemSet &)> is called on the new page
|
|
*/
|
|
|
|
{
|
|
assert(!m_pImpl->aData.empty() && "no Pages registered");
|
|
auto it = Find(m_pImpl->aData, rPage);
|
|
if (it == m_pImpl->aData.end())
|
|
{
|
|
SAL_WARN("sfx.dialog", "Tab Page ID '" << rPage << "' not known, this is pretty serious and needs investigation");
|
|
return;
|
|
}
|
|
|
|
SfxTabPage* pTabPage = (*it)->xTabPage.get();
|
|
if (!pTabPage)
|
|
return;
|
|
|
|
if ((*it)->bRefresh)
|
|
pTabPage->Reset(m_pSet.get());
|
|
(*it)->bRefresh = false;
|
|
|
|
if (m_xExampleSet)
|
|
pTabPage->ActivatePage(*m_xExampleSet);
|
|
|
|
if (pTabPage->IsReadOnly() || m_pImpl->bHideResetBtn)
|
|
m_xResetBtn->hide();
|
|
else
|
|
m_xResetBtn->show();
|
|
}
|
|
|
|
IMPL_LINK(SfxTabDialogController, DeactivatePageHdl, const OUString&, rPage, bool)
|
|
{
|
|
return DeactivatePage(rPage);
|
|
}
|
|
|
|
bool SfxTabDialogController::DeactivatePage(std::u16string_view aPage)
|
|
/* [Description]
|
|
|
|
Handler that is called by StarView before leaving a page.
|
|
|
|
[Cross-reference]
|
|
|
|
<SfxTabPage::DeactivatePage(SfxItemSet *)>
|
|
*/
|
|
|
|
{
|
|
assert(!m_pImpl->aData.empty() && "no Pages registered");
|
|
auto it = Find(m_pImpl->aData, aPage);
|
|
if (it == m_pImpl->aData.end())
|
|
{
|
|
SAL_WARN("sfx.dialog", "Tab Page ID not known, this is pretty serious and needs investigation");
|
|
return false;
|
|
}
|
|
|
|
SfxTabPage* pPage = (*it)->xTabPage.get();
|
|
if (!pPage)
|
|
return true;
|
|
|
|
DeactivateRC nRet = DeactivateRC::LeavePage;
|
|
|
|
if (!m_xExampleSet && pPage->HasExchangeSupport() && m_pSet)
|
|
m_xExampleSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
|
|
|
|
if (m_pSet)
|
|
{
|
|
SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
|
|
|
|
if (pPage->HasExchangeSupport())
|
|
nRet = pPage->DeactivatePage(&aTmp);
|
|
else
|
|
nRet = pPage->DeactivatePage(nullptr);
|
|
if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage &&
|
|
aTmp.Count() && m_xExampleSet)
|
|
{
|
|
m_xExampleSet->Put( aTmp );
|
|
m_pOutSet->Put( aTmp );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( pPage->HasExchangeSupport() ) //!!!
|
|
{
|
|
if (!m_xExampleSet)
|
|
{
|
|
SfxItemPool* pPool = pPage->GetItemSet().GetPool();
|
|
m_xExampleSet.reset(new SfxItemSet(*pPool, GetInputRanges(*pPool)));
|
|
}
|
|
nRet = pPage->DeactivatePage(m_xExampleSet.get());
|
|
}
|
|
else
|
|
nRet = pPage->DeactivatePage( nullptr );
|
|
}
|
|
|
|
if ( nRet & DeactivateRC::RefreshSet )
|
|
{
|
|
RefreshInputSet();
|
|
// Flag all Pages as to be initialized as new
|
|
|
|
for (auto const& elem : m_pImpl->aData)
|
|
{
|
|
elem->bRefresh = ( elem->xTabPage.get() != pPage ); // Do not refresh own Page anymore
|
|
}
|
|
}
|
|
return static_cast<bool>(nRet & DeactivateRC::LeavePage);
|
|
}
|
|
|
|
bool SfxTabDialogController::PrepareLeaveCurrentPage()
|
|
{
|
|
const OUString sId = m_xTabCtrl->get_current_page_ident();
|
|
auto it = Find(m_pImpl->aData, sId);
|
|
DBG_ASSERT(it != m_pImpl->aData.end(), "Id not known");
|
|
SfxTabPage* pPage = it != m_pImpl->aData.end() ? (*it)->xTabPage.get() : nullptr;
|
|
|
|
bool bEnd = !pPage;
|
|
|
|
if ( pPage )
|
|
{
|
|
DeactivateRC nRet = DeactivateRC::LeavePage;
|
|
if ( m_pSet )
|
|
{
|
|
SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
|
|
|
|
if ( pPage->HasExchangeSupport() )
|
|
nRet = pPage->DeactivatePage( &aTmp );
|
|
else
|
|
nRet = pPage->DeactivatePage( nullptr );
|
|
|
|
if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage
|
|
&& aTmp.Count() )
|
|
{
|
|
m_xExampleSet->Put( aTmp );
|
|
m_pOutSet->Put( aTmp );
|
|
}
|
|
}
|
|
else
|
|
nRet = pPage->DeactivatePage( nullptr );
|
|
bEnd = nRet != DeactivateRC::KeepPage;
|
|
}
|
|
|
|
return bEnd;
|
|
}
|
|
|
|
void SfxTabDialogController::PrepareCancel()
|
|
{
|
|
for (auto pDataObject : m_pImpl->aData)
|
|
{
|
|
if (!pDataObject->xTabPage)
|
|
continue;
|
|
|
|
SfxTabPage* pPage = pDataObject->xTabPage.get();
|
|
pPage->SetCancelMode(true);
|
|
pPage->DeactivatePage(nullptr);
|
|
}
|
|
}
|
|
|
|
const WhichRangesContainer & SfxTabDialogController::GetInputRanges(const SfxItemPool& rPool)
|
|
|
|
/* [Description]
|
|
|
|
Makes the set over the range of all pages of the dialogue. Pages have the
|
|
static method for querying their range in AddTabPage, ie deliver their
|
|
sets onDemand.
|
|
|
|
[Return value]
|
|
|
|
Pointer to a null-terminated array of sal_uInt16. This array belongs to the
|
|
dialog and is deleted when the dialogue is destroy.
|
|
|
|
[Cross-reference]
|
|
|
|
<SfxTabDialog::AddTabPage(sal_uInt16, CreateTabPage, GetTabPageRanges, bool)>
|
|
<SfxTabDialog::AddTabPage(sal_uInt16, const String &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
|
|
<SfxTabDialog::AddTabPage(sal_uInt16, const Bitmap &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
|
|
*/
|
|
|
|
{
|
|
if ( m_pSet )
|
|
{
|
|
SAL_WARN( "sfx.dialog", "Set already exists!" );
|
|
return m_pSet->GetRanges();
|
|
}
|
|
|
|
if ( !m_pRanges.empty() )
|
|
return m_pRanges;
|
|
SfxItemSet aUS(const_cast<SfxItemPool&>(rPool));
|
|
|
|
for (auto const& elem : m_pImpl->aData)
|
|
{
|
|
|
|
if ( elem->fnGetRanges )
|
|
{
|
|
const WhichRangesContainer aTmpRanges = (elem->fnGetRanges)();
|
|
|
|
for (const auto & rPair : aTmpRanges)
|
|
{
|
|
sal_uInt16 nWidFrom = rPool.GetWhichIDFromSlotID(rPair.first);
|
|
sal_uInt16 nWidTo = rPool.GetWhichIDFromSlotID(rPair.second);
|
|
aUS.MergeRange(nWidFrom, nWidTo); // Keep it valid
|
|
}
|
|
}
|
|
}
|
|
|
|
m_pRanges = aUS.GetRanges();
|
|
return m_pRanges;
|
|
}
|
|
|
|
SfxTabDialogController::~SfxTabDialogController()
|
|
{
|
|
SavePosAndId();
|
|
|
|
for (auto & elem : m_pImpl->aData)
|
|
{
|
|
if ( elem->xTabPage )
|
|
{
|
|
// save settings of all pages (user data)
|
|
elem->xTabPage->FillUserData();
|
|
OUString aPageData( elem->xTabPage->GetUserData() );
|
|
if ( !aPageData.isEmpty() )
|
|
{
|
|
// save settings of all pages (user data)
|
|
SvtViewOptions aPageOpt(EViewType::TabPage, elem->xTabPage->GetConfigId());
|
|
aPageOpt.SetUserItem( USERITEM_NAME, Any( aPageData ) );
|
|
}
|
|
|
|
elem->xTabPage.reset();
|
|
}
|
|
delete elem;
|
|
elem = nullptr;
|
|
}
|
|
}
|
|
|
|
short SfxTabDialogController::Ok()
|
|
|
|
/* [Description]
|
|
|
|
Ok handler for the Dialogue.
|
|
|
|
Dialog's current location and current page are saved for the next time
|
|
the dialog is shown.
|
|
|
|
The OutputSet is created and for each page this or the special OutputSet
|
|
is set by calling the method <SfxTabPage::FillItemSet(SfxItemSet &)>, to
|
|
insert the entered data by the user into the set.
|
|
|
|
[Return value]
|
|
|
|
RET_OK: if at least one page has returned from FillItemSet,
|
|
otherwise RET_CANCEL.
|
|
*/
|
|
{
|
|
SavePosAndId(); //See fdo#38828 "Apply" resetting window position
|
|
|
|
if ( !m_pOutSet )
|
|
{
|
|
if ( m_xExampleSet )
|
|
m_pOutSet.reset(new SfxItemSet( *m_xExampleSet ));
|
|
else if ( m_pSet )
|
|
m_pOutSet = m_pSet->Clone( false ); // without Items
|
|
}
|
|
bool bModified = false;
|
|
|
|
for (auto const& elem : m_pImpl->aData)
|
|
{
|
|
SfxTabPage* pTabPage = elem->xTabPage.get();
|
|
|
|
if ( pTabPage )
|
|
{
|
|
if ( m_pSet && !pTabPage->HasExchangeSupport() )
|
|
{
|
|
SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
|
|
|
|
if ( pTabPage->FillItemSet( &aTmp ) )
|
|
{
|
|
bModified = true;
|
|
if (m_xExampleSet)
|
|
m_xExampleSet->Put( aTmp );
|
|
m_pOutSet->Put( aTmp );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pOutSet && m_pOutSet->Count() > 0)
|
|
bModified = true;
|
|
|
|
if (m_bStandardPushed)
|
|
bModified = true;
|
|
|
|
return bModified ? RET_OK : RET_CANCEL;
|
|
}
|
|
|
|
void SfxTabDialogController::RefreshInputSet()
|
|
|
|
/* [Description]
|
|
|
|
Default implementation of the virtual Method.
|
|
This is called, when <SfxTabPage::DeactivatePage(SfxItemSet *)>
|
|
returns <DeactivateRC::RefreshSet>.
|
|
*/
|
|
|
|
{
|
|
SAL_INFO ( "sfx.dialog", "RefreshInputSet not implemented" );
|
|
}
|
|
|
|
void SfxTabDialogController::PageCreated
|
|
|
|
/* [Description]
|
|
|
|
Default implementation of the virtual method. This is called immediately
|
|
after creating a page. Here the dialogue can call the TabPage Method
|
|
directly.
|
|
*/
|
|
|
|
(
|
|
const OUString&, // Id of the created page
|
|
SfxTabPage& // Reference to the created page
|
|
)
|
|
{
|
|
}
|
|
|
|
void SfxTabDialogController::SavePosAndId()
|
|
{
|
|
// save settings (screen position and current page)
|
|
SvtViewOptions aDlgOpt(EViewType::TabDialog, m_xDialog->get_help_id());
|
|
aDlgOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
|
|
}
|
|
|
|
/*
|
|
Adds a page to the dialog. The Name must correspond to an entry in the
|
|
TabControl in the dialog .ui
|
|
*/
|
|
void SfxTabDialogController::AddTabPage(const OUString &rName /* Page ID */,
|
|
CreateTabPage pCreateFunc /* Pointer to the Factory Method */,
|
|
GetTabPageRanges pRangesFunc /* Pointer to the Method for querying Ranges onDemand */)
|
|
{
|
|
m_pImpl->aData.push_back(new Data_Impl(rName, pCreateFunc, pRangesFunc));
|
|
}
|
|
|
|
void SfxTabDialogController::AddTabPage(const OUString &rName /* Page ID */,
|
|
sal_uInt16 nPageCreateId /* Identifier of the Factory Method to create the page */)
|
|
{
|
|
SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
|
|
CreateTabPage pCreateFunc = pFact->GetTabPageCreatorFunc(nPageCreateId);
|
|
GetTabPageRanges pRangesFunc = pFact->GetTabPageRangesFunc(nPageCreateId);
|
|
AddTabPage(rName, pCreateFunc, pRangesFunc);
|
|
}
|
|
|
|
/* [Description]
|
|
|
|
Add a page to the dialog. The Rider text is passed on, the page has no
|
|
counterpart in the TabControl in the resource of the dialogue.
|
|
*/
|
|
|
|
void SfxTabDialogController::AddTabPage(const OUString &rName, /* Page ID */
|
|
const OUString& rRiderText,
|
|
CreateTabPage pCreateFunc /* Pointer to the Factory Method */)
|
|
{
|
|
assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
|
|
m_xTabCtrl->append_page(rName, rRiderText);
|
|
AddTabPage(rName, pCreateFunc, nullptr);
|
|
}
|
|
|
|
void SfxTabDialogController::AddTabPage(const OUString &rName, const OUString& rRiderText,
|
|
sal_uInt16 nPageCreateId /* Identifier of the Factory Method to create the page */)
|
|
{
|
|
assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
|
|
m_xTabCtrl->append_page(rName, rRiderText);
|
|
AddTabPage(rName, nPageCreateId);
|
|
}
|
|
|
|
/* [Description]
|
|
|
|
Default implementation of the virtual Method.
|
|
This is called when pages create their sets onDemand.
|
|
*/
|
|
SfxItemSet* SfxTabDialogController::CreateInputItemSet(const OUString&)
|
|
{
|
|
SAL_WARN( "sfx.dialog", "CreateInputItemSet not implemented" );
|
|
m_xItemSet = std::make_unique<SfxAllItemSet>(SfxGetpApp()->GetPool());
|
|
return m_xItemSet.get();
|
|
}
|
|
|
|
void SfxTabDialogController::CreatePages()
|
|
{
|
|
for (auto pDataObject : m_pImpl->aData)
|
|
{
|
|
if (pDataObject->xTabPage)
|
|
continue;
|
|
weld::Container* pPage = m_xTabCtrl->get_page(pDataObject->sId);
|
|
if (m_pSet)
|
|
pDataObject->xTabPage = (pDataObject->fnCreatePage)(pPage, this, m_pSet.get());
|
|
else
|
|
pDataObject->xTabPage = (pDataObject->fnCreatePage)(pPage, this, CreateInputItemSet(pDataObject->sId));
|
|
pDataObject->xTabPage->SetDialogController(this);
|
|
SvtViewOptions aPageOpt(EViewType::TabPage, pDataObject->xTabPage->GetConfigId());
|
|
OUString sUserData;
|
|
Any aUserItem = aPageOpt.GetUserItem(USERITEM_NAME);
|
|
OUString aTemp;
|
|
if ( aUserItem >>= aTemp )
|
|
sUserData = aTemp;
|
|
pDataObject->xTabPage->SetUserData(sUserData);
|
|
|
|
PageCreated(pDataObject->sId, *pDataObject->xTabPage);
|
|
if (pDataObject->xTabPage->DeferResetToFirstActivation())
|
|
pDataObject->bRefresh = true; // Reset will be called in ActivatePageHdl
|
|
else
|
|
pDataObject->xTabPage->Reset(m_pSet.get());
|
|
}
|
|
}
|
|
|
|
void SfxTabDialogController::setPreviewsToSamePlace()
|
|
{
|
|
//where tab pages have the same basic layout with a preview on the right,
|
|
//get both of their non-preview areas to request the same size so that the
|
|
//preview appears in the same place in each one so flipping between tabs
|
|
//isn't distracting as it jumps around
|
|
std::vector<std::unique_ptr<weld::Widget>> aGrids;
|
|
for (auto pDataObject : m_pImpl->aData)
|
|
{
|
|
if (!pDataObject->xTabPage)
|
|
continue;
|
|
if (!pDataObject->xTabPage->m_xBuilder)
|
|
continue;
|
|
std::unique_ptr<weld::Widget> pGrid = pDataObject->xTabPage->m_xBuilder->weld_widget(u"maingrid"_ustr);
|
|
if (!pGrid)
|
|
continue;
|
|
aGrids.emplace_back(std::move(pGrid));
|
|
}
|
|
|
|
m_xSizeGroup.reset();
|
|
|
|
if (aGrids.size() <= 1)
|
|
return;
|
|
|
|
m_xSizeGroup = m_xBuilder->create_size_group();
|
|
m_xSizeGroup->set_mode(VclSizeGroupMode::Both);
|
|
for (auto& rGrid : aGrids)
|
|
m_xSizeGroup->add_widget(rGrid.get());
|
|
}
|
|
|
|
void SfxTabDialogController::RemoveTabPage(const OUString& rId)
|
|
|
|
/* [Description]
|
|
|
|
Delete the TabPage with ID nId
|
|
*/
|
|
|
|
{
|
|
m_xTabCtrl->remove_page(rId);
|
|
auto it = Find(m_pImpl->aData, rId);
|
|
|
|
if (it != m_pImpl->aData.end())
|
|
{
|
|
if ((*it)->xTabPage)
|
|
{
|
|
(*it)->xTabPage->FillUserData();
|
|
OUString aPageData((*it)->xTabPage->GetUserData());
|
|
if ( !aPageData.isEmpty() )
|
|
{
|
|
// save settings of this page (user data)
|
|
SvtViewOptions aPageOpt(EViewType::TabPage, (*it)->xTabPage->GetConfigId());
|
|
aPageOpt.SetUserItem( USERITEM_NAME, Any( aPageData ) );
|
|
}
|
|
|
|
(*it)->xTabPage.reset();
|
|
}
|
|
|
|
delete *it;
|
|
m_pImpl->aData.erase(it);
|
|
}
|
|
else
|
|
{
|
|
SAL_INFO( "sfx.dialog", "TabPage-Id not known" );
|
|
}
|
|
}
|
|
|
|
void SfxTabDialogController::Start_Impl()
|
|
{
|
|
CreatePages();
|
|
|
|
setPreviewsToSamePlace();
|
|
|
|
assert(m_pImpl->aData.size() == static_cast<size_t>(m_xTabCtrl->get_n_pages())
|
|
&& "not all pages registered");
|
|
|
|
// load old settings, when exists, setting SetCurPageId will override the settings,
|
|
// something that the sort dialog in calc depends on
|
|
if (m_sAppPageId.isEmpty())
|
|
{
|
|
SvtViewOptions aDlgOpt(EViewType::TabDialog, m_xDialog->get_help_id());
|
|
if (aDlgOpt.Exists())
|
|
m_xTabCtrl->set_current_page(aDlgOpt.GetPageID());
|
|
}
|
|
|
|
ActivatePage(m_xTabCtrl->get_current_page_ident());
|
|
|
|
m_pImpl->bStarted = true;
|
|
}
|
|
|
|
void SfxTabDialogController::SetCurPageId(const OUString& rIdent)
|
|
{
|
|
m_sAppPageId = rIdent;
|
|
m_xTabCtrl->set_current_page(m_sAppPageId);
|
|
}
|
|
|
|
/* [Description]
|
|
|
|
The TabPage is activated with the specified Id.
|
|
*/
|
|
void SfxTabDialogController::ShowPage(const OUString& rIdent)
|
|
{
|
|
SetCurPageId(rIdent);
|
|
ActivatePage(rIdent);
|
|
}
|
|
|
|
OUString SfxTabDialogController::GetCurPageId() const
|
|
{
|
|
return m_xTabCtrl->get_current_page_ident();
|
|
}
|
|
|
|
short SfxTabDialogController::run()
|
|
{
|
|
Start_Impl();
|
|
return SfxDialogController::run();
|
|
}
|
|
|
|
bool SfxTabDialogController::runAsync(const std::shared_ptr<SfxTabDialogController>& rController,
|
|
const std::function<void(sal_Int32)>& rFunc)
|
|
{
|
|
rController->Start_Impl();
|
|
return weld::DialogController::runAsync(rController, rFunc);
|
|
}
|
|
|
|
void SfxTabDialogController::SetInputSet( const SfxItemSet* pInSet )
|
|
|
|
/* [Description]
|
|
|
|
With this method the Input-Set can subsequently be set initially or re-set.
|
|
*/
|
|
|
|
{
|
|
bool bSet = ( m_pSet != nullptr );
|
|
m_pSet.reset(pInSet ? new SfxItemSet(*pInSet) : nullptr);
|
|
|
|
if (!bSet && !m_xExampleSet && !m_pOutSet && m_pSet)
|
|
{
|
|
m_xExampleSet.reset(new SfxItemSet(*m_pSet));
|
|
m_pOutSet.reset(new SfxItemSet( *m_pSet->GetPool(), m_pSet->GetRanges() ));
|
|
}
|
|
}
|
|
|
|
SfxItemSet* SfxTabDialogController::GetInputSetImpl()
|
|
|
|
/* [Description]
|
|
|
|
Derived classes may create new storage for the InputSet. This has to be
|
|
released in the Destructor. To do this, this method must be called.
|
|
*/
|
|
|
|
{
|
|
return m_pSet.get();
|
|
}
|
|
|
|
void SfxTabDialogController::RemoveResetButton()
|
|
{
|
|
m_xResetBtn->hide();
|
|
m_pImpl->bHideResetBtn = true;
|
|
}
|
|
|
|
void SfxTabDialogController::RemoveStandardButton()
|
|
{
|
|
m_xBaseFmtBtn->hide();
|
|
}
|
|
|
|
SfxTabPage* SfxTabDialogController::GetTabPage(std::u16string_view rPageId) const
|
|
|
|
/* [Description]
|
|
|
|
Return TabPage with the specified Id.
|
|
*/
|
|
|
|
{
|
|
auto it = Find(m_pImpl->aData, rPageId);
|
|
if (it != m_pImpl->aData.end())
|
|
return (*it)->xTabPage.get();
|
|
return nullptr;
|
|
}
|
|
|
|
void SfxTabDialogController::SetApplyHandler(const Link<weld::Button&, void>& _rHdl)
|
|
{
|
|
DBG_ASSERT( m_xApplyBtn, "SfxTabDialog::GetApplyHandler: no apply button enabled!" );
|
|
if (m_xApplyBtn)
|
|
m_xApplyBtn->connect_clicked(_rHdl);
|
|
}
|
|
|
|
bool SfxTabDialogController::Apply()
|
|
{
|
|
bool bApplied = false;
|
|
if (PrepareLeaveCurrentPage())
|
|
{
|
|
bApplied = (Ok() == RET_OK);
|
|
//let the pages update their saved values
|
|
GetInputSetImpl()->Put(*GetOutputItemSet());
|
|
for (auto pDataObject : m_pImpl->aData)
|
|
{
|
|
if (!pDataObject->xTabPage)
|
|
continue;
|
|
pDataObject->xTabPage->ChangesApplied();
|
|
}
|
|
}
|
|
return bApplied;
|
|
}
|
|
|
|
std::vector<OUString> SfxTabDialogController::getAllPageUIXMLDescriptions() const
|
|
{
|
|
int nPages = m_xTabCtrl->get_n_pages();
|
|
std::vector<OUString> aRet;
|
|
aRet.reserve(nPages);
|
|
for (int i = 0; i < nPages; ++i)
|
|
aRet.push_back(m_xTabCtrl->get_page_ident(i));
|
|
return aRet;
|
|
}
|
|
|
|
bool SfxTabDialogController::selectPageByUIXMLDescription(const OUString& rUIXMLDescription)
|
|
{
|
|
ShowPage(rUIXMLDescription);
|
|
return m_xTabCtrl->get_current_page_ident() == rUIXMLDescription;
|
|
}
|
|
|
|
BitmapEx SfxTabDialogController::createScreenshot() const
|
|
{
|
|
// if we haven't run Start_Impl yet, do so now to create the initial pages
|
|
if (!m_pImpl->bStarted)
|
|
{
|
|
const_cast<SfxTabDialogController*>(this)->Start_Impl();
|
|
}
|
|
|
|
VclPtr<VirtualDevice> xDialogSurface(m_xDialog->screenshot());
|
|
return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
|
|
}
|
|
|
|
OUString SfxTabDialogController::GetScreenshotId() const
|
|
{
|
|
const OUString sId = m_xTabCtrl->get_current_page_ident();
|
|
auto it = Find(m_pImpl->aData, sId);
|
|
SfxTabPage* pPage = it != m_pImpl->aData.end() ? (*it)->xTabPage.get() : nullptr;
|
|
if (pPage)
|
|
{
|
|
OUString sHelpId(pPage->GetHelpId());
|
|
if (!sHelpId.isEmpty())
|
|
return sHelpId;
|
|
}
|
|
return m_xDialog->get_help_id();
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|