Index: resources/iconsets/1_7_0/1_7_0.xml
===================================================================
--- resources/iconsets/1_7_0/1_7_0.xml	(Revision 26446)
+++ resources/iconsets/1_7_0/1_7_0.xml	(Arbeitskopie)
@@ -138,8 +138,10 @@
 		<icon id="u_group.png" file="16/object-group.svg" /><!-- Outliner -->
 		<icon id="u_undo16.png" file="16/action-undo.svg" /><!-- Barcode -->
 		<icon id="ungroup.png" file="16/object-ungroup.svg" />
+		<icon id="add" file="16/action-add.svg" />
 		<icon id="collapse" file="16/action-chevron-right.svg" />
 		<icon id="context-menu" file="16/action-menu.svg" />
+		<icon id="delete" file="16/action-delete.svg" />
 		<icon id="delete-selected" file="16/action-delete-selected.svg" />
 		<icon id="erase-shadow-off" file="16/action-shadow-erase-off.svg" />
 		<icon id="erase-shadow-on" file="16/action-shadow-erase-on.svg" />
@@ -146,15 +148,14 @@
 		<icon id="expand" file="16/action-chevron-down.svg" />
 		<icon id="inherit-opacity-off" file="16/action-inherit-opacity-off.svg" />
 		<icon id="inherit-opacity-on" file="16/action-inherit-opacity-on.svg" />
+		<icon id="remove" file="16/action-remove.svg" />
 		<icon id="reset" file="16/action-reload.svg" />
 		<icon id="reset-style-changes" file="16/action-reload.svg" /> <!-- 16/action-revert-changes.svg -->
 		<icon id="scale-height" file="16/action-scale-height.svg" />
 		<icon id="scale-width" file="16/action-scale-width.svg" />
+		<icon id="settings" file="16/properties-external-tools.svg" />
 		<icon id="swap" file="16/action-swap.svg" />
 		<icon id="toggle-object-coordination" file="16/object-xycoordination.svg" />
-		<icon id="context-menu" file="16/action-menu.svg" />
-		<icon id="scale-width" file="16/action-scale-width.svg" />
-		<icon id="scale-height" file="16/action-scale-height.svg" />
 		<icon id="whitespace-review-mode" file="16/action-whitespace-review.svg" />
 			
 		<!-- Alerts -->
Index: scribus/CMakeLists_Sources.txt
===================================================================
--- scribus/CMakeLists_Sources.txt	(Revision 26446)
+++ scribus/CMakeLists_Sources.txt	(Arbeitskopie)
@@ -114,6 +114,7 @@
 	nfttemplate.cpp
 	nodeeditcontext.cpp
 	notesstyles.cpp
+	opticalmarginlookup.cpp
 	pageitem.cpp
 	pageitem_arc.cpp
 	pageitem_group.cpp
@@ -381,6 +382,7 @@
 	ui/nodeeditpalette.cpp
 	ui/notesstyleseditor.cpp
 	ui/numformatcombo.cpp
+	ui/opticalmargineditor.cpp
 	ui/opticalmarginswidget.cpp
 	ui/outlinepalette.cpp
 	ui/outputpreview_pdf.cpp
Index: scribus/pageitem_textframe.cpp
===================================================================
--- scribus/pageitem_textframe.cpp	(Revision 26446)
+++ scribus/pageitem_textframe.cpp	(Arbeitskopie)
@@ -41,6 +41,7 @@
 #include "marks.h"
 #include "notesstyles.h"
 #include "numeration.h"
+#include "opticalmarginlookup.h"
 #include "pageitem.h"
 #include "pageitem_group.h"
 #include "pageitem_noteframe.h"
@@ -647,11 +648,22 @@
 		lineData.ascent = lineData.descent = 0;
 		if (glyphs.isEmpty())
 			return;
-		const CharStyle& cStyle(glyphs.at(0).style());
-		double scaleV = cStyle.scaleV() / 1000.0;
-		double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
-		lineData.ascent = cStyle.font().ascent(cStyle.fontSize() / 10.00) * scaleV + offset;
-		lineData.descent = cStyle.font().descent(cStyle.fontSize() / 10.00) * scaleV - offset;
+
+		// #17286 seek for largest glphy in line
+		for (int i = 0; i < glyphs.count(); i++)
+		{
+			const CharStyle& cStyle(glyphs.at(i).style());
+			double scaleV = cStyle.scaleV() / 1000.0;
+			double offset = (cStyle.fontSize() / 10) * (cStyle.baselineOffset() / 1000.0);
+			double tmpAscent = cStyle.font().ascent(cStyle.fontSize() / 10.00) * scaleV + offset;
+
+			if (lineData.ascent < tmpAscent)
+			{
+				lineData.ascent = tmpAscent;
+				lineData.descent = cStyle.font().descent(cStyle.fontSize() / 10.00) * scaleV;
+			}
+
+		}
 	}
 
 // yPos should not be changed when all line is already calculated - at new y position there can be overflow!!!
@@ -901,44 +913,34 @@
 
 
 	//defined but not used
-	///// calculate how much the first char should stick out to the left
-	//double opticalLeftMargin(const StoryText& itemText)
-	//{
-	//	int b = line.firstChar;
-	//	while (b < line.lastChar && (itemText.flags(b) & ScLayout_SuppressSpace))
-	//		   ++b;
-	//
-	//	double chs = itemText.charStyle(b).fontSize() * (itemText.charStyle(b).scaleH() / 1000.0);
-	//	QChar chr = itemText.text(b);
-	//	double leftCorr = itemText.charStyle(b).font().realCharWidth(chr, chs / 10.0);
-	//	if (QString("'´`").indexOf(chr) >= 0
-	//		|| chr == QChar(0x2018) // quote 6
-	//		|| chr == QChar(0x2019) // quote 9
-	//		|| chr == QChar(0x201a) // lower quote 9
-	//		|| chr == QChar(0x201b) // upper reversed 9 6
-	//		|| chr == QChar(0x2039) // single guillemet <
-	//		|| chr == QChar(0x203a) // single guillemet >
-	//		)
-	//		leftCorr *= -0.7;
-	//	else if (QString("\"").indexOf(chr) >= 0
-	//			 || chr == QChar(0x00ab) // guillemet <<
-	//			 || chr == QChar(0x00bb) // guillemet >>
-	//			 || chr == QChar(0x201c) // quote 66
-	//			 || chr == QChar(0x201d) // quote 99
-	//			 || chr == QChar(0x201e) // lower quote 99
-	//			 || chr == QChar(0x201f) // upper reversed 99
-	//			 )
-	//		leftCorr *= -0.5;
-	//	else {
-	//		leftCorr = itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0, chr);
-	//		leftCorr -= itemText.charStyle(b).font().charWidth(QChar(' '), chs / 10.0);
-	////				double leftCorr2 = itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0, chr);
-	////				leftCorr2 -= itemText.charStyle(a).font().charWidth(QChar('K'), chs / 10.0);
-	////				leftCorr = qMin(leftCorr, leftCorr2);
-	//	}
-	//	return leftCorr;
-	//}
+	/// calculate how much the first char should stick out to the left
+	double opticalLeftMargin(const StoryText& itemText)
+	{
+		int b = 0;
+		while (b < lineData.lastCluster && (itemText.flags(b) & ScLayout_SuppressSpace))
+			   ++b;
 
+		if (b < lineData.lastCluster)
+		{
+			const CharStyle& style = glyphs[b].style();
+			const ParagraphStyle& pStyle = itemText.paragraphStyle(lineData.lastCluster);
+			const ScFace& font = style.font();
+			double chs = style.fontSize() * (style.scaleH() / 1000.0);
+			QChar chr = itemText.text(glyphs[b].firstChar());
+			double leftCorr = 0;
+
+			OpticalMarginSet set = doc->opticalMarginSets().value(pStyle.opticalMarginSetId());
+			OpticalMarginRule rule = OpticalMarginLookup::instance().offset(chr, set);
+			if ( rule.Unit == SC_PERCENT)
+				leftCorr = font.glyphBBox(font.char2CMap(chr.unicode()), chs / 10.0).width * rule.Left;
+			else
+				leftCorr = rule.Left;
+
+			return leftCorr;
+		}
+		return 0.0;
+	}
+
 	/// calculate how much the last char should stick out to the right
 	double opticalRightMargin(const StoryText& itemText)
 	{
@@ -951,46 +953,20 @@
 		if (b >= 0)
 		{
 			const CharStyle& style = glyphs[b].style();
+			const ParagraphStyle& pStyle = itemText.paragraphStyle(lineData.lastCluster);
 			const ScFace& font = style.font();
 			double chs = style.fontSize() * (style.scaleH() / 1000.0);
-			QChar chr = itemText.text(glyphs[b].lastChar());
-			double rightCorr;
-			if (glyphs[b].hasFlag(ScLayout_SoftHyphenVisible))
-				rightCorr = font.hyphenWidth(style, chs / 10.0);
+			bool softHypen = glyphs[b].hasFlag(ScLayout_SoftHyphenVisible);
+			QChar chr = softHypen ? QChar(style.hyphenChar()) : itemText.text(glyphs[b].lastChar());
+			double rightCorr = 0;
+
+			OpticalMarginSet set = doc->opticalMarginSets().value(pStyle.opticalMarginSetId());
+			OpticalMarginRule rule = OpticalMarginLookup::instance().offset(chr, set);
+			if ( rule.Unit == SC_PERCENT)
+				rightCorr = softHypen ? font.hyphenWidth(style, chs / 10.0) * rule.Right : font.glyphBBox(font.char2CMap(chr.unicode()), chs / 10.0).width * rule.Right;
 			else
-				rightCorr = font.glyphBBox(font.char2CMap(chr.unicode()), chs / 10.0).width;
-			if (glyphs[b].hasFlag(ScLayout_SoftHyphenVisible)
-				|| QString("-,.`´'~").indexOf(chr) >= 0
-				|| chr == QChar(0x2010)
-				|| chr == QChar(0x2018)
-				|| chr == QChar(0x2019)
-				|| chr == QChar(0x201a)
-				|| chr == QChar(0x201b)
-				|| chr == QChar(0x2039)
-				|| chr == QChar(0x203a)
-				|| chr == QChar(0x2032) // PRIME
-				)
-				rightCorr *= 0.7;
-			else if (QString(";:\"").indexOf(chr) >= 0
-					 || chr == QChar(0x00ab)
-					 || chr == QChar(0x00bb)
-					 || chr == QChar(0x201c)
-					 || chr == QChar(0x201d)
-					 || chr == QChar(0x201e)
-					 || chr == QChar(0x201f)
-					 || chr == QChar(0x2013) // EN DASH
-					 || chr == QChar(0x2033) // double prime
-					 )
-				rightCorr *= 0.5;
-			else {
-#if 0
-				// FIXME HOST: is the kerning with "." a really reliable way to check this?
-				rightCorr = chStyle.font().realCharWidth(chr, chs / 10.0);
-				rightCorr -= chStyle.font().charWidth(chr, chs / 10.0, QChar('.'));
-#else
-				rightCorr = 0;
-#endif
-			}
+				rightCorr = rule.Right;
+
 			return rightCorr;
 		}
 		return 0.0;
@@ -2438,6 +2414,11 @@
 					{
 						if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 							current.lineData.width += current.opticalRightMargin(itemText);
+						if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+						{
+							current.lineData.width += current.opticalLeftMargin(itemText);
+							current.lineData.x -= current.opticalLeftMargin(itemText);
+						}
 
 						OFs = 0;
 						if (style.alignment() == ParagraphStyle::RightAligned)
@@ -2467,6 +2448,9 @@
 						{
 							if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 								current.lineData.naturalWidth += current.opticalRightMargin(itemText);
+							if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+								current.lineData.naturalWidth += current.opticalLeftMargin(itemText);
+
 							double optiWidth = current.colRight - style.rightMargin() - style.lineSpacing() / 2.0 - current.lineData.x;
 							if (current.lineData.naturalWidth > optiWidth)
 								current.lineData.width = qMax(current.lineData.width - current.maxShrink, optiWidth);
@@ -2553,6 +2537,11 @@
 						// Justification
 						if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 							current.lineData.width += current.opticalRightMargin(itemText);
+						if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+						{
+							current.lineData.width += current.opticalLeftMargin(itemText);
+							current.lineData.x -= current.opticalLeftMargin(itemText);
+						}
 						// #12565: Right alignment of hyphens
 						// The additional character width has already been taken into account
 						// above via the line break position, so it's not necessary to increase
@@ -2579,6 +2568,9 @@
 						{
 							if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 								current.lineData.naturalWidth += current.opticalRightMargin(itemText);
+							if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+								current.lineData.naturalWidth += current.opticalLeftMargin(itemText);
+
 							current.indentLine(style, OFs);
 						}
 						current.xPos = current.lineData.x + current.lineData.width;
@@ -2841,6 +2833,11 @@
 
 			if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 				current.lineData.width += current.opticalRightMargin(itemText);
+			if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+			{
+				current.lineData.width += current.opticalLeftMargin(itemText);
+				current.lineData.x -= current.opticalLeftMargin(itemText);
+			}
 
 			OFs = 0;
 			if (style.alignment() == ParagraphStyle::RightAligned)
@@ -2869,6 +2866,9 @@
 			{
 				if (opticalMargins & ParagraphStyle::OM_RightHangingPunct)
 					current.lineData.naturalWidth += current.opticalRightMargin(itemText);
+				if (opticalMargins & ParagraphStyle::OM_LeftHangingPunct)
+					current.lineData.naturalWidth -= current.opticalLeftMargin(itemText);
+
 				current.indentLine(style, OFs);
 			}
 			if (current.glyphs[0].hasFlag(ScLayout_DropCap))
Index: scribus/plugins/fileloader/scribus170format/scribus170format.cpp
===================================================================
--- scribus/plugins/fileloader/scribus170format/scribus170format.cpp	(Revision 26446)
+++ scribus/plugins/fileloader/scribus170format/scribus170format.cpp	(Arbeitskopie)
@@ -1974,6 +1974,11 @@
 			if (!success) break;
 			m_Doc->setUsesMarksAndNotes(true);
 		}
+		else if (tagName == QLatin1String("OpticalMarginSets"))
+		{
+			success = readOpticalMarginSets(m_Doc, reader);
+			if (!success) break;
+		}
 		else
 		{
 			reader.skipCurrentElement();
@@ -3166,6 +3171,10 @@
 	if (attrs.hasAttribute(OpticalMargins))
 		newStyle.setOpticalMargins(attrs.valueAsInt(OpticalMargins));
 
+	static const QString OpticalMarginSetId("OpticalMarginSetId");
+	if (attrs.hasAttribute(OpticalMarginSetId))
+		newStyle.setOpticalMarginSetId(attrs.valueAsString(OpticalMarginSetId));
+
 	static const QString HyphenConsecutiveLines("HyphenConsecutiveLines");
 	if (attrs.hasAttribute(HyphenConsecutiveLines))
 		newStyle.setHyphenConsecutiveLines(attrs.valueAsInt(HyphenConsecutiveLines));
@@ -3974,6 +3983,52 @@
 	return !reader.hasError();
 }
 
+bool Scribus170Format::readOpticalMarginSets(ScribusDoc *doc, ScXmlStreamReader &reader) const
+{
+	QString tagName(reader.nameAsString());
+	OpticalMarginSets sets;
+	OpticalMarginSet set;
+	QMap<QString, QString> names;
+	OpticalMarginRules rules;
+
+	while (!reader.atEnd() && !reader.hasError())
+	{
+		reader.readNext();
+		if (reader.isEndElement() && reader.name() == tagName)
+			break;
+
+		if (reader.isStartElement() && reader.name() == QLatin1String("Set"))
+		{
+			ScXmlStreamAttributes attrs = reader.scAttributes();
+			set.id = attrs.valueAsString("Id");
+			set.type = attrs.valueAsString("Type");
+			set.name = attrs.valueAsString("Name");
+		}
+
+		if (reader.isStartElement() && reader.name() == QLatin1String("Rule"))
+		{
+			ScXmlStreamAttributes attrs = reader.scAttributes();
+			OpticalMarginRule rule(unicodeToString(attrs.valueAsString("Characters")), attrs.valueAsDouble("Left"), attrs.valueAsDouble("Right"), attrs.valueAsInt("Unit"));
+			rules.append(rule);
+		}
+
+		if (reader.isEndElement() && reader.name() == QLatin1String("Rules"))
+		{
+			set.rules = OpticalMarginLookup::instance().splitRulesToChars(rules);
+			rules.clear();
+		}
+
+		if (reader.isEndElement() && reader.name() == QLatin1String("Set"))
+			sets.insert(set.id, set);
+
+	}
+
+	doc->typographicPrefs().opticalMarginSets = sets;
+	m_Doc->setOpticalMarginSets(sets);
+
+	return !reader.hasError();
+}
+
 bool Scribus170Format::readSections(ScribusDoc* doc, ScXmlStreamReader& reader) const
 {
 	QString tagName(reader.nameAsString());
@@ -5553,6 +5608,8 @@
 		pstyle.setMaxGlyphExtension(attrs.valueAsDouble("MaxGlyphExtend"));
 	if (attrs.hasAttribute("OpticalMargins"))
 		pstyle.setOpticalMargins(attrs.valueAsInt("OpticalMargins"));
+	if (attrs.hasAttribute("OpticalMarginSetId"))
+		pstyle.setOpticalMarginSetId(attrs.valueAsString("OpticalMarginSetId"));
 	if (attrs.hasAttribute("HyphenationMode"))
 		pstyle.setHyphenationMode(attrs.valueAsInt("HyphenationMode"));
 	if (attrs.hasAttribute("leftMargin"))
Index: scribus/plugins/fileloader/scribus170format/scribus170format.h
===================================================================
--- scribus/plugins/fileloader/scribus170format/scribus170format.h	(Revision 26446)
+++ scribus/plugins/fileloader/scribus170format/scribus170format.h	(Arbeitskopie)
@@ -162,6 +162,7 @@
 		bool readNotesStyles(ScribusDoc* doc, ScXmlStreamReader& reader) const;
 		bool readNotesFrames(ScXmlStreamReader &reader);
 		bool readMarks(ScribusDoc* doc, ScXmlStreamReader& reader);
+		bool readOpticalMarginSets(ScribusDoc* doc, ScXmlStreamReader& reader) const;
 
 		//lists of items and marks with names only, which need update to pointers
 		QMap<Mark*, int> markeredItemsMap;
@@ -213,6 +214,7 @@
 		void writeIndexes(ScXmlStreamWriter& docu);
 		void writeTOC(ScXmlStreamWriter& docu);
 		void writeMarks(ScXmlStreamWriter & docu);
+		void writeOpticalMarginSets(ScXmlStreamWriter & docu);
 		void writeNotesStyles(ScXmlStreamWriter & docu);
 		void writeNotesStyles(ScXmlStreamWriter & docu, const QStringList& styleSelection);
 		void writeNotesFrames(ScXmlStreamWriter & docu);
Index: scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp
===================================================================
--- scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp	(Revision 26446)
+++ scribus/plugins/fileloader/scribus170format/scribus170format_save.cpp	(Arbeitskopie)
@@ -45,8 +45,8 @@
 #include "ui/missing.h"
 #include "units.h"
 #include "util.h"
-
 #include "util_color.h"
+#include "util_text.h"
 
 QString Scribus170Format::saveElements(double xp, double yp, double wp, double hp, Selection* selection, QByteArray &prevData)
 {
@@ -540,6 +540,7 @@
 	writeTOC(docu);
 	writeMarks(docu);
 	writeNotesStyles(docu);
+	writeOpticalMarginSets(docu);
 	writeNotesFrames(docu);
 	writeNotes(docu);
 	writePageSets(docu);
@@ -882,6 +883,8 @@
 		docu.writeAttribute("NumerationHigher", static_cast<int>(style.numHigher()));
 	if ( ! style.isInhOpticalMargins())
 		docu.writeAttribute("OpticalMargins", style.opticalMargins());
+	if ( ! style.isInhOpticalMarginSetId())
+		docu.writeAttribute("OpticalMarginSetId", style.opticalMarginSetId());
 	if ( ! style.isInhHyphenConsecutiveLines())
 		docu.writeAttribute("HyphenConsecutiveLines", style.hyphenConsecutiveLines());
 	if ( ! style.isInhHyphenationMode())
@@ -1531,6 +1534,40 @@
 	docu.writeEndElement();
 }
 
+void Scribus170Format::writeOpticalMarginSets(ScXmlStreamWriter & docu)
+{
+	docu.writeStartElement("OpticalMarginSets");
+
+	OpticalMarginSets sets = m_Doc->typographicPrefs().opticalMarginSets;
+
+	for (const auto &set : sets)
+	{
+		docu.writeStartElement("Set");
+		docu.writeAttribute("Id", set.id);
+		docu.writeAttribute("Type", set.type);
+		docu.writeAttribute("Name", set.name);
+
+		docu.writeStartElement("Rules");
+
+		OpticalMarginRules rules = OpticalMarginLookup::instance().mergeCharsToRules(set.rules);
+
+		for (const auto &rule : rules)
+		{
+			docu.writeEmptyElement("Rule");
+			docu.writeAttribute("Left", rule.Left);
+			docu.writeAttribute("Right", rule.Right);
+			docu.writeAttribute("Unit", rule.Unit);
+			docu.writeAttribute("Characters", stringToUnicode(rule.Chars));
+		}
+
+		docu.writeEndElement(); // Rules
+		docu.writeEndElement(); // Set
+
+	}
+
+	docu.writeEndElement(); // OpticalMarginSets
+}
+
 void Scribus170Format::writeNotesStyles(ScXmlStreamWriter & docu)
 {
 	if (m_Doc->m_docNotesStylesList.isEmpty())
Index: scribus/prefsmanager.cpp
===================================================================
--- scribus/prefsmanager.cpp	(Revision 26446)
+++ scribus/prefsmanager.cpp	(Arbeitskopie)
@@ -60,6 +60,7 @@
 #include "util_color.h"
 #include "util_file.h"
 #include "util_ghostscript.h"
+#include "util_text.h"
 
 #include "ui/missing.h"
 #include "ui/modetoolbar.h"
@@ -224,6 +225,7 @@
 	appPrefs.typoPrefs.valueStrikeThruPos = -1;
 	appPrefs.typoPrefs.valueStrikeThruWidth = -1;
 	appPrefs.guidesPrefs.valueBaselineGrid = 14.4;
+	appPrefs.typoPrefs.opticalMarginSets = OpticalMarginLookup::instance().defaultSets();
 	appPrefs.guidesPrefs.offsetBaselineGrid = 0.0;
 	appPrefs.displayPrefs.showToolTips = true;
 	appPrefs.displayPrefs.showMouseCoordinates = true;
@@ -1920,6 +1922,34 @@
 	experimentalElem.setAttribute("NotesEnabled", appPrefs.experimentalFeaturePrefs.notesEnabled);
 	elem.appendChild(experimentalElem);
 
+	QDomElement opticalMarginSets = docu.createElement("OpticalMarginSets");
+	OpticalMarginSets &oms = appPrefs.typoPrefs.opticalMarginSets;
+	for (const auto &set : oms)
+	{
+		QDomElement setItem = docu.createElement("Set");
+		setItem.setAttribute("Id", set.id);
+		setItem.setAttribute("Type", set.type);
+		setItem.setAttribute("Name", set.name);
+
+		QDomElement rulesItem = docu.createElement("Rules");
+		setItem.appendChild(rulesItem);
+
+		OpticalMarginRules rules = OpticalMarginLookup::instance().mergeCharsToRules(set.rules);
+
+		for (auto &rule : rules)
+		{
+			QDomElement ruleItem = docu.createElement("Rule");
+			ruleItem.setAttribute("Left", rule.Left);
+			ruleItem.setAttribute("Right", rule.Right);
+			ruleItem.setAttribute("Unit", rule.Unit);
+			ruleItem.setAttribute("Characters", stringToUnicode(rule.Chars));
+			rulesItem.appendChild(ruleItem);
+		}
+
+		opticalMarginSets.appendChild(setItem);
+	}
+	elem.appendChild(opticalMarginSets);
+
 	// write file
 	bool result = false;
 	QFile f(filePath);
@@ -2768,6 +2798,60 @@
 			appPrefs.experimentalFeaturePrefs.notesEnabled = static_cast<bool>(dc.attribute("NotesEnabled", "0").toInt());
 		}
 
+		// optical margin sets
+		if (dc.tagName() == "OpticalMarginSets")
+		{
+			OpticalMarginSets sets;
+			OpticalMarginSet set;
+
+			QDomNodeList setNodes = dc.elementsByTagName("Set");
+
+			for (int i = 0; i < setNodes.count(); i++) {
+				QDomNode setNode = setNodes.at(i);
+				if (!setNode.isElement())
+					continue;
+
+				QDomElement setElement = setNode.toElement();
+				set.id = setElement.attribute("Id");
+				set.type = setElement.attribute("Type");
+				set.name = setElement.attribute("Name");
+
+				QDomNodeList childrenList = setElement.childNodes();
+				for (int i = 0; i < childrenList.count(); i++) {
+					QDomNode child = childrenList.at(i);
+					if (!child.isElement())
+						continue;
+
+					QDomElement childElement = child.toElement();
+					if (childElement.tagName() != "Rules")
+						continue;
+
+					OpticalMarginRules rules;
+
+					QDomNodeList ruleList = childElement.elementsByTagName("Rule");
+					for (int i = 0; i < ruleList.count(); i++) {
+						QDomNode rule = ruleList.at(i);
+						if (!rule.isElement())
+							continue;
+
+						QDomElement ruleElement = rule.toElement();
+						OpticalMarginRule omr(unicodeToString(ruleElement.attribute("Characters")),
+											  ruleElement.attribute("Left").toDouble(),
+											  ruleElement.attribute("Right").toDouble(),
+											  ruleElement.attribute("Unit").toInt());
+
+						rules.append(omr);
+					}
+
+					set.rules = OpticalMarginLookup::instance().splitRulesToChars(rules);
+				}
+
+				sets.insert(set.id, set);
+			}
+
+			appPrefs.typoPrefs.opticalMarginSets = sets;
+		}
+
 		domNode = domNode.nextSibling();
 	}
 	// Some sanity checks
Index: scribus/prefsstructs.h
===================================================================
--- scribus/prefsstructs.h	(Revision 26446)
+++ scribus/prefsstructs.h	(Arbeitskopie)
@@ -20,6 +20,7 @@
 #include <QHash>
 
 #include "documentinformation.h"
+#include "opticalmarginlookup.h"
 #include "pagestructs.h"
 #include "pdfoptions.h"
 #include "scfonts.h"
@@ -80,6 +81,7 @@
 	int valueUnderlineWidth; //! Underline width
 	int valueStrikeThruPos; //! Strike-through displacement
 	int valueStrikeThruWidth; //! Strike-through line width
+	OpticalMarginSets opticalMarginSets; //! OpticalMargin Group List
 
 	inline bool operator==(const TypoPrefs &other) const
 	{
Index: scribus/resourcecollection.h
===================================================================
--- scribus/resourcecollection.h	(Revision 26446)
+++ scribus/resourcecollection.h	(Arbeitskopie)
@@ -45,65 +45,70 @@
 	public:
 		ResourceCollection() {}
 
-		void collectFont(const QString& name)         { if (!name.isEmpty()) m_fonts.insert(name, name); }
-		void collectFontfeatures(const QString& name) { if (!name.isEmpty()) m_fontfeatures.insert(name, name); }
-		void collectPattern(const QString& name)      { if (!name.isEmpty()) m_patterns.insert(name, name); }
-		void collectColor(const QString& name)        { if (!name.isEmpty()) m_colors.insert(name, name); }
-		void collectGradient(const QString& name)     { if (!name.isEmpty()) m_gradients.insert(name, name); }
-		void collectStyle(const QString& name)        { if (!name.isEmpty()) m_pstyles.insert(name, name); }
-		void collectCharStyle(const QString& name)    { if (!name.isEmpty()) m_cstyles.insert(name, name); }
-		void collectLineStyle(const QString& name)    { if (!name.isEmpty()) m_linestyles.insert(name, name); }
-		void collectTableStyle(const QString& name)   { if (!name.isEmpty()) m_tableStyles.insert(name, name); }
-		void collectCellStyle(const QString& name)    { if (!name.isEmpty()) m_cellStyles.insert(name, name); }
-		void collectNoteStyle(const QString& name)    { if (!name.isEmpty()) m_noteStyles.insert(name, name); }
+		void collectFont(const QString& name)				{ if (!name.isEmpty()) m_fonts.insert(name, name); }
+		void collectFontfeatures(const QString& name)		{ if (!name.isEmpty()) m_fontfeatures.insert(name, name); }
+		void collectPattern(const QString& name)			{ if (!name.isEmpty()) m_patterns.insert(name, name); }
+		void collectColor(const QString& name)				{ if (!name.isEmpty()) m_colors.insert(name, name); }
+		void collectGradient(const QString& name)			{ if (!name.isEmpty()) m_gradients.insert(name, name); }
+		void collectStyle(const QString& name)				{ if (!name.isEmpty()) m_pstyles.insert(name, name); }
+		void collectCharStyle(const QString& name)			{ if (!name.isEmpty()) m_cstyles.insert(name, name); }
+		void collectLineStyle(const QString& name)			{ if (!name.isEmpty()) m_linestyles.insert(name, name); }
+		void collectTableStyle(const QString& name)			{ if (!name.isEmpty()) m_tableStyles.insert(name, name); }
+		void collectCellStyle(const QString& name)			{ if (!name.isEmpty()) m_cellStyles.insert(name, name); }
+		void collectNoteStyle(const QString& name)			{ if (!name.isEmpty()) m_noteStyles.insert(name, name); }
+		void collectOpticalMarginSet(const QString& name)   { if (!name.isEmpty()) m_opticalMarginSets.insert(name, name); }
 
-		void mapFont(const QString& oldname, const QString& newname)         { m_fonts.insert(oldname, newname); }
-		void mapPattern(const QString& oldname, const QString& newname)      { m_patterns.insert(oldname, newname); }
-		void mapFontfeatures(const QString& oldname, const QString& newname) { m_fontfeatures.insert(oldname, newname); }
-		void mapColor(const QString& oldname, const QString& newname)        { m_colors.insert(oldname, newname); }
-		void mapGradients(const QString& oldname, const QString& newname)    { m_gradients.insert(oldname, newname); }
-		void mapStyle(const QString& oldname, const QString& newname)        { m_pstyles.insert(oldname, newname); }
-		void mapCharStyle(const QString& oldname, const QString& newname)    { m_cstyles.insert(oldname, newname); }
-		void mapLineStyle(const QString& oldname, const QString& newname)    { m_linestyles.insert(oldname, newname); }
-		void mapTableStyle(const QString& oldname, const QString& newname)   { m_tableStyles.insert(oldname, newname); }
-		void mapCellStyle(const QString& oldname, const QString& newname)    { m_cellStyles.insert(oldname, newname); }
-		void mapNoteStyle(const QString& oldname, const QString& newname)    { m_noteStyles.insert(oldname, newname); }
+		void mapFont(const QString& oldname, const QString& newname)				{ m_fonts.insert(oldname, newname); }
+		void mapPattern(const QString& oldname, const QString& newname)				{ m_patterns.insert(oldname, newname); }
+		void mapFontfeatures(const QString& oldname, const QString& newname)		{ m_fontfeatures.insert(oldname, newname); }
+		void mapColor(const QString& oldname, const QString& newname)				{ m_colors.insert(oldname, newname); }
+		void mapGradients(const QString& oldname, const QString& newname)			{ m_gradients.insert(oldname, newname); }
+		void mapStyle(const QString& oldname, const QString& newname)				{ m_pstyles.insert(oldname, newname); }
+		void mapCharStyle(const QString& oldname, const QString& newname)			{ m_cstyles.insert(oldname, newname); }
+		void mapLineStyle(const QString& oldname, const QString& newname)			{ m_linestyles.insert(oldname, newname); }
+		void mapTableStyle(const QString& oldname, const QString& newname)			{ m_tableStyles.insert(oldname, newname); }
+		void mapCellStyle(const QString& oldname, const QString& newname)			{ m_cellStyles.insert(oldname, newname); }
+		void mapNoteStyle(const QString& oldname, const QString& newname)			{ m_noteStyles.insert(oldname, newname); }
+		void mapOpticalMarginSet(const QString& oldname, const QString& newname)	{ m_opticalMarginSets.insert(oldname, newname); }
 
-		void mapFonts(const QMap<QString, QString>& newnames)        { m_fonts = newnames; }
-		void mapPatterns(const QMap<QString, QString>& newnames)     { m_patterns = newnames; }
-		void mapFontfeatures(const QMap<QString, QString>& newnames) { m_fontfeatures = newnames; }
-		void mapColors(const QMap<QString, QString>& newnames)       { m_colors = newnames; }
-		void mapGradients(const QMap<QString, QString>& newnames)    { m_gradients = newnames; }
-		void mapStyles(const QMap<QString, QString>& newnames)       { m_pstyles = newnames; }
-		void mapCharStyles(const QMap<QString, QString>& newnames)   { m_cstyles = newnames; }
-		void mapLineStyles(const QMap<QString, QString>& newnames)   { m_linestyles = newnames; }
-		void mapTableStyles(const QMap<QString, QString>& newnames)  { m_tableStyles = newnames; }
-		void mapCellStyles(const QMap<QString, QString>& newnames)   { m_cellStyles = newnames; }
-		void mapNoteStyles(const QMap<QString, QString>& newnames)   { m_noteStyles = newnames; }
+		void mapFonts(const QMap<QString, QString>& newnames)				{ m_fonts = newnames; }
+		void mapPatterns(const QMap<QString, QString>& newnames)			{ m_patterns = newnames; }
+		void mapFontfeatures(const QMap<QString, QString>& newnames)		{ m_fontfeatures = newnames; }
+		void mapColors(const QMap<QString, QString>& newnames)				{ m_colors = newnames; }
+		void mapGradients(const QMap<QString, QString>& newnames)			{ m_gradients = newnames; }
+		void mapStyles(const QMap<QString, QString>& newnames)				{ m_pstyles = newnames; }
+		void mapCharStyles(const QMap<QString, QString>& newnames)			{ m_cstyles = newnames; }
+		void mapLineStyles(const QMap<QString, QString>& newnames)			{ m_linestyles = newnames; }
+		void mapTableStyles(const QMap<QString, QString>& newnames)			{ m_tableStyles = newnames; }
+		void mapCellStyles(const QMap<QString, QString>& newnames)			{ m_cellStyles = newnames; }
+		void mapNoteStyles(const QMap<QString, QString>& newnames)			{ m_noteStyles = newnames; }
+		void mapOpticalMarginSets(const QMap<QString, QString>& newnames)	{ m_opticalMarginSets = newnames; }
 
-		const QMap<QString, QString>& fonts() const        { return m_fonts; }
-		const QMap<QString, QString>& fontfeatures() const { return m_fontfeatures; }
-		const QMap<QString, QString>& patterns()  const    { return m_patterns; }
-		const QMap<QString, QString>& colors() const       { return m_colors; }
-		const QMap<QString, QString>& gradients() const    { return m_gradients; }
-		const QMap<QString, QString>& styles() const       { return m_pstyles; }
-		const QMap<QString, QString>& charStyles() const   { return m_cstyles; }
-		const QMap<QString, QString>& lineStyles() const   { return m_linestyles; }
-		const QMap<QString, QString>& tableStyles() const  { return m_tableStyles; }
-		const QMap<QString, QString>& cellStyles() const   { return m_cellStyles; }
-		const QMap<QString, QString>& noteStyles() const   { return m_noteStyles; }
+		const QMap<QString, QString>& fonts() const				{ return m_fonts; }
+		const QMap<QString, QString>& fontfeatures() const		{ return m_fontfeatures; }
+		const QMap<QString, QString>& patterns()  const			{ return m_patterns; }
+		const QMap<QString, QString>& colors() const			{ return m_colors; }
+		const QMap<QString, QString>& gradients() const			{ return m_gradients; }
+		const QMap<QString, QString>& styles() const			{ return m_pstyles; }
+		const QMap<QString, QString>& charStyles() const		{ return m_cstyles; }
+		const QMap<QString, QString>& lineStyles() const		{ return m_linestyles; }
+		const QMap<QString, QString>& tableStyles() const		{ return m_tableStyles; }
+		const QMap<QString, QString>& cellStyles() const		{ return m_cellStyles; }
+		const QMap<QString, QString>& noteStyles() const		{ return m_noteStyles; }
+		const QMap<QString, QString>& opticalMarginSets() const	{ return m_opticalMarginSets; }
 
-		QList<QString> fontNames() const         { return m_fonts.keys(); }
-		QList<QString> patternNames() const      { return m_patterns.keys(); }
-		QList<QString> fontfeaturesNames() const { return m_fontfeatures.keys(); }
-		QList<QString> colorNames() const        { return m_colors.keys(); }
-		QList<QString> gradientNames() const     { return m_gradients.keys(); }
-		QList<QString> styleNames() const        { return m_pstyles.keys(); }
-		QList<QString> charStyleNames() const    { return m_cstyles.keys(); }
-		QList<QString> lineStyleNames() const    { return m_linestyles.keys(); }
-		QList<QString> tableStyleNames() const   { return m_tableStyles.keys(); }
-		QList<QString> cellStyleNames() const    { return m_cellStyles.keys(); }
-		QList<QString> noteStyleNames() const    { return m_noteStyles.keys(); }
+		QList<QString> fontNames() const				{ return m_fonts.keys(); }
+		QList<QString> patternNames() const				{ return m_patterns.keys(); }
+		QList<QString> fontfeaturesNames() const		{ return m_fontfeatures.keys(); }
+		QList<QString> colorNames() const				{ return m_colors.keys(); }
+		QList<QString> gradientNames() const			{ return m_gradients.keys(); }
+		QList<QString> styleNames() const				{ return m_pstyles.keys(); }
+		QList<QString> charStyleNames() const			{ return m_cstyles.keys(); }
+		QList<QString> lineStyleNames() const			{ return m_linestyles.keys(); }
+		QList<QString> tableStyleNames() const			{ return m_tableStyles.keys(); }
+		QList<QString> cellStyleNames() const			{ return m_cellStyles.keys(); }
+		QList<QString> noteStyleNames() const			{ return m_noteStyles.keys(); }
+		QList<QString> opticalMarginSetNames() const	{ return m_opticalMarginSets.keys(); }
 
 		// modifies newNames so that forall x in both newNames.key() and in existingNames, newNames[x] will map to a new unique name
 		static void makeUnique(QMap<QString, QString>& newNames, const QList<QString> existingNames);
@@ -126,6 +131,7 @@
 		QMap<QString, QString> m_tableStyles;
 		QMap<QString, QString> m_cellStyles;
 		QMap<QString, QString> m_noteStyles;
+		QMap<QString, QString> m_opticalMarginSets;
 };
 
 #endif
Index: scribus/scribusdoc.cpp
===================================================================
--- scribus/scribusdoc.cpp	(Revision 26446)
+++ scribus/scribusdoc.cpp	(Arbeitskopie)
@@ -1227,7 +1227,7 @@
 	// replace names in styles...
 	for (int i = m_docParagraphStyles.count() - 1; i >= 0; --i)
 	{
-		if (newNames.styles().contains(m_docParagraphStyles[i].name()))
+		if (newNames.styles().contains(m_docParagraphStyles[i].name()) && !m_docParagraphStyles[i].isDefaultStyle())
 			m_docParagraphStyles.remove(i);
 		else
 			m_docParagraphStyles[i].replaceNamedResources(newNames);
@@ -1314,7 +1314,7 @@
 	}
 	if (!isLoading() && !(newNames.colors().isEmpty() && newNames.fonts().isEmpty() && newNames.patterns().isEmpty() 
 			&& newNames.styles().isEmpty() && newNames.charStyles().isEmpty() && newNames.lineStyles().isEmpty()
-			&& newNames.tableStyles().isEmpty() && newNames.cellStyles().isEmpty()))
+			&& newNames.tableStyles().isEmpty() && newNames.cellStyles().isEmpty() && newNames.opticalMarginSets().isEmpty()))
 		changed();
 }
 
