Files
odfstudio/include/svl/style.hxx
T
Paolo Benvenuto 52010fde09 tdf#89826 Add interactive property chips to style Organizer tab
The Organizer tab of the style dialog now shows interactive "chips"
for each property that differs from the parent style. Each chip
displays the property name and value, and includes an X button to
reset that property back to parent inheritance. All properties
are shown full text, no ellipsis.

Properties are grouped by tab page (Font, Font effects, etc.)
and displayed in a scrollable area. A View/Edit toggle lets the
user switch between the traditional description text and the
interactive chip view.

Implementation summary:

- New PropertyChip and PropertyCategoryRow widgets (sfx2) with
  corresponding .ui files for the chip layout.

- SfxStyleSheetBase::GetItemPresentation() virtual method returns
  per-property presentation strings, overridden in SwDocStyleSheet
  and ScStyleSheet for module-specific attributes.

- SfxItemSet access tracker mechanism to automatically map WhichIds
  to their owning tab pages via BuildWhichToTabMap().

- SfxTabDialogController::InvalidateItem() propagates chip resets
  to the output set and affected tab pages.

- SwDocStyleSheet::ResetItems() uses SwDoc::ResetAttrAtFormat() to
  ensure proper undo support in Writer.

- SfxStyleDialogController::Ok() clears invalidated items from the
  style's item set on dialog confirmation.

- SvxAsianTabPage now calls SetExchangeSupport() and implements
  DeactivatePage() so its items are properly tracked.

- Access tracker ignore guards in SvxCharBasePage::SetPrevFontWidthScale
  and SvxTransparenceTabPage::InitPreview to avoid false positives
  from preview-only item access.

Includes a UITest for Writer (sw/qa/uitest/ui/fmtui/tdf89826.py)
that creates a child style, modifies a property, removes it via
chip, and verifies inheritance is restored including undo.

A Calc UITest is not included because the style edit dialog in Calc
is opened asynchronously (ScTabViewShell::ExecuteStyleEdit) and the
UITest framework's execute_dialog_through_command cannot capture it.
The Calc functionality has been verified manually. A Calc UITest can
be added once the framework supports async style dialogs.

Change-Id: Ia764405798c212fe5340bba254f2ff6ac62365f6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199318
Reviewed-by: Heiko Tietze <heiko.tietze@documentfoundation.org>
Tested-by: Jenkins
2026-02-28 15:52:40 +01:00

