summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLászló Németh <nemeth@numbertext.org>2022-06-01 16:38:28 +0200
committerLászló Németh <nemeth@numbertext.org>2022-06-02 09:57:39 +0200
commit7a1d4b7d1db93ca1f541856a8d00d621d50e7bd6 (patch)
tree62c14075edae32b552caf8688623d11327bc17cc
parent6585fe3fc154c518d657202295a2c5214de55b56 (diff)
tdf#149420 sw offapi xmloff: add hyphenation zone
Add hyphenation zone support, i.e. allow the specified amount of extra space in lines instead of forcing hyphenation. It's for limiting hyphenation, used especially with not justified paragraph alignment. Note: this is an OOXML interoperability feature, used also in DTP software and CSS. * Add checkbox to Text Flow in paragraph dialog * Store property in paragraph model (com::sun::star::style::ParagraphProperties::ParaHyphenationZone) * Add ODF import/export * Add ODF unit test * Add layout test Note: extend SvxHyphenZoneItem::GetPresentation() with missing No CAPS and No last word hyphenation options. Note: fix OSL_ENSURE condition in SwTextFormatInfo::GetHyphValues(). Follow-up to commit 29359fc15c435cec17987fd6221ab6833d38746e "tdf#149324 sw offapi xmloff: add option to not hyphenate short words". Change-Id: Ib8eff6ea98a9aa5ca6cb9d17faa0bbb789687ce9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135247 Tested-by: Jenkins Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r--cui/source/inc/paragrph.hxx1
-rw-r--r--cui/source/tabpages/paragrph.cxx28
-rw-r--r--cui/uiconfig/ui/textflowpage.ui48
-rw-r--r--editeng/source/items/paraitem.cxx43
-rw-r--r--include/editeng/editrids.hrc5
-rw-r--r--include/editeng/hyphenzoneitem.hxx8
-rw-r--r--include/editeng/memberids.h1
-rw-r--r--include/unotools/linguprops.hxx2
-rw-r--r--include/xmloff/xmltoken.hxx1
-rw-r--r--offapi/com/sun/star/style/ParagraphProperties.idl7
-rw-r--r--schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng12
-rw-r--r--svx/sdi/svxitems.sdi1
-rw-r--r--sw/inc/inspectorproperties.hrc1
-rw-r--r--sw/inc/unoprnms.hxx1
-rw-r--r--sw/qa/extras/layout/data/tdf149420.odtbin0 -> 38885 bytes
-rw-r--r--sw/qa/extras/layout/layout.cxx15
-rw-r--r--sw/qa/extras/odfexport/data/tdf149420.odtbin0 -> 38885 bytes
-rw-r--r--sw/qa/extras/odfexport/odfexport.cxx7
-rw-r--r--sw/qa/uitest/styleInspector/styleInspector.py20
-rw-r--r--sw/qa/uitest/styleInspector/tdf137513.py2
-rw-r--r--sw/source/core/text/guess.cxx72
-rw-r--r--sw/source/core/text/inftxt.cxx18
-rw-r--r--sw/source/core/unocore/unomapproperties.hxx2
-rw-r--r--sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx1
-rw-r--r--xmloff/source/core/xmltoken.cxx1
-rw-r--r--xmloff/source/text/txtprmap.cxx1
-rw-r--r--xmloff/source/token/tokens.txt1
27 files changed, 257 insertions, 42 deletions
diff --git a/cui/source/inc/paragrph.hxx b/cui/source/inc/paragrph.hxx
index f0c56775fc2c..3947c14d10c8 100644
--- a/cui/source/inc/paragrph.hxx
+++ b/cui/source/inc/paragrph.hxx
@@ -233,6 +233,7 @@ private:
std::unique_ptr<weld::Label> m_xMaxHyphenLabel;
std::unique_ptr<weld::SpinButton> m_xMaxHyphenEdit;
std::unique_ptr<weld::SpinButton> m_xMinWordLength;
+ std::unique_ptr<SvxRelativeField> m_xHyphenZone;
// pagebreak
std::unique_ptr<weld::CheckButton> m_xPageBreakBox;
diff --git a/cui/source/tabpages/paragrph.cxx b/cui/source/tabpages/paragrph.cxx
index 2d651fedae6a..3fa77d9fb791 100644
--- a/cui/source/tabpages/paragrph.cxx
+++ b/cui/source/tabpages/paragrph.cxx
@@ -1356,7 +1356,8 @@ bool SvxExtParagraphTabPage::FillItemSet( SfxItemSet* rOutSet )
m_xExtHyphenBeforeBox->get_value_changed_from_saved() ||
m_xExtHyphenAfterBox->get_value_changed_from_saved() ||
m_xMaxHyphenEdit->get_value_changed_from_saved() ||
- m_xMinWordLength->get_value_changed_from_saved() )
+ m_xMinWordLength->get_value_changed_from_saved() ||
+ m_xHyphenZone->get_value_changed_from_saved() )
{
SvxHyphenZoneItem aHyphen(
static_cast<const SvxHyphenZoneItem&>(GetItemSet().Get( _nWhich )) );
@@ -1372,6 +1373,11 @@ bool SvxExtParagraphTabPage::FillItemSet( SfxItemSet* rOutSet )
}
aHyphen.GetMaxHyphens() = static_cast<sal_uInt8>(m_xMaxHyphenEdit->get_value());
+ SfxItemPool* pPool = GetItemSet().GetPool();
+ DBG_ASSERT( pPool, "Where is the pool?" );
+ MapUnit eUnit = pPool->GetMetric( _nWhich );
+ aHyphen.GetTextHyphenZone() = static_cast<sal_uInt16>(m_xHyphenZone->GetCoreValue(eUnit));
+
if ( !pOld ||
*static_cast<const SvxHyphenZoneItem*>(pOld) != aHyphen ||
m_xHyphenBox->get_state_changed_from_saved())
@@ -1560,6 +1566,17 @@ bool SvxExtParagraphTabPage::FillItemSet( SfxItemSet* rOutSet )
}
void SvxExtParagraphTabPage::Reset( const SfxItemSet* rSet )
{
+ SfxItemPool* pPool = rSet->GetPool();
+ DBG_ASSERT( pPool, "Where is the pool?" );
+
+ // adjust metric
+ FieldUnit eFUnit = GetModuleFieldUnit( *rSet );
+
+ bool bApplyCharUnit = GetApplyCharUnit( *rSet );
+
+ if( SvtCJKOptions::IsAsianTypographyEnabled() && bApplyCharUnit )
+ eFUnit = FieldUnit::CHAR;
+
sal_uInt16 _nWhich = GetWhich( SID_ATTR_PARA_HYPHENZONE );
SfxItemState eItemState = rSet->GetItemState( _nWhich );
@@ -1580,6 +1597,8 @@ void SvxExtParagraphTabPage::Reset( const SfxItemSet* rSet )
m_xExtHyphenAfterBox->set_value(rHyphen.GetMinTrail());
m_xMaxHyphenEdit->set_value(rHyphen.GetMaxHyphens());
m_xMinWordLength->set_value(rHyphen.GetMinWordLength());
+ m_xHyphenZone->SetFieldUnit(eFUnit);
+ m_xHyphenZone->SetMetricValue(rHyphen.GetTextHyphenZone(), MapUnit::MapTwip);
}
else
{
@@ -1597,6 +1616,7 @@ void SvxExtParagraphTabPage::Reset( const SfxItemSet* rSet )
m_xMaxHyphenLabel->set_sensitive(bEnable);
m_xMaxHyphenEdit->set_sensitive(bEnable);
m_xMinWordLength->set_sensitive(bEnable);
+ m_xHyphenZone->set_sensitive(bEnable);
switch (rSet->GetItemState(SID_ATTR_PARA_PAGENUM))
{
@@ -1857,6 +1877,11 @@ void SvxExtParagraphTabPage::ChangesApplied()
m_xExtHyphenAfterBox->set_value(m_xExtHyphenAfterBox->get_value());
m_xMaxHyphenEdit->set_value(m_xMaxHyphenEdit->get_value());
m_xMinWordLength->set_value(m_xMinWordLength->get_value());
+ SfxItemPool* pPool = GetItemSet().GetPool();
+ DBG_ASSERT( pPool, "Where is the pool?" );
+ FieldUnit eUnit =
+ MapToFieldUnit( pPool->GetMetric( GetWhich( SID_ATTR_PARA_HYPHENZONE ) ) );
+ m_xHyphenZone->set_value(m_xHyphenZone->get_value(eUnit), eUnit);
m_xPageBreakBox->save_state();
m_xBreakPositionLB->save_value();
m_xBreakTypeLB->save_value();
@@ -1908,6 +1933,7 @@ SvxExtParagraphTabPage::SvxExtParagraphTabPage(weld::Container* pPage, weld::Dia
, m_xMaxHyphenLabel(m_xBuilder->weld_label("labelMaxNum"))
, m_xMaxHyphenEdit(m_xBuilder->weld_spin_button("spinMaxNum"))
, m_xMinWordLength(m_xBuilder->weld_spin_button("spinMinLen"))
+ , m_xHyphenZone(new SvxRelativeField(m_xBuilder->weld_metric_spin_button("spinHyphenZone", FieldUnit::CM)))
//Page break
, m_xPageBreakBox(m_xBuilder->weld_check_button("checkInsert"))
, m_xBreakTypeFT(m_xBuilder->weld_label("labelType"))
diff --git a/cui/uiconfig/ui/textflowpage.ui b/cui/uiconfig/ui/textflowpage.ui
index 89ac8a3a22dd..496f22f05619 100644
--- a/cui/uiconfig/ui/textflowpage.ui
+++ b/cui/uiconfig/ui/textflowpage.ui
@@ -48,6 +48,11 @@
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
+ <object class="GtkAdjustment" id="adjustment8">
+ <property name="upper">55.88</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
<!-- n-columns=1 n-rows=1 -->
<object class="GtkGrid" id="TextFlowPage">
<property name="visible">True</property>
@@ -258,6 +263,49 @@
<property name="width">2</property>
</packing>
</child>
+ <child>
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="gridHyphenZone">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+ <property name="margin-start">12</property>
+ <property name="margin-top">6</property>
+ <child>
+ <object class="GtkSpinButton" id="spinHyphenZone">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ <property name="truncate_multiline">True</property>
+ <property name="adjustment">adjustment8</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="labelHyphenZone">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes" context="textflowpage|labelHyphenZone">Hyphenation _zone:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">spinHyphenZone</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">7</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
</object>
</child>
<child type="label">
diff --git a/editeng/source/items/paraitem.cxx b/editeng/source/items/paraitem.cxx
index 202341caa949..9368dfdf3c2a 100644
--- a/editeng/source/items/paraitem.cxx
+++ b/editeng/source/items/paraitem.cxx
@@ -559,7 +559,8 @@ SvxHyphenZoneItem::SvxHyphenZoneItem( const bool bHyph, const sal_uInt16 nId ) :
nMinLead(0),
nMinTrail(0),
nMaxHyphens(255),
- nMinWordLength(0)
+ nMinWordLength(0),
+ nTextHyphenZone(0)
{
}
@@ -590,6 +591,9 @@ bool SvxHyphenZoneItem::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) con
case MID_HYPHEN_MIN_WORD_LENGTH:
rVal <<= static_cast<sal_Int16>(nMinWordLength);
break;
+ case MID_HYPHEN_ZONE:
+ rVal <<= static_cast<sal_Int16>(nTextHyphenZone);
+ break;
}
return true;
}
@@ -629,6 +633,9 @@ bool SvxHyphenZoneItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
case MID_HYPHEN_MIN_WORD_LENGTH:
nMinWordLength = static_cast<sal_uInt8>(nNewVal);
break;
+ case MID_HYPHEN_ZONE:
+ nTextHyphenZone = nNewVal;
+ break;
}
return true;
}
@@ -646,7 +653,8 @@ bool SvxHyphenZoneItem::operator==( const SfxPoolItem& rAttr ) const
&& rItem.nMinLead == nMinLead
&& rItem.nMinTrail == nMinTrail
&& rItem.nMaxHyphens == nMaxHyphens
- && rItem.nMinWordLength == nMinWordLength );
+ && rItem.nMinWordLength == nMinWordLength
+ && rItem.nTextHyphenZone == nTextHyphenZone );
}
SvxHyphenZoneItem* SvxHyphenZoneItem::Clone( SfxItemPool * ) const
@@ -657,9 +665,9 @@ SvxHyphenZoneItem* SvxHyphenZoneItem::Clone( SfxItemPool * ) const
bool SvxHyphenZoneItem::GetPresentation
(
SfxItemPresentation ePres,
- MapUnit /*eCoreUnit*/,
- MapUnit /*ePresUnit*/,
- OUString& rText, const IntlWrapper&
+ MapUnit eCoreUnit,
+ MapUnit ePresUnit,
+ OUString& rText, const IntlWrapper& rIntl
) const
{
OUString cpDelimTmp(cpDelim);
@@ -680,7 +688,16 @@ bool SvxHyphenZoneItem::GetPresentation
OUString::number( nMinLead ) + cpDelimTmp +
OUString::number( nMinTrail ) + cpDelimTmp +
OUString::number( nMaxHyphens ) + cpDelimTmp +
- OUString::number( nMinWordLength );
+ OUString::number( nMinWordLength ) + cpDelimTmp +
+ GetMetricText( nTextHyphenZone, eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId(GetMetricId(ePresUnit));
+
+ if ( bNoCapsHyphenation )
+ rText += cpDelimTmp + EditResId(RID_SVXITEMS_HYPHEN_NO_CAPS_TRUE);
+
+ if ( bNoLastWordHyphenation )
+ rText += cpDelimTmp + EditResId(RID_SVXITEMS_HYPHEN_LAST_WORD_TRUE);
+
return true;
}
case SfxItemPresentation::Complete:
@@ -703,6 +720,20 @@ bool SvxHyphenZoneItem::GetPresentation
EditResId(RID_SVXITEMS_HYPHEN_MAX).replaceAll("%1", OUString::number(nMaxHyphens)) +
cpDelimTmp +
EditResId(RID_SVXITEMS_HYPHEN_MINWORDLEN).replaceAll("%1", OUString::number(nMinWordLength));
+
+ if ( nTextHyphenZone > 0 )
+ {
+ rText += cpDelimTmp + EditResId(RID_SVXITEMS_HYPHEN_ZONE) +
+ GetMetricText( nTextHyphenZone, eCoreUnit, ePresUnit, &rIntl ) +
+ " " + EditResId(GetMetricId(ePresUnit));
+ }
+
+ if ( bNoCapsHyphenation )
+ rText += cpDelimTmp + EditResId(RID_SVXITEMS_HYPHEN_NO_CAPS_TRUE);
+
+ if ( bNoLastWordHyphenation )
+ rText += cpDelimTmp + EditResId(RID_SVXITEMS_HYPHEN_LAST_WORD_TRUE);
+
return true;
}
default: ;//prevent warning
diff --git a/include/editeng/editrids.hrc b/include/editeng/editrids.hrc
index 57342e7c1deb..31ac07a1d22b 100644
--- a/include/editeng/editrids.hrc
+++ b/include/editeng/editrids.hrc
@@ -230,7 +230,10 @@
#define RID_SVXITEMS_HYPHEN_MINLEAD NC_("RID_SVXITEMS_HYPHEN_MINLEAD", "%1 characters at end of line")
#define RID_SVXITEMS_HYPHEN_MINTRAIL NC_("RID_SVXITEMS_HYPHEN_MINTRAIL", "%1 characters at beginning of line")
#define RID_SVXITEMS_HYPHEN_MAX NC_("RID_SVXITEMS_HYPHEN_MAX", "%1 hyphens")
-#define RID_SVXITEMS_HYPHEN_MINWORDLEN NC_("RID_SVXITEMS_HYPHEN_MINWORDLEN", "Words with at least %1 characters")
+#define RID_SVXITEMS_HYPHEN_NO_CAPS_TRUE NC_("RID_SVXITEMS_HYPHEN_NO_CAPS_TRUE", "Not hyphenated CAPS")
+#define RID_SVXITEMS_HYPHEN_LAST_WORD_TRUE NC_("RID_SVXITEMS_HYPHEN_NO_CAPS_FALSE", "Not hyphenated last word")
+#define RID_SVXITEMS_HYPHEN_MINWORDLEN NC_("RID_SVXITEMS_HYPHEN_MINWORDLEN", "%1 characters in words")
+#define RID_SVXITEMS_HYPHEN_ZONE NC_("RID_SVXITEMS_HYPHEN_ZONE", "Hyphenation zone ")
#define RID_SVXITEMS_PAGEMODEL_COMPLETE NC_("RID_SVXITEMS_PAGEMODEL_COMPLETE", "Page Style: ")
#define RID_SVXITEMS_KERNING_COMPLETE NC_("RID_SVXITEMS_KERNING_COMPLETE", "Kerning ")
#define RID_SVXITEMS_KERNING_EXPANDED NC_("RID_SVXITEMS_KERNING_EXPANDED", "locked ")
diff --git a/include/editeng/hyphenzoneitem.hxx b/include/editeng/hyphenzoneitem.hxx
index b1ec7cba3a45..7104d2d7db58 100644
--- a/include/editeng/hyphenzoneitem.hxx
+++ b/include/editeng/hyphenzoneitem.hxx
@@ -38,8 +38,9 @@ class EDITENG_DLLPUBLIC SvxHyphenZoneItem final : public SfxPoolItem
bool bNoLastWordHyphenation : 1;
sal_uInt8 nMinLead;
sal_uInt8 nMinTrail;
- sal_uInt8 nMaxHyphens;
- sal_uInt8 nMinWordLength;
+ sal_uInt8 nMaxHyphens; // max. consecutive lines with hyphenation
+ sal_uInt8 nMinWordLength; // hyphenate only words with at least nMinWordLength characters
+ sal_uInt16 nTextHyphenZone; // don't force hyphenation at line end, allow this extra white space
public:
static SfxPoolItem* CreateDefault();
@@ -81,6 +82,9 @@ public:
sal_uInt8 &GetMinWordLength() { return nMinWordLength; }
sal_uInt8 GetMinWordLength() const { return nMinWordLength; }
+
+ sal_uInt16 &GetTextHyphenZone() { return nTextHyphenZone; }
+ sal_uInt16 GetTextHyphenZone() const { return nTextHyphenZone; }
};
#endif
diff --git a/include/editeng/memberids.h b/include/editeng/memberids.h
index 4ec470f31db7..9b89ebafaefb 100644
--- a/include/editeng/memberids.h
+++ b/include/editeng/memberids.h
@@ -49,6 +49,7 @@
#define MID_HYPHEN_NO_CAPS 4
#define MID_HYPHEN_NO_LAST_WORD 5
#define MID_HYPHEN_MIN_WORD_LENGTH 6
+#define MID_HYPHEN_ZONE 7
// SvxBoxInfoItem
#define MID_HORIZONTAL 1
diff --git a/include/unotools/linguprops.hxx b/include/unotools/linguprops.hxx
index adede0b91777..971c0280444c 100644
--- a/include/unotools/linguprops.hxx
+++ b/include/unotools/linguprops.hxx
@@ -42,6 +42,7 @@ inline constexpr OUStringLiteral UPN_HYPH_MIN_TRAILING = u"HyphMin
inline constexpr OUStringLiteral UPN_HYPH_MIN_WORD_LENGTH = u"HyphMinWordLength";
inline constexpr OUStringLiteral UPN_HYPH_NO_CAPS = u"HyphNoCaps";
inline constexpr OUStringLiteral UPN_HYPH_NO_LAST_WORD = u"HyphNoLastWord";
+inline constexpr OUStringLiteral UPN_HYPH_ZONE = u"HyphZone";
// UNO property names for Lingu
// (those not covered by the SpellChecker and Hyphenator
@@ -109,6 +110,7 @@ inline constexpr OUStringLiteral UPN_IS_GRAMMAR_INTERACTIVE = u"IsInter
#define UPH_IS_GRAMMAR_INTERACTIVE 35
#define UPH_HYPH_NO_CAPS 36
#define UPH_HYPH_NO_LAST_WORD 37
+#define UPH_HYPH_ZONE 38
#ifdef __GNUC__
#pragma GCC diagnostic pop
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index 4592c01c75fb..69a495687da6 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -1053,6 +1053,7 @@ namespace xmloff::token {
XML_HYPHENATION_NO_CAPS,
XML_HYPHENATION_NO_LAST_WORD,
XML_HYPHENATION_WORD_CHAR_COUNT,
+ XML_HYPHENATION_ZONE,
XML_I,
XML_ICON,
XML_ICON_SET,
diff --git a/offapi/com/sun/star/style/ParagraphProperties.idl b/offapi/com/sun/star/style/ParagraphProperties.idl
index e9522d77d1cd..32a63282d54e 100644
--- a/offapi/com/sun/star/style/ParagraphProperties.idl
+++ b/offapi/com/sun/star/style/ParagraphProperties.idl
@@ -428,6 +428,13 @@ published service ParagraphProperties
@since LibreOffice 7.4
*/
[optional, property] short ParaHyphenationMinWordLength;
+
+ /** specifies the hyphenation zone, i.e. allowed extra white space
+ in the line before applying hyphenation.
+
+ @since LibreOffice 7.4
+ */
+ [optional, property] long ParaHyphenationZone;
};
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index d5857c132e37..293e40d9601c 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2727,6 +2727,18 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
</rng:define>
<!-- TODO no proposal -->
+ <rng:define name="style-text-properties-attlist" combine="interleave">
+ <rng:optional>
+ <rng:attribute name="loext:hyphenation-zone">
+ <rng:choice>
+ <rng:value>no-limit</rng:value>
+ <rng:ref name="positiveInteger"/>
+ </rng:choice>
+ </rng:attribute>
+ </rng:optional>
+ </rng:define>
+
+ <!-- TODO no proposal -->
<rng:define name="chart-data-point-attlist" combine="interleave">
<rng:optional>
<rng:attribute name="loext:custom-label-pos-x">
diff --git a/svx/sdi/svxitems.sdi b/svx/sdi/svxitems.sdi
index 00e4b74237a2..df389994a868 100644
--- a/svx/sdi/svxitems.sdi
+++ b/svx/sdi/svxitems.sdi
@@ -260,6 +260,7 @@ struct SvxHyphenZone
INT16 MinTrail MID_HYPHEN_MIN_TRAIL;
INT16 MaxHyphens MID_HYPHEN_MAX_HYPHENS;
INT16 MinWordLength MID_HYPHEN_MIN_WORD_LENGTH;
+ INT16 HyphenZone MID_HYPHEN_ZONE;
};
item SvxHyphenZone SvxHyphenZoneItem;
diff --git a/sw/inc/inspectorproperties.hrc b/sw/inc/inspectorproperties.hrc
index f1327ec348c1..c2fd2a106f63 100644
--- a/sw/inc/inspectorproperties.hrc
+++ b/sw/inc/inspectorproperties.hrc
@@ -208,6 +208,7 @@
#define RID_PARA_HYPHENATION_NO_CAPS NC_("RID_ATTRIBUTE_NAMES_MAP", "Para Hyphenation No Caps")
#define RID_PARA_HYPHENATION_NO_LAST_WORD NC_("RID_ATTRIBUTE_NAMES_MAP", "Para Hyphenation No Last Word")
#define RID_PARA_HYPHENATION_MIN_WORD_LENGTH NC_("RID_ATTRIBUTE_NAMES_MAP", "Para Hyphenation Min Word Length")
+#define RID_PARA_HYPHENATION_ZONE NC_("RID_ATTRIBUTE_NAMES_MAP", "Para Hyphenation Zone")
#define RID_PARA_INTEROP_GRAB_BAG NC_("RID_ATTRIBUTE_NAMES_MAP", "Para Interop Grab Bag")
#define RID_PARA_IS_AUTO_FIRST_LINE_INDENT NC_("RID_ATTRIBUTE_NAMES_MAP", "Para is Auto First Line Indent")
#define RID_PARA_IS_CHARACTER_DISTANCE NC_("RID_ATTRIBUTE_NAMES_MAP", "Para is Character Distance")
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 14da263acd96..c3a7d97b32e8 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -65,6 +65,7 @@
#define UNO_NAME_PARA_HYPHENATION_MAX_TRAILING_CHARS "ParaHyphenationMaxTrailingChars"
#define UNO_NAME_PARA_HYPHENATION_MAX_HYPHENS "ParaHyphenationMaxHyphens"
#define UNO_NAME_PARA_HYPHENATION_MIN_WORD_LENGTH "ParaHyphenationMinWordLength"
+#define UNO_NAME_PARA_HYPHENATION_ZONE "ParaHyphenationZone"
#define UNO_NAME_PARA_HYPHENATION_NO_CAPS "ParaHyphenationNoCaps"
#define UNO_NAME_PARA_HYPHENATION_NO_LAST_WORD "ParaHyphenationNoLastWord"
#define UNO_NAME_LEFT_MARGIN "LeftMargin"
diff --git a/sw/qa/extras/layout/data/tdf149420.odt b/sw/qa/extras/layout/data/tdf149420.odt
new file mode 100644
index 000000000000..249d7267eb27
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf149420.odt
Binary files differ
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index e42f5c22b83a..2a6b2ca099c9 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -4379,6 +4379,21 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf121658)
assertXPath(pXmlDoc, "//Special[@nType='PortionType::Hyphen']", 2);
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf149420)
+{
+ uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
+ if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
+ return;
+
+ createSwDoc(DATA_DIRECTORY, "tdf149420.odt");
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ // Only 3 hyphenated words should appear in the document (last paragraph
+ // has got a 1 cm hyphenation zone, removing two hyphenations, which visible
+ // in the second paragraph).
+ assertXPath(pXmlDoc, "//Special[@nType='PortionType::Hyphen']", 8);
+}
+
CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf149324)
{
uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
diff --git a/sw/qa/extras/odfexport/data/tdf149420.odt b/sw/qa/extras/odfexport/data/tdf149420.odt
new file mode 100644
index 000000000000..249d7267eb27
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/tdf149420.odt
Binary files differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index 6f85db1d99a8..e58b772b8cdf 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -3052,6 +3052,13 @@ DECLARE_ODFEXPORT_TEST(tdf149324, "tdf149324.odt")
CPPUNIT_ASSERT_EQUAL(sal_uInt16(7), getProperty<sal_uInt16>(getParagraph(4), "ParaHyphenationMinWordLength"));
}
+DECLARE_ODFEXPORT_TEST(tdf149420, "tdf149420.odt")
+{
+ CPPUNIT_ASSERT_EQUAL(1, getPages());
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), getProperty<sal_uInt16>(getParagraph(2), "ParaHyphenationZone"));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt16(567), getProperty<sal_uInt16>(getParagraph(4), "ParaHyphenationZone"));
+}
+
DECLARE_ODFEXPORT_TEST(testArabicZeroNumbering, "arabic-zero-numbering.odt")
{
CPPUNIT_ASSERT_EQUAL(1, getPages());
diff --git a/sw/qa/uitest/styleInspector/styleInspector.py b/sw/qa/uitest/styleInspector/styleInspector.py
index 29300f60ff17..f5ce2cd6bc75 100644
--- a/sw/qa/uitest/styleInspector/styleInspector.py
+++ b/sw/qa/uitest/styleInspector/styleInspector.py
@@ -26,7 +26,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without formatting and default style
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -36,7 +36,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with direct formatting
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
@@ -54,7 +54,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with paragraph direct formatting
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
xParDirFormatting = xListBox.getChild('1')
self.assertEqual(7, len(xParDirFormatting.getChildren()))
@@ -75,7 +75,7 @@ class styleNavigator(UITestCase):
xParStyle = xListBox.getChild('0')
self.assertEqual(3, len(xParStyle.getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xParStyle.getChild('0'))['Text'])
- self.assertEqual(139, len(xParStyle.getChild('0').getChildren()))
+ self.assertEqual(140, len(xParStyle.getChild('0').getChildren()))
self.assertEqual("Heading\t", get_state_as_dict(xParStyle.getChild('1'))['Text'])
self.assertEqual(28, len(xParStyle.getChild('1').getChildren()))
@@ -109,7 +109,7 @@ class styleNavigator(UITestCase):
xParStyle = xListBox.getChild('0')
self.assertEqual(3, len(xParStyle.getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xParStyle.getChild('0'))['Text'])
- self.assertEqual(139, len(xParStyle.getChild('0').getChildren()))
+ self.assertEqual(140, len(xParStyle.getChild('0').getChildren()))
self.assertEqual("Text Body\t", get_state_as_dict(xParStyle.getChild('1'))['Text'])
self.assertEqual(6, len(xParStyle.getChild('1').getChildren()))
@@ -144,7 +144,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without metadata
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -154,7 +154,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with paragraph metadata showed under direct paragraph formatting
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
xParDirFormatting = xListBox.getChild('1')
self.assertEqual(1, len(xParDirFormatting.getChildren()))
@@ -207,7 +207,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without metadata
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
self.assertEqual(0, len(xListBox.getChild('3').getChildren()))
@@ -217,7 +217,7 @@ class styleNavigator(UITestCase):
# The cursor is on text with paragraph metadata showed under direct paragraph formatting
self.assertEqual(1, len(xListBox.getChild('1').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('1').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('1').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('1').getChild('0').getChildren()))
# Outer bookmark
xBookmarkFormatting = xListBox.getChild('0')
@@ -264,7 +264,7 @@ class styleNavigator(UITestCase):
# The cursor is on text without metadata
self.assertEqual(1, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
self.assertEqual(0, len(xListBox.getChild('1').getChildren()))
self.assertEqual(0, len(xListBox.getChild('2').getChildren()))
diff --git a/sw/qa/uitest/styleInspector/tdf137513.py b/sw/qa/uitest/styleInspector/tdf137513.py
index 8dfc5929c0c1..a0c9ddaafed0 100644
--- a/sw/qa/uitest/styleInspector/tdf137513.py
+++ b/sw/qa/uitest/styleInspector/tdf137513.py
@@ -35,7 +35,7 @@ class tdf137513(UITestCase):
self.assertEqual(2, len(xListBox.getChild('0').getChildren()))
self.assertEqual("Default Paragraph Style\t", get_state_as_dict(xListBox.getChild('0').getChild('0'))['Text'])
self.assertEqual("Table Contents\t", get_state_as_dict(xListBox.getChild('0').getChild('1'))['Text'])
- self.assertEqual(139, len(xListBox.getChild('0').getChild('0').getChildren()))
+ self.assertEqual(140, len(xListBox.getChild('0').getChild('0').getChildren()))
xTableContent = xListBox.getChild('0').getChild('1')
self.assertEqual(5, len(xTableContent.getChildren()))
diff --git a/sw/source/core/text/guess.cxx b/sw/source/core/text/guess.cxx
index d2711d4087d2..3055c69957cc 100644
--- a/sw/source/core/text/guess.cxx
+++ b/sw/source/core/text/guess.cxx
@@ -196,29 +196,69 @@ bool SwTextGuess::Guess( const SwTextPortion& rPor, SwTextFormatInfo &rInf,
// considering an additional "-" for hyphenation
if( bHyph )
{
- // search start of the last word, if needed
- sal_Int32 nLastWord = rInf.GetText().getLength() - 1;
- bool bHyphenationNoLastWord = false;
+ // nHyphZone is the first character not fitting in the hyphenation zone,
+ // or 0, if the whole line in the hyphenation zone,
+ // or -1, if no hyphenation zone defined (i.e. it is 0)
+ sal_Int32 nHyphZone = -1;
const css::beans::PropertyValues & rHyphValues = rInf.GetHyphValues();
- assert( rHyphValues.getLength() > 3 && rHyphValues[3].Name == UPN_HYPH_NO_LAST_WORD );
- if ( rHyphValues[3].Value >>= bHyphenationNoLastWord )
+ assert( rHyphValues.getLength() > 5 && rHyphValues[5].Name == UPN_HYPH_ZONE );
+ // hyphenation zone (distance from the line end in twips)
+ sal_uInt16 nTextHyphenZone;
+ if ( rHyphValues[5].Value >>= nTextHyphenZone )
+ nHyphZone = nTextHyphenZone >= nLineWidth
+ ? 0
+ : sal_Int32(rInf.GetTextBreak( nLineWidth - nTextHyphenZone,
+ nMaxLen, nMaxComp, rInf.GetCachedVclData().get() ));
+
+ m_nCutPos = rInf.GetTextBreak( nLineWidth, nMaxLen, nMaxComp, nHyphPos, rInf.GetCachedVclData().get() );
+
+ // don't try to hyphenate in the hyphenation zone
+ if ( nHyphZone != -1 && TextFrameIndex(COMPLETE_STRING) != m_nCutPos )
{
- bool bCutBlank = false;
- for (; sal_Int32(rInf.GetIdx()) <= nLastWord; --nLastWord )
+ sal_Int32 nZonePos = sal_Int32(m_nCutPos);
+ // disable hyphenation, if there is a space within the hyphenation zone
+ // Note: for better interoperability, not fitting space character at
+ // rInf.GetIdx()[nHyphZone] always disables the hyphenation, don't need to calculate
+ // with its fitting part. Moreover, do not check double or more spaces there, they
+ // are accepted outside of the hyphenation zone, too.
+ for (; sal_Int32(rInf.GetIdx()) <= nZonePos && nHyphZone <= nZonePos; --nZonePos )
{
- sal_Unicode cChar = rInf.GetText()[nLastWord];
- if ( cChar != CH_BLANK && cChar != CH_FULL_BLANK && cChar != CH_SIX_PER_EM )
- bCutBlank = true;
- else if ( bCutBlank )
- break;
+ sal_Unicode cChar = rInf.GetText()[nZonePos];
+ if ( cChar == CH_BLANK || cChar == CH_FULL_BLANK || cChar == CH_SIX_PER_EM )
+ {
+ bHyph = false;
+ }
}
}
- m_nCutPos = rInf.GetTextBreak( nLineWidth, nMaxLen, nMaxComp, nHyphPos, rInf.GetCachedVclData().get() );
+ // search start of the last word, if needed
+ if ( bHyph )
+ {
+ // nLastWord is the space character before the last word
+ sal_Int32 nLastWord = rInf.GetText().getLength() - 1;
+ bool bHyphenationNoLastWord = false;
+ assert( rHyphValues.getLength() > 3 && rHyphValues[3].Name == UPN_HYPH_NO_LAST_WORD );
+ if ( rHyphValues[3].Value >>= bHyphenationNoLastWord )
+ {
+ // skip spaces after the last word
+ bool bCutBlank = false;
+ for (; sal_Int32(rInf.GetIdx()) <= nLastWord; --nLastWord )
+ {
+ sal_Unicode cChar = rInf.GetText()[nLastWord];
+ if ( cChar != CH_BLANK && cChar != CH_FULL_BLANK && cChar != CH_SIX_PER_EM )
+ bCutBlank = true;
+ else if ( bCutBlank )
+ break;
+ }
+ }
- // don't hyphenate last word of the paragraph
- if ( bHyphenationNoLastWord && sal_Int32(m_nCutPos) > nLastWord )
- m_nCutPos = TextFrameIndex(nLastWord);
+ // don't hyphenate the last word of the paragraph
+ if ( bHyphenationNoLastWord && sal_Int32(m_nCutPos) > nLastWord &&
+ TextFrameIndex(COMPLETE_STRING) != m_nCutPos )
+ {
+ m_nCutPos = TextFrameIndex(nLastWord);
+ }
+ }
if ( !nHyphPos && rInf.GetIdx() )
nHyphPos = rInf.GetIdx() - TextFrameIndex(1);
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index 5a794370b6da..c3a5068b3cf9 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -1361,13 +1361,14 @@ void SwTextPaintInfo::DrawViewOpt( const SwLinePortion &rPor,
static void lcl_InitHyphValues( PropertyValues &rVals,
sal_Int16 nMinLeading, sal_Int16 nMinTrailing,
- bool bNoCapsHyphenation, bool bNoLastWordHyphenation, sal_Int16 nMinWordLength )
+ bool bNoCapsHyphenation, bool bNoLastWordHyphenation,
+ sal_Int16 nMinWordLength, sal_Int16 nTextHyphZone )
{
sal_Int32 nLen = rVals.getLength();
if (0 == nLen) // yet to be initialized?
{
- rVals.realloc( 5 );
+ rVals.realloc( 6 );
PropertyValue *pVal = rVals.getArray();
pVal[0].Name = UPN_HYPH_MIN_LEADING;
@@ -1389,8 +1390,12 @@ static void lcl_InitHyphValues( PropertyValues &rVals,
pVal[4].Name = UPN_HYPH_MIN_WORD_LENGTH;
pVal[4].Handle = UPH_HYPH_MIN_WORD_LENGTH;
pVal[4].Value <<= nMinWordLength;
+
+ pVal[5].Name = UPN_HYPH_ZONE;
+ pVal[5].Handle = UPH_HYPH_ZONE;
+ pVal[5].Value <<= nTextHyphZone;
}
- else if (5 == nLen) // already initialized once?
+ else if (6 == nLen) // already initialized once?
{
PropertyValue *pVal = rVals.getArray();
pVal[0].Value <<= nMinLeading;
@@ -1398,6 +1403,7 @@ static void lcl_InitHyphValues( PropertyValues &rVals,
pVal[2].Value <<= bNoCapsHyphenation;
pVal[3].Value <<= bNoLastWordHyphenation;
pVal[4].Value <<= nMinWordLength;
+ pVal[5].Value <<= nTextHyphZone;
}
else {
OSL_FAIL( "unexpected size of sequence" );
@@ -1406,7 +1412,7 @@ static void lcl_InitHyphValues( PropertyValues &rVals,
const PropertyValues & SwTextFormatInfo::GetHyphValues() const
{
- OSL_ENSURE( 4 == m_aHyphVals.getLength(),
+ OSL_ENSURE( 6 == m_aHyphVals.getLength(),
"hyphenation values not yet initialized" );
return m_aHyphVals;
}
@@ -1427,8 +1433,10 @@ bool SwTextFormatInfo::InitHyph( const bool bAutoHyphen )
const sal_Int16 nMinimalWordLength = rAttr.GetMinWordLength();
const bool bNoCapsHyphenation = rAttr.IsNoCapsHyphenation();
const bool bNoLastWordHyphenation = rAttr.IsNoLastWordHyphenation();
+ const sal_Int16 nTextHyphZone = rAttr.GetTextHyphenZone();
lcl_InitHyphValues( m_aHyphVals, nMinimalLeading, nMinimalTrailing,
- bNoCapsHyphenation, bNoLastWordHyphenation, nMinimalWordLength );
+ bNoCapsHyphenation, bNoLastWordHyphenation,
+ nMinimalWordLength, nTextHyphZone );
}
return bAuto;
}
diff --git a/sw/source/core/unocore/unomapproperties.hxx b/sw/source/core/unocore/unomapproperties.hxx
index 1f679b2e38fd..da2d4d907adf 100644
--- a/sw/source/core/unocore/unomapproperties.hxx
+++ b/sw/source/core/unocore/unomapproperties.hxx
@@ -118,6 +118,7 @@
{ u"" UNO_NAME_PARA_HYPHENATION_MAX_TRAILING_CHARS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_TRAIL }, \
{ u"" UNO_NAME_PARA_HYPHENATION_MAX_HYPHENS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MAX_HYPHENS }, \
{ u"" UNO_NAME_PARA_HYPHENATION_MIN_WORD_LENGTH, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_WORD_LENGTH }, \
+ { u"" UNO_NAME_PARA_HYPHENATION_ZONE, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_ZONE}, \
{ u"" UNO_NAME_CHAR_AUTO_KERNING, RES_CHRATR_AUTOKERN, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, 0 }, \
{ u"" UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACK_COLOR }, \
{ u"" UNO_NAME_CHAR_HIGHLIGHT, RES_CHRATR_HIGHLIGHT, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACK_COLOR }, \
@@ -442,6 +443,7 @@
{ u"" UNO_NAME_PARA_HYPHENATION_MAX_TRAILING_CHARS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_TRAIL },\
{ u"" UNO_NAME_PARA_HYPHENATION_MAX_HYPHENS, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MAX_HYPHENS},\
{ u"" UNO_NAME_PARA_HYPHENATION_MIN_WORD_LENGTH, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_MIN_WORD_LENGTH},\
+ { u"" UNO_NAME_PARA_HYPHENATION_ZONE, RES_PARATR_HYPHENZONE, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_HYPHEN_ZONE},\
{ u"" UNO_NAME_NUMBERING_STYLE_NAME, RES_PARATR_NUMRULE, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0},\
{ UNO_NAME_NUMBERING_LEVEL, RES_PARATR_LIST_LEVEL, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0},\
{ u"" UNO_NAME_PARA_USER_DEFINED_ATTRIBUTES, RES_UNKNOWNATR_CONTAINER, cppu::UnoType<css::container::XNameContainer>::get(), PropertyAttribute::MAYBEVOID, 0 },\
diff --git a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
index 530f72cdc923..913703366451 100644
--- a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
+++ b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
@@ -258,6 +258,7 @@ static OUString PropertyNametoRID(const OUString& rName)
{ "ParaHyphenationNoCaps", RID_PARA_HYPHENATION_NO_CAPS },
{ "ParaHyphenationNoLastWord", RID_PARA_HYPHENATION_NO_LAST_WORD },
{ "ParaHyphenationMinWordLength", RID_PARA_HYPHENATION_MIN_WORD_LENGTH },
+ { "ParaHyphenationZone", RID_PARA_HYPHENATION_ZONE },
{ "ParaInteropGrabBag", RID_PARA_INTEROP_GRAB_BAG },
{ "ParaIsAutoFirstLineIndent", RID_PARA_IS_AUTO_FIRST_LINE_INDENT },
{ "ParaIsCharacterDistance", RID_PARA_IS_CHARACTER_DISTANCE },
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 356b98051ec0..efdd8a912cf8 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -1066,6 +1066,7 @@ namespace xmloff::token {
TOKEN( "hyphenation-no-caps", XML_HYPHENATION_NO_CAPS ),
TOKEN( "hyphenation-no-last-word", XML_HYPHENATION_NO_LAST_WORD ),
TOKEN( "hyphenation-word-char-count", XML_HYPHENATION_WORD_CHAR_COUNT ),
+ TOKEN( "hyphenation-zone", XML_HYPHENATION_ZONE ),
TOKEN( "i", XML_I ),
TOKEN( "icon", XML_ICON ),
TOKEN( "icon-set", XML_ICON_SET ),
diff --git a/xmloff/source/text/txtprmap.cxx b/xmloff/source/text/txtprmap.cxx
index a2e110e5bdb0..66bda55a8e3f 100644
--- a/xmloff/source/text/txtprmap.cxx
+++ b/xmloff/source/text/txtprmap.cxx
@@ -345,6 +345,7 @@ XMLPropertyMapEntry const aXMLParaPropMap[] =
MAP_EXT( "ParaHyphenationNoCaps", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_NO_CAPS, XML_TYPE_BOOL|XML_TYPE_PROP_TEXT, 0 ),
MAP_EXT( "ParaHyphenationNoLastWord", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_NO_LAST_WORD, XML_TYPE_BOOL|XML_TYPE_PROP_TEXT, 0 ),
MAP_EXT( "ParaHyphenationMinWordLength", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_WORD_CHAR_COUNT, XML_TYPE_NUMBER16_NONE|XML_TYPE_PROP_TEXT, 0 ),
+ MAP_EXT( "ParaHyphenationZone", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_ZONE, XML_TYPE_NUMBER16_NONE|XML_TYPE_PROP_TEXT, 0 ),
// RES_PARATR_DROP
MP_E( "DropCapWholeWord", STYLE, LENGTH, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_DROPCAPWHOLEWORD ),
MP_E( "DropCapCharStyleName", STYLE, STYLE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_DROPCAPCHARSTYLE ),
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index ee0adc36055d..aaf1442d1dc6 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -966,6 +966,7 @@ hyphenation-remain-char-count
hyphenation-no-caps
hyphenation-no-last-word
hyphenation-word-char-count
+hyphenation-zone
i
icon
icon-set