@@ -9046,10 +9046,11 @@
 	itemSelection_ApplyCharStyle(newStyle, customSelection, "EFFECTS");
 }
 
-void ScribusDoc::itemSelection_SetOpticalMargins(int i, Selection* customSelection)
+void ScribusDoc::itemSelection_SetOpticalMargins(int i, const QString id, Selection* customSelection)
 {
 	ParagraphStyle newStyle;
-	newStyle.setOpticalMargins(i);
+	newStyle.setOpticalMarginSetId(id);
+	newStyle.setOpticalMargins(i);	
 	itemSelection_ApplyParagraphStyle(newStyle, customSelection);
 }
 
Index: scribus/scribusdoc.h
===================================================================
--- scribus/scribusdoc.h	(Revision 26446)
+++ scribus/scribusdoc.h	(Arbeitskopie)
@@ -49,6 +49,7 @@
 #include "nodeeditcontext.h"
 #include "notesstyles.h"
 #include "observable.h"
+#include "opticalmarginlookup.h"
 #include "pageitem.h"
 #include "pageitem_group.h"
 #include "pageitem_latexframe.h"
@@ -226,6 +227,9 @@
 	int marginPreset() const { return m_docPrefsData.docSetupPrefs.marginPreset; }
 	void setMarginPreset(int mp) { m_docPrefsData.docSetupPrefs.marginPreset = mp; }
 