388 lines
14 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 .
*/
#ifndef INCLUDED_SVL_STYLE_HXX
#define INCLUDED_SVL_STYLE_HXX
#include <config_options.h>
#include <com/sun/star/style/XStyle.hpp>
#include <cppuhelper/implbase.hxx>
#include <svl/svldllapi.h>
#include <svl/hint.hxx>
#include <svl/lstner.hxx>
#include <svl/SfxBroadcaster.hxx>
#include <svl/stylesheetuser.hxx>
#include <o3tl/typed_flags_set.hxx>
#include <memory>
#include <optional>
#include <vector>
#include <utility>
// This is used as a flags enum in sw/, but only there,
// so I don't pull in o3tl::typed_flags here
enum class SfxStyleFamily {
None = 0x00,
Char = 0x01,
Para = 0x02,
Frame = 0x04,
Page = 0x08,
Pseudo = 0x10,
Table = 0x20,
Cell = 0x40,
All = 0x7fff
};
enum class SfxStyleSearchBits {
// sc/calc styles
ScStandard = 0x0001,
// sw/writer styles
SwText = 0x0001,
SwChapter = 0x0002,
SwList = 0x0004,
SwIndex = 0x0008,
SwExtra = 0x0010,
SwHtml = 0x0020,
SwCondColl = 0x0040,
Auto = 0x0000, ///< automatic: flags from application
Favourite = 0x0100, ///< styles selected to be always visible (search mask)
Hidden = 0x0200, ///< hidden styles (search mask)
ReadOnly = 0x2000, ///< readonly styles (search mask)
Used = 0x4000, ///< used styles (search mask)
UserDefined = 0x8000, ///< user defined styles (search mask)
AllVisible = 0xe07f, ///< all visible styles
All = 0xe27f, ///< all styles
};
namespace o3tl {
template<> struct typed_flags<SfxStyleSearchBits> : is_typed_flags<SfxStyleSearchBits, 0xe37f> {};
}
class SfxItemSet;
class SfxItemPool;
class SfxStyleSheetBasePool;
namespace svl { class IndexedStyleSheets; }
typedef struct _xmlTextWriter* xmlTextWriterPtr;
namespace rtl { template <class reference_type> class Reference; }
enum class MapUnit : sal_uInt8;
/*
Everyone changing instances of SfxStyleSheetBasePool or SfxStyleSheetBase
must broadcast this using <SfxStyleSheetBasePool::GetBroadcaster()> broadcasts.
The class <SfxStyleSheetHint> is used for this, it contains an Action-Id and a
pointer to the <SfxStyleSheetBase>. The actions are:
#define SfxHintId::StyleSheetCreated // style is created
#define SfxHintId::StyleSheetModified // style is modified
#define SfxHintId::StyleSheetChanged // style is replaced
#define SfxHintId::StyleSheetErased // style is deleted
The following methods already broadcast themself
SfxSimpleHint(SfxHintId::Dying) from:
SfxStyleSheetBasePool::~SfxStyleSheetBasePool()
SfxStyleSheetHint( SfxHintId::StyleSheetCreated, *p ) from:
SfxStyleSheetBasePool::Make( const String& rName,
SfxStyleFamily eFam, SfxStyleSearchBits mask)
SfxStyleSheetHint( SfxHintId::StyleSheetChanged, *pNew ) from:
SfxStyleSheetBasePool::Add( SfxStyleSheetBase& rSheet )
SfxStyleSheetHint( SfxHintId::StyleSheetErased, *p ) from:
SfxStyleSheetBasePool::Erase( SfxStyleSheetBase* p )
SfxStyleSheetBasePool::Clear()
*/
// avoid LNK2005 duplicate WeakImplHelper definitions with MSVC
class SAL_DLLPUBLIC_TEMPLATE SfxStyleSheetBase_Base : public cppu::WeakImplHelper<>
{
};
class SVL_DLLPUBLIC SfxStyleSheetBase : public SfxStyleSheetBase_Base
{
private:
friend class SfxStyleSheetBasePool;
protected:
SfxStyleSheetBasePool* m_pPool; // related pool
SfxStyleFamily nFamily;
OUString aName, aParent, aFollow;
OUString aHelpFile; // name of the help file
SfxItemSet* pSet; // ItemSet
SfxStyleSearchBits nMask; // Flags
sal_uInt32 nHelpId; // help ID
bool bMySet; // sal_True: delete Set in dtor
bool bHidden;
SfxStyleSheetBase( const OUString&, SfxStyleSheetBasePool*, SfxStyleFamily eFam,
SfxStyleSearchBits mask, const OUString& rParentStyleSheetName );
SfxStyleSheetBase( const SfxStyleSheetBase& );
virtual ~SfxStyleSheetBase() override;
public:
// returns the internal name of this style
const OUString& GetName() const;
// sets the internal name of this style.
//
// If the name of a style is changed, then the styles container needs to be
// reindexed (see IndexedStyleSheets). If you set bReindexNow to false to
// defer that indexing, then you must call the Reindex manually on the
// SfxStyleSheetBasePool parent.
virtual bool SetName(const OUString& rNewName, bool bReindexNow = true);
virtual const OUString& GetParent() const;
virtual bool SetParent( const OUString& );
virtual const OUString& GetFollow() const;
virtual bool SetFollow( const OUString& );
virtual bool HasFollowSupport() const; // Default true
virtual bool HasParentSupport() const; // Default true
virtual bool HasClearParentSupport() const; // Default false
virtual bool IsUsed() const; // Default true
virtual OUString GetDescription( MapUnit eMetric );
/// Returns individual property presentations for building UI chips
/// Each pair contains: WhichId and presentation string
virtual std::vector<std::pair<sal_uInt16, OUString>> GetItemPresentation(
MapUnit eMetric, const SfxItemSet* pWorkingSet = nullptr);
virtual OUString GetUsedBy() { return OUString(); }
SfxStyleSheetBasePool* GetPool() { return m_pPool; }
SfxStyleFamily GetFamily() const { return nFamily; }
SfxStyleSearchBits GetMask() const { return nMask; }
void SetMask( SfxStyleSearchBits mask) { nMask = mask; }
bool IsUserDefined() const
{ return bool( nMask & SfxStyleSearchBits::UserDefined); }
virtual bool IsHidden() const { return bHidden; }
virtual void SetHidden( bool bValue );
virtual sal_uInt32 GetHelpId( OUString& rFile );
virtual void SetHelpId( const OUString& r, sal_uInt32 nId );
// Spotlight Id, @return -1 for style not in use
virtual sal_Int32 GetSpotlightId();
virtual SfxItemSet& GetItemSet();
/// Due to writer's usual lack of sanity this is a separate function for
/// preview only; it shall not create the style in case it does not exist.
/// If the style has parents, it is _not_ required that the returned item
/// set has parents (i.e. use it for display purposes only).
virtual std::optional<SfxItemSet> GetItemSetForPreview();
/// Fix for expensive dynamic_cast
virtual bool isScStyleSheet() const { return false; }
void dumpAsXml(xmlTextWriterPtr pWriter) const;
};
/* Class to iterate and search on a SfxStyleSheetBasePool */
class SVL_DLLPUBLIC SfxStyleSheetIterator
{
public:
/** Constructor.
* The iterator will only iterate over style sheets which have the family \p eFam
*/
SfxStyleSheetIterator(const SfxStyleSheetBasePool *pBase,
SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All );
SfxStyleSearchBits GetSearchMask() const;
SfxStyleFamily GetSearchFamily() const { return nSearchFamily; }
virtual sal_Int32 Count();
virtual SfxStyleSheetBase *operator[](sal_Int32 nIdx);
virtual SfxStyleSheetBase* First();
virtual SfxStyleSheetBase* Next();
virtual SfxStyleSheetBase* Find(const OUString& rStr);
virtual ~SfxStyleSheetIterator();
bool SearchUsed() const { return bSearchUsed; }
protected:
const SfxStyleSheetBasePool* pBasePool;
SfxStyleFamily nSearchFamily;
SfxStyleSearchBits nMask;
private:
SVL_DLLPRIVATE bool IsTrivialSearch() const;
SfxStyleSheetBase* pCurrentStyle;
sal_Int32 mnCurrentPosition;
bool bSearchUsed;
friend class SfxStyleSheetBasePool;
};
class SfxStyleSheetBasePool_Impl;
// avoid LNK2005 duplicate WeakImplHelper definitions with MSVC
class SAL_DLLPUBLIC_TEMPLATE SfxStyleSheetBasePool_Base : public cppu::WeakImplHelper<>
{
};
typedef struct _xmlTextWriter* xmlTextWriterPtr;
class SVL_DLLPUBLIC SfxStyleSheetBasePool : public SfxBroadcaster, public SfxStyleSheetBasePool_Base
{
friend class SfxStyleSheetIterator;
friend class SfxStyleSheetBase;
std::unique_ptr<SfxStyleSheetBasePool_Impl> pImpl;
SfxStyleSheetIterator& GetIterator_Impl(SfxStyleFamily eFamily, SfxStyleSearchBits eMask);
protected:
SfxStyleSheetIterator* GetCachedIterator();
SfxItemPool& rPool;
void ChangeParent(std::u16string_view rOld, const OUString& rNew, SfxStyleFamily eFamily, bool bVirtual = true);
virtual rtl::Reference<SfxStyleSheetBase> Create( const OUString&, SfxStyleFamily, SfxStyleSearchBits, const OUString& rParentStyleSheetName );
virtual rtl::Reference<SfxStyleSheetBase> Create( const SfxStyleSheetBase& );
virtual ~SfxStyleSheetBasePool() override;
void StoreStyleSheet(const rtl::Reference< SfxStyleSheetBase >&);
/** Obtain the indexed style sheets.
*/
const svl::IndexedStyleSheets&
GetIndexedStyleSheets() const;
SfxStyleSheetBase* GetStyleSheetByPositionInIndex(unsigned pos);
public:
SfxStyleSheetBasePool( SfxItemPool& );
SfxStyleSheetBasePool( const SfxStyleSheetBasePool& );
SfxItemPool& GetPool() { return rPool;}
const SfxItemPool& GetPool() const { return rPool;}
virtual std::unique_ptr<SfxStyleSheetIterator> CreateIterator(SfxStyleFamily, SfxStyleSearchBits nMask = SfxStyleSearchBits::All);
virtual SfxStyleSheetBase& Make(const OUString&,
SfxStyleFamily eFam,
SfxStyleSearchBits nMask = SfxStyleSearchBits::All,
const OUString& rParentStyleSheetName = u""_ustr);
virtual void Remove( SfxStyleSheetBase* );
void Insert( SfxStyleSheetBase* );
void Clear();
SfxStyleSheetBasePool& operator=( const SfxStyleSheetBasePool& );
SfxStyleSheetBasePool& operator+=( const SfxStyleSheetBasePool& );
SfxStyleSheetBase* First(SfxStyleFamily eFamily, SfxStyleSearchBits eMask = SfxStyleSearchBits::All);
SfxStyleSheetBase* Next();
virtual SfxStyleSheetBase* Find( const OUString&, SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All );
void Reindex();
void ReindexOnNameChange(const SfxStyleSheetBase& style, const OUString& rOldName, const OUString& rNewName);
/** Add a style sheet.
* Not an actual public function. Do not call it from non-subclasses.
*/
void Add( const SfxStyleSheetBase& );
void dumpAsXml(xmlTextWriterPtr pWriter) const;
};
class SVL_DLLPUBLIC SfxStyleSheet: public SfxStyleSheetBase,
public SfxListener, public SfxBroadcaster, public svl::StyleSheetUser
{
public:
SfxStyleSheet( const OUString&, const SfxStyleSheetBasePool&, SfxStyleFamily,
SfxStyleSearchBits, const OUString& rParentStyleSheetName = u""_ustr );
SfxStyleSheet( const SfxStyleSheet& );
virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
virtual bool isUsedByModel() const override final;
virtual bool SetParent( const OUString& ) override;
virtual bool IsSfxStyleSheet() const override final;
protected:
virtual ~SfxStyleSheet() override;
};
class SVL_DLLPUBLIC SfxStyleSheetPool: public SfxStyleSheetBasePool
{
protected:
using SfxStyleSheetBasePool::Create;
virtual rtl::Reference<SfxStyleSheetBase> Create(const OUString&, SfxStyleFamily,
SfxStyleSearchBits mask, const OUString& rParentStyleSheetName) override;
public:
SfxStyleSheetPool( SfxItemPool const& );
};
class SVL_DLLPUBLIC SfxStyleSheetPoolHint final : public SfxHint
{
public:
SfxStyleSheetPoolHint() : SfxHint(SfxHintId::SfxStyleSheetPool) {}
};
class SVL_DLLPUBLIC SfxStyleSheetHint: public SfxHint
{
SfxStyleSheetBase* pStyleSh;
public:
SfxStyleSheetHint( SfxHintId, SfxStyleSheetBase& );
SfxStyleSheetBase* GetStyleSheet() const
{ return pStyleSh; }
};
class UNLESS_MERGELIBS(SVL_DLLPUBLIC) SfxStyleSheetModifiedHint final : public SfxStyleSheetHint
{
OUString aName;
public:
SfxStyleSheetModifiedHint( OUString aOld,
SfxStyleSheetBase& );
const OUString& GetOldName() const { return aName; }
};
class SVL_DLLPUBLIC SfxUnoStyleSheet : public cppu::ImplInheritanceHelper<SfxStyleSheet, css::style::XStyle>
{
public:
SfxUnoStyleSheet( const OUString& _rName, const SfxStyleSheetBasePool& _rPool, SfxStyleFamily _eFamily,
SfxStyleSearchBits _nMask,
const OUString& rParentStyleSheetName = u""_ustr );
static SfxUnoStyleSheet* getUnoStyleSheet( const css::uno::Reference< css::style::XStyle >& xStyle );
};
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */