/* -*- 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 <memory>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/menu.hxx>
#include <vcl/settings.hxx>
#include <svl/intitem.hxx>
#include <svl/stritem.hxx>
#include <svl/style.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <unotools/intlwrapper.hxx>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/frame/ModuleManager.hpp>
#include <com/sun/star/frame/UnknownModuleException.hpp>
#include <officecfg/Office/Common.hxx>
#include <sal/log.hxx>
#include <sfx2/sfxhelp.hxx>
#include <sfx2/app.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/bindings.hxx>
#include <sfx2/templdlg.hxx>
#include <templdgi.hxx>
#include <tplcitem.hxx>
#include <sfxtypes.hxx>
#include <sfx2/styfitem.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/newstyle.hxx>
#include <sfx2/tplpitem.hxx>
#include <sfx2/sfxresid.hxx>
#include <sfx2/strings.hrc>
#include <arrdecl.hxx>
#include <sfx2/docfilt.hxx>
#include <sfx2/docfac.hxx>
#include <sfx2/doctempl.hxx>
#include <sfx2/module.hxx>
#include <helpids.h>
#include <bitmaps.hlst>
#include <appdata.hxx>
#include <sfx2/viewfrm.hxx>
#include <svtools/svlbitm.hxx>
#include <svtools/treelistentry.hxx>
#include <comphelper/string.hxx>
#include <sfx2/StyleManager.hxx>
#include <sfx2/StylePreviewRenderer.hxx>
#include <o3tl/make_unique.hxx>
#define STD_ENTRY_HEIGHT 17
using namespace css;
using namespace css::beans;
using namespace css::frame;
using namespace css::uno;
namespace
{
class StyleLBoxString : public SvLBoxString
{
SfxStyleFamily meStyleFamily;
SvViewDataItem* mpViewData;
public:
StyleLBoxString(const OUString& sText,
const SfxStyleFamily& eStyleFamily);
virtual void Paint(const Point& aPos,
SvTreeListBox& rDevice,
vcl::RenderContext& rRenderContext,
const SvViewDataEntry* pView,
const SvTreeListEntry& rEntry) override;
virtual void InitViewData(SvTreeListBox* pView,
SvTreeListEntry* pEntry,
SvViewDataItem* pViewData = nullptr) override;
};
StyleLBoxString::StyleLBoxString(const OUString& sText, const SfxStyleFamily& eStyleFamily)
: SvLBoxString(sText)
, meStyleFamily(eStyleFamily)
, mpViewData(nullptr)
{}
void StyleLBoxString::InitViewData(SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData)
{
if (!pViewData)
{
pViewData = pView->GetViewDataItem(pEntry, this);
}
mpViewData = pViewData;
}
void StyleLBoxString::Paint(
const Point& aPos, SvTreeListBox& rDevice, vcl::RenderContext& rRenderContext,
const SvViewDataEntry* pView, const SvTreeListEntry& rEntry)
{
bool bPainted = false;
SfxObjectShell* pShell = SfxObjectShell::Current();
sfx2::StyleManager* pStyleManager = pShell? pShell->GetStyleManager(): nullptr;
if (pStyleManager)
{
SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(GetText(), meStyleFamily);
if (pStyleSheet)
{
sal_Int32 nSize = 32 * rRenderContext.GetDPIScaleFactor();
std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
if (pStylePreviewRenderer)
{
if (pStylePreviewRenderer->recalculate())
{
mpViewData->maSize = pStylePreviewRenderer->getRenderSize();
}
else
{
SvLBoxString::InitViewData( &rDevice, const_cast<SvTreeListEntry*>(&rEntry), mpViewData);
}
tools::Rectangle aPaintRectangle = pView->GetPaintRectangle();
bPainted = pStylePreviewRenderer->render(aPaintRectangle);
}
}
}
if (!bPainted)
{
rRenderContext.DrawText(aPos, GetText());
}
}
} // end anonymous namespace
// Window is now created dynamically. So here margins, etc.
#define SFX_TEMPLDLG_HFRAME 3
#define SFX_TEMPLDLG_VTOPFRAME 3
#define SFX_TEMPLDLG_VBOTFRAME 3
#define SFX_TEMPLDLG_MIDHSPACE 3
#define SFX_TEMPLDLG_MIDVSPACE 3
#define SFX_TEMPLDLG_FILTERHEIGHT 100
// filter box has maximum 14 entries visible
#define MAX_FILTER_ENTRIES 14
class SfxCommonTemplateDialog_Impl::DeletionWatcher
{
typedef void (DeletionWatcher::* bool_type)();
public:
explicit DeletionWatcher(SfxCommonTemplateDialog_Impl& rDialog)
: m_pDialog(&rDialog)
, m_pPrevious(m_pDialog->impl_setDeletionWatcher(this))
{
}
~DeletionWatcher()
{
if (m_pDialog)
m_pDialog->impl_setDeletionWatcher(m_pPrevious);
}
DeletionWatcher(const DeletionWatcher&) = delete;
DeletionWatcher& operator=(const DeletionWatcher&) = delete;
// Signal that the dialog was deleted
void signal()
{
m_pDialog = nullptr;
if (m_pPrevious)
m_pPrevious->signal();
}
// Return true if the dialog was deleted
operator bool_type() const
{
return m_pDialog ? nullptr : &DeletionWatcher::signal;
}
private:
SfxCommonTemplateDialog_Impl* m_pDialog;
DeletionWatcher *const m_pPrevious; /// let's add more epicycles!
};
void DropListBox_Impl::MouseButtonDown( const MouseEvent& rMEvt )
{
nModifier = rMEvt.GetModifier();
bool bHitEmptySpace = ( nullptr == GetEntry( rMEvt.GetPosPixel(), true ) );
if( bHitEmptySpace && ( rMEvt.GetClicks() == 2 ) && rMEvt.IsMod1() )
Control::MouseButtonDown( rMEvt );
else
SvTreeListBox::MouseButtonDown( rMEvt );
}
/** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
create a style out of the current selection.
*/
sal_Int8 DropListBox_Impl::AcceptDrop( const AcceptDropEvent& rEvt )
{
if ( IsDropFormatSupported( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
{
// special case: page styles are allowed to create new styles by example
// but not allowed to be created by drag and drop
if (pDialog->GetActualFamily() == SfxStyleFamily::Page ||
pDialog->bNewByExampleDisabled)
return DND_ACTION_NONE;
else
return DND_ACTION_COPY;
}
return SvTreeListBox::AcceptDrop( rEvt );
}
sal_Int8 DropListBox_Impl::ExecuteDrop( const ExecuteDropEvent& rEvt )
{
sal_Int8 nRet = DND_ACTION_NONE;
SfxObjectShell* pDocShell = pDialog->GetObjectShell();
TransferableDataHelper aHelper( rEvt.maDropEvent.Transferable );
sal_uInt32 nFormatCount = aHelper.GetFormatCount();
if ( pDocShell )
{
bool bFormatFound = false;
for ( sal_uInt32 i = 0; i < nFormatCount; ++i )
{
SotClipboardFormatId nId = aHelper.GetFormat(i);
TransferableObjectDescriptor aDesc;
if ( aHelper.GetTransferableObjectDescriptor( nId, aDesc ) )
{
if ( aDesc.maClassName == pDocShell->GetFactory().GetClassId() )
{
PostUserEvent( LINK( this, DropListBox_Impl, OnAsyncExecuteDrop ), nullptr, true );
bFormatFound = true;
nRet = rEvt.mnAction;
break;
}
}
}
if ( !bFormatFound )
return SvTreeListBox::ExecuteDrop( rEvt );
}
return nRet;
}
IMPL_LINK_NOARG(DropListBox_Impl, OnAsyncExecuteDrop, void*, void)
{
pDialog->ActionSelect( SID_STYLE_NEW_BY_EXAMPLE );
}
bool DropListBox_Impl::EventNotify( NotifyEvent& rNEvt )
{
bool bRet = false;
if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
{
const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
if(!rKeyCode.GetModifier())
{
if( pDialog->bCanDel && KEY_DELETE == rKeyCode.GetCode())
{
pDialog->DeleteHdl();
bRet = true;
}
else if( KEY_RETURN == rKeyCode.GetCode())
{
GetDoubleClickHdl().Call(this);
bRet = true;
}
}
}
if(!bRet)
bRet = SvTreeListBox::EventNotify( rNEvt );
return bRet;
}
/** ListBox class that starts a PopupMenu (designer specific) in the
command handler.
*/
SfxActionListBox::SfxActionListBox(SfxCommonTemplateDialog_Impl* pParent, WinBits nWinBits)
: DropListBox_Impl(pParent->GetWindow(), nWinBits, pParent)
{
EnableContextMenuHandling();
}
void SfxActionListBox::Recalc()
{
if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
SetEntryHeight(32 * GetDPIScaleFactor());
else
SetEntryHeight(STD_ENTRY_HEIGHT, true);
RecalcViewData();
}
VclPtr<PopupMenu> SfxActionListBox::CreateContextMenu()
{
if( GetSelectionCount() <= 0 )
{
pDialog->EnableEdit( false );
pDialog->EnableDel( false );
}
return pDialog->CreateContextMenu();
}
SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, vcl::Window* pParentWindow)
: Window(pParentWindow, WB_DIALOGCONTROL)
, pImpl(new SfxTemplateDialog_Impl(pBindings, this))
, mpBindings(pBindings)
{
OSL_ASSERT(mpBindings!=nullptr);
SetStyle(GetStyle() & ~WB_DOCKABLE);
}
SfxTemplatePanelControl::~SfxTemplatePanelControl()
{
disposeOnce();
}
void SfxTemplatePanelControl::dispose()
{
pImpl.reset();
Window::dispose();
}
void SfxTemplatePanelControl::Resize()
{
if(pImpl)
pImpl->Resize();
Window::Resize();
}
void SfxTemplatePanelControl::StateChanged( StateChangedType nStateChange )
{
if (nStateChange == StateChangedType::InitShow)
{
SfxViewFrame* pFrame = mpBindings->GetDispatcher_Impl()->GetFrame();
vcl::Window* pEditWin = pFrame->GetViewShell()->GetWindow();
Size aSize = pEditWin->GetSizePixel();
Point aPoint = pEditWin->OutputToScreenPixel( pEditWin->GetPosPixel() );
aPoint = GetParent()->ScreenToOutputPixel( aPoint );
Size aWinSize = GetSizePixel();
aPoint.AdjustX(aSize.Width() - aWinSize.Width() - 20 );
aPoint.AdjustY(aSize.Height() / 2 - aWinSize.Height() / 2 );
// SetFloatingPos( aPoint );
}
Window::StateChanged( nStateChange );
}
void StyleTreeListBox_Impl::MakeExpanded_Impl(std::vector<OUString>& rEntries) const
{
SvTreeListEntry* pEntry;
for (pEntry = FirstVisible(); pEntry; pEntry = NextVisible(pEntry))
{
if (IsExpanded(pEntry))
{
rEntries.push_back(GetEntryText(pEntry));
}
}
}
VclPtr<PopupMenu> StyleTreeListBox_Impl::CreateContextMenu()
{
return pDialog->CreateContextMenu();
}
/** DoubleClick-Handler; calls the link.
SV virtual method.
*/
bool StyleTreeListBox_Impl::DoubleClickHdl()
{
aDoubleClickLink.Call(nullptr);
return false;
}
bool StyleTreeListBox_Impl::EventNotify( NotifyEvent& rNEvt )
{
// handle <RETURN> as double click
bool bRet = false;
if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
{
const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode();
if ( !rKeyCode.GetModifier() && KEY_RETURN == rKeyCode.GetCode() )
{
aDoubleClickLink.Call( nullptr );
bRet = true;
}
}
if ( !bRet )
bRet = DropListBox_Impl::EventNotify( rNEvt );
return bRet;
}
/** NotifyMoving Handler; This leads via a link on the event to the dialog.
SV virtual method.
*/
TriState StyleTreeListBox_Impl::NotifyMoving(SvTreeListEntry* pTarget,
SvTreeListEntry* pEntry,
SvTreeListEntry*& rpNewParent,
sal_uIntPtr& lPos)
{
if(!pTarget || !pEntry)
return TRISTATE_FALSE;
aParent = GetEntryText(pTarget);
aStyle = GetEntryText(pEntry);
const bool bRet = aDropLink.Call(*this);
rpNewParent = pTarget;
lPos=0;
IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag());
const CollatorWrapper* pCollator = aIntlWrapper.getCaseCollator();
for(SvTreeListEntry *pTmpEntry=FirstChild(pTarget);
pTmpEntry && pCollator->compareString(
GetEntryText(pTmpEntry),GetEntryText(pEntry)) < 0;
pTmpEntry=pTmpEntry->NextSibling(),lPos++) ;
return bRet ? TRISTATE_INDET : TRISTATE_FALSE;
}
/** ExpandingHdl Handler; the current entry is noticed.
SV virtual method.
[Cross-reference]
<StyleTreeListBox_Impl::ExpandedHdl()>
*/
bool StyleTreeListBox_Impl::ExpandingHdl()
{
pCurEntry = GetCurEntry();
return true;
}
/** ExpandedHdl Handler;
SV virtual method.
[Cross-reference]
<StyleTreeListBox_Impl::ExpandingHdl()>
*/
void StyleTreeListBox_Impl::ExpandedHdl()
{
SvTreeListEntry *pEntry = GetHdlEntry();
if(!IsExpanded(pEntry) && pCurEntry != GetCurEntry())
SelectAll( false );
pCurEntry = nullptr;
}
/** Constructor StyleTreeListBox_Impl */
StyleTreeListBox_Impl::StyleTreeListBox_Impl(SfxCommonTemplateDialog_Impl* pParent, WinBits nWinStyle)
: DropListBox_Impl(pParent->GetWindow(), nWinStyle, pParent)
, pCurEntry(nullptr)
{
EnableContextMenuHandling();
}
void StyleTreeListBox_Impl::Recalc()
{
if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
SetEntryHeight(32 * GetDPIScaleFactor());
else
SetEntryHeight(STD_ENTRY_HEIGHT, true);
RecalcViewData();
}
/** Internal structure for the establishment of the hierarchical view */
class StyleTree_Impl;
typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;
class StyleTree_Impl
{
private:
OUString aName;
OUString aParent;
StyleTreeArr_Impl pChildren;
public:
bool HasParent() const { return !aParent.isEmpty(); }
StyleTree_Impl(const OUString &rName, const OUString &rParent):
aName(rName), aParent(rParent), pChildren(0) {}
const OUString& getName() { return aName; }
const OUString& getParent() { return aParent; }
StyleTreeArr_Impl& getChildren() { return pChildren; }
};
void MakeTree_Impl(StyleTreeArr_Impl& rArr)
{
const comphelper::string::NaturalStringSorter aSorter(
::comphelper::getProcessComponentContext(),
Application::GetSettings().GetLanguageTag().getLocale());
std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
styleFinder.reserve(rArr.size());
for (const auto& pEntry : rArr)
{
styleFinder.emplace(pEntry->getName(), pEntry.get());
}
// Arrange all under their Parents
for (auto& pEntry : rArr)
{
if (!pEntry->HasParent())
continue;
auto it = styleFinder.find(pEntry->getParent());
if (it != styleFinder.end())
{
StyleTree_Impl* pCmp = it->second;
// Insert child entries sorted
auto iPos = std::lower_bound(pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
[&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) { return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0; });
pCmp->getChildren().insert(iPos, std::move(pEntry));
}
}
// Only keep tree roots in rArr, child elements can be accessed through the hierarchy
rArr.erase(std::remove_if(rArr.begin(), rArr.end(), [](std::unique_ptr<StyleTree_Impl> const & pEntry) { return !pEntry; }), rArr.end());
// tdf#91106 sort top level styles
std::sort(rArr.begin(), rArr.end(),
[&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) {
if (pEntry2->getName() == "Default Style")
return false;
if (pEntry1->getName() == "Default Style")
return true; // default always first
return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
});
}
inline bool IsExpanded_Impl( const std::vector<OUString>& rEntries,
const OUString &rStr)
{
for (const auto & rEntry : rEntries)
{
if (rEntry == rStr)
return true;
}
return false;
}
SvTreeListEntry* FillBox_Impl(SvTreeListBox* pBox,
StyleTree_Impl* pEntry,
const std::vector<OUString>& rEntries,
SfxStyleFamily eStyleFamily,
SvTreeListEntry* pParent)
{
SvTreeListEntry* pTreeListEntry = pBox->InsertEntry(pEntry->getName(), pParent);
if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
{
pTreeListEntry->ReplaceItem(o3tl::make_unique<StyleLBoxString>(pEntry->getName(), eStyleFamily), 1);
}
pBox->GetModel()->InvalidateEntry(pTreeListEntry);
for(size_t i = 0; i < pEntry->getChildren().size(); ++i)
{
FillBox_Impl(pBox, pEntry->getChildren()[i].get(), rEntries, eStyleFamily, pTreeListEntry);
}
return pTreeListEntry;
}
namespace SfxTemplate
{
// converts from SFX_STYLE_FAMILY Ids to 1-6
sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
{
switch ( nFamily )
{
case SfxStyleFamily::Char: return 1;
case SfxStyleFamily::Para: return 2;
case SfxStyleFamily::Frame: return 3;
case SfxStyleFamily::Page: return 4;
case SfxStyleFamily::Pseudo: return 5;
case SfxStyleFamily::Table: return 6;
default: return 0xffff;
}
}
// converts from 1-6 to SFX_STYLE_FAMILY Ids
SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
{
switch (nId)
{
case 1: return SfxStyleFamily::Char;
case 2: return SfxStyleFamily::Para;
case 3: return SfxStyleFamily::Frame;
case 4: return SfxStyleFamily::Page;
case 5: return SfxStyleFamily::Pseudo;
case 6: return SfxStyleFamily::Table;
default: return SfxStyleFamily::All;
}
}
}
// Constructor
SfxCommonTemplateDialog_Impl::SfxCommonTemplateDialog_Impl( SfxBindings* pB, vcl::Window* pW )
: pBindings(pB)
, pWindow(pW)
, pModule(nullptr)
, pStyleSheetPool(nullptr)
, pCurObjShell(nullptr)
, xModuleManager(frame::ModuleManager::create(::comphelper::getProcessComponentContext()))
, m_pDeletionWatcher(nullptr)
, aFmtLb( VclPtr<SfxActionListBox>::Create(this, WB_BORDER | WB_TABSTOP | WB_SORT) )
, pTreeBox( VclPtr<StyleTreeListBox_Impl>::Create(this, WB_HASBUTTONS | WB_HASLINES |
WB_BORDER | WB_TABSTOP | WB_HASLINESATROOT |
WB_HASBUTTONSATROOT | WB_HIDESELECTION) )
, aPreviewCheckbox( VclPtr<CheckBox>::Create( pW, WB_VCENTER ))
, aFilterLb( VclPtr<ListBox>::Create(pW, WB_BORDER | WB_DROPDOWN | WB_TABSTOP) )
, nActFamily(0xffff)
, nActFilter(0)
, nAppFilter(SfxStyleSearchBits::Auto)
, bDontUpdate(false)
, bIsWater(false)
, bUpdate(false)
, bUpdateFamily(false)
, bCanEdit(false)
, bCanDel(false)
, bCanNew(true)
, bCanHide(true)
, bCanShow(false)
, bWaterDisabled(false)
, bNewByExampleDisabled(false)
, bUpdateByExampleDisabled(false)
, bTreeDrag(true)
, bHierarchical(false)
, m_bWantHierarchical(false)
, bBindingUpdate(true)
{
aFmtLb->SetQuickSearch(true);
aFmtLb->SetAccessibleName(SfxResId(STR_STYLE_ELEMTLIST));
aFmtLb->SetHelpId( HID_TEMPLATE_FMT );
aFilterLb->SetHelpId( HID_TEMPLATE_FILTER );
aFmtLb->SetStyle( aFmtLb->GetStyle() | WB_SORT | WB_HIDESELECTION );
vcl::Font aFont = aFmtLb->GetFont();
aFont.SetWeight( WEIGHT_NORMAL );
aFmtLb->SetFont( aFont );
pTreeBox->SetQuickSearch(true);
pTreeBox->SetNodeDefaultImages();
pTreeBox->SetOptimalImageIndent();
pTreeBox->SetAccessibleName(SfxResId(STR_STYLE_ELEMTLIST));
aPreviewCheckbox->Check(officecfg::Office::Common::StylesAndFormatting::Preview::get());
aPreviewCheckbox->SetText( SfxResId(STR_PREVIEW_CHECKBOX) );
}
sal_uInt16 SfxCommonTemplateDialog_Impl::StyleNrToInfoOffset(sal_uInt16 nId)
{
const SfxStyleFamilyItem& rItem = pStyleFamilies->at( nId );
return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily())-1;
}
void SfxTemplateDialog_Impl::EnableEdit(bool bEnable)
{
SfxCommonTemplateDialog_Impl::EnableEdit( bEnable );
if( !bEnable || !bUpdateByExampleDisabled )
EnableItem( SID_STYLE_UPDATE_BY_EXAMPLE, bEnable);
}
void SfxCommonTemplateDialog_Impl::ReadResource()
{
// Read global user resource
for (auto & i : pFamilyState)
i.reset();
SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
pCurObjShell = pViewFrame->GetObjectShell();
pModule = pCurObjShell ? pCurObjShell->GetModule() : nullptr;
if (pModule)
pStyleFamilies = pModule->CreateStyleFamilies();
if (!pStyleFamilies)
pStyleFamilies.reset(new SfxStyleFamilies);
nActFilter = 0xffff;
if (pCurObjShell)
{
nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pCurObjShell ) );
if ( 0xffff == nActFilter )
nActFilter = pCurObjShell->GetAutoStyleFilterIndex();
}
// Paste in the toolbox
// reverse order, since always inserted at the head
size_t nCount = pStyleFamilies->size();
pBindings->ENTERREGISTRATIONS();
size_t i;
for (i = 0; i < nCount; ++i)
{
sal_uInt16 nSlot = 0;
switch (pStyleFamilies->at(i).GetFamily())
{
case SfxStyleFamily::Char:
nSlot = SID_STYLE_FAMILY1; break;
case SfxStyleFamily::Para:
nSlot = SID_STYLE_FAMILY2; break;
case SfxStyleFamily::Frame:
nSlot = SID_STYLE_FAMILY3; break;
case SfxStyleFamily::Page:
nSlot = SID_STYLE_FAMILY4; break;
case SfxStyleFamily::Pseudo:
nSlot = SID_STYLE_FAMILY5; break;
case SfxStyleFamily::Table:
nSlot = SID_STYLE_FAMILY6; break;
default: OSL_FAIL("unknown StyleFamily"); break;
}
pBoundItems[i].reset(
new SfxTemplateControllerItem(nSlot, *this, *pBindings) );
}
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_WATERCAN, *this, *pBindings) );
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_NEW_BY_EXAMPLE, *this, *pBindings) );
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_UPDATE_BY_EXAMPLE, *this, *pBindings) );
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_NEW, *this, *pBindings) );
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_DRAGHIERARCHIE, *this, *pBindings) );
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_EDIT, *this, *pBindings) );
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_DELETE, *this, *pBindings) );
pBoundItems[i++].reset( new SfxTemplateControllerItem(
SID_STYLE_FAMILY, *this, *pBindings) );
pBindings->LEAVEREGISTRATIONS();
for(; i < COUNT_BOUND_FUNC; ++i)
pBoundItems[i] = nullptr;
StartListening(*pBindings);
// Insert in the reverse order of occurrence in the Style Families. This is for
// the toolbar of the designer. The list box of the catalog respects the
// correct order by itself.
// Sequences: the order of Resource = the order of Toolbar for example list box.
// Order of ascending SIDs: Low SIDs are displayed first when templates of
// several families are active.
// in the Writer the UpdateStyleByExample Toolbox button is removed and
// the NewStyle button gets a PopupMenu
if(nCount > 4)
ReplaceUpdateButtonByMenu();
for( ; nCount--; )
{
const SfxStyleFamilyItem &rItem = pStyleFamilies->at( nCount );
sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId( rItem.GetFamily() );
InsertFamilyItem(nId, rItem);
}
LoadedFamilies();
for ( i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++ )
pBindings->Update(i);
}
void SfxCommonTemplateDialog_Impl::ClearResource()
{
ClearFamilyList();
impl_clear();
}
void SfxCommonTemplateDialog_Impl::impl_clear()
{
pStyleFamilies.reset();
for (auto & i : pFamilyState)
i.reset();
for (auto & i : pBoundItems)
i.reset();
pCurObjShell = nullptr;
}
SfxCommonTemplateDialog_Impl::DeletionWatcher *
SfxCommonTemplateDialog_Impl::impl_setDeletionWatcher(
DeletionWatcher *const pNewWatcher)
{
DeletionWatcher *const pRet(m_pDeletionWatcher);
m_pDeletionWatcher = pNewWatcher;
return pRet;
}
void SfxCommonTemplateDialog_Impl::Initialize()
{
// Read global user resource
ReadResource();
pBindings->Invalidate( SID_STYLE_FAMILY );
pBindings->Update( SID_STYLE_FAMILY );
Update_Impl();
aFilterLb->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FilterSelectHdl ) );
aFmtLb->SetDoubleClickHdl( LINK( this, SfxCommonTemplateDialog_Impl, TreeListApplyHdl ) );
aFmtLb->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FmtSelectHdl ) );
aFmtLb->SetSelectionMode(SelectionMode::Multiple);
pTreeBox->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FmtSelectHdl ) );
pTreeBox->SetDoubleClickHdl( LINK( this, SfxCommonTemplateDialog_Impl, ApplyHdl ) );
pTreeBox->SetDropHdl( LINK( this, SfxCommonTemplateDialog_Impl, DropHdl ) );
aPreviewCheckbox->SetClickHdl( LINK(this, SfxCommonTemplateDialog_Impl, PreviewHdl));
aFilterLb->Show();
if (!bHierarchical)
aFmtLb->Show();
aPreviewCheckbox->Show();
}
SfxCommonTemplateDialog_Impl::~SfxCommonTemplateDialog_Impl()
{
#if defined STYLESPREVIEW
Execute_Impl(SID_STYLE_END_PREVIEW,
OUString(), OUString(),
0, 0, 0, 0 );
#endif
if ( bIsWater )
Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
GetWindow()->Hide();
impl_clear();
if ( pStyleSheetPool )
EndListening(*pStyleSheetPool);
pStyleSheetPool = nullptr;
pTreeBox.disposeAndClear();
pIdle.reset();
if ( m_pDeletionWatcher )
m_pDeletionWatcher->signal();
aFmtLb.disposeAndClear();
aPreviewCheckbox.disposeAndClear();
aFilterLb.disposeAndClear();
}
// Helper function: Access to the current family item
const SfxStyleFamilyItem *SfxCommonTemplateDialog_Impl::GetFamilyItem_Impl() const
{
const size_t nCount = pStyleFamilies->size();
for(size_t i = 0; i < nCount; ++i)
{
const SfxStyleFamilyItem &rItem = pStyleFamilies->at( i );
sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
if(nId == nActFamily)
return &rItem;
}
return nullptr;
}
void SfxCommonTemplateDialog_Impl::GetSelectedStyle() const
{
if (!IsInitialized() || !pStyleSheetPool || !HasSelectedStyle())
return;
const OUString aTemplName( GetSelectedEntry() );
const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );
}
/**
* Is it safe to show the water-can / fill icon. If we've a
* hierarchical widget - we have only single select, otherwise
* we need to check if we have a multi-selection. We either have
* a pTreeBox showing or an aFmtLb (which we hide when not shown)
*/
bool SfxCommonTemplateDialog_Impl::IsSafeForWaterCan() const
{
if ( pTreeBox->IsVisible() )
return pTreeBox->FirstSelected() != nullptr;
else
return aFmtLb->GetSelectionCount() == 1;
}
void SfxCommonTemplateDialog_Impl::SelectStyle(const OUString &rStr)
{
const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
if ( !pItem )
return;
const SfxStyleFamily eFam = pItem->GetFamily();
SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( rStr, eFam );
if( pStyle )
{
bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
EnableEdit( bReadWrite );
EnableHide( bReadWrite && !pStyle->IsHidden( ) && !pStyle->IsUsed( ) );
EnableShow( bReadWrite && pStyle->IsHidden( ) );
}
else
{
EnableEdit( false );
EnableHide( false );
EnableShow( false );
}
if ( pTreeBox->IsVisible() )
{
if ( !rStr.isEmpty() )
{
SvTreeListEntry* pEntry = pTreeBox->First();
while ( pEntry )
{
if ( pTreeBox->GetEntryText( pEntry ) == rStr )
{
pTreeBox->MakeVisible( pEntry );
pTreeBox->Select( pEntry );
return;
}
pEntry = pTreeBox->Next( pEntry );
}
}
else
pTreeBox->SelectAll( false );
}
else
{
bool bSelect = ! rStr.isEmpty();
if ( bSelect )
{
SvTreeListEntry* pEntry = aFmtLb->FirstVisible();
while ( pEntry && aFmtLb->GetEntryText( pEntry ) != rStr )
pEntry = aFmtLb->NextVisible( pEntry );
if ( !pEntry )
bSelect = false;
else
{
if (!aFmtLb->IsSelected(pEntry))
{
aFmtLb->MakeVisible( pEntry );
aFmtLb->SelectAll(false);
aFmtLb->Select( pEntry );
bWaterDisabled = !IsSafeForWaterCan();
FmtSelectHdl( nullptr );
}
}
}
if ( !bSelect )
{
aFmtLb->SelectAll( false );
EnableEdit(false);
EnableHide( false );
EnableShow( false );
}
}
}
OUString SfxCommonTemplateDialog_Impl::GetSelectedEntry() const
{
OUString aRet;
if ( pTreeBox->IsVisible() )
{
SvTreeListEntry* pEntry = pTreeBox->FirstSelected();
if ( pEntry )
aRet = pTreeBox->GetEntryText( pEntry );
}
else
{
SvTreeListEntry* pEntry = aFmtLb->FirstSelected();
if ( pEntry )
aRet = aFmtLb->GetEntryText( pEntry );
}
return aRet;
}
void SfxCommonTemplateDialog_Impl::EnableTreeDrag( bool bEnable )
{
if ( pStyleSheetPool )
{
SfxStyleSheetBase* pStyle = pStyleSheetPool->First();
if ( pTreeBox->IsVisible() )
{
if ( pStyle && pStyle->HasParentSupport() && bEnable )
pTreeBox->SetDragDropMode(DragDropMode::CTRL_MOVE);
else
pTreeBox->SetDragDropMode(DragDropMode::NONE);
}
}
bTreeDrag = bEnable;
}
void SfxCommonTemplateDialog_Impl::FillTreeBox()
{
OSL_ENSURE( pTreeBox, "FillTreeBox() without treebox");
if (pStyleSheetPool && nActFamily != 0xffff)
{
const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
if (!pItem)
return;
pStyleSheetPool->SetSearchMask(pItem->GetFamily(), SfxStyleSearchBits::AllVisible);
StyleTreeArr_Impl aArr;
SfxStyleSheetBase* pStyle = pStyleSheetPool->First();
if(pStyle && pStyle->HasParentSupport() && bTreeDrag )
pTreeBox->SetDragDropMode(DragDropMode::CTRL_MOVE);
else
pTreeBox->SetDragDropMode(DragDropMode::NONE);
while (pStyle)
{
StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent());
aArr.emplace_back(pNew);
pStyle = pStyleSheetPool->Next();
}
MakeTree_Impl(aArr);
std::vector<OUString> aEntries;
pTreeBox->MakeExpanded_Impl(aEntries);
pTreeBox->SetUpdateMode( false );
pTreeBox->Clear();
const sal_uInt16 nCount = aArr.size();
for (sal_uInt16 i = 0; i < nCount; ++i)
{
FillBox_Impl(pTreeBox, aArr[i].get(), aEntries, pItem->GetFamily(), nullptr);
aArr[i].reset();
}
pTreeBox->Recalc();
EnableItem(SID_STYLE_WATERCAN, false);
SfxTemplateItem* pState = pFamilyState[nActFamily - 1].get();
if (nCount)
pTreeBox->Expand(pTreeBox->First());
for (SvTreeListEntry* pEntry = pTreeBox->First(); pEntry; pEntry = pTreeBox->Next(pEntry))
{
if (IsExpanded_Impl(aEntries, pTreeBox->GetEntryText(pEntry)))
pTreeBox->Expand(pEntry);
}
pTreeBox->SetUpdateMode( true );
OUString aStyle;
if(pState) // Select current entry
aStyle = pState->GetStyleName();
SelectStyle(aStyle);
EnableDelete();
}
}
bool SfxCommonTemplateDialog_Impl::HasSelectedStyle() const
{
return pTreeBox->IsVisible()? pTreeBox->FirstSelected() != nullptr:
aFmtLb->GetSelectionCount() != 0;
}
// internal: Refresh the display
// nFlags: what we should update.
void SfxCommonTemplateDialog_Impl::UpdateStyles_Impl(StyleFlags nFlags)
{
OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
if (!pItem)
{
// Is the case for the template catalog
const size_t nFamilyCount = pStyleFamilies->size();
size_t n;
for( n = 0; n < nFamilyCount; n++ )
if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;
if ( n == nFamilyCount )
// It happens sometimes, God knows why
return;
nAppFilter = pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
FamilySelect( StyleNrToInfoOffset(n)+1 );
pItem = GetFamilyItem_Impl();
}
const SfxStyleFamily eFam = pItem->GetFamily();
SfxStyleSearchBits nFilter (nActFilter < pItem->GetFilterList().size() ? pItem->GetFilterList()[nActFilter].nFlags : SfxStyleSearchBits::Auto);
if(nFilter == SfxStyleSearchBits::Auto) // automatic
nFilter = nAppFilter;
OSL_ENSURE(pStyleSheetPool, "no StyleSheetPool");
if(pStyleSheetPool)
{
pStyleSheetPool->SetSearchMask(eFam, nFilter);
pItem = GetFamilyItem_Impl();
if(nFlags & StyleFlags::UpdateFamily) // Update view type list (Hierarchical, All, etc.
{
CheckItem(nActFamily); // check Button in Toolbox
aFilterLb->SetUpdateMode(false);
aFilterLb->Clear();
//insert hierarchical at the beginning
sal_Int32 nPos = aFilterLb->InsertEntry(SfxResId(STR_STYLE_FILTER_HIERARCHICAL), 0);
aFilterLb->SetEntryData( nPos, reinterpret_cast<void*>(SfxStyleSearchBits::All) );
const SfxStyleFilter& rFilter = pItem->GetFilterList();
for(const SfxFilterTuple& i : rFilter)
{
SfxStyleSearchBits nFilterFlags = i.nFlags;
nPos = aFilterLb->InsertEntry( i.aName );
aFilterLb->SetEntryData( nPos, reinterpret_cast<void*>(nFilterFlags) );
}
if(nActFilter < aFilterLb->GetEntryCount() - 1)
aFilterLb->SelectEntryPos(nActFilter + 1);
else
{
nActFilter = 0;
aFilterLb->SelectEntryPos(1);
SfxStyleSearchBits nFilterFlags = (nActFilter < rFilter.size()) ? rFilter[nActFilter].nFlags : SfxStyleSearchBits::Auto;
pStyleSheetPool->SetSearchMask(eFam, nFilterFlags);
}
// if the tree view again, select family hierarchy
if (pTreeBox->IsVisible() || m_bWantHierarchical)
{
aFilterLb->SelectEntry(SfxResId(STR_STYLE_FILTER_HIERARCHICAL));
EnableHierarchical(true);
}
// show maximum 14 entries
aFilterLb->SetDropDownLineCount( MAX_FILTER_ENTRIES );
aFilterLb->SetUpdateMode(true);
}
else
{
if (nActFilter < aFilterLb->GetEntryCount() - 1)
aFilterLb->SelectEntryPos(nActFilter + 1);
else
{
nActFilter = 0;
aFilterLb->SelectEntryPos(1);
}
}
if(nFlags & StyleFlags::UpdateFamilyList)
{
EnableItem(SID_STYLE_WATERCAN,false);
SfxStyleSheetBase *pStyle = pStyleSheetPool->First();
SvTreeListEntry* pEntry = aFmtLb->First();
std::vector<OUString> aStrings;
comphelper::string::NaturalStringSorter aSorter(
::comphelper::getProcessComponentContext(),
Application::GetSettings().GetLanguageTag().getLocale());
while( pStyle )
{
//Bubblesort
size_t nPos;
for(nPos = aStrings.size(); nPos && aSorter.compare(aStrings[nPos-1], pStyle->GetName()) > 0; --nPos)
{};
aStrings.insert(aStrings.begin() + nPos, pStyle->GetName());
pStyle = pStyleSheetPool->Next();
}
size_t nCount = aStrings.size();
size_t nPos = 0;
while(nPos < nCount && pEntry &&
aStrings[nPos] == aFmtLb->GetEntryText(pEntry))
{
++nPos;
pEntry = aFmtLb->Next( pEntry );
}
if( nPos < nCount || pEntry )
{
// Fills the display box
aFmtLb->SetUpdateMode(false);
aFmtLb->Clear();
for(nPos = 0; nPos < nCount; ++nPos)
{
SvTreeListEntry* pTreeListEntry = aFmtLb->InsertEntry(aStrings[nPos], nullptr, false, nPos);
if (officecfg::Office::Common::StylesAndFormatting::Preview::get())
{
pTreeListEntry->ReplaceItem(o3tl::make_unique<StyleLBoxString>(aStrings[nPos], eFam), 1);
}
aFmtLb->GetModel()->InvalidateEntry(pTreeListEntry);
}
aFmtLb->Recalc();
aFmtLb->SetUpdateMode(true);
}
// Selects the current style if any
SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
OUString aStyle;
if(pState)
aStyle = pState->GetStyleName();
#if defined STYLESPREVIEW
mbIgnoreSelect = true; // in case we get a selection change
// in any case we should stop any preview
Execute_Impl(SID_STYLE_END_PREVIEW,
OUString(), OUString(),
0, 0, 0, 0 );
#endif
SelectStyle(aStyle);
EnableDelete();
}
}
}
// Updated display: Watering the house
void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem)
{
bWaterDisabled = (pItem == nullptr);
if(!bWaterDisabled)
//make sure the watercan is only activated when there is (only) one selection
bWaterDisabled = !IsSafeForWaterCan();
if(pItem && !bWaterDisabled)
{
CheckItem(SID_STYLE_WATERCAN, pItem->GetValue());
EnableItem( SID_STYLE_WATERCAN );
}
else
{
if(!bWaterDisabled)
EnableItem(SID_STYLE_WATERCAN);
else
EnableItem(SID_STYLE_WATERCAN, false);
}
// Ignore while in watercan mode statusupdates
size_t nCount = pStyleFamilies->size();
pBindings->EnterRegistrations();
for(size_t n = 0; n < nCount; n++)
{
SfxControllerItem *pCItem=pBoundItems[n].get();
bool bChecked = pItem && pItem->GetValue();
if( pCItem->IsBound() == bChecked )
{
if( !bChecked )
pCItem->ReBind();
else
pCItem->UnBind();
}
}
pBindings->LeaveRegistrations();
}
// Item with the status of a Family is copied and noted
// (is updated when all states have also been updated.)
// See also: <SfxBindings::AddDoneHdl(const Link &)>
void SfxCommonTemplateDialog_Impl::SetFamilyState( sal_uInt16 nSlotId, const SfxTemplateItem* pItem )
{
sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
pFamilyState[nIdx].reset();
if ( pItem )
pFamilyState[nIdx].reset( new SfxTemplateItem(*pItem) );
bUpdate = true;
// If used templates (how the hell you find this out??)
bUpdateFamily = true;
}
// Notice from SfxBindings that the update is completed. Pushes out the update
// of the display.
void SfxCommonTemplateDialog_Impl::Update_Impl()
{
bool bDocChanged=false;
SfxStyleSheetBasePool* pNewPool = nullptr;
SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
if( pDocShell )
pNewPool = pDocShell->GetStyleSheetPool();
if ( pNewPool != pStyleSheetPool && pDocShell )
{
SfxModule* pNewModule = pDocShell->GetModule();
if( pNewModule && pNewModule != pModule )
{
ClearResource();
ReadResource();
}
if ( pStyleSheetPool )
{
EndListening(*pStyleSheetPool);
pStyleSheetPool = nullptr;
}
if ( pNewPool )
{
StartListening(*pNewPool);
pStyleSheetPool = pNewPool;
bDocChanged=true;
}
}
if (bUpdateFamily)
UpdateFamily_Impl();
sal_uInt16 i;
for(i = 0; i < MAX_FAMILIES; ++i)
if(pFamilyState[i])
break;
if(i == MAX_FAMILIES || !pNewPool)
// nothing is allowed
return;
SfxTemplateItem *pItem = nullptr;
// current region not within the allowed region or default
if(nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get() ) )
{
CheckItem(nActFamily, false);
const size_t nFamilyCount = pStyleFamilies->size();
size_t n;
for( n = 0; n < nFamilyCount; n++ )
if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break;
std::unique_ptr<SfxTemplateItem> & pNewItem = pFamilyState[StyleNrToInfoOffset(n)];
nAppFilter = pNewItem->GetValue();
FamilySelect( StyleNrToInfoOffset(n) + 1 );
pItem = pNewItem.get();
}
else if( bDocChanged )
{
// other DocShell -> all new
CheckItem( nActFamily );
nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pDocShell ) );
if ( 0xffff == nActFilter )
nActFilter = pDocShell->GetAutoStyleFilterIndex();
nAppFilter = pItem->GetValue();
if(!pTreeBox->IsVisible())
{
UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
}
else
FillTreeBox();
}
else
{
// other filters for automatic
CheckItem( nActFamily );
const SfxStyleFamilyItem *pStyleItem = GetFamilyItem_Impl();
if ( pStyleItem && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[nActFilter].nFlags
&& nAppFilter != pItem->GetValue())
{
nAppFilter = pItem->GetValue();
if(!pTreeBox->IsVisible())
UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
else
FillTreeBox();
}
else
nAppFilter = pItem->GetValue();
}
const OUString aStyle(pItem->GetStyleName());
SelectStyle(aStyle);
EnableDelete();
EnableNew( bCanNew );
}
IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TimeOut, Timer *, void )
{
if(!bDontUpdate)
{
bDontUpdate=true;
if(!pTreeBox->IsVisible())
UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
else
{
FillTreeBox();
SfxTemplateItem *pState = pFamilyState[nActFamily-1].get();
if(pState)
{
const OUString aStyle(pState->GetStyleName());
SelectStyle(aStyle);
EnableDelete();
}
}
bDontUpdate=false;
pIdle.reset();
}
else
pIdle->Start();
}
void SfxCommonTemplateDialog_Impl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
{
const SfxHintId nId = rHint.GetId();
// tap update
switch(nId)
{
case SfxHintId::UpdateDone:
{
SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();
if (
bUpdate &&
(
!IsCheckedItem(SID_STYLE_WATERCAN) ||
(pDocShell && pDocShell->GetStyleSheetPool() != pStyleSheetPool)
)
)
{
bUpdate = false;
Update_Impl();
}
else if ( bUpdateFamily )
{
UpdateFamily_Impl();
}
if( pStyleSheetPool )
{
OUString aStr = GetSelectedEntry();
if( !aStr.isEmpty() && pStyleSheetPool )
{
const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
if( !pItem ) break;
const SfxStyleFamily eFam = pItem->GetFamily();
SfxStyleSheetBase *pStyle = pStyleSheetPool->Find( aStr, eFam );
if( pStyle )
{
bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
EnableEdit( bReadWrite );
EnableHide( bReadWrite && !pStyle->IsUsed( ) && !pStyle->IsHidden( ) );
EnableShow( bReadWrite && pStyle->IsHidden( ) );
}
else
{
EnableEdit(false);
EnableHide(false);
EnableShow(false);
}
}
}
break;
}
// Necessary if switching between documents and in both documents
// the same template is used. Do not immediately call Update_Impl,
// for the case that one of the documents is an internal InPlaceObject!
case SfxHintId::DocChanged:
bUpdate = true;
break;
case SfxHintId::Dying:
{
EndListening(*pStyleSheetPool);
pStyleSheetPool=nullptr;
break;
}
default: break;
}
// Do not set timer when the stylesheet pool is in the box, because it is
// possible that a new one is registered after the timer is up -
// works bad in UpdateStyles_Impl ()!
if(!bDontUpdate && nId != SfxHintId::Dying &&
(dynamic_cast<const SfxStyleSheetPoolHint*>(&rHint) ||
dynamic_cast<const SfxStyleSheetHint*>(&rHint) ||
dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint)))
{
if(!pIdle)
{
pIdle.reset(new Idle("SfxCommonTemplate"));
pIdle->SetPriority(TaskPriority::LOWEST);
pIdle->SetInvokeHandler(LINK(this,SfxCommonTemplateDialog_Impl,TimeOut));
}
pIdle->Start();
}
}
// Other filters; can be switched by the users or as a result of new or
// editing, if the current document has been assigned a different filter.
void SfxCommonTemplateDialog_Impl::FilterSelect(
sal_uInt16 nEntry, // Idx of the new Filters
bool bForce ) // Force update, even if the new filter is
// equal to the current
{
if( nEntry != nActFilter || bForce )
{
nActFilter = nEntry;
SfxObjectShell *const pDocShell = SaveSelection();
SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
if ( pOldStyleSheetPool != pStyleSheetPool )
{
if ( pOldStyleSheetPool )
EndListening(*pOldStyleSheetPool);
if ( pStyleSheetPool )
StartListening(*pStyleSheetPool);
}
UpdateStyles_Impl(StyleFlags::UpdateFamilyList);
}
}
// Internal: Perform functions through the Dispatcher
bool SfxCommonTemplateDialog_Impl::Execute_Impl(
sal_uInt16 nId, const OUString &rStr, const OUString& rRefStr, sal_uInt16 nFamily,
SfxStyleSearchBits nMask, sal_uInt16 *pIdx, const sal_uInt16* pModifier)
{
SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl();
SfxStringItem aItem(nId, rStr);
SfxUInt16Item aFamily(SID_STYLE_FAMILY, nFamily);
SfxUInt16Item aMask( SID_STYLE_MASK, static_cast<sal_uInt16>(nMask) );
SfxStringItem aUpdName(SID_STYLE_UPD_BY_EX_NAME, rStr);
SfxStringItem aRefName( SID_STYLE_REFERENCE, rRefStr );
const SfxPoolItem* pItems[ 6 ];
sal_uInt16 nCount = 0;
if( !rStr.isEmpty() )
pItems[ nCount++ ] = &aItem;
pItems[ nCount++ ] = &aFamily;
if( nMask != SfxStyleSearchBits::Auto )
pItems[ nCount++ ] = &aMask;
if(SID_STYLE_UPDATE_BY_EXAMPLE == nId)
{
// Special solution for Numbering update in Writer
const OUString aTemplName(GetSelectedEntry());
aUpdName.SetValue(aTemplName);
pItems[ nCount++ ] = &aUpdName;
}
if ( !rRefStr.isEmpty() )
pItems[ nCount++ ] = &aRefName;
pItems[ nCount++ ] = nullptr;
DeletionWatcher aDeleted(*this);
sal_uInt16 nModi = pModifier ? *pModifier : 0;
const SfxPoolItem* pItem = rDispatcher.Execute(
nId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD | SfxCallMode::MODAL,
pItems, nModi );
// Dialog can be destroyed while in Execute() because started
// subdialogs are not modal to it (#i97888#).
if ( !pItem || aDeleted )
return false;
if ( (nId == SID_STYLE_NEW || SID_STYLE_EDIT == nId) && (pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1) )
{
const SfxUInt16Item *pFilterItem = dynamic_cast< const SfxUInt16Item* >(pItem);
OSL_ENSURE(pFilterItem, "SfxUINT16Item expected");
SfxStyleSearchBits nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue()) & ~SfxStyleSearchBits::UserDefined;
if(nFilterFlags == SfxStyleSearchBits::Auto) // User Template?
nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue());
const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
const size_t nFilterCount = pFamilyItem->GetFilterList().size();
for ( size_t i = 0; i < nFilterCount; ++i )
{
const SfxFilterTuple &rTupel = pFamilyItem->GetFilterList()[ i ];
if ( ( rTupel.nFlags & nFilterFlags ) == nFilterFlags && pIdx )
*pIdx = i;
}
}
return true;
}
// Handler Listbox of Filter
void SfxCommonTemplateDialog_Impl::EnableHierarchical(bool const bEnable)
{
if (bEnable)
{
if (!bHierarchical)
{
// Turn on treeView
bHierarchical=true;
m_bWantHierarchical = true;
SaveSelection(); // fdo#61429 store "hierarchical"
const OUString aSelectEntry( GetSelectedEntry());
aFmtLb->Hide();
pTreeBox->SetFont( aFmtLb->GetFont() );
pTreeBox->SetPosSizePixel(aFmtLb->GetPosPixel(), aFmtLb->GetSizePixel());
FillTreeBox();
SelectStyle(aSelectEntry);
pTreeBox->Show();
}
}
else
{
pTreeBox->Hide();
aFmtLb->Show();
// If bHierarchical, then the family can have changed
// minus one since hierarchical is inserted at the start
m_bWantHierarchical = false; // before FilterSelect
FilterSelect(aFilterLb->GetSelectedEntryPos() - 1, bHierarchical );
bHierarchical=false;
}
}
IMPL_LINK( SfxCommonTemplateDialog_Impl, FilterSelectHdl, ListBox&, rBox, void )
{
if (SfxResId(STR_STYLE_FILTER_HIERARCHICAL) == rBox.GetSelectedEntry())
{
EnableHierarchical(true);
}
else
{
EnableHierarchical(false);
}
}
// Select-Handler for the Toolbox
void SfxCommonTemplateDialog_Impl::FamilySelect(sal_uInt16 nEntry, bool bPreviewRefresh)
{
assert((0 < nEntry && nEntry <= MAX_FAMILIES) || 0xffff == nEntry);
if( nEntry != nActFamily || bPreviewRefresh )
{
CheckItem( nActFamily, false );
nActFamily = nEntry;
SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
SfxUInt16Item const aItem(SID_STYLE_FAMILY,
static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
pBindings->Invalidate( SID_STYLE_FAMILY );
pBindings->Update( SID_STYLE_FAMILY );
UpdateFamily_Impl();
}
}
void SfxCommonTemplateDialog_Impl::ActionSelect(sal_uInt16 nEntry)
{
switch(nEntry)
{
case SID_STYLE_WATERCAN:
{
const bool bState = IsCheckedItem(nEntry);
bool bCheck;
SfxBoolItem aBool;
// when a template is chosen.
if (!bState && HasSelectedStyle())
{
const OUString aTemplName(
GetSelectedEntry());
Execute_Impl(
SID_STYLE_WATERCAN, aTemplName, "",
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
bCheck = true;
}
else
{
Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
bCheck = false;
}
CheckItem(nEntry, bCheck);
aBool.SetValue(bCheck);
SetWaterCanState(&aBool);
break;
}
case SID_STYLE_NEW_BY_EXAMPLE:
{
if(pStyleSheetPool && nActFamily != 0xffff)
{
const SfxStyleFamily eFam=GetFamilyItem_Impl()->GetFamily();
const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
SfxStyleSearchBits nFilter;
if( pItem && nActFilter != 0xffff )
{
nFilter = pItem->GetFilterList()[nActFilter].nFlags;
if(nFilter == SfxStyleSearchBits::Auto) // automatic
nFilter = nAppFilter;
}
else
nFilter=pStyleSheetPool->GetSearchMask();
pStyleSheetPool->SetSearchMask( eFam, SfxStyleSearchBits::UserDefined );
// why? : FloatingWindow must not be parent of a modal dialog
SfxNewStyleDlg aDlg(pWindow ? pWindow->GetFrameWeld() : nullptr, *pStyleSheetPool);
if (aDlg.run() == RET_OK)
{
pStyleSheetPool->SetSearchMask(eFam, nFilter);
const OUString aTemplName(aDlg.GetName());
Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE,
aTemplName, "",
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
nFilter);
}
pStyleSheetPool->SetSearchMask( eFam, nFilter );
}
break;
}
case SID_STYLE_UPDATE_BY_EXAMPLE:
{
Execute_Impl(SID_STYLE_UPDATE_BY_EXAMPLE,
"", "",
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
break;
}
case SID_TEMPLATE_LOAD:
SfxGetpApp()->GetDispatcher_Impl()->Execute(nEntry);
break;
default: OSL_FAIL("not implemented"); break;
}
}
static OUString getModuleIdentifier( const Reference< XModuleManager2 >& i_xModMgr, SfxObjectShell const * i_pObjSh )
{
OSL_ENSURE( i_xModMgr.is(), "getModuleIdentifier(): no XModuleManager" );
OSL_ENSURE( i_pObjSh, "getModuleIdentifier(): no ObjectShell" );
OUString sIdentifier;
try
{
sIdentifier = i_xModMgr->identify( i_pObjSh->GetModel() );
}
catch ( css::frame::UnknownModuleException& )
{
SAL_WARN("sfx", "getModuleIdentifier(): unknown module" );
}
catch ( Exception& )
{
OSL_FAIL( "getModuleIdentifier(): exception of XModuleManager::identify()" );
}
return sIdentifier;
}
sal_Int32 SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter( SfxObjectShell const * i_pObjSh )
{
OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
::comphelper::SequenceAsHashMap aFactoryProps(
xModuleManager->getByName( getModuleIdentifier( xModuleManager, i_pObjSh ) ) );
sal_Int32 nFilter = aFactoryProps.getUnpackedValueOrDefault( "ooSetupFactoryStyleFilter", sal_Int32(-1) );
m_bWantHierarchical = (nFilter & 0x1000) != 0;
nFilter &= ~0x1000; // clear it
return nFilter;
}
void SfxCommonTemplateDialog_Impl::SaveFactoryStyleFilter( SfxObjectShell const * i_pObjSh, sal_Int32 i_nFilter )
{
OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" );
Sequence< PropertyValue > lProps(1);
lProps[0].Name = "ooSetupFactoryStyleFilter";
lProps[0].Value <<= i_nFilter | (m_bWantHierarchical ? 0x1000 : 0);
xModuleManager->replaceByName( getModuleIdentifier( xModuleManager, i_pObjSh ), makeAny( lProps ) );
}
SfxObjectShell* SfxCommonTemplateDialog_Impl::SaveSelection()
{
SfxViewFrame *const pViewFrame(pBindings->GetDispatcher_Impl()->GetFrame());
SfxObjectShell *const pDocShell(pViewFrame->GetObjectShell());
if (pDocShell)
{
pDocShell->SetAutoStyleFilterIndex(nActFilter);
SaveFactoryStyleFilter( pDocShell, nActFilter );
}
return pDocShell;
}
IMPL_LINK( SfxCommonTemplateDialog_Impl, DropHdl, StyleTreeListBox_Impl&, rBox, bool )
{
bDontUpdate = true;
const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
const SfxStyleFamily eFam = pItem->GetFamily();
bool ret = pStyleSheetPool->SetParent(eFam, rBox.GetStyle(), rBox.GetParent());
bDontUpdate = false;
return ret;
}
// Handler for the New-Buttons
void SfxCommonTemplateDialog_Impl::NewHdl()
{
if ( nActFamily != 0xffff && (pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1))
{
const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
const SfxStyleFamily eFam=pItem->GetFamily();
SfxStyleSearchBits nMask;
if( nActFilter != 0xffff )
{
nMask = pItem->GetFilterList()[nActFilter].nFlags;
if(nMask == SfxStyleSearchBits::Auto) // automatic
nMask = nAppFilter;
}
else
nMask=pStyleSheetPool->GetSearchMask();
pStyleSheetPool->SetSearchMask(eFam,nMask);
Execute_Impl(SID_STYLE_NEW,
"", GetSelectedEntry(),
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
nMask);
}
}
// Handler for the edit-Buttons
void SfxCommonTemplateDialog_Impl::EditHdl()
{
if(IsInitialized() && HasSelectedStyle())
{
sal_uInt16 nFilter = nActFilter;
OUString aTemplName(GetSelectedEntry());
GetSelectedStyle(); // -Wall required??
Execute_Impl( SID_STYLE_EDIT, aTemplName, OUString(),
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), SfxStyleSearchBits::Auto, &nFilter );
}
}
// Handler for the Delete-Buttons
void SfxCommonTemplateDialog_Impl::DeleteHdl()
{
if ( IsInitialized() && HasSelectedStyle() )
{
bool bUsedStyle = false; // one of the selected styles are used in the document?
std::vector<SvTreeListEntry*> aList;
SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected();
const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
OUStringBuffer aMsg;
aMsg.append(SfxResId(STR_DELETE_STYLE_USED)).append(SfxResId(STR_DELETE_STYLE));
while (pEntry)
{
aList.push_back( pEntry );
// check the style is used or not
const OUString aTemplName(pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry));
SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( aTemplName, pItem->GetFamily() );
if ( pStyle->IsUsed() ) // pStyle is in use in the document?
{
if (bUsedStyle) // add a separator for the second and later styles
aMsg.append(", ");
aMsg.append(aTemplName);
bUsedStyle = true;
}
pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry);
}
bool aApproved = false;
// we only want to show the dialog once and if we want to delete a style in use (UX-advice)
if ( bUsedStyle )
{
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
VclMessageType::Question, VclButtonsType::YesNo,
aMsg.makeStringAndClear()));
aApproved = xBox->run() == RET_YES;
}
// if there are no used styles selected or the user approved the changes
if ( !bUsedStyle || aApproved )
{
for (auto const& elem : aList)
{
const OUString aTemplName(pTreeBox->IsVisible() ? pTreeBox->GetEntryText(elem) : aFmtLb->GetEntryText(elem));
bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
Execute_Impl( SID_STYLE_DELETE, aTemplName,
OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
if ( pTreeBox->IsVisible() )
{
pTreeBox->RemoveParentKeepChildren(elem);
bDontUpdate = false;
}
}
bDontUpdate = false; //if everything is deleted set bDontUpdate back to false
UpdateStyles_Impl(StyleFlags::UpdateFamilyList); //and force-update the list
}
}
}
void SfxCommonTemplateDialog_Impl::HideHdl()
{
if ( IsInitialized() && HasSelectedStyle() )
{
SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected();
while (pEntry)
{
OUString aTemplName = pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry);
Execute_Impl( SID_STYLE_HIDE, aTemplName,
OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry);
}
}
}
void SfxCommonTemplateDialog_Impl::ShowHdl()
{
if ( IsInitialized() && HasSelectedStyle() )
{
SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected();
while (pEntry)
{
OUString aTemplName = pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry);
Execute_Impl( SID_STYLE_SHOW, aTemplName,
OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) );
pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry);
}
}
}
void SfxCommonTemplateDialog_Impl::EnableDelete()
{
if(IsInitialized() && HasSelectedStyle())
{
OSL_ENSURE(pStyleSheetPool, "No StyleSheetPool");
const OUString aTemplName(GetSelectedEntry());
const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl();
const SfxStyleFamily eFam = pItem->GetFamily();
SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
if (pItem->GetFilterList().size() > nActFilter)
nFilter = pItem->GetFilterList()[nActFilter].nFlags;
if(nFilter == SfxStyleSearchBits::Auto) // automatic
nFilter = nAppFilter;
const SfxStyleSheetBase *pStyle =
pStyleSheetPool->Find(aTemplName,eFam, pTreeBox->IsVisible()? SfxStyleSearchBits::All : nFilter);
OSL_ENSURE(pStyle, "Style not found");
if(pStyle && pStyle->IsUserDefined())
{
EnableDel(true);
}
else
{
EnableDel(false);
}
}
else
{
EnableDel(false);
}
}
IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TreeListApplyHdl, SvTreeListBox *, bool )
{
ApplyHdl(nullptr);
return false;
}
// Double-click on a style sheet in the ListBox is applied.
IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, ApplyHdl, LinkParamNone*, void )
{
// only if that region is allowed
if ( IsInitialized() && nullptr != pFamilyState[nActFamily-1] &&
!GetSelectedEntry().isEmpty() )
{
sal_uInt16 nModifier = aFmtLb->GetModifier();
Execute_Impl(SID_STYLE_APPLY,
GetSelectedEntry(), OUString(),
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()),
SfxStyleSearchBits::Auto, nullptr, &nModifier );
}
// After selecting a focused item if possible again on the app window
if ( dynamic_cast< const SfxTemplateDialog_Impl* >(this) != nullptr )
{
SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame();
SfxViewShell *pVu = pViewFrame->GetViewShell();
vcl::Window *pAppWin = pVu ? pVu->GetWindow(): nullptr;
if(pAppWin)
pAppWin->GrabFocus();
}
}
IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, PreviewHdl, Button*, void)
{
std::shared_ptr<comphelper::ConfigurationChanges> batch( comphelper::ConfigurationChanges::create() );
officecfg::Office::Common::StylesAndFormatting::Preview::set( aPreviewCheckbox->IsChecked(), batch );
batch->commit();
if(!bHierarchical)
{
sal_uInt16 nSize = aFmtLb->GetEntryCount();
for (sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
{
SvTreeListEntry* pTreeListEntry = aFmtLb->GetEntry(nPos);
OUString aEntryStr = aFmtLb->GetEntryText(pTreeListEntry);
const SfxStyleFamily eFam = aPreviewCheckbox->IsChecked() ? GetFamilyItem_Impl()->GetFamily(): SfxStyleFamily::None;
pTreeListEntry->ReplaceItem(o3tl::make_unique<StyleLBoxString>(aEntryStr, eFam), 1);
aFmtLb->GetModel()->InvalidateEntry(pTreeListEntry);
aFmtLb->Recalc();
}
}
else
{
FamilySelect(nActFamily, true);
}
}
// Selection of a template during the Watercan-Status
IMPL_LINK( SfxCommonTemplateDialog_Impl, FmtSelectHdl, SvTreeListBox *, pListBox, void )
{
// Trigger Help PI, if this is permitted of call handlers and field
if( !pListBox || pListBox->IsSelected( pListBox->GetHdlEntry() ) )
{
// Only when the watercan is on
if ( IsInitialized() &&
IsCheckedItem(SID_STYLE_WATERCAN) &&
// only if that region is allowed
nullptr != pFamilyState[nActFamily-1] && (pTreeBox || aFmtLb->GetSelectionCount() <= 1) )
{
Execute_Impl(SID_STYLE_WATERCAN,
"", "", 0);
Execute_Impl(SID_STYLE_WATERCAN,
GetSelectedEntry(), "",
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
}
EnableItem(SID_STYLE_WATERCAN, !bWaterDisabled);
EnableDelete();
}
if( pListBox )
{
SelectStyle( pListBox->GetEntryText( pListBox->GetHdlEntry() ));
#if defined STYLESPREVIEW
sal_uInt16 nModifier = aFmtLb->GetModifier();
if ( mbIgnoreSelect )
{
Execute_Impl(SID_STYLE_END_PREVIEW,
OUString(), OUString(),
0, 0, 0, 0 );
mbIgnoreSelect = false;
}
else
{
Execute_Impl(SID_STYLE_PREVIEW,
GetSelectedEntry(), OUString(),
( sal_uInt16 )GetFamilyItem_Impl()->GetFamily(),
0, 0, &nModifier );
}
#endif
}
}
IMPL_LINK( SfxCommonTemplateDialog_Impl, MenuSelectHdl, Menu*, pMenu, bool )
{
sLastItemIdent = pMenu->GetCurItemIdent();
Application::PostUserEvent(
LINK( this, SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl ) );
return true;
}
IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl, void*, void )
{
if (sLastItemIdent == "new")
NewHdl();
else if (sLastItemIdent == "edit")
EditHdl();
else if (sLastItemIdent == "delete")
DeleteHdl();
else if (sLastItemIdent == "hide")
HideHdl();
else if (sLastItemIdent == "show")
ShowHdl();
}
SfxStyleFamily SfxCommonTemplateDialog_Impl::GetActualFamily() const
{
const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl();
if( !pFamilyItem || nActFamily == 0xffff )
return SfxStyleFamily::Para;
else
return pFamilyItem->GetFamily();
}
void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnable)
{
bool bDisable = !bEnable || !IsSafeForWaterCan();
if( nId == SID_STYLE_NEW_BY_EXAMPLE )
bNewByExampleDisabled = bDisable;
else if( nId == SID_STYLE_UPDATE_BY_EXAMPLE )
bUpdateByExampleDisabled = bDisable;
EnableItem(nId, bEnable);
}
VclPtr<PopupMenu> const & SfxCommonTemplateDialog_Impl::CreateContextMenu()
{
if ( bBindingUpdate )
{
pBindings->Invalidate( SID_STYLE_NEW, true );
pBindings->Update( SID_STYLE_NEW );
bBindingUpdate = false;
}
mxMenu.disposeAndClear();
mxBuilder.reset(new VclBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "sfx/ui/stylecontextmenu.ui", ""));
mxMenu.set(mxBuilder->get_menu("menu"));
mxMenu->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, MenuSelectHdl ) );
mxMenu->EnableItem(mxMenu->GetItemId("edit"), bCanEdit);
mxMenu->EnableItem(mxMenu->GetItemId("delete"), bCanDel);
mxMenu->EnableItem(mxMenu->GetItemId("new"), bCanNew);
mxMenu->EnableItem(mxMenu->GetItemId("hide"), bCanHide);
mxMenu->EnableItem(mxMenu->GetItemId("show"), bCanShow);
const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl();
if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
{
mxMenu->EnableItem(mxMenu->GetItemId("edit"), false);
mxMenu->EnableItem(mxMenu->GetItemId("new"), false);
}
return mxMenu;
}
SfxTemplateDialog_Impl::SfxTemplateDialog_Impl(SfxBindings* pB, SfxTemplatePanelControl* pDlgWindow)
: SfxCommonTemplateDialog_Impl(pB, pDlgWindow)
, m_pFloat(pDlgWindow)
, m_aActionTbL(VclPtrInstance<DropToolBox_Impl>(pDlgWindow, this))
, m_aActionTbR(VclPtrInstance<ToolBox>(pDlgWindow))
{
m_aActionTbR->InsertItem(SID_STYLE_WATERCAN, Image(BitmapEx(RID_SFXBMP_WATERCAN)), SfxResId(STR_STYLE_FILL_FORMAT_MODE));
m_aActionTbR->SetHelpId(SID_STYLE_WATERCAN, HID_TEMPLDLG_WATERCAN);
m_aActionTbR->InsertItem(SID_STYLE_NEW_BY_EXAMPLE, Image(BitmapEx(RID_SFXBMP_NEW_BY_EXAMPLE)), SfxResId(STR_STYLE_NEW_STYLE_FROM_SELECTION));
m_aActionTbR->SetHelpId(SID_STYLE_NEW_BY_EXAMPLE, HID_TEMPLDLG_NEWBYEXAMPLE);
m_aActionTbR->InsertItem(SID_STYLE_UPDATE_BY_EXAMPLE, Image(BitmapEx(RID_SFXBMP_UPDATE_BY_EXAMPLE)), SfxResId(STR_STYLE_UPDATE_STYLE));
m_aActionTbR->SetHelpId(SID_STYLE_UPDATE_BY_EXAMPLE, HID_TEMPLDLG_UPDATEBYEXAMPLE);
Initialize();
}
void SfxTemplateDialog_Impl::Initialize()
{
SfxCommonTemplateDialog_Impl::Initialize();
m_aActionTbL->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxLSelect));
m_aActionTbR->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxRSelect));
m_aActionTbR->SetDropdownClickHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxRClick));
m_aActionTbL->Show();
m_aActionTbR->Show();
vcl::Font aFont = aFilterLb->GetFont();
aFont.SetWeight( WEIGHT_NORMAL );
aFilterLb->SetFont( aFont );
m_aActionTbL->SetHelpId( HID_TEMPLDLG_TOOLBOX_LEFT );
}
void SfxTemplateDialog_Impl::EnableFamilyItem( sal_uInt16 nId, bool bEnable )
{
m_aActionTbL->EnableItem( nId, bEnable );
}
// Insert element into dropdown filter "Frame Styles", "List Styles", etc.
void SfxTemplateDialog_Impl::InsertFamilyItem(sal_uInt16 nId,const SfxStyleFamilyItem &rItem)
{
OString sHelpId;
switch( rItem.GetFamily() )
{
case SfxStyleFamily::Char: sHelpId = ".uno:CharStyle"; break;
case SfxStyleFamily::Para: sHelpId = ".uno:ParaStyle"; break;
case SfxStyleFamily::Frame: sHelpId = ".uno:FrameStyle"; break;
case SfxStyleFamily::Page: sHelpId = ".uno:PageStyle"; break;
case SfxStyleFamily::Pseudo: sHelpId = ".uno:ListStyle"; break;
case SfxStyleFamily::Table: sHelpId = ".uno:TableStyle"; break;
default: OSL_FAIL("unknown StyleFamily"); break;
}
m_aActionTbL->InsertItem( nId, rItem.GetImage(), rItem.GetText(), ToolBoxItemBits::NONE, 0);
m_aActionTbL->SetHelpId( nId, sHelpId );
}
void SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
{
m_aActionTbR->HideItem(SID_STYLE_UPDATE_BY_EXAMPLE);
m_aActionTbR->SetItemBits( SID_STYLE_NEW_BY_EXAMPLE,
ToolBoxItemBits::DROPDOWNONLY|m_aActionTbR->GetItemBits( SID_STYLE_NEW_BY_EXAMPLE ));
}
void SfxTemplateDialog_Impl::ClearFamilyList()
{
m_aActionTbL->Clear();
}
void SfxCommonTemplateDialog_Impl::InvalidateBindings()
{
pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
pBindings->Update( SID_STYLE_NEW_BY_EXAMPLE );
pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
pBindings->Update( SID_STYLE_UPDATE_BY_EXAMPLE );
pBindings->Invalidate( SID_STYLE_WATERCAN, true);
pBindings->Update( SID_STYLE_WATERCAN );
pBindings->Invalidate( SID_STYLE_NEW, true);
pBindings->Update( SID_STYLE_NEW );
pBindings->Invalidate( SID_STYLE_DRAGHIERARCHIE, true);
pBindings->Update( SID_STYLE_DRAGHIERARCHIE );
}
SfxTemplateDialog_Impl::~SfxTemplateDialog_Impl()
{
m_pFloat.clear();
m_aActionTbL.disposeAndClear();
m_aActionTbR.disposeAndClear();
}
void SfxTemplateDialog_Impl::LoadedFamilies()
{
Resize();
}
// Override Resize-Handler ( StarView )
// The size of the Listboxen is adjusted
void SfxTemplateDialog_Impl::Resize()
{
if (m_pFloat == nullptr)
return;
Size aDlgSize=m_pFloat->PixelToLogic(m_pFloat->GetOutputSizePixel());
Size aSizeATL=m_pFloat->PixelToLogic(m_aActionTbL->CalcWindowSizePixel());
Size aSizeATR=m_pFloat->PixelToLogic(m_aActionTbR->CalcWindowSizePixel());
Size aMinSize = GetMinOutputSizePixel();
long nListHeight = m_pFloat->PixelToLogic( aFilterLb->GetSizePixel() ).Height();
long nWidth = aDlgSize.Width()- 2 * SFX_TEMPLDLG_HFRAME;
m_aActionTbL->SetPosSizePixel(m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME,SFX_TEMPLDLG_VTOPFRAME)),
m_pFloat->LogicToPixel(aSizeATL));
// only change the position of the right toolbox, when the window is wide
// enough
Point aPosATR(aDlgSize.Width()-SFX_TEMPLDLG_HFRAME-aSizeATR.Width(),SFX_TEMPLDLG_VTOPFRAME);
if(aDlgSize.Width() >= aMinSize.Width())
m_aActionTbR->SetPosPixel(m_pFloat->LogicToPixel(aPosATR));
else
m_aActionTbR->SetPosPixel( m_pFloat->LogicToPixel(
Point( SFX_TEMPLDLG_HFRAME + aSizeATL.Width() + SFX_TEMPLDLG_MIDHSPACE,
SFX_TEMPLDLG_VTOPFRAME ) ) );
m_aActionTbR->SetSizePixel(m_pFloat->LogicToPixel(aSizeATR));
Point aFilterPos(
m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME,
aDlgSize.Height()-SFX_TEMPLDLG_VBOTFRAME-nListHeight)) );
Size aFilterSize(
m_pFloat->LogicToPixel(Size(nWidth,SFX_TEMPLDLG_FILTERHEIGHT)) );
Point aCheckBoxPos(
m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME,
aDlgSize.Height()-SFX_TEMPLDLG_VBOTFRAME-2*nListHeight)) );
Size aCheckBoxSize(
m_pFloat->LogicToPixel(Size(nWidth, nListHeight)) );
Point aFmtPos(
m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME, SFX_TEMPLDLG_VTOPFRAME +
SFX_TEMPLDLG_MIDVSPACE+aSizeATL.Height())) );
Size aFmtSize(
m_pFloat->LogicToPixel(Size(nWidth,
aDlgSize.Height() - SFX_TEMPLDLG_VBOTFRAME -
SFX_TEMPLDLG_VTOPFRAME - 2*SFX_TEMPLDLG_MIDVSPACE-
2*nListHeight-aSizeATL.Height())) );
// only change the position of the listbox, when the window is high enough
if(aDlgSize.Height() >= aMinSize.Height())
{
aFilterLb->SetPosPixel(aFilterPos);
aFmtLb->SetPosPixel( aFmtPos );
aPreviewCheckbox->SetPosPixel(aCheckBoxPos);
if(pTreeBox->IsVisible())
pTreeBox->SetPosPixel(aFmtPos);
}
else
aFmtSize.AdjustHeight(aFilterSize.Height() );
aFilterLb->SetSizePixel(aFilterSize);
aFmtLb->SetSizePixel( aFmtSize );
aPreviewCheckbox->SetSizePixel( aCheckBoxSize );
if(pTreeBox->IsVisible())
pTreeBox->SetSizePixel(aFmtSize);
}
Size SfxTemplateDialog_Impl::GetMinOutputSizePixel()
{
if (m_pFloat != nullptr)
{
Size aSizeATL=m_pFloat->PixelToLogic(m_aActionTbL->CalcWindowSizePixel());
Size aSizeATR=m_pFloat->PixelToLogic(m_aActionTbR->CalcWindowSizePixel());
Size aMinSize=Size(
aSizeATL.Width()+aSizeATR.Width()+
2*SFX_TEMPLDLG_HFRAME + SFX_TEMPLDLG_MIDHSPACE,
4*aSizeATL.Height()+2*SFX_TEMPLDLG_MIDVSPACE);
return aMinSize;
}
else
return Size(0,0);
}
void SfxTemplateDialog_Impl::EnableItem(sal_uInt16 nMesId, bool bCheck)
{
switch(nMesId)
{
case SID_STYLE_WATERCAN :
if(!bCheck && IsCheckedItem(SID_STYLE_WATERCAN))
Execute_Impl(SID_STYLE_WATERCAN, "", "", 0);
SAL_FALLTHROUGH;
case SID_STYLE_NEW_BY_EXAMPLE:
case SID_STYLE_UPDATE_BY_EXAMPLE:
m_aActionTbR->EnableItem(nMesId,bCheck);
break;
}
}
void SfxTemplateDialog_Impl::CheckItem(sal_uInt16 nMesId, bool bCheck)
{
switch(nMesId)
{
case SID_STYLE_WATERCAN :
bIsWater=bCheck;
m_aActionTbR->CheckItem(SID_STYLE_WATERCAN,bCheck);
break;
default:
m_aActionTbL->CheckItem(nMesId,bCheck); break;
}
}
bool SfxTemplateDialog_Impl::IsCheckedItem(sal_uInt16 nMesId)
{
switch(nMesId)
{
case SID_STYLE_WATERCAN :
return m_aActionTbR->GetItemState(SID_STYLE_WATERCAN)==TRISTATE_TRUE;
default:
return m_aActionTbL->GetItemState(nMesId)==TRISTATE_TRUE;
}
}
IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxLSelect, ToolBox *, pBox, void )
{
const sal_uInt16 nEntry = pBox->GetCurItemId();
FamilySelect(nEntry);
}
IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxRSelect, ToolBox *, pBox, void )
{
const sal_uInt16 nEntry = pBox->GetCurItemId();
if(nEntry != SID_STYLE_NEW_BY_EXAMPLE ||
ToolBoxItemBits::DROPDOWN != (pBox->GetItemBits(nEntry)&ToolBoxItemBits::DROPDOWN))
ActionSelect(nEntry);
}
IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxRClick, ToolBox *, pBox, void )
{
const sal_uInt16 nEntry = pBox->GetCurItemId();
if(nEntry == SID_STYLE_NEW_BY_EXAMPLE &&
ToolBoxItemBits::DROPDOWN == (pBox->GetItemBits(nEntry)&ToolBoxItemBits::DROPDOWN))
{
//create a popup menu in Writer
ScopedVclPtrInstance<PopupMenu> pMenu;
OUString sTextDoc("com.sun.star.text.TextDocument");
OUString sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(".uno:StyleNewByExample", sTextDoc);
pMenu->InsertItem( SID_STYLE_NEW_BY_EXAMPLE, sLabel );
pMenu->SetHelpId(SID_STYLE_NEW_BY_EXAMPLE, HID_TEMPLDLG_NEWBYEXAMPLE);
sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(".uno:StyleUpdateByExample", sTextDoc);
pMenu->InsertItem( SID_STYLE_UPDATE_BY_EXAMPLE, sLabel );
pMenu->SetHelpId(SID_STYLE_UPDATE_BY_EXAMPLE, HID_TEMPLDLG_UPDATEBYEXAMPLE);
sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(".uno:LoadStyles", sTextDoc);
pMenu->InsertItem( SID_TEMPLATE_LOAD, sLabel );
pMenu->SetHelpId(SID_TEMPLATE_LOAD, ".uno:LoadStyles");
pMenu->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, MenuSelectHdl));
pMenu->Execute( pBox,
pBox->GetItemRect(nEntry),
PopupMenuFlags::ExecuteDown );
pBox->EndSelection();
pBox->Invalidate();
}
}
IMPL_LINK( SfxTemplateDialog_Impl, MenuSelectHdl, Menu*, pMenu, bool)
{
sal_uInt16 nMenuId = pMenu->GetCurItemId();
ActionSelect(nMenuId);
return false;
}
void SfxCommonTemplateDialog_Impl::SetFamily(SfxStyleFamily const nFamily)
{
sal_uInt16 const nId(SfxTemplate::SfxFamilyIdToNId(nFamily));
assert((0 < nId && nId <= MAX_FAMILIES) || 0xffff == nId);
if ( nId != nActFamily )
{
if ( nActFamily != 0xFFFF )
CheckItem( nActFamily, false );
nActFamily = nId;
if ( nId != 0xFFFF )
bUpdateFamily = true;
}
}
void SfxCommonTemplateDialog_Impl::UpdateFamily_Impl()
{
bUpdateFamily = false;
SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl();
SfxViewFrame *pViewFrame = pDispat->GetFrame();
SfxObjectShell *pDocShell = pViewFrame->GetObjectShell();
SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool;
pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr;
if ( pOldStyleSheetPool != pStyleSheetPool )
{
if ( pOldStyleSheetPool )
EndListening(*pOldStyleSheetPool);
if ( pStyleSheetPool )
StartListening(*pStyleSheetPool);
}
bWaterDisabled = false;
bCanNew = pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1;
bTreeDrag = true;
bUpdateByExampleDisabled = false;
if (pStyleSheetPool)
{
if (!pTreeBox->IsVisible())
UpdateStyles_Impl(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
else
{
UpdateStyles_Impl(StyleFlags::UpdateFamily);
FillTreeBox();
}
}
InvalidateBindings();
if (IsCheckedItem(SID_STYLE_WATERCAN) &&
// only if that area is allowed
nullptr != pFamilyState[nActFamily - 1])
{
Execute_Impl(SID_STYLE_APPLY,
GetSelectedEntry(),
OUString(),
static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()));
}
}
void SfxCommonTemplateDialog_Impl::ReplaceUpdateButtonByMenu()
{
//does nothing
}
DropToolBox_Impl::DropToolBox_Impl(vcl::Window* pParent, SfxTemplateDialog_Impl* pTemplateDialog) :
ToolBox(pParent),
DropTargetHelper(this),
rParent(*pTemplateDialog)
{
}
sal_Int8 DropToolBox_Impl::AcceptDrop( const AcceptDropEvent& rEvt )
{
sal_Int8 nReturn = DND_ACTION_NONE;
sal_uInt16 nItemId = GetItemId( rEvt.maPosPixel );
if(USHRT_MAX != nItemId && !IsItemChecked( nItemId ))
{
SetCurItemId(nItemId);
GetSelectHdl().Call(this);
}
// special case: page styles are allowed to create new styles by example
// but not allowed to be created by drag and drop
if ( nItemId != SfxTemplate::SfxFamilyIdToNId( SfxStyleFamily::Page )&&
IsDropFormatSupported( SotClipboardFormatId::OBJECTDESCRIPTOR ) &&
!rParent.bNewByExampleDisabled )
{
nReturn = DND_ACTION_COPY;
}
return nReturn;
}
sal_Int8 DropToolBox_Impl::ExecuteDrop( const ExecuteDropEvent& rEvt )
{
return rParent.aFmtLb->ExecuteDrop(rEvt);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.
↑ V560 A part of conditional expression is always true: pStyleSheetPool.
↑ V522 There might be dereferencing of a potential null pointer 'pFilterItem'.