+	OpticalMarginSets opticalMarginSets() { return m_docPrefsData.typoPrefs.opticalMarginSets; }
+	void setOpticalMarginSets(OpticalMarginSets sets) { m_docPrefsData.typoPrefs.opticalMarginSets = sets; }
+
 	TypoPrefs& typographicPrefs() { return m_docPrefsData.typoPrefs; }
 	GuidesPrefs& guidesPrefs() { return m_docPrefsData.guidesPrefs; }
 	ItemToolPrefs& itemToolPrefs() { return m_docPrefsData.itemToolPrefs; }
@@ -1156,7 +1160,7 @@
 	void itemSelection_SetUnderline(int pos, int wid, Selection* customSelection = nullptr);
 	void itemSelection_SetStrikethru(int pos, int wid, Selection* customSelection = nullptr);
 	void itemSelection_SetEffects(int s, Selection* customSelection = nullptr);
-	void itemSelection_SetOpticalMargins(int i, Selection* customSelection = nullptr);
+	void itemSelection_SetOpticalMargins(int i, const QString id, Selection* customSelection = nullptr);
 	void itemSelection_SetColorProfile(const QString& profileName, Selection* customSelection = nullptr);
 	void itemSelection_SetRenderIntent(int intentIndex, Selection* customSelection = nullptr);
 	void itemSelection_SetCompressionMethod(int cmIndex, Selection* customSelection = nullptr);
Index: scribus/styles/paragraphstyle.attrdefs.cxx
===================================================================
--- scribus/styles/paragraphstyle.attrdefs.cxx	(Revision 26446)
+++ scribus/styles/paragraphstyle.attrdefs.cxx	(Arbeitskopie)
@@ -57,3 +57,4 @@
 ATTRDEF(QString, backgroundColor, BackgroundColor, "None")
 ATTRDEF(double, backgroundShade, BackgroundShade, 100)
 ATTRDEF(int, hyphenConsecutiveLines, HyphenConsecutiveLines, 2)
+ATTRDEF(QString, opticalMarginSetId, OpticalMarginSetId, OpticalMarginLookup::instance().defaultSetId())
Index: scribus/styles/paragraphstyle.cpp
===================================================================
--- scribus/styles/paragraphstyle.cpp	(Revision 26446)
+++ scribus/styles/paragraphstyle.cpp	(Arbeitskopie)
@@ -219,10 +219,14 @@
 	if (backgroundColorName != CommonStrings::None)
 		lists.collectColor(backgroundColorName);
 
+	const QString& opticalMarginSet = opticalMarginSetId();
+	if (!opticalMarginSet.isEmpty())
+		lists.collectOpticalMarginSet(opticalMarginSet);
+
 	QString parEffectStyle = peCharStyleName();
 	if (parEffectStyle.length() > 0)
 	{
-		const CharStyle *peCharStyle = dynamic_cast<const CharStyle*>(m_cstyleContext.resolve(parEffectStyle));
+		const CharStyle* peCharStyle = dynamic_cast<const CharStyle*>(m_cstyleContext.resolve(parEffectStyle));
 		if (peCharStyle)
 			peCharStyle->getNamedResources(lists);
 		lists.collectCharStyle(parEffectStyle);
@@ -243,6 +247,9 @@
 	if (!inh_BackgroundColor && (it = newNames.colors().find(backgroundColor())) != newNames.colors().end())
 		setBackgroundColor(it.value());
 
+	if (!inh_OpticalMarginSetId && (it = newNames.opticalMarginSets().find(opticalMarginSetId())) != newNames.opticalMarginSets().end())
+		setOpticalMarginSetId(it.value());
+
 	if ((it = (newNames.charStyles().find(peCharStyleName()))) != newNames.charStyles().end())
 		setPeCharStyleName(it.value());
 	m_cstyle.replaceNamedResources(newNames);
@@ -358,7 +365,6 @@
 	return Tablist();
 }
 
-
 using namespace desaxe;
 
 const Xml_string ParagraphStyle::saxxDefaultElem("style");
Index: scribus/styles/paragraphstyle.h
===================================================================
--- scribus/styles/paragraphstyle.h	(Revision 26446)
+++ scribus/styles/paragraphstyle.h	(Arbeitskopie)
@@ -18,6 +18,7 @@
 
 #include "style.h"
 #include "charstyle.h"
+#include "opticalmarginlookup.h"
 #include "styles/stylecontextproxy.h"
 
 
Index: scribus/ui/opticalmarginswidget.cpp
===================================================================
--- scribus/ui/opticalmarginswidget.cpp	(Revision 26446)
+++ scribus/ui/opticalmarginswidget.cpp	(Arbeitskopie)
@@ -22,6 +22,8 @@
 	parentButton = new QToolButton();
 	parentButton->hide(); // only used for style manager
 
+	setsCombo = new QComboBox();
+
 	QHBoxLayout* mainLayout = new QHBoxLayout();
 	mainLayout->setSpacing(4);
 	mainLayout->setContentsMargins(0, 0, 0, 0);
@@ -29,6 +31,7 @@
 	mainLayout->addWidget(leftButton);
 	mainLayout->addWidget(rightButton);
 	mainLayout->addSpacerItem(new QSpacerItem(4, 0, QSizePolicy::Fixed));
+	mainLayout->addWidget(setsCombo);
 	mainLayout->addWidget(parentButton);
 	mainLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding));
 
@@ -40,6 +43,7 @@
 	connect(ScQApp, SIGNAL(iconSetChanged()), this, SLOT(iconSetChange()));
 	connect(rightButton, SIGNAL(clicked()), this, SIGNAL(opticalMarginChanged()));
 	connect(leftButton, SIGNAL(clicked()), this, SIGNAL(opticalMarginChanged()));
+	connect(setsCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(opticalMarginChanged()));
 }
 
 int OpticalMarginsWidget::opticalMargin()
@@ -86,6 +90,26 @@
 	blockSignals(blocked);
 }
 
+void OpticalMarginsWidget::setOpticalMarginSets(OpticalMarginSets sets)
+{
+	m_sets = sets;
+}
+
+void OpticalMarginsWidget::setOpticalMarginSetId(const QString id)
+{	
+	if (m_sets.size() <= 0)
+		return;
+
+	m_setId = m_sets.contains(id) ? id : m_sets.firstKey();
+
+	updateSetSelector();
+}
+
+const QString OpticalMarginsWidget::opticalMarginSetId()
+{
+	return setsCombo->currentData().toString();
+}
+
 void OpticalMarginsWidget::iconSetChange()
 {
 	IconManager &im = IconManager::instance();
@@ -103,9 +127,25 @@
 	QWidget::changeEvent(e);
 }
 
+void OpticalMarginsWidget::updateSetSelector()
+{
+	if (m_sets.size() <= 0)
+		return;
+
+	QSignalBlocker blockSets(setsCombo);
+	setsCombo->setVisible( m_sets.size() > 1 ? true : false );
+	setsCombo->clear();
+
+	for (auto [id, set] : m_sets.asKeyValueRange())
+		setsCombo->addItem(set.name, id);
+
+	int index = setsCombo->findData(m_setId);
+	setsCombo->setCurrentIndex(index);
+}
+
 void OpticalMarginsWidget::languageChange()
 {
-	setText(tr("Optical &Margins"));
+	setText( tr("Optical &Margins") );
 
 	leftButton->setToolTip( tr("Optical character offset on left side"));
 	rightButton->setToolTip( tr("Optical character offset on right side"));
Index: scribus/ui/opticalmarginswidget.h
===================================================================
--- scribus/ui/opticalmarginswidget.h	(Revision 26446)
+++ scribus/ui/opticalmarginswidget.h	(Arbeitskopie)
@@ -7,7 +7,9 @@
 #ifndef OPTICALMARGINSWIDGET_H
 #define OPTICALMARGINSWIDGET_H
 
+#include <QComboBox>
 #include <QToolButton>
+#include "opticalmarginlookup.h"
 #include "ui/widgets/form_widget.h"
 
 class ParagraphStyle;
@@ -25,13 +27,23 @@
 	QToolButton *leftButton = {nullptr};
 	QToolButton *rightButton = {nullptr};
 	QToolButton *parentButton = {nullptr};
+	QComboBox *setsCombo = {nullptr};
 
 	int opticalMargin();
 	void setOpticalMargin(int omt);
 
+	void setOpticalMarginSets(OpticalMarginSets sets);
+	OpticalMarginSets opticalMarginSets() { return m_sets; };
+
+	void setOpticalMarginSetId(const QString id);
+	const QString opticalMarginSetId();
+
 protected:
 
 	void changeEvent(QEvent *e) override;
+	void updateSetSelector();
+	OpticalMarginSets m_sets;
+	QString m_setId;
 
 public slots:
 
Index: scribus/ui/prefs_typography.cpp
===================================================================
--- scribus/ui/prefs_typography.cpp	(Revision 26446)
+++ scribus/ui/prefs_typography.cpp	(Arbeitskopie)
@@ -7,10 +7,14 @@
 
 #include "prefs_typography.h"
 #include "prefsstructs.h"
+#include "scribus.h"
 #include "scribusdoc.h"
+#include "stylemanager.h"
+#include "ui/smtextstyles.h"
 
-Prefs_Typography::Prefs_Typography(QWidget* parent, ScribusDoc* /*doc*/)
-	: Prefs_Pane(parent)
+Prefs_Typography::Prefs_Typography(QWidget* parent, ScribusDoc* doc)
+	: Prefs_Pane(parent),
+	  m_Doc(doc)
 {
 	setupUi(this);
 	languageChange();
@@ -17,6 +21,8 @@
 
 	m_caption = tr("Typography");
 	m_icon = "16/draw-text.png";
+
+	connect(opticalMarginsEditor, &OpticalMarginEditor::setDeleted, this, &Prefs_Typography::updateParagraphStyles);
 }
 
 Prefs_Typography::~Prefs_Typography() = default;
@@ -41,6 +47,21 @@
 	automaticLineSpacingSpinBox->setToolTip( tr( "Percentage increase over the font size for the line spacing" ) );
 }
 
+void Prefs_Typography::updateParagraphStyles(QString removedID, QString newID)
+{
+	if (!m_Doc)
+		return;
+
+	ResourceCollection res;
+	m_Doc->getNamedResources(res);
+	res.mapOpticalMarginSet(removedID, newID);
+	m_Doc->replaceNamedResources(res);
+
+	// We also need to update the Style Manager to load the updated paragraph styles.
+	// updateColorList() does what we want.
+	m_Doc->scMW()->styleMgr()->updateColorList();
+}
+
 void Prefs_Typography::restoreDefaults(struct ApplicationPrefs *prefsData)
 {
 	subscriptDisplacementSpinBox->setValue(prefsData->typoPrefs.valueSubScript);
@@ -53,6 +74,7 @@
 	strikeoutLineWidthSpinBox->setValue(prefsData->typoPrefs.valueStrikeThruWidth / 10.0);
 	smallcapsScalingSpinBox->setValue(prefsData->typoPrefs.valueSmallCaps);
 	automaticLineSpacingSpinBox->setValue(prefsData->typoPrefs.autoLineSpacing);
+	opticalMarginsEditor->setOpticalMarginSets(prefsData->typoPrefs.opticalMarginSets);
 }
 
 void Prefs_Typography::saveGuiToPrefs(struct ApplicationPrefs *prefsData) const
@@ -67,5 +89,6 @@
 	prefsData->typoPrefs.valueStrikeThruWidth = strikeoutLineWidthSpinBox->value() * 10.0;
 	prefsData->typoPrefs.valueSmallCaps = smallcapsScalingSpinBox->value();
 	prefsData->typoPrefs.autoLineSpacing = automaticLineSpacingSpinBox->value();
+	prefsData->typoPrefs.opticalMarginSets = opticalMarginsEditor->opticalMarginSets();
 }
 
Index: scribus/ui/prefs_typography.h
===================================================================
--- scribus/ui/prefs_typography.h	(Revision 26446)
+++ scribus/ui/prefs_typography.h	(Arbeitskopie)
@@ -25,8 +25,15 @@
 		void restoreDefaults(struct ApplicationPrefs *prefsData) override;
 		void saveGuiToPrefs(struct ApplicationPrefs *prefsData) const override;
 
+	protected:
+		ScribusDoc* m_Doc {nullptr};
+
 	public slots:
 		void languageChange();
+
+	private slots:
+		void updateParagraphStyles(QString removedID, QString newID);
+
 };
 
 #endif // PREFS_TYPOGRAPHY_H
Index: scribus/ui/propertywidget_alignment.cpp
===================================================================
--- scribus/ui/propertywidget_alignment.cpp	(Revision 26446)
+++ scribus/ui/propertywidget_alignment.cpp	(Arbeitskopie)
@@ -44,7 +44,7 @@
 
 	m_haveItem = tmp;
 
-	showOpticalMargins(newCurrent.opticalMargins());
+	showOpticalMargins(newCurrent.opticalMargins(), newCurrent.opticalMarginSetId());
 }
 
 void PropertyWidget_Alignment::setMainWindow(ScribusMainWindow* mw)
@@ -150,7 +150,6 @@
 	connect(tabsButton    , SIGNAL(clicked())           , this, SLOT(handleTabs()), Qt::UniqueConnection);
 	connect(flopWidget->flopGroup, SIGNAL(idClicked(int)), this, SLOT(handleFirstLinePolicy(int)));
 	connect(opticalMarginsWidget, SIGNAL(opticalMarginChanged()), this, SLOT(handleOpticalMargins()) );
-//	connect(opticalMarginsWidget->resetButton, SIGNAL(clicked()), this, SLOT(resetOpticalMargins()) );
 	connect(textAlignment , SIGNAL(State(int))   , this, SLOT(handleAlignment(int)));
 	connect(textVerticalAlignment, SIGNAL(State(int)), this, SLOT(handleVAlignment(int)));
 	connect(textDirection , SIGNAL(State(int))   , this, SLOT(handleDirection(int)));
@@ -161,7 +160,6 @@
 	disconnect(tabsButton    , SIGNAL(clicked())           , this, SLOT(handleTabs()));
 	disconnect(flopWidget->flopGroup, SIGNAL(idClicked(int)), this, SLOT(handleFirstLinePolicy(int)));
 	disconnect(opticalMarginsWidget, SIGNAL(opticalMarginChanged()), this, SLOT(handleOpticalMargins()) );
-//	disconnect(opticalMarginsWidget->resetButton, SIGNAL(clicked()), this, SLOT(resetOpticalMargins()) );
 	disconnect(textAlignment , SIGNAL(State(int))   , this, SLOT(handleAlignment(int)));
 	disconnect(textVerticalAlignment, SIGNAL(State(int)), this, SLOT(handleVAlignment(int)));
 	disconnect(textDirection , SIGNAL(State(int))   , this, SLOT(handleDirection(int)));
@@ -254,7 +252,7 @@
 		flopWidget->flopBaselineGrid->setChecked(true);
 }
 
-void PropertyWidget_Alignment::showOpticalMargins(int e)
+void PropertyWidget_Alignment::showOpticalMargins(int e, const QString &setId)
 {
 	if (!m_ScMW || m_ScMW->scriptIsRunning())
 		return;
@@ -261,6 +259,8 @@
 	bool tmp = m_haveItem;
 	m_haveItem = false;
 	opticalMarginsWidget->setOpticalMargin(e);
+	opticalMarginsWidget->setOpticalMarginSets(m_doc->opticalMarginSets());
+	opticalMarginsWidget->setOpticalMarginSetId(setId);
 	m_haveItem = tmp;
 }
 
@@ -389,8 +389,6 @@
 	if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
 		return;
 
-	int omt(opticalMarginsWidget->opticalMargin());
-
 	PageItem *item = m_item;
 	if (m_doc->appMode == modeEditTable)
 		item = m_item->asTable()->activeCell().textFrame();
@@ -398,25 +396,10 @@
 	{
 		Selection tempSelection(this, false);
 		tempSelection.addItem(item, true);
-		m_doc->itemSelection_SetOpticalMargins(omt, &tempSelection);
+		m_doc->itemSelection_SetOpticalMargins(opticalMarginsWidget->opticalMargin(), opticalMarginsWidget->opticalMarginSetId(), &tempSelection);
 	}
 }
 
-// void PropertyWidget_Alignment::resetOpticalMargins()
-// {
-// 	// if (!m_doc || !m_item || !m_ScMW || m_ScMW->scriptIsRunning())
-// 	// 	return;
-// 	// PageItem *item = m_item;
-// 	// if (m_doc->appMode == modeEditTable)
-// 	// 	item = m_item->asTable()->activeCell().textFrame();
-// 	// if (item != nullptr)
-// 	// {
-// 	// 	Selection tempSelection(this, false);
-// 	// 	tempSelection.addItem(item, true);
-// 	// 	m_doc->itemSelection_resetOpticalMargins(&tempSelection);
-// 	// }
-// }
-
 void PropertyWidget_Alignment::changeEvent(QEvent *e)
 {
 	if (e->type() == QEvent::LanguageChange)
Index: scribus/ui/propertywidget_alignment.h
===================================================================
--- scribus/ui/propertywidget_alignment.h	(Revision 26446)
+++ scribus/ui/propertywidget_alignment.h	(Arbeitskopie)
@@ -53,7 +53,7 @@
 	void toggleLabelVisibility(bool v);
 
 	void showFirstLinePolicy(FirstLineOffsetPolicy f);
-	void showOpticalMargins(int e);
+	void showOpticalMargins(int e, const QString &setId);
 	void showAlignment(int e);
 	void showDirection(int e);
 
@@ -62,8 +62,6 @@
 	void handleTabs();
 	void handleFirstLinePolicy(int);
 	void handleOpticalMargins();
-//	void resetOpticalMargins();
-
 	void handleAlignment(int a);
 	void handleVAlignment(int a);
 	void handleDirection(int d);
Index: scribus/ui/smopticalmarginswidget.cpp
===================================================================
--- scribus/ui/smopticalmarginswidget.cpp	(Revision 26446)
+++ scribus/ui/smopticalmarginswidget.cpp	(Arbeitskopie)
@@ -54,12 +54,50 @@
 	connect(parentButton, SIGNAL(pressed()), this, SLOT(pbPressed()));
 }
 
+void SMOpticalMarginsWidget::setOpticalMarginSetId(const QString o)
+{
+	disconnect(parentButton, SIGNAL(pressed()), this, SLOT(pbPressed()));
+	disconnect(this, SIGNAL(opticalMarginChanged()), this, SLOT(styleChanged()));
+
+	m_hasParent = false;
+	parentButton->hide();
+	m_pSetId = "";
+
+	OpticalMarginsWidget::setOpticalMarginSetId(o);
+
+	connect(this, SIGNAL(opticalMarginChanged()), this, SLOT(styleChanged()));
+	connect(parentButton, SIGNAL(pressed()), this, SLOT(pbPressed()));
+}
+
+void SMOpticalMarginsWidget::setOpticalMarginSetId(const QString o, const QString ps, bool isParentValue)
+{
+	disconnect(parentButton, SIGNAL(pressed()), this, SLOT(pbPressed()));
+	disconnect(this, SIGNAL(opticalMarginChanged()), this, SLOT(styleChanged()));
+
+	if (!ps.isEmpty())
+	{
+		m_hasParent = true;
+		parentButton->setVisible(!isParentValue);
+		m_pSetId = ps;
+	}
+	else
+		m_hasParent = false;
+
+	OpticalMarginsWidget::setOpticalMarginSetId(o);
+
+	connect(this, SIGNAL(opticalMarginChanged()), this, SLOT(styleChanged()));
+	connect(parentButton, SIGNAL(pressed()), this, SLOT(pbPressed()));
+}
+
 bool SMOpticalMarginsWidget::useParentValue()
 {
 	bool ret = m_useParentStyle;
 	m_useParentStyle = false;
 	if (ret)
+	{
 		setOpticalMargins(m_pStyle, m_pStyle, true);
+		setOpticalMarginSetId(m_pSetId, m_pSetId, true);
+	}
 
 	return ret;
 }
Index: scribus/ui/smopticalmarginswidget.h
===================================================================
--- scribus/ui/smopticalmarginswidget.h	(Revision 26446)
+++ scribus/ui/smopticalmarginswidget.h	(Arbeitskopie)
@@ -20,6 +20,9 @@
 	void setOpticalMargins(int o);
 	void setOpticalMargins(int o, int ps, bool isParentValue);
 
+	void setOpticalMarginSetId(const QString o);
+	void setOpticalMarginSetId(const QString o, const QString ps, bool isParentValue);
+
 	bool useParentValue();
 
 private:
@@ -26,6 +29,7 @@
 	bool m_hasParent = false;
 	bool m_useParentStyle = false;
 	int m_pStyle = -1;
+	QString m_pSetId;
 
 private slots:
 	void styleChanged();
Index: scribus/ui/smpstylewidget.cpp
===================================================================
--- scribus/ui/smpstylewidget.cpp	(Revision 26446)
+++ scribus/ui/smpstylewidget.cpp	(Arbeitskopie)
@@ -224,6 +224,8 @@
 	//fillNumerationsCombo();
 	//fillNumRestartCombo();
 
+	optMarginWidget->setOpticalMarginSets(m_Doc->opticalMarginSets());
+
 	if (m_hasParent)
 	{
 		lineSpacingMode->setCurrentItem(pstyle->lineSpacingMode(), pstyle->isInhLineSpacingMode());
@@ -231,7 +233,8 @@
 		
 //		optMarginCombo->setCurrentItemByData( pstyle->opticalMargins(),  pstyle->isInhOpticalMargins() );
 //		optMarginCombo->setParentItem(optMarginCombo->getItemIndexForData( parent->opticalMargins()));
-		optMarginWidget->setOpticalMargins(pstyle->opticalMargins(), parent->opticalMargins(), pstyle->isInhOpticalMargins());
+		optMarginWidget->setOpticalMargins(pstyle->opticalMargins(), parent->opticalMargins(), pstyle->isInhOpticalMargins());		
+		optMarginWidget->setOpticalMarginSetId(pstyle->opticalMarginSetId(), parent->opticalMarginSetId(), pstyle->isInhOpticalMarginSetId());
 		
 		minSpaceSpin->setValue(pstyle->minWordTracking() * 100.0,  pstyle->isInhMinWordTracking());
 		minSpaceSpin->setParentValue(parent->minWordTracking());
@@ -350,7 +353,8 @@
 		spaceAbove->setValue(pstyle->gapBefore());
 		spaceBelow->setValue(pstyle->gapAfter());
 //		optMarginCombo->setCurrentItemByData( pstyle->opticalMargins() );
-		optMarginWidget->setOpticalMargins(pstyle->opticalMargins());
+		optMarginWidget->setOpticalMargins(pstyle->opticalMargins());
+		optMarginWidget->setOpticalMarginSetId(pstyle->opticalMarginSetId());
 		minSpaceSpin->setValue(pstyle->minWordTracking() * 100.0);
 		minGlyphExtSpin->setValue(pstyle->minGlyphExtension() * 100.0);
 		maxGlyphExtSpin->setValue(pstyle->maxGlyphExtension() * 100.0);
@@ -658,7 +662,9 @@
 //		}
 //	}
 //	optMarginCombo->setCurrentItemByData(o);
-	optMarginWidget->setOpticalMargins(pstyles[0]->opticalMargins());
+	optMarginWidget->setOpticalMargins(pstyles[0]->opticalMargins());
+	optMarginWidget->setOpticalMarginSets(m_Doc->opticalMarginSets());
+	optMarginWidget->setOpticalMarginSetId(pstyles[0]->opticalMarginSetId());
 }
 
 void SMPStyleWidget::showMinSpace(const QList< ParagraphStyle * > & pstyles)
@@ -870,21 +876,21 @@
 	bulletStrEdit->lineEdit()->setText(chars);
 }
 
-void SMPStyleWidget::slotParentParEffects()
+void SMPStyleWidget::slotParentParEffects()
 {
-	parentParEffectsButton->hide();
+	parentParEffectsButton->hide();
 
-	if (m_parentDC)
-		setParagraphEffect(1);
-	else if (m_parentBul)
-		setParagraphEffect(2);
-	else if (m_parentNum)
-		setParagraphEffect(3);
+	if (m_parentDC)
+		setParagraphEffect(1);
+	else if (m_parentBul)
+		setParagraphEffect(2);
+	else if (m_parentNum)
+		setParagraphEffect(3);
 	else
-		setParagraphEffect(0);
+		setParagraphEffect(0);
 
 	emit useParentParaEffects();
-
+
 }
 
 void SMPStyleWidget::openEnhanced()
@@ -938,178 +944,178 @@
 	if (updateFlags & reqNumUpdate)
 		fillNumerationsCombo();
 }
-
-void SMPStyleWidget::fillBulletStrEditCombo()
-{
-	bulletStrEdit->clear();
-	bulletStrEdit->addItem(QChar(0x2022));
-	bulletStrEdit->addItem("*");
-	bulletStrEdit->addItem(QChar(0x2013));
-	bulletStrEdit->setMinimumWidth(50);
-	if (bulletStrEdit->currentText().isEmpty())
-		bulletStrEdit->setEditText(QChar(0x2022));
-}
-
-void SMPStyleWidget::fillNumerationsCombo()
-{
-	QStringList numNames;
-	const auto numerationKeys = m_Doc->numerations.keys();
-	for (const QString& numName : numerationKeys)
-	{
-		if (numName.isEmpty())
-			continue;
-		numNames.append(numName);
-	}
-	numNames.sort();
-	numComboBox->clear();
-	numComboBox->insertItems(0, numNames);
-	numComboBox->setCurrentItem(0);
-}
-
-void SMPStyleWidget::fillNumRestartCombo()
-{
-	numRestartCombo->clear();
-	numRestartCombo->addItem(tr("Document"), static_cast<int>(NSRdocument));
-	numRestartCombo->addItem(tr("Story") , static_cast<int>(NSRstory));
-}
-
-void SMPStyleWidget::fillPECombo()
-{
-	QSignalBlocker sb(peCombo);
-	int currIndex = peCombo->currentIndex();
-	peCombo->clear();
-	peCombo->addItem(tr("No Paragraph Effects"), -1);
-	peCombo->addItem(tr("Drop Caps"), 0);
-	peCombo->addItem(tr("Bulleted List"), 1);
-	peCombo->addItem(tr("Numbered List"), 2);
-	peCombo->setCurrentIndex(currIndex);
-}
-
-void SMPStyleWidget::setParagraphEffect(int index)
-{
-	QSignalBlocker sigPECombo(peCombo);
-
-	peCombo->setCurrentIndex(index);
-	int id = peCombo->currentIndex();
-
-	if (id == 1 || id == 2 || id == 3)
-	{
-		stackedWidget->setCurrentIndex(id - 1);
-		stackedWidget->setVisible(true);
-		peGroup->setVisible(true);
-
-		if (id == 2) // Bullet List
-		{
-			if (bulletStrEdit->currentText().isEmpty())
-				bulletStrEdit->setEditText(bulletStrEdit->itemText(0));
-		}
-		else if (id == 3) // Numbered List
-		{
-			if (numComboBox->currentIndex() < 0)
-				numComboBox->setCurrentIndex(0);
-		}
-	}
-	else // No effect
-	{
-		stackedWidget->setVisible(false);
-		peGroup->setVisible(false);
-		peCombo->setCurrentIndex(0);
-	}
-}
-
-void SMPStyleWidget::showDropCap(const QList<ParagraphStyle*> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
-{
-	bool dc = pstyles[0]->hasDropCap();
-	for (int i = 0; i < pstyles.count(); ++i)
-	{
-		if (dc != pstyles[i]->hasDropCap())
-		{
-			dc = false;
-			break;
-		}
-	}
-
-	if (dc)
-		setParagraphEffect(1);
-
-	int lines = -1;
-	for (int i = 0; i < pstyles.count(); ++i)
-	{
-		if (lines > -1 && pstyles[i]->dropCapLines() != lines)
-		{
-			lines = -1;
-			break;
-		}
-		lines = pstyles[i]->dropCapLines();
-	}
-	if (lines == -1)
-		dropCapLines->clear();
-	else
-		dropCapLines->setValue(lines);
-}
-
-void SMPStyleWidget::showBullet(const QList<ParagraphStyle *> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
-{
-//	double unitRatio = unitGetRatioFromIndex(unitIndex);
-
-	bool hb = pstyles[0]->hasBullet();
-	for (int i = 0; i < pstyles.count(); ++i)
-	{
-		if (hb != pstyles[i]->hasBullet())
-		{
-			hb = false;
-			break;
-		}
-	}
-
-	if (hb)
-		setParagraphEffect(2);
-
-	QString chStr = pstyles[0]->bulletStr();
-	for (int i = 0; i < pstyles.count(); ++i)
-	{
-		if (chStr != pstyles[i]->bulletStr())
-		{
-			chStr.clear();
-			break;
-		}
-		chStr = pstyles[i]->bulletStr();
-	}
-	bulletStrEdit->setEditText(chStr);
-}
-
-void SMPStyleWidget::showNumeration(const QList<ParagraphStyle *> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
-{
-
-	QString prefix = pstyles[0]->numPrefix();
-	for (int i = 0; i < pstyles.count(); ++i)
-	{
-		if (prefix != pstyles[i]->numPrefix())
-		{
-			prefix.clear();
-			break;
-		}
-		prefix = pstyles[i]->numPrefix();
-	}
-	numPrefix->setText(prefix);
-
-	QString suffix = pstyles[0]->numSuffix();
-	for (int i = 0; i < pstyles.count(); ++i)
-	{
-		if (suffix != pstyles[i]->numSuffix())
-		{
-			suffix.clear();
-			break;
-		}
-		suffix = pstyles[i]->numSuffix();
-	}
-	numSuffix->setText(suffix);
-}
-
-void SMPStyleWidget::handleParEffectUse(int index)
-{
-	if (m_hasParent)
-		parentParEffectsButton->show();
-
-	setParagraphEffect(index);
-}
+
+void SMPStyleWidget::fillBulletStrEditCombo()
+{
+	bulletStrEdit->clear();
+	bulletStrEdit->addItem(QChar(0x2022));
+	bulletStrEdit->addItem("*");
+	bulletStrEdit->addItem(QChar(0x2013));
+	bulletStrEdit->setMinimumWidth(50);
+	if (bulletStrEdit->currentText().isEmpty())
+		bulletStrEdit->setEditText(QChar(0x2022));
+}
+
+void SMPStyleWidget::fillNumerationsCombo()
+{
+	QStringList numNames;
+	const auto numerationKeys = m_Doc->numerations.keys();
+	for (const QString& numName : numerationKeys)
+	{
+		if (numName.isEmpty())
+			continue;
+		numNames.append(numName);
+	}
+	numNames.sort();
+	numComboBox->clear();
+	numComboBox->insertItems(0, numNames);
+	numComboBox->setCurrentItem(0);
+}
+
+void SMPStyleWidget::fillNumRestartCombo()
+{
+	numRestartCombo->clear();
+	numRestartCombo->addItem(tr("Document"), static_cast<int>(NSRdocument));
+	numRestartCombo->addItem(tr("Story") , static_cast<int>(NSRstory));
+}
+
+void SMPStyleWidget::fillPECombo()
+{
+	QSignalBlocker sb(peCombo);
+	int currIndex = peCombo->currentIndex();
+	peCombo->clear();
+	peCombo->addItem(tr("No Paragraph Effects"), -1);
+	peCombo->addItem(tr("Drop Caps"), 0);
+	peCombo->addItem(tr("Bulleted List"), 1);
+	peCombo->addItem(tr("Numbered List"), 2);
+	peCombo->setCurrentIndex(currIndex);
+}
+
+void SMPStyleWidget::setParagraphEffect(int index)
+{
+	QSignalBlocker sigPECombo(peCombo);
+
+	peCombo->setCurrentIndex(index);
+	int id = peCombo->currentIndex();
+
+	if (id == 1 || id == 2 || id == 3)
+	{
+		stackedWidget->setCurrentIndex(id - 1);
+		stackedWidget->setVisible(true);
+		peGroup->setVisible(true);
+
+		if (id == 2) // Bullet List
+		{
+			if (bulletStrEdit->currentText().isEmpty())
+				bulletStrEdit->setEditText(bulletStrEdit->itemText(0));
+		}
+		else if (id == 3) // Numbered List
+		{
+			if (numComboBox->currentIndex() < 0)
+				numComboBox->setCurrentIndex(0);
+		}
+	}
+	else // No effect
+	{
+		stackedWidget->setVisible(false);
+		peGroup->setVisible(false);
+		peCombo->setCurrentIndex(0);
+	}
+}
+
+void SMPStyleWidget::showDropCap(const QList<ParagraphStyle*> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
+{
+	bool dc = pstyles[0]->hasDropCap();
+	for (int i = 0; i < pstyles.count(); ++i)
+	{
+		if (dc != pstyles[i]->hasDropCap())
+		{
+			dc = false;
+			break;
+		}
+	}
+
+	if (dc)
+		setParagraphEffect(1);
+
+	int lines = -1;
+	for (int i = 0; i < pstyles.count(); ++i)
+	{
+		if (lines > -1 && pstyles[i]->dropCapLines() != lines)
+		{
+			lines = -1;
+			break;
+		}
+		lines = pstyles[i]->dropCapLines();
+	}
+	if (lines == -1)
+		dropCapLines->clear();
+	else
+		dropCapLines->setValue(lines);
+}
+
+void SMPStyleWidget::showBullet(const QList<ParagraphStyle *> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
+{
+//	double unitRatio = unitGetRatioFromIndex(unitIndex);
+
+	bool hb = pstyles[0]->hasBullet();
+	for (int i = 0; i < pstyles.count(); ++i)
+	{
+		if (hb != pstyles[i]->hasBullet())
+		{
+			hb = false;
+			break;
+		}
+	}
+
+	if (hb)
+		setParagraphEffect(2);
+
+	QString chStr = pstyles[0]->bulletStr();
+	for (int i = 0; i < pstyles.count(); ++i)
+	{
+		if (chStr != pstyles[i]->bulletStr())
+		{
+			chStr.clear();
+			break;
+		}
+		chStr = pstyles[i]->bulletStr();
+	}
+	bulletStrEdit->setEditText(chStr);
+}
+
+void SMPStyleWidget::showNumeration(const QList<ParagraphStyle *> &pstyles, const QList<CharStyle> &cstyles, int unitIndex)
+{
+
+	QString prefix = pstyles[0]->numPrefix();
+	for (int i = 0; i < pstyles.count(); ++i)
+	{
+		if (prefix != pstyles[i]->numPrefix())
+		{
+			prefix.clear();
+			break;
+		}
+		prefix = pstyles[i]->numPrefix();
+	}
+	numPrefix->setText(prefix);
+
+	QString suffix = pstyles[0]->numSuffix();
+	for (int i = 0; i < pstyles.count(); ++i)
+	{
+		if (suffix != pstyles[i]->numSuffix())
+		{
+			suffix.clear();
+			break;
+		}
+		suffix = pstyles[i]->numSuffix();
+	}
+	numSuffix->setText(suffix);
+}
+
+void SMPStyleWidget::handleParEffectUse(int index)
+{
+	if (m_hasParent)
+		parentParEffectsButton->show();
+
+	setParagraphEffect(index);
+}
Index: scribus/ui/smtextstyles.cpp
===================================================================
--- scribus/ui/smtextstyles.cpp	(Revision 26446)
+++ scribus/ui/smtextstyles.cpp	(Arbeitskopie)
@@ -230,6 +230,7 @@
 	ParagraphStyle p;
 	p.setDefaultStyle(false);
 	p.setName(s);
+	p.setOpticalMarginSetId(m_doc->opticalMarginSets().firstKey());
 	p.charStyle().setLanguage(m_doc->language());
 	m_tmpStyles.create(p);
 	return s;
@@ -508,14 +509,11 @@
 
 	connect(m_pwidget, SIGNAL(useParentParaEffects()), this, SLOT(slotParentParaEffects()));
 	connect(m_pwidget->peCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPargraphEffects(int)));
-//	connect(m_pwidget->dropCapsBox, SIGNAL(toggled(bool)), this, SLOT(slotDropCap(bool)));
 	connect(m_pwidget->dropCapLines, SIGNAL(valueChanged(int)), this, SLOT(slotDropCapLines(int)));
 	connect(m_pwidget->parEffectOffset, SIGNAL(valueChanged(double)), this, SLOT(slotParEffectOffset()));
 	connect(m_pwidget->parEffectIndentBox, SIGNAL(toggled(bool)), this, SLOT(slotParEffectIndent(bool)));
 	connect(m_pwidget->parEffectCharStyleCombo, SIGNAL(activated(int)), this, SLOT(slotParEffectCharStyle(int)));
-//	connect(m_pwidget->bulletBox, SIGNAL(toggled(bool)), this, SLOT(slotBullet(bool)));
 	connect(m_pwidget->bulletStrEdit, SIGNAL(editTextChanged(QString)), this, SLOT(slotBulletStr(QString)));
-//	connect(m_pwidget->numBox, SIGNAL(toggled(bool)), this, SLOT(slotNumeration(bool)));
 	connect(m_pwidget->numComboBox, SIGNAL(textActivated(QString)), this, SLOT(slotNumName(QString)));
 	connect(m_pwidget->numLevelSpin, SIGNAL(valueChanged(int)), this, SLOT(slotNumLevel(int)));
 	connect(m_pwidget->numFormatCombo, SIGNAL(activated(int)), this, SLOT(slotNumFormat(int)));
@@ -553,10 +551,6 @@
 	connect(m_pwidget->cpage->effects_->UnderlineVal->LWidth, SIGNAL(valueChanged(double)), this, SLOT(slotEffectProperties()));
 	connect(m_pwidget->cpage->effects_->StrikeVal->LPos, SIGNAL(valueChanged(double)), this, SLOT(slotEffectProperties()));
 	connect(m_pwidget->cpage->effects_->StrikeVal->LWidth, SIGNAL(valueChanged(double)), this, SLOT(slotEffectProperties()));
-	// connect(m_pwidget->cpage->fillColor_, SIGNAL(currentTextChanged(QString)), this, SLOT(slotFillColor()));
-	// connect(m_pwidget->cpage->fillShade_, SIGNAL(clicked()), this, SLOT(slotFillShade()));
-	// connect(m_pwidget->cpage->strokeColor_, SIGNAL(currentTextChanged(QString)), this, SLOT(slotStrokeColor()));
-	// connect(m_pwidget->cpage->strokeShade_, SIGNAL(clicked()), this, SLOT(slotStrokeShade()));
 	connect(m_pwidget->cpage->language_, SIGNAL(activated(int)), this, SLOT(slotLanguage()));
 	connect(m_pwidget->cpage->fontSize_, SIGNAL(valueChanged(double)), this, SLOT(slotFontSize()));
 	connect(m_pwidget->cpage->fontHScale_, SIGNAL(valueChanged(double)), this, SLOT(slotScaleH()));
@@ -565,8 +559,6 @@
 	connect(m_pwidget->cpage->widthSpaceSpin, SIGNAL(valueChanged(double)), this, SLOT(slotWordTracking()));
 	connect(m_pwidget->cpage->baselineOffset_, SIGNAL(valueChanged(double)), this, SLOT(slotBaselineOffset()));
 	connect(m_pwidget->cpage->parentCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(slotCharParentChanged(QString)));
-	// connect(m_pwidget->cpage->backColor_, SIGNAL(currentTextChanged(QString)), this, SLOT(slotBackColor()));
-	// connect(m_pwidget->cpage->backShade_, SIGNAL(clicked()), this, SLOT(slotBackShade()));
 
 	connect(m_pwidget->cpage->textColor->colorButton, SIGNAL(colorChanged()), this, SLOT(slotFillColor()));
 	connect(m_pwidget->cpage->textColor->parentButton, SIGNAL(clicked()), this, SLOT(slotFillColor()));
@@ -612,14 +604,11 @@
 
 	disconnect(m_pwidget, SIGNAL(useParentParaEffects()), this, SLOT(slotParentParaEffects()));
 	disconnect(m_pwidget->peCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotPargraphEffects(int)));
-//	disconnect(m_pwidget->dropCapsBox, SIGNAL(toggled(bool)), this, SLOT(slotDropCap(bool)));
 	disconnect(m_pwidget->dropCapLines, SIGNAL(valueChanged(int)), this, SLOT(slotDropCapLines(int)));
 	disconnect(m_pwidget->parEffectOffset, SIGNAL(valueChanged(double)), this, SLOT(slotParEffectOffset()));
 	disconnect(m_pwidget->parEffectIndentBox, SIGNAL(toggled(bool)), this, SLOT(slotParEffectIndent(bool)));
 	disconnect(m_pwidget->parEffectCharStyleCombo, SIGNAL(activated(int)), this, SLOT(slotParEffectCharStyle(int)));
-//	disconnect(m_pwidget->bulletBox, SIGNAL(toggled(bool)), this, SLOT(slotBullet(bool)));
 	disconnect(m_pwidget->bulletStrEdit, SIGNAL(editTextChanged(QString)), this, SLOT(slotBulletStr(QString)));
-//	disconnect(m_pwidget->numBox, SIGNAL(toggled(bool)), this, SLOT(slotNumeration(bool)));
 	disconnect(m_pwidget->numComboBox, SIGNAL(textActivated(QString)), this, SLOT(slotNumName(QString)));
 	disconnect(m_pwidget->numFormatCombo, SIGNAL(activated(int)), this, SLOT(slotNumFormat(int)));
 	disconnect(m_pwidget->numLevelSpin, SIGNAL(valueChanged(int)), this, SLOT(slotNumLevel(int)));
@@ -655,10 +644,6 @@
 	disconnect(m_pwidget->cpage->effects_->UnderlineVal->LWidth, SIGNAL(valueChanged(double)), this, SLOT(slotEffectProperties()));
 	disconnect(m_pwidget->cpage->effects_->StrikeVal->LPos, SIGNAL(valueChanged(double)), this, SLOT(slotEffectProperties()));
 	disconnect(m_pwidget->cpage->effects_->StrikeVal->LWidth, SIGNAL(valueChanged(double)), this, SLOT(slotEffectProperties()));
-	// disconnect(m_pwidget->cpage->fillColor_, SIGNAL(currentTextChanged(QString)), this, SLOT(slotFillColor()));
-	// disconnect(m_pwidget->cpage->fillShade_, SIGNAL(clicked()), this, SLOT(slotFillShade()));
-	// disconnect(m_pwidget->cpage->strokeColor_, SIGNAL(currentTextChanged(QString)), this, SLOT(slotStrokeColor()));
-	// disconnect(m_pwidget->cpage->strokeShade_, SIGNAL(clicked()), this, SLOT(slotStrokeShade()));
 	disconnect(m_pwidget->cpage->language_, SIGNAL(activated(int)), this, SLOT(slotLanguage()));
 	disconnect(m_pwidget->cpage->fontSize_, SIGNAL(valueChanged(double)), this, SLOT(slotFontSize()));
 	disconnect(m_pwidget->cpage->fontHScale_, SIGNAL(valueChanged(double)), this, SLOT(slotScaleH()));
@@ -667,8 +652,6 @@
 	disconnect(m_pwidget->cpage->widthSpaceSpin, SIGNAL(valueChanged(double)), this, SLOT(slotWordTracking()));
 	disconnect(m_pwidget->cpage->baselineOffset_, SIGNAL(valueChanged(double)), this, SLOT(slotBaselineOffset()));
 	disconnect(m_pwidget->cpage->parentCombo, SIGNAL(currentTextChanged(QString)), this, SLOT(slotCharParentChanged(QString)));
-	// disconnect(m_pwidget->cpage->backColor_, SIGNAL(currentTextChanged(QString)), this, SLOT(slotBackColor()));
-	// disconnect(m_pwidget->cpage->backShade_, SIGNAL(clicked()), this, SLOT(slotBackShade()));
 
 	disconnect(m_pwidget->cpage->textColor->colorButton, SIGNAL(colorChanged()), this, SLOT(slotFillColor()));
 	disconnect(m_pwidget->cpage->textColor->parentButton, SIGNAL(clicked()), this, SLOT(slotFillColor()));
@@ -796,23 +779,21 @@
 	ParagraphStyle::OpticalMarginType omt( static_cast<ParagraphStyle::OpticalMarginType>(m_pwidget->optMarginWidget->opticalMargin()));
 	if (m_pwidget->optMarginWidget->useParentValue())
 		for (int i = 0; i < m_selection.count(); ++i)
+		{
 			m_selection[i]->resetOpticalMargins();
+			m_selection[i]->resetOpticalMarginSetId();
+		}
 	else
 		for (int i = 0; i < m_selection.count(); ++i)
-			m_selection[i]->setOpticalMargins(omt);
+		{
+			m_selection[i]->setOpticalMarginSetId(m_pwidget->optMarginWidget->opticalMarginSetId());
+			m_selection[i]->setOpticalMargins(omt);			
+		}
 
 	slotSelectionDirty();
 
 }
 
-void SMParagraphStyle::slotParentOpticalMargin()
-{
-	for (int i = 0; i < m_selection.count(); ++i)
-		m_selection[i]->resetOpticalMargins();
-
-	slotSelectionDirty();
-}
-
 void SMParagraphStyle::slotMinSpace()
 {
 	if (m_pwidget->minSpaceSpin->useParentValue())
Index: scribus/ui/smtextstyles.h
===================================================================
--- scribus/ui/smtextstyles.h	(Revision 26446)
+++ scribus/ui/smtextstyles.h	(Arbeitskopie)
@@ -97,7 +97,6 @@
 	void slotDirection();
 	void slotOpticalMargin(int i);
 	void slotOpticalMarginSelector();
-	void slotParentOpticalMargin();
 	void slotMinSpace();
 	void slotMinGlyphExt();
 	void slotMaxGlyphExt();
Index: scribus/ui/stylemanager.cpp
===================================================================
--- scribus/ui/stylemanager.cpp	(Revision 26446)
+++ scribus/ui/stylemanager.cpp	(Arbeitskopie)
@@ -473,6 +473,9 @@
 		QStringList neededColors;
 		neededColors.clear();
 
+		QStringList neededOpticalMarginSets;
+		neededOpticalMarginSets.clear();
+
 		foreach (const QString& aStyle, dia2->paragraphStyles())
 		{
 			ParagraphStyle& sty(tmpParaStyles[tmpParaStyles.find(aStyle)]);
@@ -493,6 +496,9 @@
 				neededColors.append(sty.charStyle().strokeColor());
 			if ((!m_doc->PageColors.contains(sty.charStyle().fillColor())) && (!neededColors.contains(sty.charStyle().fillColor())))
 				neededColors.append(sty.charStyle().fillColor());
+
+			if ((!m_doc->opticalMarginSets().contains(sty.opticalMarginSetId())) && (!neededOpticalMarginSets.contains(sty.opticalMarginSetId())))
+				neededOpticalMarginSets.append(sty.opticalMarginSetId());
 		}
 
 		foreach (const QString& aStyle, dia2->characterStyles())
@@ -554,6 +560,11 @@
 				}
 			}
 		}
+
+		if (!neededOpticalMarginSets.isEmpty())
+		{
+			// TODO: Load missing optical margin sets from doc
+		}
 	}
 	delete dia2;
 // Start hack part 2
Index: scribus/util_text.cpp
===================================================================
--- scribus/util_text.cpp	(Revision 26446)
+++ scribus/util_text.cpp	(Arbeitskopie)
@@ -94,3 +94,29 @@
 	return QString(xml.c_str());
 }
 
+
+const QString stringToUnicode(const QString &text)
+{
+	QString out;
+
+	for (auto c : text)
+		out += QString("U+%1,").arg(c.unicode(), 4, 16, QChar('0')).toUpper();
+
+	return out.mid(0, out.length() -1);
+
+}
+
+const QString unicodeToString(const QString &text)
+{
+	QString out;
+	for (const auto &str : text.split(",", Qt::SkipEmptyParts))
+	{
+		QString tmp(str);
+		tmp.remove("U+");
+
+		bool ok;
+		out += QChar(tmp.toInt(&ok, 16));
+	}
+
+	return out;
+}
Index: scribus/util_text.h
===================================================================
--- scribus/util_text.h	(Revision 26446)
+++ scribus/util_text.h	(Arbeitskopie)
@@ -30,4 +30,7 @@
 //returns string with saxed story
 QString SCRIBUS_API saxedText(StoryText* story);
 
+const QString SCRIBUS_API stringToUnicode(const QString &text);
+const QString SCRIBUS_API unicodeToString(const QString &text);
+
 #endif
